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)
87 /* Start channel numbers */
88 #define MLXPLAT_CPLD_CH1 2
89 #define MLXPLAT_CPLD_CH2 10
91 /* Number of LPC attached MUX platform devices */
92 #define MLXPLAT_CPLD_LPC_MUX_DEVS 2
94 /* Hotplug devices adapter numbers */
95 #define MLXPLAT_CPLD_NR_NONE -1
96 #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
97 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
98 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
99 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
100 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
101 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
103 /* mlxplat_priv - platform private data
104 * @pdev_i2c - i2c controller platform device
105 * @pdev_mux - array of mux platform devices
106 * @pdev_hotplug - hotplug platform devices
108 struct mlxplat_priv {
109 struct platform_device *pdev_i2c;
110 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
111 struct platform_device *pdev_hotplug;
114 /* Regions for LPC I2C controller and LPC base register space */
115 static const struct resource mlxplat_lpc_resources[] = {
116 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
117 MLXPLAT_CPLD_LPC_IO_RANGE,
118 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
119 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
120 MLXPLAT_CPLD_LPC_IO_RANGE,
121 "mlxplat_cpld_lpc_regs",
125 /* Platform default channels */
126 static const int mlxplat_default_channels[][8] = {
128 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
129 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
130 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
133 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
134 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
135 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
139 /* Platform channels for MSN21xx system family */
140 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
142 /* Platform mux data */
143 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
146 .base_nr = MLXPLAT_CPLD_CH1,
148 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
154 .base_nr = MLXPLAT_CPLD_CH2,
156 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
163 /* Platform hotplug devices */
164 static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
166 I2C_BOARD_INFO("24c02", 0x51),
169 I2C_BOARD_INFO("24c02", 0x50),
173 static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
175 I2C_BOARD_INFO("dps460", 0x59),
178 I2C_BOARD_INFO("dps460", 0x58),
182 static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
184 I2C_BOARD_INFO("24c32", 0x50),
187 I2C_BOARD_INFO("24c32", 0x50),
190 I2C_BOARD_INFO("24c32", 0x50),
193 I2C_BOARD_INFO("24c32", 0x50),
197 /* Platform hotplug default data */
198 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
201 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
203 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
204 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
208 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
210 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
211 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
215 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
218 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
220 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
221 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
225 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
227 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
228 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
232 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
235 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
237 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
238 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
242 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
244 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
245 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
249 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
251 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
252 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
256 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
258 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
259 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
263 static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
265 .data = mlxplat_mlxcpld_default_psu_items_data,
266 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
267 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
268 .mask = MLXPLAT_CPLD_PSU_MASK,
269 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
274 .data = mlxplat_mlxcpld_default_pwr_items_data,
275 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
276 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
277 .mask = MLXPLAT_CPLD_PWR_MASK,
278 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
283 .data = mlxplat_mlxcpld_default_fan_items_data,
284 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
285 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
286 .mask = MLXPLAT_CPLD_FAN_MASK,
287 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
294 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
295 .items = mlxplat_mlxcpld_default_items,
296 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
297 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
298 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
301 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
304 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
306 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
310 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
312 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
316 /* Platform hotplug MSN21xx system family data */
317 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
319 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
320 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
321 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
322 .mask = MLXPLAT_CPLD_PWR_MASK,
323 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
330 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
331 .items = mlxplat_mlxcpld_msn21xx_items,
332 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
333 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
334 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
335 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
336 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
339 /* Platform hotplug msn274x system family data */
340 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
343 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
345 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
346 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
350 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
352 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
353 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
357 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
360 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
362 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
363 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
367 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
369 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
370 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
374 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
377 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
379 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
383 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
385 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
389 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
391 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
395 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
397 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
401 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
403 .data = mlxplat_mlxcpld_msn274x_psu_items_data,
404 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
405 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
406 .mask = MLXPLAT_CPLD_PSU_MASK,
407 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data),
412 .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
413 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
414 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
415 .mask = MLXPLAT_CPLD_PWR_MASK,
416 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
421 .data = mlxplat_mlxcpld_msn274x_fan_items_data,
422 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
423 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
424 .mask = MLXPLAT_CPLD_FAN_MASK,
425 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data),
432 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = {
433 .items = mlxplat_mlxcpld_msn274x_items,
434 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items),
435 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
436 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
437 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
438 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
441 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
444 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
445 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
446 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
447 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
448 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
449 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
450 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
451 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
457 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
460 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
461 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
462 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
463 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
464 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
465 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
466 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
467 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
468 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
469 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
470 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
471 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
472 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
478 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
481 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
482 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
483 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
484 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
485 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
486 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
487 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
488 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
489 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
490 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
491 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
492 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
493 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
499 struct mlxplat_mlxcpld_regmap_context {
503 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
506 mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
508 struct mlxplat_mlxcpld_regmap_context *ctx = context;
510 *val = ioread8(ctx->base + reg);
515 mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
517 struct mlxplat_mlxcpld_regmap_context *ctx = context;
519 iowrite8(val, ctx->base + reg);
523 static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
527 .cache_type = REGCACHE_FLAT,
528 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
529 .readable_reg = mlxplat_mlxcpld_readable_reg,
530 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
531 .reg_read = mlxplat_mlxcpld_reg_read,
532 .reg_write = mlxplat_mlxcpld_reg_write,
535 static struct resource mlxplat_mlxcpld_resources[] = {
536 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
539 static struct platform_device *mlxplat_dev;
540 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
542 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
546 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
547 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
548 mlxplat_mux_data[i].n_values =
549 ARRAY_SIZE(mlxplat_default_channels[i]);
551 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
556 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
560 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
561 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
562 mlxplat_mux_data[i].n_values =
563 ARRAY_SIZE(mlxplat_msn21xx_channels);
565 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
570 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
574 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
575 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
576 mlxplat_mux_data[i].n_values =
577 ARRAY_SIZE(mlxplat_msn21xx_channels);
579 mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
584 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
586 .callback = mlxplat_dmi_msn274x_matched,
588 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
589 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
593 .callback = mlxplat_dmi_default_matched,
595 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
596 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
600 .callback = mlxplat_dmi_default_matched,
602 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
603 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
607 .callback = mlxplat_dmi_default_matched,
609 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
610 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
614 .callback = mlxplat_dmi_default_matched,
616 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
617 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
621 .callback = mlxplat_dmi_msn21xx_matched,
623 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
624 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
630 MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
632 static int __init mlxplat_init(void)
634 struct mlxplat_priv *priv;
637 if (!dmi_check_system(mlxplat_dmi_table))
640 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
641 mlxplat_lpc_resources,
642 ARRAY_SIZE(mlxplat_lpc_resources));
644 if (IS_ERR(mlxplat_dev))
645 return PTR_ERR(mlxplat_dev);
647 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
653 platform_set_drvdata(mlxplat_dev, priv);
655 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
657 if (IS_ERR(priv->pdev_i2c)) {
658 err = PTR_ERR(priv->pdev_i2c);
662 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
663 priv->pdev_mux[i] = platform_device_register_resndata(
665 "i2c-mux-reg", i, NULL,
666 0, &mlxplat_mux_data[i],
667 sizeof(mlxplat_mux_data[i]));
668 if (IS_ERR(priv->pdev_mux[i])) {
669 err = PTR_ERR(priv->pdev_mux[i]);
670 goto fail_platform_mux_register;
674 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
675 mlxplat_lpc_resources[1].start, 1);
676 if (!mlxplat_mlxcpld_regmap_ctx.base) {
678 goto fail_platform_mux_register;
681 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
682 &mlxplat_mlxcpld_regmap_ctx,
683 &mlxplat_mlxcpld_regmap_config);
684 if (IS_ERR(mlxplat_hotplug->regmap)) {
685 err = PTR_ERR(mlxplat_hotplug->regmap);
686 goto fail_platform_mux_register;
689 priv->pdev_hotplug = platform_device_register_resndata(
690 &mlxplat_dev->dev, "mlxreg-hotplug",
692 mlxplat_mlxcpld_resources,
693 ARRAY_SIZE(mlxplat_mlxcpld_resources),
694 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
695 if (IS_ERR(priv->pdev_hotplug)) {
696 err = PTR_ERR(priv->pdev_hotplug);
697 goto fail_platform_mux_register;
700 /* Sync registers with hardware. */
701 regcache_mark_dirty(mlxplat_hotplug->regmap);
702 err = regcache_sync(mlxplat_hotplug->regmap);
704 goto fail_platform_hotplug_register;
708 fail_platform_hotplug_register:
709 platform_device_unregister(priv->pdev_hotplug);
710 fail_platform_mux_register:
712 platform_device_unregister(priv->pdev_mux[i]);
713 platform_device_unregister(priv->pdev_i2c);
715 platform_device_unregister(mlxplat_dev);
719 module_init(mlxplat_init);
721 static void __exit mlxplat_exit(void)
723 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
726 platform_device_unregister(priv->pdev_hotplug);
728 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
729 platform_device_unregister(priv->pdev_mux[i]);
731 platform_device_unregister(priv->pdev_i2c);
732 platform_device_unregister(mlxplat_dev);
734 module_exit(mlxplat_exit);
736 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
737 MODULE_DESCRIPTION("Mellanox platform driver");
738 MODULE_LICENSE("Dual BSD/GPL");