Merge tag 'platform-drivers-x86-v4.17-1' of git://git.infradead.org/linux-platform...
[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 /* Default I2C parent bus number */
89 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR        1
90
91 /* Maximum number of possible physical buses equipped on system */
92 #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM       16
93
94 /* Number of channels in group */
95 #define MLXPLAT_CPLD_GRP_CHNL_NUM               8
96
97 /* Start channel numbers */
98 #define MLXPLAT_CPLD_CH1                        2
99 #define MLXPLAT_CPLD_CH2                        10
100
101 /* Number of LPC attached MUX platform devices */
102 #define MLXPLAT_CPLD_LPC_MUX_DEVS               2
103
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
112
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
117  */
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;
122 };
123
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),
133 };
134
135 /* Platform default channels */
136 static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
137         {
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
141         },
142         {
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
146         },
147 };
148
149 /* Platform channels for MSN21xx system family */
150 static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
151
152 /* Platform mux data */
153 static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
154         {
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,
161         },
162         {
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,
169         },
170
171 };
172
173 /* Platform hotplug devices */
174 static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
175         {
176                 I2C_BOARD_INFO("24c02", 0x51),
177         },
178         {
179                 I2C_BOARD_INFO("24c02", 0x50),
180         },
181 };
182
183 static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = {
184         {
185                 I2C_BOARD_INFO("24c32", 0x51),
186         },
187         {
188                 I2C_BOARD_INFO("24c32", 0x50),
189         },
190 };
191
192 static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
193         {
194                 I2C_BOARD_INFO("dps460", 0x59),
195         },
196         {
197                 I2C_BOARD_INFO("dps460", 0x58),
198         },
199 };
200
201 static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
202         {
203                 I2C_BOARD_INFO("24c32", 0x50),
204         },
205         {
206                 I2C_BOARD_INFO("24c32", 0x50),
207         },
208         {
209                 I2C_BOARD_INFO("24c32", 0x50),
210         },
211         {
212                 I2C_BOARD_INFO("24c32", 0x50),
213         },
214 };
215
216 /* Platform hotplug default data */
217 static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
218         {
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,
224         },
225         {
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,
231         },
232 };
233
234 static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
235         {
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,
241         },
242         {
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,
248         },
249 };
250
251 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
252         {
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,
258         },
259         {
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,
265         },
266         {
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,
272         },
273         {
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,
279         },
280 };
281
282 static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
283         {
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,
291         },
292         {
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,
300         },
301         {
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,
309         },
310 };
311
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,
318 };
319
320 static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
321         {
322                 .label = "pwr1",
323                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
324                 .mask = BIT(0),
325                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
326         },
327         {
328                 .label = "pwr2",
329                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
330                 .mask = BIT(1),
331                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
332         },
333 };
334
335 /* Platform hotplug MSN21xx system family data */
336 static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
337         {
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,
345         },
346 };
347
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,
356 };
357
358 /* Platform hotplug msn274x system family data */
359 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
360         {
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,
366         },
367         {
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,
373         },
374 };
375
376 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
377         {
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,
383         },
384         {
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,
390         },
391 };
392
393 static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
394         {
395                 .label = "fan1",
396                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
397                 .mask = BIT(0),
398                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
399         },
400         {
401                 .label = "fan2",
402                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
403                 .mask = BIT(1),
404                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
405         },
406         {
407                 .label = "fan3",
408                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
409                 .mask = BIT(2),
410                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
411         },
412         {
413                 .label = "fan4",
414                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
415                 .mask = BIT(3),
416                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
417         },
418 };
419
420 static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
421         {
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,
429         },
430         {
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,
438         },
439         {
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,
447         },
448 };
449
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,
458 };
459
460 /* Platform hotplug MSN201x system family data */
461 static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = {
462         {
463                 .label = "pwr1",
464                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
465                 .mask = BIT(0),
466                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
467         },
468         {
469                 .label = "pwr2",
470                 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
471                 .mask = BIT(1),
472                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
473         },
474 };
475
476 static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
477         {
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,
485         },
486 };
487
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,
496 };
497
498 /* Platform hotplug next generation system family data */
499 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = {
500         {
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,
506         },
507         {
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,
513         },
514 };
515
516 static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
517         {
518                 .label = "fan1",
519                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
520                 .mask = BIT(0),
521                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
522         },
523         {
524                 .label = "fan2",
525                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
526                 .mask = BIT(1),
527                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
528         },
529         {
530                 .label = "fan3",
531                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
532                 .mask = BIT(2),
533                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
534         },
535         {
536                 .label = "fan4",
537                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
538                 .mask = BIT(3),
539                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
540         },
541         {
542                 .label = "fan5",
543                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
544                 .mask = BIT(4),
545                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
546         },
547         {
548                 .label = "fan6",
549                 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
550                 .mask = BIT(5),
551                 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
552         },
553 };
554
555 static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = {
556         {
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,
564         },
565         {
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,
573         },
574         {
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,
582         },
583 };
584
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,
593 };
594
595 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
596 {
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;
607         }
608         return false;
609 }
610
611 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
612 {
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;
628         }
629         return false;
630 }
631
632 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
633 {
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;
649         }
650         return false;
651 }
652
653 struct mlxplat_mlxcpld_regmap_context {
654         void __iomem *base;
655 };
656
657 static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
658
659 static int
660 mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
661 {
662         struct mlxplat_mlxcpld_regmap_context *ctx = context;
663
664         *val = ioread8(ctx->base + reg);
665         return 0;
666 }
667
668 static int
669 mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
670 {
671         struct mlxplat_mlxcpld_regmap_context *ctx = context;
672
673         iowrite8(val, ctx->base + reg);
674         return 0;
675 }
676
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,
687 };
688
689 static struct resource mlxplat_mlxcpld_resources[] = {
690         [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
691 };
692
693 static struct platform_device *mlxplat_dev;
694 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
695
696 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
697 {
698         int i;
699
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]);
704         }
705         mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
706         mlxplat_hotplug->deferred_nr =
707                 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
708
709         return 1;
710 };
711
712 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
713 {
714         int i;
715
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);
720         }
721         mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
722         mlxplat_hotplug->deferred_nr =
723                 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
724
725         return 1;
726 };
727
728 static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
729 {
730         int i;
731
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);
736         }
737         mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
738         mlxplat_hotplug->deferred_nr =
739                 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
740
741         return 1;
742 };
743
744 static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
745 {
746         int i;
747
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);
752         }
753         mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
754         mlxplat_hotplug->deferred_nr =
755                 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
756
757         return 1;
758 };
759
760 static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
761 {
762         int i;
763
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);
768         }
769         mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
770         mlxplat_hotplug->deferred_nr =
771                 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
772
773         return 1;
774 };
775
776 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
777         {
778                 .callback = mlxplat_dmi_msn274x_matched,
779                 .matches = {
780                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
781                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
782                 },
783         },
784         {
785                 .callback = mlxplat_dmi_default_matched,
786                 .matches = {
787                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
788                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
789                 },
790         },
791         {
792                 .callback = mlxplat_dmi_default_matched,
793                 .matches = {
794                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
795                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
796                 },
797         },
798         {
799                 .callback = mlxplat_dmi_default_matched,
800                 .matches = {
801                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
802                         DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
803                 },
804         },
805         {
806                 .callback = mlxplat_dmi_default_matched,
807                 .matches = {
808                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
809                         DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
810                 },
811         },
812         {
813                 .callback = mlxplat_dmi_msn21xx_matched,
814                 .matches = {
815                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
816                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
817                 },
818         },
819         {
820                 .callback = mlxplat_dmi_msn201x_matched,
821                 .matches = {
822                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
823                         DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
824                 },
825         },
826         {
827                 .callback = mlxplat_dmi_qmb7xx_matched,
828                 .matches = {
829                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
830                         DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
831                 },
832         },
833         {
834                 .callback = mlxplat_dmi_qmb7xx_matched,
835                 .matches = {
836                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
837                         DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
838                 },
839         },
840         {
841                 .callback = mlxplat_dmi_qmb7xx_matched,
842                 .matches = {
843                         DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
844                         DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
845                 },
846         },
847         { }
848 };
849
850 MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
851
852 static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
853 {
854         struct i2c_adapter *search_adap;
855         int shift, i;
856
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;
865                 }
866
867                 /* Return if expected parent adapter is free. */
868                 if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
869                         return 0;
870                 break;
871         }
872
873         /* Return with error if free id for adapter is not found. */
874         if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
875                 return -ENODEV;
876
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;
885         }
886
887         return 0;
888 }
889
890 static int __init mlxplat_init(void)
891 {
892         struct mlxplat_priv *priv;
893         int i, nr, err;
894
895         if (!dmi_check_system(mlxplat_dmi_table))
896                 return -ENODEV;
897
898         mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
899                                         mlxplat_lpc_resources,
900                                         ARRAY_SIZE(mlxplat_lpc_resources));
901
902         if (IS_ERR(mlxplat_dev))
903                 return PTR_ERR(mlxplat_dev);
904
905         priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
906                             GFP_KERNEL);
907         if (!priv) {
908                 err = -ENOMEM;
909                 goto fail_alloc;
910         }
911         platform_set_drvdata(mlxplat_dev, priv);
912
913         err = mlxplat_mlxcpld_verify_bus_topology(&nr);
914         if (nr < 0)
915                 goto fail_alloc;
916
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;
923         }
924
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;
934                 }
935         }
936
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;
942         }
943
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;
950         }
951
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;
961         }
962
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;
968
969         return 0;
970
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);
979
980         return err;
981 }
982 module_init(mlxplat_init);
983
984 static void __exit mlxplat_exit(void)
985 {
986         struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
987         int i;
988
989         platform_device_unregister(priv->pdev_hotplug);
990
991         for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
992                 platform_device_unregister(priv->pdev_mux[i]);
993
994         platform_device_unregister(priv->pdev_i2c);
995         platform_device_unregister(mlxplat_dev);
996 }
997 module_exit(mlxplat_exit);
998
999 MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
1000 MODULE_DESCRIPTION("Mellanox platform driver");
1001 MODULE_LICENSE("Dual BSD/GPL");