2 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
3 * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the names of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include <linux/device.h>
35 #include <linux/dmi.h>
36 #include <linux/i2c.h>
37 #include <linux/i2c-mux.h>
39 #include <linux/module.h>
40 #include <linux/platform_device.h>
41 #include <linux/platform_data/i2c-mux-reg.h>
42 #include <linux/platform_data/mlxreg.h>
43 #include <linux/regmap.h>
45 #define MLX_PLAT_DEVICE_NAME "mlxplat"
47 /* LPC bus IO offsets */
48 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
49 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
50 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
51 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
52 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
53 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
54 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
55 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59
56 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a
57 #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
58 #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65
59 #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66
60 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
61 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
62 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
63 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
64 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
65 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
66 #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
67 #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
68 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
69 MLXPLAT_CPLD_LPC_PIO_OFFSET)
70 #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
71 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
72 MLXPLAT_CPLD_LPC_PIO_OFFSET)
74 /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
75 #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08
76 #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08
77 #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40
78 #define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
79 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
80 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04
81 #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0
82 #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04
83 #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
84 #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
85 #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
86 #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0)
88 /* Start channel numbers */
89 #define MLXPLAT_CPLD_CH1 2
90 #define MLXPLAT_CPLD_CH2 10
92 /* Number of LPC attached MUX platform devices */
93 #define MLXPLAT_CPLD_LPC_MUX_DEVS 2
95 /* Hotplug devices adapter numbers */
96 #define MLXPLAT_CPLD_NR_NONE -1
97 #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
98 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
99 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
100 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
101 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
102 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
104 /* mlxplat_priv - platform private data
105 * @pdev_i2c - i2c controller platform device
106 * @pdev_mux - array of mux platform devices
107 * @pdev_hotplug - hotplug platform devices
109 struct mlxplat_priv
{
110 struct platform_device
*pdev_i2c
;
111 struct platform_device
*pdev_mux
[MLXPLAT_CPLD_LPC_MUX_DEVS
];
112 struct platform_device
*pdev_hotplug
;
115 /* Regions for LPC I2C controller and LPC base register space */
116 static const struct resource mlxplat_lpc_resources
[] = {
117 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR
,
118 MLXPLAT_CPLD_LPC_IO_RANGE
,
119 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO
),
120 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR
,
121 MLXPLAT_CPLD_LPC_IO_RANGE
,
122 "mlxplat_cpld_lpc_regs",
126 /* Platform default channels */
127 static const int mlxplat_default_channels
[][8] = {
129 MLXPLAT_CPLD_CH1
, MLXPLAT_CPLD_CH1
+ 1, MLXPLAT_CPLD_CH1
+ 2,
130 MLXPLAT_CPLD_CH1
+ 3, MLXPLAT_CPLD_CH1
+ 4, MLXPLAT_CPLD_CH1
+
131 5, MLXPLAT_CPLD_CH1
+ 6, MLXPLAT_CPLD_CH1
+ 7
134 MLXPLAT_CPLD_CH2
, MLXPLAT_CPLD_CH2
+ 1, MLXPLAT_CPLD_CH2
+ 2,
135 MLXPLAT_CPLD_CH2
+ 3, MLXPLAT_CPLD_CH2
+ 4, MLXPLAT_CPLD_CH2
+
136 5, MLXPLAT_CPLD_CH2
+ 6, MLXPLAT_CPLD_CH2
+ 7
140 /* Platform channels for MSN21xx system family */
141 static const int mlxplat_msn21xx_channels
[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
143 /* Platform mux data */
144 static struct i2c_mux_reg_platform_data mlxplat_mux_data
[] = {
147 .base_nr
= MLXPLAT_CPLD_CH1
,
149 .reg
= (void __iomem
*)MLXPLAT_CPLD_LPC_REG1
,
155 .base_nr
= MLXPLAT_CPLD_CH2
,
157 .reg
= (void __iomem
*)MLXPLAT_CPLD_LPC_REG2
,
164 /* Platform hotplug devices */
165 static struct i2c_board_info mlxplat_mlxcpld_psu
[] = {
167 I2C_BOARD_INFO("24c02", 0x51),
170 I2C_BOARD_INFO("24c02", 0x50),
174 static struct i2c_board_info mlxplat_mlxcpld_ng_psu
[] = {
176 I2C_BOARD_INFO("24c32", 0x51),
179 I2C_BOARD_INFO("24c32", 0x50),
183 static struct i2c_board_info mlxplat_mlxcpld_pwr
[] = {
185 I2C_BOARD_INFO("dps460", 0x59),
188 I2C_BOARD_INFO("dps460", 0x58),
192 static struct i2c_board_info mlxplat_mlxcpld_fan
[] = {
194 I2C_BOARD_INFO("24c32", 0x50),
197 I2C_BOARD_INFO("24c32", 0x50),
200 I2C_BOARD_INFO("24c32", 0x50),
203 I2C_BOARD_INFO("24c32", 0x50),
207 /* Platform hotplug default data */
208 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data
[] = {
211 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
213 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[0],
214 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
218 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
220 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[1],
221 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
225 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data
[] = {
228 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
230 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[0],
231 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
235 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
237 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[1],
238 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
242 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data
[] = {
245 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
247 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[0],
248 .hpdev
.nr
= MLXPLAT_CPLD_FAN1_DEFAULT_NR
,
252 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
254 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[1],
255 .hpdev
.nr
= MLXPLAT_CPLD_FAN2_DEFAULT_NR
,
259 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
261 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[2],
262 .hpdev
.nr
= MLXPLAT_CPLD_FAN3_DEFAULT_NR
,
266 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
268 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[3],
269 .hpdev
.nr
= MLXPLAT_CPLD_FAN4_DEFAULT_NR
,
273 static struct mlxreg_core_item mlxplat_mlxcpld_default_items
[] = {
275 .data
= mlxplat_mlxcpld_default_psu_items_data
,
276 .aggr_mask
= MLXPLAT_CPLD_AGGR_PSU_MASK_DEF
,
277 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
278 .mask
= MLXPLAT_CPLD_PSU_MASK
,
279 .count
= ARRAY_SIZE(mlxplat_mlxcpld_psu
),
284 .data
= mlxplat_mlxcpld_default_pwr_items_data
,
285 .aggr_mask
= MLXPLAT_CPLD_AGGR_PWR_MASK_DEF
,
286 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
287 .mask
= MLXPLAT_CPLD_PWR_MASK
,
288 .count
= ARRAY_SIZE(mlxplat_mlxcpld_pwr
),
293 .data
= mlxplat_mlxcpld_default_fan_items_data
,
294 .aggr_mask
= MLXPLAT_CPLD_AGGR_FAN_MASK_DEF
,
295 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
296 .mask
= MLXPLAT_CPLD_FAN_MASK
,
297 .count
= ARRAY_SIZE(mlxplat_mlxcpld_fan
),
304 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data
= {
305 .items
= mlxplat_mlxcpld_default_items
,
306 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_default_items
),
307 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
308 .mask
= MLXPLAT_CPLD_AGGR_MASK_DEF
,
311 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data
[] = {
314 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
316 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
320 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
322 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
326 /* Platform hotplug MSN21xx system family data */
327 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items
[] = {
329 .data
= mlxplat_mlxcpld_msn21xx_pwr_items_data
,
330 .aggr_mask
= MLXPLAT_CPLD_AGGR_PWR_MASK_DEF
,
331 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
332 .mask
= MLXPLAT_CPLD_PWR_MASK
,
333 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data
),
340 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data
= {
341 .items
= mlxplat_mlxcpld_msn21xx_items
,
342 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items
),
343 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
344 .mask
= MLXPLAT_CPLD_AGGR_MASK_DEF
,
345 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
346 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
349 /* Platform hotplug msn274x system family data */
350 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data
[] = {
353 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
355 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[0],
356 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
360 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
362 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[1],
363 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
367 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data
[] = {
370 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
372 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[0],
373 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
377 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
379 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[1],
380 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
384 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data
[] = {
387 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
389 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
393 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
395 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
399 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
401 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
405 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
407 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
411 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items
[] = {
413 .data
= mlxplat_mlxcpld_msn274x_psu_items_data
,
414 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
415 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
416 .mask
= MLXPLAT_CPLD_PSU_MASK
,
417 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data
),
422 .data
= mlxplat_mlxcpld_default_ng_pwr_items_data
,
423 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
424 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
425 .mask
= MLXPLAT_CPLD_PWR_MASK
,
426 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data
),
431 .data
= mlxplat_mlxcpld_msn274x_fan_items_data
,
432 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
433 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
434 .mask
= MLXPLAT_CPLD_FAN_MASK
,
435 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data
),
442 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data
= {
443 .items
= mlxplat_mlxcpld_msn274x_items
,
444 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items
),
445 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
446 .mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
447 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
448 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
451 /* Platform hotplug MSN201x system family data */
452 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data
[] = {
455 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
457 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
461 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
463 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
467 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items
[] = {
469 .data
= mlxplat_mlxcpld_msn201x_pwr_items_data
,
470 .aggr_mask
= MLXPLAT_CPLD_AGGR_PWR_MASK_DEF
,
471 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
472 .mask
= MLXPLAT_CPLD_PWR_MASK
,
473 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data
),
480 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data
= {
481 .items
= mlxplat_mlxcpld_msn21xx_items
,
482 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items
),
483 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
484 .mask
= MLXPLAT_CPLD_AGGR_MASK_DEF
,
485 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
486 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
489 /* Platform hotplug next generation system family data */
490 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data
[] = {
493 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
495 .hpdev
.brdinfo
= &mlxplat_mlxcpld_ng_psu
[0],
496 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
500 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
502 .hpdev
.brdinfo
= &mlxplat_mlxcpld_ng_psu
[1],
503 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
507 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data
[] = {
510 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
512 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
516 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
518 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
522 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
524 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
528 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
530 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
534 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
536 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
540 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
542 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
546 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items
[] = {
548 .data
= mlxplat_mlxcpld_default_ng_psu_items_data
,
549 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
550 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
551 .mask
= MLXPLAT_CPLD_PSU_MASK
,
552 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data
),
557 .data
= mlxplat_mlxcpld_default_ng_pwr_items_data
,
558 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
559 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
560 .mask
= MLXPLAT_CPLD_PWR_MASK
,
561 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data
),
566 .data
= mlxplat_mlxcpld_default_ng_fan_items_data
,
567 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
568 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
569 .mask
= MLXPLAT_CPLD_FAN_NG_MASK
,
570 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data
),
577 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data
= {
578 .items
= mlxplat_mlxcpld_default_ng_items
,
579 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items
),
580 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
581 .mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
582 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
583 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
586 static bool mlxplat_mlxcpld_writeable_reg(struct device
*dev
, unsigned int reg
)
589 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET
:
590 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET
:
591 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET
:
592 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET
:
593 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET
:
594 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET
:
595 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET
:
596 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET
:
602 static bool mlxplat_mlxcpld_readable_reg(struct device
*dev
, unsigned int reg
)
605 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
:
606 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET
:
607 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
:
608 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET
:
609 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
:
610 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET
:
611 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET
:
612 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
:
613 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET
:
614 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET
:
615 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
:
616 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET
:
617 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET
:
623 static bool mlxplat_mlxcpld_volatile_reg(struct device
*dev
, unsigned int reg
)
626 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
:
627 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET
:
628 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
:
629 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET
:
630 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
:
631 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET
:
632 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET
:
633 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
:
634 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET
:
635 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET
:
636 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
:
637 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET
:
638 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET
:
644 struct mlxplat_mlxcpld_regmap_context
{
648 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx
;
651 mlxplat_mlxcpld_reg_read(void *context
, unsigned int reg
, unsigned int *val
)
653 struct mlxplat_mlxcpld_regmap_context
*ctx
= context
;
655 *val
= ioread8(ctx
->base
+ reg
);
660 mlxplat_mlxcpld_reg_write(void *context
, unsigned int reg
, unsigned int val
)
662 struct mlxplat_mlxcpld_regmap_context
*ctx
= context
;
664 iowrite8(val
, ctx
->base
+ reg
);
668 static const struct regmap_config mlxplat_mlxcpld_regmap_config
= {
672 .cache_type
= REGCACHE_FLAT
,
673 .writeable_reg
= mlxplat_mlxcpld_writeable_reg
,
674 .readable_reg
= mlxplat_mlxcpld_readable_reg
,
675 .volatile_reg
= mlxplat_mlxcpld_volatile_reg
,
676 .reg_read
= mlxplat_mlxcpld_reg_read
,
677 .reg_write
= mlxplat_mlxcpld_reg_write
,
680 static struct resource mlxplat_mlxcpld_resources
[] = {
681 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
684 static struct platform_device
*mlxplat_dev
;
685 static struct mlxreg_core_hotplug_platform_data
*mlxplat_hotplug
;
687 static int __init
mlxplat_dmi_default_matched(const struct dmi_system_id
*dmi
)
691 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
692 mlxplat_mux_data
[i
].values
= mlxplat_default_channels
[i
];
693 mlxplat_mux_data
[i
].n_values
=
694 ARRAY_SIZE(mlxplat_default_channels
[i
]);
696 mlxplat_hotplug
= &mlxplat_mlxcpld_default_data
;
701 static int __init
mlxplat_dmi_msn21xx_matched(const struct dmi_system_id
*dmi
)
705 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
706 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
707 mlxplat_mux_data
[i
].n_values
=
708 ARRAY_SIZE(mlxplat_msn21xx_channels
);
710 mlxplat_hotplug
= &mlxplat_mlxcpld_msn21xx_data
;
715 static int __init
mlxplat_dmi_msn274x_matched(const struct dmi_system_id
*dmi
)
719 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
720 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
721 mlxplat_mux_data
[i
].n_values
=
722 ARRAY_SIZE(mlxplat_msn21xx_channels
);
724 mlxplat_hotplug
= &mlxplat_mlxcpld_msn274x_data
;
729 static int __init
mlxplat_dmi_msn201x_matched(const struct dmi_system_id
*dmi
)
733 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
734 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
735 mlxplat_mux_data
[i
].n_values
=
736 ARRAY_SIZE(mlxplat_msn21xx_channels
);
738 mlxplat_hotplug
= &mlxplat_mlxcpld_msn201x_data
;
743 static int __init
mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id
*dmi
)
747 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
748 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
749 mlxplat_mux_data
[i
].n_values
=
750 ARRAY_SIZE(mlxplat_msn21xx_channels
);
752 mlxplat_hotplug
= &mlxplat_mlxcpld_default_ng_data
;
757 static const struct dmi_system_id mlxplat_dmi_table
[] __initconst
= {
759 .callback
= mlxplat_dmi_msn274x_matched
,
761 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
762 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN274"),
766 .callback
= mlxplat_dmi_default_matched
,
768 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
769 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN24"),
773 .callback
= mlxplat_dmi_default_matched
,
775 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
776 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN27"),
780 .callback
= mlxplat_dmi_default_matched
,
782 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
783 DMI_MATCH(DMI_PRODUCT_NAME
, "MSB"),
787 .callback
= mlxplat_dmi_default_matched
,
789 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
790 DMI_MATCH(DMI_PRODUCT_NAME
, "MSX"),
794 .callback
= mlxplat_dmi_msn21xx_matched
,
796 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
797 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN21"),
801 .callback
= mlxplat_dmi_msn201x_matched
,
803 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
804 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN201"),
808 .callback
= mlxplat_dmi_qmb7xx_matched
,
810 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
811 DMI_MATCH(DMI_PRODUCT_NAME
, "QMB7"),
815 .callback
= mlxplat_dmi_qmb7xx_matched
,
817 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
818 DMI_MATCH(DMI_PRODUCT_NAME
, "SN37"),
822 .callback
= mlxplat_dmi_qmb7xx_matched
,
824 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
825 DMI_MATCH(DMI_PRODUCT_NAME
, "SN34"),
831 MODULE_DEVICE_TABLE(dmi
, mlxplat_dmi_table
);
833 static int __init
mlxplat_init(void)
835 struct mlxplat_priv
*priv
;
838 if (!dmi_check_system(mlxplat_dmi_table
))
841 mlxplat_dev
= platform_device_register_simple(MLX_PLAT_DEVICE_NAME
, -1,
842 mlxplat_lpc_resources
,
843 ARRAY_SIZE(mlxplat_lpc_resources
));
845 if (IS_ERR(mlxplat_dev
))
846 return PTR_ERR(mlxplat_dev
);
848 priv
= devm_kzalloc(&mlxplat_dev
->dev
, sizeof(struct mlxplat_priv
),
854 platform_set_drvdata(mlxplat_dev
, priv
);
856 priv
->pdev_i2c
= platform_device_register_simple("i2c_mlxcpld", -1,
858 if (IS_ERR(priv
->pdev_i2c
)) {
859 err
= PTR_ERR(priv
->pdev_i2c
);
863 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
864 priv
->pdev_mux
[i
] = platform_device_register_resndata(
866 "i2c-mux-reg", i
, NULL
,
867 0, &mlxplat_mux_data
[i
],
868 sizeof(mlxplat_mux_data
[i
]));
869 if (IS_ERR(priv
->pdev_mux
[i
])) {
870 err
= PTR_ERR(priv
->pdev_mux
[i
]);
871 goto fail_platform_mux_register
;
875 mlxplat_mlxcpld_regmap_ctx
.base
= devm_ioport_map(&mlxplat_dev
->dev
,
876 mlxplat_lpc_resources
[1].start
, 1);
877 if (!mlxplat_mlxcpld_regmap_ctx
.base
) {
879 goto fail_platform_mux_register
;
882 mlxplat_hotplug
->regmap
= devm_regmap_init(&mlxplat_dev
->dev
, NULL
,
883 &mlxplat_mlxcpld_regmap_ctx
,
884 &mlxplat_mlxcpld_regmap_config
);
885 if (IS_ERR(mlxplat_hotplug
->regmap
)) {
886 err
= PTR_ERR(mlxplat_hotplug
->regmap
);
887 goto fail_platform_mux_register
;
890 priv
->pdev_hotplug
= platform_device_register_resndata(
891 &mlxplat_dev
->dev
, "mlxreg-hotplug",
893 mlxplat_mlxcpld_resources
,
894 ARRAY_SIZE(mlxplat_mlxcpld_resources
),
895 mlxplat_hotplug
, sizeof(*mlxplat_hotplug
));
896 if (IS_ERR(priv
->pdev_hotplug
)) {
897 err
= PTR_ERR(priv
->pdev_hotplug
);
898 goto fail_platform_mux_register
;
901 /* Sync registers with hardware. */
902 regcache_mark_dirty(mlxplat_hotplug
->regmap
);
903 err
= regcache_sync(mlxplat_hotplug
->regmap
);
905 goto fail_platform_hotplug_register
;
909 fail_platform_hotplug_register
:
910 platform_device_unregister(priv
->pdev_hotplug
);
911 fail_platform_mux_register
:
913 platform_device_unregister(priv
->pdev_mux
[i
]);
914 platform_device_unregister(priv
->pdev_i2c
);
916 platform_device_unregister(mlxplat_dev
);
920 module_init(mlxplat_init
);
922 static void __exit
mlxplat_exit(void)
924 struct mlxplat_priv
*priv
= platform_get_drvdata(mlxplat_dev
);
927 platform_device_unregister(priv
->pdev_hotplug
);
929 for (i
= ARRAY_SIZE(mlxplat_mux_data
) - 1; i
>= 0 ; i
--)
930 platform_device_unregister(priv
->pdev_mux
[i
]);
932 platform_device_unregister(priv
->pdev_i2c
);
933 platform_device_unregister(mlxplat_dev
);
935 module_exit(mlxplat_exit
);
937 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
938 MODULE_DESCRIPTION("Mellanox platform driver");
939 MODULE_LICENSE("Dual BSD/GPL");