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 /* Default I2C parent bus number */
89 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
91 /* Maximum number of possible physical buses equipped on system */
92 #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
94 /* Number of channels in group */
95 #define MLXPLAT_CPLD_GRP_CHNL_NUM 8
97 /* Start channel numbers */
98 #define MLXPLAT_CPLD_CH1 2
99 #define MLXPLAT_CPLD_CH2 10
101 /* Number of LPC attached MUX platform devices */
102 #define MLXPLAT_CPLD_LPC_MUX_DEVS 2
104 /* Hotplug devices adapter numbers */
105 #define MLXPLAT_CPLD_NR_NONE -1
106 #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
107 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
108 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
109 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
110 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
111 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
113 /* mlxplat_priv - platform private data
114 * @pdev_i2c - i2c controller platform device
115 * @pdev_mux - array of mux platform devices
116 * @pdev_hotplug - hotplug platform devices
118 struct mlxplat_priv
{
119 struct platform_device
*pdev_i2c
;
120 struct platform_device
*pdev_mux
[MLXPLAT_CPLD_LPC_MUX_DEVS
];
121 struct platform_device
*pdev_hotplug
;
124 /* Regions for LPC I2C controller and LPC base register space */
125 static const struct resource mlxplat_lpc_resources
[] = {
126 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR
,
127 MLXPLAT_CPLD_LPC_IO_RANGE
,
128 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO
),
129 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR
,
130 MLXPLAT_CPLD_LPC_IO_RANGE
,
131 "mlxplat_cpld_lpc_regs",
135 /* Platform default channels */
136 static const int mlxplat_default_channels
[][MLXPLAT_CPLD_GRP_CHNL_NUM
] = {
138 MLXPLAT_CPLD_CH1
, MLXPLAT_CPLD_CH1
+ 1, MLXPLAT_CPLD_CH1
+ 2,
139 MLXPLAT_CPLD_CH1
+ 3, MLXPLAT_CPLD_CH1
+ 4, MLXPLAT_CPLD_CH1
+
140 5, MLXPLAT_CPLD_CH1
+ 6, MLXPLAT_CPLD_CH1
+ 7
143 MLXPLAT_CPLD_CH2
, MLXPLAT_CPLD_CH2
+ 1, MLXPLAT_CPLD_CH2
+ 2,
144 MLXPLAT_CPLD_CH2
+ 3, MLXPLAT_CPLD_CH2
+ 4, MLXPLAT_CPLD_CH2
+
145 5, MLXPLAT_CPLD_CH2
+ 6, MLXPLAT_CPLD_CH2
+ 7
149 /* Platform channels for MSN21xx system family */
150 static const int mlxplat_msn21xx_channels
[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
152 /* Platform mux data */
153 static struct i2c_mux_reg_platform_data mlxplat_mux_data
[] = {
156 .base_nr
= MLXPLAT_CPLD_CH1
,
158 .reg
= (void __iomem
*)MLXPLAT_CPLD_LPC_REG1
,
164 .base_nr
= MLXPLAT_CPLD_CH2
,
166 .reg
= (void __iomem
*)MLXPLAT_CPLD_LPC_REG2
,
173 /* Platform hotplug devices */
174 static struct i2c_board_info mlxplat_mlxcpld_psu
[] = {
176 I2C_BOARD_INFO("24c02", 0x51),
179 I2C_BOARD_INFO("24c02", 0x50),
183 static struct i2c_board_info mlxplat_mlxcpld_ng_psu
[] = {
185 I2C_BOARD_INFO("24c32", 0x51),
188 I2C_BOARD_INFO("24c32", 0x50),
192 static struct i2c_board_info mlxplat_mlxcpld_pwr
[] = {
194 I2C_BOARD_INFO("dps460", 0x59),
197 I2C_BOARD_INFO("dps460", 0x58),
201 static struct i2c_board_info mlxplat_mlxcpld_fan
[] = {
203 I2C_BOARD_INFO("24c32", 0x50),
206 I2C_BOARD_INFO("24c32", 0x50),
209 I2C_BOARD_INFO("24c32", 0x50),
212 I2C_BOARD_INFO("24c32", 0x50),
216 /* Platform hotplug default data */
217 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data
[] = {
220 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
222 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[0],
223 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
227 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
229 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[1],
230 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
234 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data
[] = {
237 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
239 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[0],
240 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
244 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
246 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[1],
247 .hpdev
.nr
= MLXPLAT_CPLD_PSU_DEFAULT_NR
,
251 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data
[] = {
254 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
256 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[0],
257 .hpdev
.nr
= MLXPLAT_CPLD_FAN1_DEFAULT_NR
,
261 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
263 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[1],
264 .hpdev
.nr
= MLXPLAT_CPLD_FAN2_DEFAULT_NR
,
268 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
270 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[2],
271 .hpdev
.nr
= MLXPLAT_CPLD_FAN3_DEFAULT_NR
,
275 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
277 .hpdev
.brdinfo
= &mlxplat_mlxcpld_fan
[3],
278 .hpdev
.nr
= MLXPLAT_CPLD_FAN4_DEFAULT_NR
,
282 static struct mlxreg_core_item mlxplat_mlxcpld_default_items
[] = {
284 .data
= mlxplat_mlxcpld_default_psu_items_data
,
285 .aggr_mask
= MLXPLAT_CPLD_AGGR_PSU_MASK_DEF
,
286 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
287 .mask
= MLXPLAT_CPLD_PSU_MASK
,
288 .count
= ARRAY_SIZE(mlxplat_mlxcpld_psu
),
293 .data
= mlxplat_mlxcpld_default_pwr_items_data
,
294 .aggr_mask
= MLXPLAT_CPLD_AGGR_PWR_MASK_DEF
,
295 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
296 .mask
= MLXPLAT_CPLD_PWR_MASK
,
297 .count
= ARRAY_SIZE(mlxplat_mlxcpld_pwr
),
302 .data
= mlxplat_mlxcpld_default_fan_items_data
,
303 .aggr_mask
= MLXPLAT_CPLD_AGGR_FAN_MASK_DEF
,
304 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
305 .mask
= MLXPLAT_CPLD_FAN_MASK
,
306 .count
= ARRAY_SIZE(mlxplat_mlxcpld_fan
),
313 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data
= {
314 .items
= mlxplat_mlxcpld_default_items
,
315 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_default_items
),
316 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
317 .mask
= MLXPLAT_CPLD_AGGR_MASK_DEF
,
320 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data
[] = {
323 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
325 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
329 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
331 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
335 /* Platform hotplug MSN21xx system family data */
336 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items
[] = {
338 .data
= mlxplat_mlxcpld_msn21xx_pwr_items_data
,
339 .aggr_mask
= MLXPLAT_CPLD_AGGR_PWR_MASK_DEF
,
340 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
341 .mask
= MLXPLAT_CPLD_PWR_MASK
,
342 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data
),
349 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data
= {
350 .items
= mlxplat_mlxcpld_msn21xx_items
,
351 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items
),
352 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
353 .mask
= MLXPLAT_CPLD_AGGR_MASK_DEF
,
354 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
355 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
358 /* Platform hotplug msn274x system family data */
359 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data
[] = {
362 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
364 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[0],
365 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
369 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
371 .hpdev
.brdinfo
= &mlxplat_mlxcpld_psu
[1],
372 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
376 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data
[] = {
379 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
381 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[0],
382 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
386 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
388 .hpdev
.brdinfo
= &mlxplat_mlxcpld_pwr
[1],
389 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
393 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data
[] = {
396 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
398 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
402 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
404 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
408 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
410 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
414 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
416 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
420 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items
[] = {
422 .data
= mlxplat_mlxcpld_msn274x_psu_items_data
,
423 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
424 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
425 .mask
= MLXPLAT_CPLD_PSU_MASK
,
426 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data
),
431 .data
= mlxplat_mlxcpld_default_ng_pwr_items_data
,
432 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
433 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
434 .mask
= MLXPLAT_CPLD_PWR_MASK
,
435 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data
),
440 .data
= mlxplat_mlxcpld_msn274x_fan_items_data
,
441 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
442 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
443 .mask
= MLXPLAT_CPLD_FAN_MASK
,
444 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data
),
451 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data
= {
452 .items
= mlxplat_mlxcpld_msn274x_items
,
453 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items
),
454 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
455 .mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
456 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
457 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
460 /* Platform hotplug MSN201x system family data */
461 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data
[] = {
464 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
466 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
470 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
472 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
476 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items
[] = {
478 .data
= mlxplat_mlxcpld_msn201x_pwr_items_data
,
479 .aggr_mask
= MLXPLAT_CPLD_AGGR_PWR_MASK_DEF
,
480 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
481 .mask
= MLXPLAT_CPLD_PWR_MASK
,
482 .count
= ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data
),
489 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data
= {
490 .items
= mlxplat_mlxcpld_msn21xx_items
,
491 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items
),
492 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
493 .mask
= MLXPLAT_CPLD_AGGR_MASK_DEF
,
494 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
495 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
498 /* Platform hotplug next generation system family data */
499 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data
[] = {
502 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
504 .hpdev
.brdinfo
= &mlxplat_mlxcpld_ng_psu
[0],
505 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
509 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
511 .hpdev
.brdinfo
= &mlxplat_mlxcpld_ng_psu
[1],
512 .hpdev
.nr
= MLXPLAT_CPLD_PSU_MSNXXXX_NR
,
516 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data
[] = {
519 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
521 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
525 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
527 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
531 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
533 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
537 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
539 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
543 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
545 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
549 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
551 .hpdev
.nr
= MLXPLAT_CPLD_NR_NONE
,
555 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items
[] = {
557 .data
= mlxplat_mlxcpld_default_ng_psu_items_data
,
558 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
559 .reg
= MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
,
560 .mask
= MLXPLAT_CPLD_PSU_MASK
,
561 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data
),
566 .data
= mlxplat_mlxcpld_default_ng_pwr_items_data
,
567 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
568 .reg
= MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
,
569 .mask
= MLXPLAT_CPLD_PWR_MASK
,
570 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data
),
575 .data
= mlxplat_mlxcpld_default_ng_fan_items_data
,
576 .aggr_mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
577 .reg
= MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
,
578 .mask
= MLXPLAT_CPLD_FAN_NG_MASK
,
579 .count
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data
),
586 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data
= {
587 .items
= mlxplat_mlxcpld_default_ng_items
,
588 .counter
= ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items
),
589 .cell
= MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
,
590 .mask
= MLXPLAT_CPLD_AGGR_MASK_NG_DEF
,
591 .cell_low
= MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
,
592 .mask_low
= MLXPLAT_CPLD_LOW_AGGR_MASK_LOW
,
595 static bool mlxplat_mlxcpld_writeable_reg(struct device
*dev
, unsigned int reg
)
598 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET
:
599 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET
:
600 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET
:
601 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET
:
602 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET
:
603 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET
:
604 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET
:
605 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET
:
611 static bool mlxplat_mlxcpld_readable_reg(struct device
*dev
, unsigned int reg
)
614 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
:
615 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET
:
616 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
:
617 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET
:
618 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
:
619 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET
:
620 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET
:
621 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
:
622 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET
:
623 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET
:
624 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
:
625 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET
:
626 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET
:
632 static bool mlxplat_mlxcpld_volatile_reg(struct device
*dev
, unsigned int reg
)
635 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET
:
636 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET
:
637 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET
:
638 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET
:
639 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET
:
640 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET
:
641 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET
:
642 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET
:
643 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET
:
644 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET
:
645 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET
:
646 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET
:
647 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET
:
653 struct mlxplat_mlxcpld_regmap_context
{
657 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx
;
660 mlxplat_mlxcpld_reg_read(void *context
, unsigned int reg
, unsigned int *val
)
662 struct mlxplat_mlxcpld_regmap_context
*ctx
= context
;
664 *val
= ioread8(ctx
->base
+ reg
);
669 mlxplat_mlxcpld_reg_write(void *context
, unsigned int reg
, unsigned int val
)
671 struct mlxplat_mlxcpld_regmap_context
*ctx
= context
;
673 iowrite8(val
, ctx
->base
+ reg
);
677 static const struct regmap_config mlxplat_mlxcpld_regmap_config
= {
681 .cache_type
= REGCACHE_FLAT
,
682 .writeable_reg
= mlxplat_mlxcpld_writeable_reg
,
683 .readable_reg
= mlxplat_mlxcpld_readable_reg
,
684 .volatile_reg
= mlxplat_mlxcpld_volatile_reg
,
685 .reg_read
= mlxplat_mlxcpld_reg_read
,
686 .reg_write
= mlxplat_mlxcpld_reg_write
,
689 static struct resource mlxplat_mlxcpld_resources
[] = {
690 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
693 static struct platform_device
*mlxplat_dev
;
694 static struct mlxreg_core_hotplug_platform_data
*mlxplat_hotplug
;
696 static int __init
mlxplat_dmi_default_matched(const struct dmi_system_id
*dmi
)
700 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
701 mlxplat_mux_data
[i
].values
= mlxplat_default_channels
[i
];
702 mlxplat_mux_data
[i
].n_values
=
703 ARRAY_SIZE(mlxplat_default_channels
[i
]);
705 mlxplat_hotplug
= &mlxplat_mlxcpld_default_data
;
706 mlxplat_hotplug
->deferred_nr
=
707 mlxplat_default_channels
[i
- 1][MLXPLAT_CPLD_GRP_CHNL_NUM
- 1];
712 static int __init
mlxplat_dmi_msn21xx_matched(const struct dmi_system_id
*dmi
)
716 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
717 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
718 mlxplat_mux_data
[i
].n_values
=
719 ARRAY_SIZE(mlxplat_msn21xx_channels
);
721 mlxplat_hotplug
= &mlxplat_mlxcpld_msn21xx_data
;
722 mlxplat_hotplug
->deferred_nr
=
723 mlxplat_msn21xx_channels
[MLXPLAT_CPLD_GRP_CHNL_NUM
- 1];
728 static int __init
mlxplat_dmi_msn274x_matched(const struct dmi_system_id
*dmi
)
732 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
733 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
734 mlxplat_mux_data
[i
].n_values
=
735 ARRAY_SIZE(mlxplat_msn21xx_channels
);
737 mlxplat_hotplug
= &mlxplat_mlxcpld_msn274x_data
;
738 mlxplat_hotplug
->deferred_nr
=
739 mlxplat_msn21xx_channels
[MLXPLAT_CPLD_GRP_CHNL_NUM
- 1];
744 static int __init
mlxplat_dmi_msn201x_matched(const struct dmi_system_id
*dmi
)
748 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
749 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
750 mlxplat_mux_data
[i
].n_values
=
751 ARRAY_SIZE(mlxplat_msn21xx_channels
);
753 mlxplat_hotplug
= &mlxplat_mlxcpld_msn201x_data
;
754 mlxplat_hotplug
->deferred_nr
=
755 mlxplat_default_channels
[i
- 1][MLXPLAT_CPLD_GRP_CHNL_NUM
- 1];
760 static int __init
mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id
*dmi
)
764 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
765 mlxplat_mux_data
[i
].values
= mlxplat_msn21xx_channels
;
766 mlxplat_mux_data
[i
].n_values
=
767 ARRAY_SIZE(mlxplat_msn21xx_channels
);
769 mlxplat_hotplug
= &mlxplat_mlxcpld_default_ng_data
;
770 mlxplat_hotplug
->deferred_nr
=
771 mlxplat_msn21xx_channels
[MLXPLAT_CPLD_GRP_CHNL_NUM
- 1];
776 static const struct dmi_system_id mlxplat_dmi_table
[] __initconst
= {
778 .callback
= mlxplat_dmi_msn274x_matched
,
780 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
781 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN274"),
785 .callback
= mlxplat_dmi_default_matched
,
787 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
788 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN24"),
792 .callback
= mlxplat_dmi_default_matched
,
794 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
795 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN27"),
799 .callback
= mlxplat_dmi_default_matched
,
801 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
802 DMI_MATCH(DMI_PRODUCT_NAME
, "MSB"),
806 .callback
= mlxplat_dmi_default_matched
,
808 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
809 DMI_MATCH(DMI_PRODUCT_NAME
, "MSX"),
813 .callback
= mlxplat_dmi_msn21xx_matched
,
815 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
816 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN21"),
820 .callback
= mlxplat_dmi_msn201x_matched
,
822 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
823 DMI_MATCH(DMI_PRODUCT_NAME
, "MSN201"),
827 .callback
= mlxplat_dmi_qmb7xx_matched
,
829 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
830 DMI_MATCH(DMI_PRODUCT_NAME
, "QMB7"),
834 .callback
= mlxplat_dmi_qmb7xx_matched
,
836 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
837 DMI_MATCH(DMI_PRODUCT_NAME
, "SN37"),
841 .callback
= mlxplat_dmi_qmb7xx_matched
,
843 DMI_MATCH(DMI_BOARD_VENDOR
, "Mellanox Technologies"),
844 DMI_MATCH(DMI_PRODUCT_NAME
, "SN34"),
850 MODULE_DEVICE_TABLE(dmi
, mlxplat_dmi_table
);
852 static int mlxplat_mlxcpld_verify_bus_topology(int *nr
)
854 struct i2c_adapter
*search_adap
;
857 /* Scan adapters from expected id to verify it is free. */
858 *nr
= MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR
;
859 for (i
= MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR
; i
<
860 MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM
; i
++) {
861 search_adap
= i2c_get_adapter(i
);
863 i2c_put_adapter(search_adap
);
867 /* Return if expected parent adapter is free. */
868 if (i
== MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR
)
873 /* Return with error if free id for adapter is not found. */
874 if (i
== MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM
)
877 /* Shift adapter ids, since expected parent adapter is not free. */
879 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
880 shift
= *nr
- mlxplat_mux_data
[i
].parent
;
881 mlxplat_mux_data
[i
].parent
= *nr
;
882 mlxplat_mux_data
[i
].base_nr
+= shift
;
884 mlxplat_hotplug
->shift_nr
= shift
;
890 static int __init
mlxplat_init(void)
892 struct mlxplat_priv
*priv
;
895 if (!dmi_check_system(mlxplat_dmi_table
))
898 mlxplat_dev
= platform_device_register_simple(MLX_PLAT_DEVICE_NAME
, -1,
899 mlxplat_lpc_resources
,
900 ARRAY_SIZE(mlxplat_lpc_resources
));
902 if (IS_ERR(mlxplat_dev
))
903 return PTR_ERR(mlxplat_dev
);
905 priv
= devm_kzalloc(&mlxplat_dev
->dev
, sizeof(struct mlxplat_priv
),
911 platform_set_drvdata(mlxplat_dev
, priv
);
913 err
= mlxplat_mlxcpld_verify_bus_topology(&nr
);
917 nr
= (nr
== MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM
) ? -1 : nr
;
918 priv
->pdev_i2c
= platform_device_register_simple("i2c_mlxcpld", nr
,
920 if (IS_ERR(priv
->pdev_i2c
)) {
921 err
= PTR_ERR(priv
->pdev_i2c
);
925 for (i
= 0; i
< ARRAY_SIZE(mlxplat_mux_data
); i
++) {
926 priv
->pdev_mux
[i
] = platform_device_register_resndata(
928 "i2c-mux-reg", i
, NULL
,
929 0, &mlxplat_mux_data
[i
],
930 sizeof(mlxplat_mux_data
[i
]));
931 if (IS_ERR(priv
->pdev_mux
[i
])) {
932 err
= PTR_ERR(priv
->pdev_mux
[i
]);
933 goto fail_platform_mux_register
;
937 mlxplat_mlxcpld_regmap_ctx
.base
= devm_ioport_map(&mlxplat_dev
->dev
,
938 mlxplat_lpc_resources
[1].start
, 1);
939 if (!mlxplat_mlxcpld_regmap_ctx
.base
) {
941 goto fail_platform_mux_register
;
944 mlxplat_hotplug
->regmap
= devm_regmap_init(&mlxplat_dev
->dev
, NULL
,
945 &mlxplat_mlxcpld_regmap_ctx
,
946 &mlxplat_mlxcpld_regmap_config
);
947 if (IS_ERR(mlxplat_hotplug
->regmap
)) {
948 err
= PTR_ERR(mlxplat_hotplug
->regmap
);
949 goto fail_platform_mux_register
;
952 priv
->pdev_hotplug
= platform_device_register_resndata(
953 &mlxplat_dev
->dev
, "mlxreg-hotplug",
955 mlxplat_mlxcpld_resources
,
956 ARRAY_SIZE(mlxplat_mlxcpld_resources
),
957 mlxplat_hotplug
, sizeof(*mlxplat_hotplug
));
958 if (IS_ERR(priv
->pdev_hotplug
)) {
959 err
= PTR_ERR(priv
->pdev_hotplug
);
960 goto fail_platform_mux_register
;
963 /* Sync registers with hardware. */
964 regcache_mark_dirty(mlxplat_hotplug
->regmap
);
965 err
= regcache_sync(mlxplat_hotplug
->regmap
);
967 goto fail_platform_hotplug_register
;
971 fail_platform_hotplug_register
:
972 platform_device_unregister(priv
->pdev_hotplug
);
973 fail_platform_mux_register
:
975 platform_device_unregister(priv
->pdev_mux
[i
]);
976 platform_device_unregister(priv
->pdev_i2c
);
978 platform_device_unregister(mlxplat_dev
);
982 module_init(mlxplat_init
);
984 static void __exit
mlxplat_exit(void)
986 struct mlxplat_priv
*priv
= platform_get_drvdata(mlxplat_dev
);
989 platform_device_unregister(priv
->pdev_hotplug
);
991 for (i
= ARRAY_SIZE(mlxplat_mux_data
) - 1; i
>= 0 ; i
--)
992 platform_device_unregister(priv
->pdev_mux
[i
]);
994 platform_device_unregister(priv
->pdev_i2c
);
995 platform_device_unregister(mlxplat_dev
);
997 module_exit(mlxplat_exit
);
999 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
1000 MODULE_DESCRIPTION("Mellanox platform driver");
1001 MODULE_LICENSE("Dual BSD/GPL");