1 /*
2  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
3  * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
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.
16  *
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.
20  *
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.
32  */
33 
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>
44 
45 #define MLX_PLAT_DEVICE_NAME		"mlxplat"
46 
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_LED1_OFFSET	0x20
51 #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET	0x21
52 #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET	0x22
53 #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET	0x23
54 #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET	0x24
55 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET	0x3a
56 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET	0x3b
57 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET	0x40
58 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET	0x41
59 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET		0x58
60 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET	0x59
61 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET	0x5a
62 #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET		0x64
63 #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET	0x65
64 #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET	0x66
65 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET		0x88
66 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET	0x89
67 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET	0x8a
68 #define MLXPLAT_CPLD_LPC_IO_RANGE		0x100
69 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF		0xdb
70 #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF		0xda
71 #define MLXPLAT_CPLD_LPC_PIO_OFFSET		0x10000UL
72 #define MLXPLAT_CPLD_LPC_REG1	((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
73 				  MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
74 				  MLXPLAT_CPLD_LPC_PIO_OFFSET)
75 #define MLXPLAT_CPLD_LPC_REG2	((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
76 				  MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
77 				  MLXPLAT_CPLD_LPC_PIO_OFFSET)
78 
79 /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
80 #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF	0x08
81 #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF	0x08
82 #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF	0x40
83 #define MLXPLAT_CPLD_AGGR_MASK_DEF	(MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
84 					 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
85 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF	0x04
86 #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW	0xc0
87 #define MLXPLAT_CPLD_AGGR_MASK_MSN21XX	0x04
88 #define MLXPLAT_CPLD_PSU_MASK		GENMASK(1, 0)
89 #define MLXPLAT_CPLD_PWR_MASK		GENMASK(1, 0)
90 #define MLXPLAT_CPLD_FAN_MASK		GENMASK(3, 0)
91 #define MLXPLAT_CPLD_FAN_NG_MASK	GENMASK(5, 0)
92 #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK	GENMASK(7, 4)
93 #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK	GENMASK(3, 0)
94 
95 /* Default I2C parent bus number */
96 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR	1
97 
98 /* Maximum number of possible physical buses equipped on system */
99 #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM	16
100 
101 /* Number of channels in group */
102 #define MLXPLAT_CPLD_GRP_CHNL_NUM		8
103 
104 /* Start channel numbers */
105 #define MLXPLAT_CPLD_CH1			2
106 #define MLXPLAT_CPLD_CH2			10
107 
108 /* Number of LPC attached MUX platform devices */
109 #define MLXPLAT_CPLD_LPC_MUX_DEVS		2
110 
111 /* Hotplug devices adapter numbers */
112 #define MLXPLAT_CPLD_NR_NONE			-1
113 #define MLXPLAT_CPLD_PSU_DEFAULT_NR		10
114 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR		4
115 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR		11
116 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR		12
117 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR		13
118 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR		14
119 
120 /* mlxplat_priv - platform private data
121  * @pdev_i2c - i2c controller platform device
122  * @pdev_mux - array of mux platform devices
123  * @pdev_hotplug - hotplug platform devices
124  * @pdev_led - led platform devices
125  */
126 struct mlxplat_priv {
127 	struct platform_device *pdev_i2c;
128 	struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
129 	struct platform_device *pdev_hotplug;
130 	struct platform_device *pdev_led;
131 };
132 
133 /* Regions for LPC I2C controller and LPC base register space */
134 static const struct resource mlxplat_lpc_resources[] = {
135 	[0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
136 			       MLXPLAT_CPLD_LPC_IO_RANGE,
137 			       "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
138 	[1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
139 			       MLXPLAT_CPLD_LPC_IO_RANGE,
140 			       "mlxplat_cpld_lpc_regs",
141 			       IORESOURCE_IO),
142 };
143 
144 /* Platform default channels */
145 static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
146 	{
147 		MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
148 		MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
149 		5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
150 	},
151 	{
152 		MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
153 		MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
154 		5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
155 	},
156 };
157 
158 /* Platform channels for MSN21xx system family */
159 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
160 
161 /* Platform mux data */
162 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
163 	{
164 		.parent = 1,
165 		.base_nr = MLXPLAT_CPLD_CH1,
166 		.write_only = 1,
167 		.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
168 		.reg_size = 1,
169 		.idle_in_use = 1,
170 	},
171 	{
172 		.parent = 1,
173 		.base_nr = MLXPLAT_CPLD_CH2,
174 		.write_only = 1,
175 		.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
176 		.reg_size = 1,
177 		.idle_in_use = 1,
178 	},
179 
180 };
181 
182 /* Platform hotplug devices */
183 static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
184 	{
185 		I2C_BOARD_INFO("24c02", 0x51),
186 	},
187 	{
188 		I2C_BOARD_INFO("24c02", 0x50),
189 	},
190 };
191 
192 static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = {
193 	{
194 		I2C_BOARD_INFO("24c32", 0x51),
195 	},
196 	{
197 		I2C_BOARD_INFO("24c32", 0x50),
198 	},
199 };
200 
201 static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
202 	{
203 		I2C_BOARD_INFO("dps460", 0x59),
204 	},
205 	{
206 		I2C_BOARD_INFO("dps460", 0x58),
207 	},
208 };
209 
210 static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
211 	{
212 		I2C_BOARD_INFO("24c32", 0x50),
213 	},
214 	{
215 		I2C_BOARD_INFO("24c32", 0x50),
216 	},
217 	{
218 		I2C_BOARD_INFO("24c32", 0x50),
219 	},
220 	{
221 		I2C_BOARD_INFO("24c32", 0x50),
222 	},
223 };
224 
225 /* Platform hotplug default data */
226 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
227 	{
228 		.label = "psu1",
229 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
230 		.mask = BIT(0),
231 		.hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
232 		.hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
233 	},
234 	{
235 		.label = "psu2",
236 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
237 		.mask = BIT(1),
238 		.hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
239 		.hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
240 	},
241 };
242 
243 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
244 	{
245 		.label = "pwr1",
246 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
247 		.mask = BIT(0),
248 		.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
249 		.hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
250 	},
251 	{
252 		.label = "pwr2",
253 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
254 		.mask = BIT(1),
255 		.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
256 		.hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
257 	},
258 };
259 
260 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
261 	{
262 		.label = "fan1",
263 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
264 		.mask = BIT(0),
265 		.hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
266 		.hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
267 	},
268 	{
269 		.label = "fan2",
270 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
271 		.mask = BIT(1),
272 		.hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
273 		.hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
274 	},
275 	{
276 		.label = "fan3",
277 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
278 		.mask = BIT(2),
279 		.hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
280 		.hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
281 	},
282 	{
283 		.label = "fan4",
284 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
285 		.mask = BIT(3),
286 		.hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
287 		.hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
288 	},
289 };
290 
291 static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
292 	{
293 		.data = mlxplat_mlxcpld_default_psu_items_data,
294 		.aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
295 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
296 		.mask = MLXPLAT_CPLD_PSU_MASK,
297 		.count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
298 		.inversed = 1,
299 		.health = false,
300 	},
301 	{
302 		.data = mlxplat_mlxcpld_default_pwr_items_data,
303 		.aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
304 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
305 		.mask = MLXPLAT_CPLD_PWR_MASK,
306 		.count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
307 		.inversed = 0,
308 		.health = false,
309 	},
310 	{
311 		.data = mlxplat_mlxcpld_default_fan_items_data,
312 		.aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
313 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
314 		.mask = MLXPLAT_CPLD_FAN_MASK,
315 		.count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
316 		.inversed = 1,
317 		.health = false,
318 	},
319 };
320 
321 static
322 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
323 	.items = mlxplat_mlxcpld_default_items,
324 	.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
325 	.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
326 	.mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
327 };
328 
329 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
330 	{
331 		.label = "pwr1",
332 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
333 		.mask = BIT(0),
334 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
335 	},
336 	{
337 		.label = "pwr2",
338 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
339 		.mask = BIT(1),
340 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
341 	},
342 };
343 
344 /* Platform hotplug MSN21xx system family data */
345 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
346 	{
347 		.data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
348 		.aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
349 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
350 		.mask = MLXPLAT_CPLD_PWR_MASK,
351 		.count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
352 		.inversed = 0,
353 		.health = false,
354 	},
355 };
356 
357 static
358 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
359 	.items = mlxplat_mlxcpld_msn21xx_items,
360 	.counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
361 	.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
362 	.mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
363 	.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
364 	.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
365 };
366 
367 /* Platform hotplug msn274x system family data */
368 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
369 	{
370 		.label = "psu1",
371 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
372 		.mask = BIT(0),
373 		.hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
374 		.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
375 	},
376 	{
377 		.label = "psu2",
378 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
379 		.mask = BIT(1),
380 		.hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
381 		.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
382 	},
383 };
384 
385 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
386 	{
387 		.label = "pwr1",
388 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
389 		.mask = BIT(0),
390 		.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
391 		.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
392 	},
393 	{
394 		.label = "pwr2",
395 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
396 		.mask = BIT(1),
397 		.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
398 		.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
399 	},
400 };
401 
402 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
403 	{
404 		.label = "fan1",
405 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
406 		.mask = BIT(0),
407 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
408 	},
409 	{
410 		.label = "fan2",
411 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
412 		.mask = BIT(1),
413 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
414 	},
415 	{
416 		.label = "fan3",
417 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
418 		.mask = BIT(2),
419 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
420 	},
421 	{
422 		.label = "fan4",
423 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
424 		.mask = BIT(3),
425 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
426 	},
427 };
428 
429 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
430 	{
431 		.data = mlxplat_mlxcpld_msn274x_psu_items_data,
432 		.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
433 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
434 		.mask = MLXPLAT_CPLD_PSU_MASK,
435 		.count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data),
436 		.inversed = 1,
437 		.health = false,
438 	},
439 	{
440 		.data = mlxplat_mlxcpld_default_ng_pwr_items_data,
441 		.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
442 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
443 		.mask = MLXPLAT_CPLD_PWR_MASK,
444 		.count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
445 		.inversed = 0,
446 		.health = false,
447 	},
448 	{
449 		.data = mlxplat_mlxcpld_msn274x_fan_items_data,
450 		.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
451 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
452 		.mask = MLXPLAT_CPLD_FAN_MASK,
453 		.count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data),
454 		.inversed = 1,
455 		.health = false,
456 	},
457 };
458 
459 static
460 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = {
461 	.items = mlxplat_mlxcpld_msn274x_items,
462 	.counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items),
463 	.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
464 	.mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
465 	.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
466 	.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
467 };
468 
469 /* Platform hotplug MSN201x system family data */
470 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = {
471 	{
472 		.label = "pwr1",
473 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
474 		.mask = BIT(0),
475 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
476 	},
477 	{
478 		.label = "pwr2",
479 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
480 		.mask = BIT(1),
481 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
482 	},
483 };
484 
485 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
486 	{
487 		.data = mlxplat_mlxcpld_msn201x_pwr_items_data,
488 		.aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
489 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
490 		.mask = MLXPLAT_CPLD_PWR_MASK,
491 		.count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data),
492 		.inversed = 0,
493 		.health = false,
494 	},
495 };
496 
497 static
498 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = {
499 	.items = mlxplat_mlxcpld_msn21xx_items,
500 	.counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items),
501 	.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
502 	.mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
503 	.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
504 	.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
505 };
506 
507 /* Platform hotplug next generation system family data */
508 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = {
509 	{
510 		.label = "psu1",
511 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
512 		.mask = BIT(0),
513 		.hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0],
514 		.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
515 	},
516 	{
517 		.label = "psu2",
518 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
519 		.mask = BIT(1),
520 		.hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1],
521 		.hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
522 	},
523 };
524 
525 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
526 	{
527 		.label = "fan1",
528 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
529 		.mask = BIT(0),
530 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
531 	},
532 	{
533 		.label = "fan2",
534 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
535 		.mask = BIT(1),
536 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
537 	},
538 	{
539 		.label = "fan3",
540 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
541 		.mask = BIT(2),
542 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
543 	},
544 	{
545 		.label = "fan4",
546 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
547 		.mask = BIT(3),
548 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
549 	},
550 	{
551 		.label = "fan5",
552 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
553 		.mask = BIT(4),
554 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
555 	},
556 	{
557 		.label = "fan6",
558 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
559 		.mask = BIT(5),
560 		.hpdev.nr = MLXPLAT_CPLD_NR_NONE,
561 	},
562 };
563 
564 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = {
565 	{
566 		.data = mlxplat_mlxcpld_default_ng_psu_items_data,
567 		.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
568 		.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
569 		.mask = MLXPLAT_CPLD_PSU_MASK,
570 		.count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data),
571 		.inversed = 1,
572 		.health = false,
573 	},
574 	{
575 		.data = mlxplat_mlxcpld_default_ng_pwr_items_data,
576 		.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
577 		.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
578 		.mask = MLXPLAT_CPLD_PWR_MASK,
579 		.count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
580 		.inversed = 0,
581 		.health = false,
582 	},
583 	{
584 		.data = mlxplat_mlxcpld_default_ng_fan_items_data,
585 		.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
586 		.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
587 		.mask = MLXPLAT_CPLD_FAN_NG_MASK,
588 		.count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
589 		.inversed = 1,
590 		.health = false,
591 	},
592 };
593 
594 static
595 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
596 	.items = mlxplat_mlxcpld_default_ng_items,
597 	.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items),
598 	.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
599 	.mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
600 	.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
601 	.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
602 };
603 
604 /* Platform led default data */
605 static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = {
606 	{
607 		.label = "status:green",
608 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
609 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
610 	},
611 	{
612 		.label = "status:red",
613 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
614 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
615 	},
616 	{
617 		.label = "psu:green",
618 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
619 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
620 	},
621 	{
622 		.label = "psu:red",
623 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
624 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
625 	},
626 	{
627 		.label = "fan1:green",
628 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
629 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
630 	},
631 	{
632 		.label = "fan1:red",
633 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
634 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
635 	},
636 	{
637 		.label = "fan2:green",
638 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
639 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
640 	},
641 	{
642 		.label = "fan2:red",
643 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
644 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
645 	},
646 	{
647 		.label = "fan3:green",
648 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
649 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
650 	},
651 	{
652 		.label = "fan3:red",
653 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
654 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
655 	},
656 	{
657 		.label = "fan4:green",
658 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
659 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
660 	},
661 	{
662 		.label = "fan4:red",
663 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
664 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
665 	},
666 };
667 
668 static struct mlxreg_core_platform_data mlxplat_default_led_data = {
669 		.data = mlxplat_mlxcpld_default_led_data,
670 		.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data),
671 };
672 
673 /* Platform led MSN21xx system family data */
674 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = {
675 	{
676 		.label = "status:green",
677 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
678 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
679 	},
680 	{
681 		.label = "status:red",
682 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
683 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
684 	},
685 	{
686 		.label = "fan:green",
687 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
688 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
689 	},
690 	{
691 		.label = "fan:red",
692 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
693 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
694 	},
695 	{
696 		.label = "psu1:green",
697 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
698 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
699 	},
700 	{
701 		.label = "psu1:red",
702 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
703 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
704 	},
705 	{
706 		.label = "psu2:green",
707 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
708 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
709 	},
710 	{
711 		.label = "psu2:red",
712 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
713 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
714 	},
715 	{
716 		.label = "uid:blue",
717 		.reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET,
718 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
719 	},
720 };
721 
722 static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = {
723 		.data = mlxplat_mlxcpld_msn21xx_led_data,
724 		.counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data),
725 };
726 
727 /* Platform led for default data for 200GbE systems */
728 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = {
729 	{
730 		.label = "status:green",
731 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
732 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
733 	},
734 	{
735 		.label = "status:orange",
736 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
737 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
738 	},
739 	{
740 		.label = "psu:green",
741 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
742 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
743 	},
744 	{
745 		.label = "psu:orange",
746 		.reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
747 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
748 	},
749 	{
750 		.label = "fan1:green",
751 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
752 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
753 	},
754 	{
755 		.label = "fan1:orange",
756 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
757 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
758 	},
759 	{
760 		.label = "fan2:green",
761 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
762 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
763 	},
764 	{
765 		.label = "fan2:orange",
766 		.reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
767 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
768 	},
769 	{
770 		.label = "fan3:green",
771 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
772 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
773 	},
774 	{
775 		.label = "fan3:orange",
776 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
777 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
778 	},
779 	{
780 		.label = "fan4:green",
781 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
782 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
783 	},
784 	{
785 		.label = "fan4:orange",
786 		.reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
787 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
788 	},
789 	{
790 		.label = "fan5:green",
791 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
792 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
793 	},
794 	{
795 		.label = "fan5:orange",
796 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
797 		.mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
798 	},
799 	{
800 		.label = "fan6:green",
801 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
802 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
803 	},
804 	{
805 		.label = "fan6:orange",
806 		.reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
807 		.mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
808 	},
809 };
810 
811 static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = {
812 		.data = mlxplat_mlxcpld_default_ng_led_data,
813 		.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data),
814 };
815 
816 
817 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
818 {
819 	switch (reg) {
820 	case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
821 	case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
822 	case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
823 	case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
824 	case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
825 	case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
826 	case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
827 	case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
828 	case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
829 	case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
830 	case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
831 	case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
832 	case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
833 		return true;
834 	}
835 	return false;
836 }
837 
838 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
839 {
840 	switch (reg) {
841 	case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
842 	case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
843 	case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
844 	case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
845 	case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
846 	case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
847 	case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
848 	case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
849 	case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
850 	case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
851 	case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
852 	case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
853 	case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
854 	case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
855 	case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
856 	case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
857 	case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
858 	case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
859 		return true;
860 	}
861 	return false;
862 }
863 
864 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
865 {
866 	switch (reg) {
867 	case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
868 	case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
869 	case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
870 	case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
871 	case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
872 	case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
873 	case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
874 	case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
875 	case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
876 	case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
877 	case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
878 	case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
879 	case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
880 	case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
881 	case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
882 	case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
883 	case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
884 	case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
885 		return true;
886 	}
887 	return false;
888 }
889 
890 struct mlxplat_mlxcpld_regmap_context {
891 	void __iomem *base;
892 };
893 
894 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
895 
896 static int
897 mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
898 {
899 	struct mlxplat_mlxcpld_regmap_context *ctx = context;
900 
901 	*val = ioread8(ctx->base + reg);
902 	return 0;
903 }
904 
905 static int
906 mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
907 {
908 	struct mlxplat_mlxcpld_regmap_context *ctx = context;
909 
910 	iowrite8(val, ctx->base + reg);
911 	return 0;
912 }
913 
914 static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
915 	.reg_bits = 8,
916 	.val_bits = 8,
917 	.max_register = 255,
918 	.cache_type = REGCACHE_FLAT,
919 	.writeable_reg = mlxplat_mlxcpld_writeable_reg,
920 	.readable_reg = mlxplat_mlxcpld_readable_reg,
921 	.volatile_reg = mlxplat_mlxcpld_volatile_reg,
922 	.reg_read = mlxplat_mlxcpld_reg_read,
923 	.reg_write = mlxplat_mlxcpld_reg_write,
924 };
925 
926 static struct resource mlxplat_mlxcpld_resources[] = {
927 	[0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
928 };
929 
930 static struct platform_device *mlxplat_dev;
931 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
932 static struct mlxreg_core_platform_data *mlxplat_led;
933 
934 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
935 {
936 	int i;
937 
938 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
939 		mlxplat_mux_data[i].values = mlxplat_default_channels[i];
940 		mlxplat_mux_data[i].n_values =
941 				ARRAY_SIZE(mlxplat_default_channels[i]);
942 	}
943 	mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
944 	mlxplat_hotplug->deferred_nr =
945 		mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
946 	mlxplat_led = &mlxplat_default_led_data;
947 
948 	return 1;
949 };
950 
951 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
952 {
953 	int i;
954 
955 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
956 		mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
957 		mlxplat_mux_data[i].n_values =
958 				ARRAY_SIZE(mlxplat_msn21xx_channels);
959 	}
960 	mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
961 	mlxplat_hotplug->deferred_nr =
962 		mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
963 	mlxplat_led = &mlxplat_msn21xx_led_data;
964 
965 	return 1;
966 };
967 
968 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
969 {
970 	int i;
971 
972 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
973 		mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
974 		mlxplat_mux_data[i].n_values =
975 				ARRAY_SIZE(mlxplat_msn21xx_channels);
976 	}
977 	mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
978 	mlxplat_hotplug->deferred_nr =
979 		mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
980 	mlxplat_led = &mlxplat_default_led_data;
981 
982 	return 1;
983 };
984 
985 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
986 {
987 	int i;
988 
989 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
990 		mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
991 		mlxplat_mux_data[i].n_values =
992 				ARRAY_SIZE(mlxplat_msn21xx_channels);
993 	}
994 	mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
995 	mlxplat_hotplug->deferred_nr =
996 		mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
997 	mlxplat_led = &mlxplat_default_ng_led_data;
998 
999 	return 1;
1000 };
1001 
1002 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
1003 {
1004 	int i;
1005 
1006 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
1007 		mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
1008 		mlxplat_mux_data[i].n_values =
1009 				ARRAY_SIZE(mlxplat_msn21xx_channels);
1010 	}
1011 	mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
1012 	mlxplat_hotplug->deferred_nr =
1013 		mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
1014 	mlxplat_led = &mlxplat_msn21xx_led_data;
1015 
1016 	return 1;
1017 };
1018 
1019 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
1020 	{
1021 		.callback = mlxplat_dmi_msn274x_matched,
1022 		.matches = {
1023 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1024 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
1025 		},
1026 	},
1027 	{
1028 		.callback = mlxplat_dmi_default_matched,
1029 		.matches = {
1030 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1031 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
1032 		},
1033 	},
1034 	{
1035 		.callback = mlxplat_dmi_default_matched,
1036 		.matches = {
1037 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1038 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
1039 		},
1040 	},
1041 	{
1042 		.callback = mlxplat_dmi_default_matched,
1043 		.matches = {
1044 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1045 			DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
1046 		},
1047 	},
1048 	{
1049 		.callback = mlxplat_dmi_default_matched,
1050 		.matches = {
1051 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1052 			DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
1053 		},
1054 	},
1055 	{
1056 		.callback = mlxplat_dmi_msn21xx_matched,
1057 		.matches = {
1058 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1059 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
1060 		},
1061 	},
1062 	{
1063 		.callback = mlxplat_dmi_msn201x_matched,
1064 		.matches = {
1065 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1066 			DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
1067 		},
1068 	},
1069 	{
1070 		.callback = mlxplat_dmi_qmb7xx_matched,
1071 		.matches = {
1072 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1073 			DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
1074 		},
1075 	},
1076 	{
1077 		.callback = mlxplat_dmi_qmb7xx_matched,
1078 		.matches = {
1079 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1080 			DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
1081 		},
1082 	},
1083 	{
1084 		.callback = mlxplat_dmi_qmb7xx_matched,
1085 		.matches = {
1086 			DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
1087 			DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
1088 		},
1089 	},
1090 	{
1091 		.callback = mlxplat_dmi_default_matched,
1092 		.matches = {
1093 			DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"),
1094 		},
1095 	},
1096 	{
1097 		.callback = mlxplat_dmi_msn21xx_matched,
1098 		.matches = {
1099 			DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"),
1100 		},
1101 	},
1102 	{
1103 		.callback = mlxplat_dmi_msn274x_matched,
1104 		.matches = {
1105 			DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"),
1106 		},
1107 	},
1108 	{
1109 		.callback = mlxplat_dmi_msn201x_matched,
1110 		.matches = {
1111 			DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"),
1112 		},
1113 	},
1114 	{
1115 		.callback = mlxplat_dmi_qmb7xx_matched,
1116 		.matches = {
1117 			DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"),
1118 		},
1119 	},
1120 	{ }
1121 };
1122 
1123 MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
1124 
1125 static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
1126 {
1127 	struct i2c_adapter *search_adap;
1128 	int shift, i;
1129 
1130 	/* Scan adapters from expected id to verify it is free. */
1131 	*nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
1132 	for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
1133 	     MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
1134 		search_adap = i2c_get_adapter(i);
1135 		if (search_adap) {
1136 			i2c_put_adapter(search_adap);
1137 			continue;
1138 		}
1139 
1140 		/* Return if expected parent adapter is free. */
1141 		if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
1142 			return 0;
1143 		break;
1144 	}
1145 
1146 	/* Return with error if free id for adapter is not found. */
1147 	if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
1148 		return -ENODEV;
1149 
1150 	/* Shift adapter ids, since expected parent adapter is not free. */
1151 	*nr = i;
1152 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
1153 		shift = *nr - mlxplat_mux_data[i].parent;
1154 		mlxplat_mux_data[i].parent = *nr;
1155 		mlxplat_mux_data[i].base_nr += shift;
1156 		if (shift > 0)
1157 			mlxplat_hotplug->shift_nr = shift;
1158 	}
1159 
1160 	return 0;
1161 }
1162 
1163 static int __init mlxplat_init(void)
1164 {
1165 	struct mlxplat_priv *priv;
1166 	int i, nr, err;
1167 
1168 	if (!dmi_check_system(mlxplat_dmi_table))
1169 		return -ENODEV;
1170 
1171 	mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
1172 					mlxplat_lpc_resources,
1173 					ARRAY_SIZE(mlxplat_lpc_resources));
1174 
1175 	if (IS_ERR(mlxplat_dev))
1176 		return PTR_ERR(mlxplat_dev);
1177 
1178 	priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
1179 			    GFP_KERNEL);
1180 	if (!priv) {
1181 		err = -ENOMEM;
1182 		goto fail_alloc;
1183 	}
1184 	platform_set_drvdata(mlxplat_dev, priv);
1185 
1186 	err = mlxplat_mlxcpld_verify_bus_topology(&nr);
1187 	if (nr < 0)
1188 		goto fail_alloc;
1189 
1190 	nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
1191 	priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
1192 							 NULL, 0);
1193 	if (IS_ERR(priv->pdev_i2c)) {
1194 		err = PTR_ERR(priv->pdev_i2c);
1195 		goto fail_alloc;
1196 	}
1197 
1198 	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
1199 		priv->pdev_mux[i] = platform_device_register_resndata(
1200 						&mlxplat_dev->dev,
1201 						"i2c-mux-reg", i, NULL,
1202 						0, &mlxplat_mux_data[i],
1203 						sizeof(mlxplat_mux_data[i]));
1204 		if (IS_ERR(priv->pdev_mux[i])) {
1205 			err = PTR_ERR(priv->pdev_mux[i]);
1206 			goto fail_platform_mux_register;
1207 		}
1208 	}
1209 
1210 	mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
1211 			       mlxplat_lpc_resources[1].start, 1);
1212 	if (!mlxplat_mlxcpld_regmap_ctx.base) {
1213 		err = -ENOMEM;
1214 		goto fail_platform_mux_register;
1215 	}
1216 
1217 	mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
1218 					&mlxplat_mlxcpld_regmap_ctx,
1219 					&mlxplat_mlxcpld_regmap_config);
1220 	if (IS_ERR(mlxplat_hotplug->regmap)) {
1221 		err = PTR_ERR(mlxplat_hotplug->regmap);
1222 		goto fail_platform_mux_register;
1223 	}
1224 
1225 	priv->pdev_hotplug = platform_device_register_resndata(
1226 				&mlxplat_dev->dev, "mlxreg-hotplug",
1227 				PLATFORM_DEVID_NONE,
1228 				mlxplat_mlxcpld_resources,
1229 				ARRAY_SIZE(mlxplat_mlxcpld_resources),
1230 				mlxplat_hotplug, sizeof(*mlxplat_hotplug));
1231 	if (IS_ERR(priv->pdev_hotplug)) {
1232 		err = PTR_ERR(priv->pdev_hotplug);
1233 		goto fail_platform_mux_register;
1234 	}
1235 
1236 	/* Add LED driver. */
1237 	mlxplat_led->regmap = mlxplat_hotplug->regmap;
1238 	priv->pdev_led = platform_device_register_resndata(
1239 				&mlxplat_dev->dev, "leds-mlxreg",
1240 				PLATFORM_DEVID_NONE, NULL, 0,
1241 				mlxplat_led, sizeof(*mlxplat_led));
1242 	if (IS_ERR(priv->pdev_led)) {
1243 		err = PTR_ERR(priv->pdev_led);
1244 		goto fail_platform_hotplug_register;
1245 	}
1246 
1247 	/* Sync registers with hardware. */
1248 	regcache_mark_dirty(mlxplat_hotplug->regmap);
1249 	err = regcache_sync(mlxplat_hotplug->regmap);
1250 	if (err)
1251 		goto fail_platform_led_register;
1252 
1253 	return 0;
1254 
1255 fail_platform_led_register:
1256 	platform_device_unregister(priv->pdev_led);
1257 fail_platform_hotplug_register:
1258 	platform_device_unregister(priv->pdev_hotplug);
1259 fail_platform_mux_register:
1260 	while (--i >= 0)
1261 		platform_device_unregister(priv->pdev_mux[i]);
1262 	platform_device_unregister(priv->pdev_i2c);
1263 fail_alloc:
1264 	platform_device_unregister(mlxplat_dev);
1265 
1266 	return err;
1267 }
1268 module_init(mlxplat_init);
1269 
1270 static void __exit mlxplat_exit(void)
1271 {
1272 	struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
1273 	int i;
1274 
1275 	platform_device_unregister(priv->pdev_led);
1276 	platform_device_unregister(priv->pdev_hotplug);
1277 
1278 	for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
1279 		platform_device_unregister(priv->pdev_mux[i]);
1280 
1281 	platform_device_unregister(priv->pdev_i2c);
1282 	platform_device_unregister(mlxplat_dev);
1283 }
1284 module_exit(mlxplat_exit);
1285 
1286 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
1287 MODULE_DESCRIPTION("Mellanox platform driver");
1288 MODULE_LICENSE("Dual BSD/GPL");
1289