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");