Merge tag 'platform-drivers-x86-v4.16-3' of git://github.com/dvhart/linux-pdx86
[sfrench/cifs-2.6.git] / drivers / platform / x86 / mlx-platform.c
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_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)
73
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)
87
88 /* Start channel numbers */
89 #define MLXPLAT_CPLD_CH1                        2
90 #define MLXPLAT_CPLD_CH2                        10
91
92 /* Number of LPC attached MUX platform devices */
93 #define MLXPLAT_CPLD_LPC_MUX_DEVS               2
94
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
103
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
108  */
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;
113 };
114
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),
124 };
125
126 /* Platform default channels */
127 static const int mlxplat_default_channels[][8] = {
128         {
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
132         },
133         {
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
137         },
138 };
139
140 /* Platform channels for MSN21xx system family */
141 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
142
143 /* Platform mux data */
144 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
145         {
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,
152         },
153         {
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,
160         },
161
162 };
163
164 /* Platform hotplug devices */
165 static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
166         {
167                 I2C_BOARD_INFO("24c02", 0x51),
168         },
169         {
170                 I2C_BOARD_INFO("24c02", 0x50),
171         },
172 };
173
174 static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = {
175         {
176                 I2C_BOARD_INFO("24c32", 0x51),
177         },
178         {
179                 I2C_BOARD_INFO("24c32", 0x50),
180         },
181 };
182
183 static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
184         {
185                 I2C_BOARD_INFO("dps460", 0x59),
186         },
187         {
188                 I2C_BOARD_INFO("dps460", 0x58),
189         },
190 };
191
192 static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
193         {
194                 I2C_BOARD_INFO("24c32", 0x50),
195         },
196         {
197                 I2C_BOARD_INFO("24c32", 0x50),
198         },
199         {
200                 I2C_BOARD_INFO("24c32", 0x50),
201         },
202         {
203                 I2C_BOARD_INFO("24c32", 0x50),
204         },
205 };
206
207 /* Platform hotplug default data */
208 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
209         {
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,
215         },
216         {
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,
222         },
223 };
224
225 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
226         {
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,
232         },
233         {
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,
239         },
240 };
241
242 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
243         {
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,
249         },
250         {
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,
256         },
257         {
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,
263         },
264         {
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,
270         },
271 };
272
273 static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
274         {
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,
282         },
283         {
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,
291         },
292         {
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,
300         },
301 };
302
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,
309 };
310
311 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
312         {
313                 .label = "pwr1",
314                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
315                 .mask = BIT(0),
316                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
317         },
318         {
319                 .label = "pwr2",
320                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
321                 .mask = BIT(1),
322                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
323         },
324 };
325
326 /* Platform hotplug MSN21xx system family data */
327 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
328         {
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,
336         },
337 };
338
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,
347 };
348
349 /* Platform hotplug msn274x system family data */
350 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
351         {
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,
357         },
358         {
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,
364         },
365 };
366
367 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
368         {
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,
374         },
375         {
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,
381         },
382 };
383
384 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
385         {
386                 .label = "fan1",
387                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
388                 .mask = BIT(0),
389                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
390         },
391         {
392                 .label = "fan2",
393                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
394                 .mask = BIT(1),
395                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
396         },
397         {
398                 .label = "fan3",
399                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
400                 .mask = BIT(2),
401                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
402         },
403         {
404                 .label = "fan4",
405                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
406                 .mask = BIT(3),
407                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
408         },
409 };
410
411 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
412         {
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,
420         },
421         {
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,
429         },
430         {
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,
438         },
439 };
440
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,
449 };
450
451 /* Platform hotplug MSN201x system family data */
452 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = {
453         {
454                 .label = "pwr1",
455                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
456                 .mask = BIT(0),
457                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
458         },
459         {
460                 .label = "pwr2",
461                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
462                 .mask = BIT(1),
463                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
464         },
465 };
466
467 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
468         {
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,
476         },
477 };
478
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,
487 };
488
489 /* Platform hotplug next generation system family data */
490 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = {
491         {
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,
497         },
498         {
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,
504         },
505 };
506
507 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
508         {
509                 .label = "fan1",
510                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
511                 .mask = BIT(0),
512                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
513         },
514         {
515                 .label = "fan2",
516                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
517                 .mask = BIT(1),
518                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
519         },
520         {
521                 .label = "fan3",
522                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
523                 .mask = BIT(2),
524                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
525         },
526         {
527                 .label = "fan4",
528                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
529                 .mask = BIT(3),
530                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
531         },
532         {
533                 .label = "fan5",
534                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
535                 .mask = BIT(4),
536                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
537         },
538         {
539                 .label = "fan6",
540                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
541                 .mask = BIT(5),
542                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
543         },
544 };
545
546 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = {
547         {
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,
555         },
556         {
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,
564         },
565         {
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,
573         },
574 };
575
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,
584 };
585
586 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
587 {
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;
598         }
599         return false;
600 }
601
602 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
603 {
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;
619         }
620         return false;
621 }
622
623 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
624 {
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;
640         }
641         return false;
642 }
643
644 struct mlxplat_mlxcpld_regmap_context {
645         void __iomem *base;
646 };
647
648 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
649
650 static int
651 mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
652 {
653         struct mlxplat_mlxcpld_regmap_context *ctx = context;
654
655         *val = ioread8(ctx->base + reg);
656         return 0;
657 }
658
659 static int
660 mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
661 {
662         struct mlxplat_mlxcpld_regmap_context *ctx = context;
663
664         iowrite8(val, ctx->base + reg);
665         return 0;
666 }
667
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,
678 };
679
680 static struct resource mlxplat_mlxcpld_resources[] = {
681         [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
682 };
683
684 static struct platform_device *mlxplat_dev;
685 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
686
687 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
688 {
689         int i;
690
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]);
695         }
696         mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
697
698         return 1;
699 };
700
701 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
702 {
703         int i;
704
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);
709         }
710         mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
711
712         return 1;
713 };
714
715 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
716 {
717         int i;
718
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);
723         }
724         mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
725
726         return 1;
727 };
728
729 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
730 {
731         int i;
732
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);
737         }
738         mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
739
740         return 1;
741 };
742
743 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
744 {
745         int i;
746
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);
751         }
752         mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
753
754         return 1;
755 };
756
757 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
758         {
759                 .callback = mlxplat_dmi_msn274x_matched,
760                 .matches = {
761                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
762                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
763                 },
764         },
765         {
766                 .callback = mlxplat_dmi_default_matched,
767                 .matches = {
768                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
769                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
770                 },
771         },
772         {
773                 .callback = mlxplat_dmi_default_matched,
774                 .matches = {
775                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
776                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
777                 },
778         },
779         {
780                 .callback = mlxplat_dmi_default_matched,
781                 .matches = {
782                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
783                         DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
784                 },
785         },
786         {
787                 .callback = mlxplat_dmi_default_matched,
788                 .matches = {
789                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
790                         DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
791                 },
792         },
793         {
794                 .callback = mlxplat_dmi_msn21xx_matched,
795                 .matches = {
796                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
797                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
798                 },
799         },
800         {
801                 .callback = mlxplat_dmi_msn201x_matched,
802                 .matches = {
803                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
804                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
805                 },
806         },
807         {
808                 .callback = mlxplat_dmi_qmb7xx_matched,
809                 .matches = {
810                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
811                         DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
812                 },
813         },
814         {
815                 .callback = mlxplat_dmi_qmb7xx_matched,
816                 .matches = {
817                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
818                         DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
819                 },
820         },
821         {
822                 .callback = mlxplat_dmi_qmb7xx_matched,
823                 .matches = {
824                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
825                         DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
826                 },
827         },
828         { }
829 };
830
831 MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
832
833 static int __init mlxplat_init(void)
834 {
835         struct mlxplat_priv *priv;
836         int i, err;
837
838         if (!dmi_check_system(mlxplat_dmi_table))
839                 return -ENODEV;
840
841         mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
842                                         mlxplat_lpc_resources,
843                                         ARRAY_SIZE(mlxplat_lpc_resources));
844
845         if (IS_ERR(mlxplat_dev))
846                 return PTR_ERR(mlxplat_dev);
847
848         priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
849                             GFP_KERNEL);
850         if (!priv) {
851                 err = -ENOMEM;
852                 goto fail_alloc;
853         }
854         platform_set_drvdata(mlxplat_dev, priv);
855
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;
861         }
862
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;
872                 }
873         }
874
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;
880         }
881
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;
888         }
889
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;
899         }
900
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;
906
907         return 0;
908
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);
917
918         return err;
919 }
920 module_init(mlxplat_init);
921
922 static void __exit mlxplat_exit(void)
923 {
924         struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
925         int i;
926
927         platform_device_unregister(priv->pdev_hotplug);
928
929         for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
930                 platform_device_unregister(priv->pdev_mux[i]);
931
932         platform_device_unregister(priv->pdev_i2c);
933         platform_device_unregister(mlxplat_dev);
934 }
935 module_exit(mlxplat_exit);
936
937 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
938 MODULE_DESCRIPTION("Mellanox platform driver");
939 MODULE_LICENSE("Dual BSD/GPL");