workqueue: Make worker_attach/detach_pool() update worker->pool
[linux/fpc-iii.git] / drivers / platform / x86 / mlx-platform.c
blob7a0bd24c1ae2dcd5304150d52a54d124192e753a
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 /* 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",
132 IORESOURCE_IO),
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[] = {
155 .parent = 1,
156 .base_nr = MLXPLAT_CPLD_CH1,
157 .write_only = 1,
158 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
159 .reg_size = 1,
160 .idle_in_use = 1,
163 .parent = 1,
164 .base_nr = MLXPLAT_CPLD_CH2,
165 .write_only = 1,
166 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
167 .reg_size = 1,
168 .idle_in_use = 1,
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[] = {
219 .label = "psu1",
220 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
221 .mask = BIT(0),
222 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
223 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
226 .label = "psu2",
227 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
228 .mask = BIT(1),
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[] = {
236 .label = "pwr1",
237 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
238 .mask = BIT(0),
239 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
240 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
243 .label = "pwr2",
244 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
245 .mask = BIT(1),
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[] = {
253 .label = "fan1",
254 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
255 .mask = BIT(0),
256 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
257 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
260 .label = "fan2",
261 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
262 .mask = BIT(1),
263 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
264 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
267 .label = "fan3",
268 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
269 .mask = BIT(2),
270 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
271 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
274 .label = "fan4",
275 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
276 .mask = BIT(3),
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),
289 .inversed = 1,
290 .health = false,
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),
298 .inversed = 0,
299 .health = false,
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),
307 .inversed = 1,
308 .health = false,
312 static
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[] = {
322 .label = "pwr1",
323 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
324 .mask = BIT(0),
325 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
328 .label = "pwr2",
329 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
330 .mask = BIT(1),
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),
343 .inversed = 0,
344 .health = false,
348 static
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[] = {
361 .label = "psu1",
362 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
363 .mask = BIT(0),
364 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
365 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
368 .label = "psu2",
369 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
370 .mask = BIT(1),
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[] = {
378 .label = "pwr1",
379 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
380 .mask = BIT(0),
381 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
382 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
385 .label = "pwr2",
386 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
387 .mask = BIT(1),
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[] = {
395 .label = "fan1",
396 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
397 .mask = BIT(0),
398 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
401 .label = "fan2",
402 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
403 .mask = BIT(1),
404 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
407 .label = "fan3",
408 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
409 .mask = BIT(2),
410 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
413 .label = "fan4",
414 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
415 .mask = BIT(3),
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),
427 .inversed = 1,
428 .health = false,
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),
436 .inversed = 0,
437 .health = false,
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),
445 .inversed = 1,
446 .health = false,
450 static
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[] = {
463 .label = "pwr1",
464 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
465 .mask = BIT(0),
466 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
469 .label = "pwr2",
470 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
471 .mask = BIT(1),
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),
483 .inversed = 0,
484 .health = false,
488 static
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[] = {
501 .label = "psu1",
502 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
503 .mask = BIT(0),
504 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0],
505 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
508 .label = "psu2",
509 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
510 .mask = BIT(1),
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[] = {
518 .label = "fan1",
519 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
520 .mask = BIT(0),
521 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
524 .label = "fan2",
525 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
526 .mask = BIT(1),
527 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
530 .label = "fan3",
531 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
532 .mask = BIT(2),
533 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
536 .label = "fan4",
537 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
538 .mask = BIT(3),
539 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
542 .label = "fan5",
543 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
544 .mask = BIT(4),
545 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
548 .label = "fan6",
549 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
550 .mask = BIT(5),
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),
562 .inversed = 1,
563 .health = false,
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),
571 .inversed = 0,
572 .health = false,
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),
580 .inversed = 1,
581 .health = false,
585 static
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)
597 switch (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:
606 return true;
608 return false;
611 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
613 switch (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:
627 return true;
629 return false;
632 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
634 switch (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:
648 return true;
650 return false;
653 struct mlxplat_mlxcpld_regmap_context {
654 void __iomem *base;
657 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
659 static int
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);
665 return 0;
668 static int
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);
674 return 0;
677 static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
678 .reg_bits = 8,
679 .val_bits = 8,
680 .max_register = 255,
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)
698 int i;
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];
709 return 1;
712 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
714 int i;
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];
725 return 1;
728 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
730 int i;
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];
741 return 1;
744 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
746 int i;
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];
757 return 1;
760 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
762 int i;
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];
773 return 1;
776 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
778 .callback = mlxplat_dmi_msn274x_matched,
779 .matches = {
780 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
781 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
785 .callback = mlxplat_dmi_default_matched,
786 .matches = {
787 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
788 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
792 .callback = mlxplat_dmi_default_matched,
793 .matches = {
794 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
795 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
799 .callback = mlxplat_dmi_default_matched,
800 .matches = {
801 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
802 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
806 .callback = mlxplat_dmi_default_matched,
807 .matches = {
808 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
809 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
813 .callback = mlxplat_dmi_msn21xx_matched,
814 .matches = {
815 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
816 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
820 .callback = mlxplat_dmi_msn201x_matched,
821 .matches = {
822 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
823 DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
827 .callback = mlxplat_dmi_qmb7xx_matched,
828 .matches = {
829 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
830 DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
834 .callback = mlxplat_dmi_qmb7xx_matched,
835 .matches = {
836 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
837 DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
841 .callback = mlxplat_dmi_qmb7xx_matched,
842 .matches = {
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;
855 int shift, i;
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);
862 if (search_adap) {
863 i2c_put_adapter(search_adap);
864 continue;
867 /* Return if expected parent adapter is free. */
868 if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
869 return 0;
870 break;
873 /* Return with error if free id for adapter is not found. */
874 if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
875 return -ENODEV;
877 /* Shift adapter ids, since expected parent adapter is not free. */
878 *nr = i;
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;
883 if (shift > 0)
884 mlxplat_hotplug->shift_nr = shift;
887 return 0;
890 static int __init mlxplat_init(void)
892 struct mlxplat_priv *priv;
893 int i, nr, err;
895 if (!dmi_check_system(mlxplat_dmi_table))
896 return -ENODEV;
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),
906 GFP_KERNEL);
907 if (!priv) {
908 err = -ENOMEM;
909 goto fail_alloc;
911 platform_set_drvdata(mlxplat_dev, priv);
913 err = mlxplat_mlxcpld_verify_bus_topology(&nr);
914 if (nr < 0)
915 goto fail_alloc;
917 nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
918 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
919 NULL, 0);
920 if (IS_ERR(priv->pdev_i2c)) {
921 err = PTR_ERR(priv->pdev_i2c);
922 goto fail_alloc;
925 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
926 priv->pdev_mux[i] = platform_device_register_resndata(
927 &mlxplat_dev->dev,
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) {
940 err = -ENOMEM;
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",
954 PLATFORM_DEVID_NONE,
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);
966 if (err)
967 goto fail_platform_hotplug_register;
969 return 0;
971 fail_platform_hotplug_register:
972 platform_device_unregister(priv->pdev_hotplug);
973 fail_platform_mux_register:
974 while (--i >= 0)
975 platform_device_unregister(priv->pdev_mux[i]);
976 platform_device_unregister(priv->pdev_i2c);
977 fail_alloc:
978 platform_device_unregister(mlxplat_dev);
980 return err;
982 module_init(mlxplat_init);
984 static void __exit mlxplat_exit(void)
986 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
987 int i;
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");