Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / drivers / platform / x86 / mlx-platform.c
blob454e14f022855000ecfb9961388c812e6763a20d
1 /*
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>
38 #include <linux/io.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",
123 IORESOURCE_IO),
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[] = {
146 .parent = 1,
147 .base_nr = MLXPLAT_CPLD_CH1,
148 .write_only = 1,
149 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
150 .reg_size = 1,
151 .idle_in_use = 1,
154 .parent = 1,
155 .base_nr = MLXPLAT_CPLD_CH2,
156 .write_only = 1,
157 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
158 .reg_size = 1,
159 .idle_in_use = 1,
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[] = {
210 .label = "psu1",
211 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
212 .mask = BIT(0),
213 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
214 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
217 .label = "psu2",
218 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
219 .mask = BIT(1),
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[] = {
227 .label = "pwr1",
228 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
229 .mask = BIT(0),
230 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
231 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
234 .label = "pwr2",
235 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
236 .mask = BIT(1),
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[] = {
244 .label = "fan1",
245 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
246 .mask = BIT(0),
247 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
248 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
251 .label = "fan2",
252 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
253 .mask = BIT(1),
254 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
255 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
258 .label = "fan3",
259 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
260 .mask = BIT(2),
261 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
262 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
265 .label = "fan4",
266 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
267 .mask = BIT(3),
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),
280 .inversed = 1,
281 .health = false,
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),
289 .inversed = 0,
290 .health = false,
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),
298 .inversed = 1,
299 .health = false,
303 static
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[] = {
313 .label = "pwr1",
314 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
315 .mask = BIT(0),
316 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
319 .label = "pwr2",
320 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
321 .mask = BIT(1),
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),
334 .inversed = 0,
335 .health = false,
339 static
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[] = {
352 .label = "psu1",
353 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
354 .mask = BIT(0),
355 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
356 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
359 .label = "psu2",
360 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
361 .mask = BIT(1),
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[] = {
369 .label = "pwr1",
370 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
371 .mask = BIT(0),
372 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
373 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
376 .label = "pwr2",
377 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
378 .mask = BIT(1),
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[] = {
386 .label = "fan1",
387 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
388 .mask = BIT(0),
389 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
392 .label = "fan2",
393 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
394 .mask = BIT(1),
395 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
398 .label = "fan3",
399 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
400 .mask = BIT(2),
401 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
404 .label = "fan4",
405 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
406 .mask = BIT(3),
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),
418 .inversed = 1,
419 .health = false,
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),
427 .inversed = 0,
428 .health = false,
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),
436 .inversed = 1,
437 .health = false,
441 static
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[] = {
454 .label = "pwr1",
455 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
456 .mask = BIT(0),
457 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
460 .label = "pwr2",
461 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
462 .mask = BIT(1),
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),
474 .inversed = 0,
475 .health = false,
479 static
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[] = {
492 .label = "psu1",
493 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
494 .mask = BIT(0),
495 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0],
496 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
499 .label = "psu2",
500 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
501 .mask = BIT(1),
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[] = {
509 .label = "fan1",
510 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
511 .mask = BIT(0),
512 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
515 .label = "fan2",
516 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
517 .mask = BIT(1),
518 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
521 .label = "fan3",
522 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
523 .mask = BIT(2),
524 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
527 .label = "fan4",
528 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
529 .mask = BIT(3),
530 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
533 .label = "fan5",
534 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
535 .mask = BIT(4),
536 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
539 .label = "fan6",
540 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
541 .mask = BIT(5),
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),
553 .inversed = 1,
554 .health = false,
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),
562 .inversed = 0,
563 .health = false,
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),
571 .inversed = 1,
572 .health = false,
576 static
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)
588 switch (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:
597 return true;
599 return false;
602 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
604 switch (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:
618 return true;
620 return false;
623 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
625 switch (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:
639 return true;
641 return false;
644 struct mlxplat_mlxcpld_regmap_context {
645 void __iomem *base;
648 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
650 static int
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);
656 return 0;
659 static int
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);
665 return 0;
668 static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
669 .reg_bits = 8,
670 .val_bits = 8,
671 .max_register = 255,
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)
689 int i;
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;
698 return 1;
701 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
703 int i;
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;
712 return 1;
715 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
717 int i;
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;
726 return 1;
729 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
731 int i;
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;
740 return 1;
743 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
745 int i;
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;
754 return 1;
757 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
759 .callback = mlxplat_dmi_msn274x_matched,
760 .matches = {
761 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
762 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
766 .callback = mlxplat_dmi_default_matched,
767 .matches = {
768 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
769 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
773 .callback = mlxplat_dmi_default_matched,
774 .matches = {
775 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
776 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
780 .callback = mlxplat_dmi_default_matched,
781 .matches = {
782 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
783 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
787 .callback = mlxplat_dmi_default_matched,
788 .matches = {
789 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
790 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
794 .callback = mlxplat_dmi_msn21xx_matched,
795 .matches = {
796 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
797 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
801 .callback = mlxplat_dmi_msn201x_matched,
802 .matches = {
803 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
804 DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
808 .callback = mlxplat_dmi_qmb7xx_matched,
809 .matches = {
810 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
811 DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
815 .callback = mlxplat_dmi_qmb7xx_matched,
816 .matches = {
817 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
818 DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
822 .callback = mlxplat_dmi_qmb7xx_matched,
823 .matches = {
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;
836 int i, err;
838 if (!dmi_check_system(mlxplat_dmi_table))
839 return -ENODEV;
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),
849 GFP_KERNEL);
850 if (!priv) {
851 err = -ENOMEM;
852 goto fail_alloc;
854 platform_set_drvdata(mlxplat_dev, priv);
856 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
857 NULL, 0);
858 if (IS_ERR(priv->pdev_i2c)) {
859 err = PTR_ERR(priv->pdev_i2c);
860 goto fail_alloc;
863 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
864 priv->pdev_mux[i] = platform_device_register_resndata(
865 &mlxplat_dev->dev,
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) {
878 err = -ENOMEM;
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",
892 PLATFORM_DEVID_NONE,
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);
904 if (err)
905 goto fail_platform_hotplug_register;
907 return 0;
909 fail_platform_hotplug_register:
910 platform_device_unregister(priv->pdev_hotplug);
911 fail_platform_mux_register:
912 while (--i >= 0)
913 platform_device_unregister(priv->pdev_mux[i]);
914 platform_device_unregister(priv->pdev_i2c);
915 fail_alloc:
916 platform_device_unregister(mlxplat_dev);
918 return err;
920 module_init(mlxplat_init);
922 static void __exit mlxplat_exit(void)
924 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
925 int i;
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");