blob: 03c9e7a76d89dfd69d5ae2c04d4d7fc94f6cc7d2 [file] [log] [blame]
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00001/*
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00002 * 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>
Vadim Pasternakc6acad62018-01-22 19:55:11 -080038#include <linux/io.h>
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000039#include <linux/module.h>
40#include <linux/platform_device.h>
41#include <linux/platform_data/i2c-mux-reg.h>
Vadim Pasternak1f976f62018-01-17 18:21:53 +000042#include <linux/platform_data/mlxreg.h>
Vadim Pasternakc6acad62018-01-22 19:55:11 -080043#include <linux/regmap.h>
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000044
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
Vadim Pasternakc6acad62018-01-22 19:55:11 -080050#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
51#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
52#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
53#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000054#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
55#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
56#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
57#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
58#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
59 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
60 MLXPLAT_CPLD_LPC_PIO_OFFSET)
61#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
62 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
63 MLXPLAT_CPLD_LPC_PIO_OFFSET)
64
Vadim Pasternak9a38b672016-12-14 12:05:15 +000065/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
66#define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08
67#define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08
68#define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40
69#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
70 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
71#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04
72#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
73#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
74#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
75
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000076/* Start channel numbers */
77#define MLXPLAT_CPLD_CH1 2
78#define MLXPLAT_CPLD_CH2 10
79
80/* Number of LPC attached MUX platform devices */
81#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
82
83/* mlxplat_priv - platform private data
84 * @pdev_i2c - i2c controller platform device
85 * @pdev_mux - array of mux platform devices
86 */
87struct mlxplat_priv {
88 struct platform_device *pdev_i2c;
89 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +000090 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000091};
92
93/* Regions for LPC I2C controller and LPC base register space */
94static const struct resource mlxplat_lpc_resources[] = {
95 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
96 MLXPLAT_CPLD_LPC_IO_RANGE,
97 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
98 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
99 MLXPLAT_CPLD_LPC_IO_RANGE,
100 "mlxplat_cpld_lpc_regs",
101 IORESOURCE_IO),
102};
103
104/* Platform default channels */
105static const int mlxplat_default_channels[][8] = {
106 {
107 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
108 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
109 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
110 },
111 {
112 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
113 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
114 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
115 },
116};
117
118/* Platform channels for MSN21xx system family */
119static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
120
121/* Platform mux data */
122static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
123 {
124 .parent = 1,
125 .base_nr = MLXPLAT_CPLD_CH1,
126 .write_only = 1,
127 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
128 .reg_size = 1,
129 .idle_in_use = 1,
130 },
131 {
132 .parent = 1,
133 .base_nr = MLXPLAT_CPLD_CH2,
134 .write_only = 1,
135 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
136 .reg_size = 1,
137 .idle_in_use = 1,
138 },
139
140};
141
Vadim Pasternakafc47152016-10-27 19:55:54 +0000142/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800143static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000144 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800145 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000146 },
147 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800148 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000149 },
150};
151
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800152static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000153 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800154 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000155 },
156 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800157 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000158 },
159};
160
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800161static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000162 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800163 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000164 },
165 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800166 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000167 },
168 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800169 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000170 },
171 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800172 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000173 },
174};
175
176/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800177static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
178 {
179 .label = "psu1",
180 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
181 .mask = BIT(0),
182 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
183 .hpdev.nr = 10,
184 },
185 {
186 .label = "psu2",
187 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
188 .mask = BIT(1),
189 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
190 .hpdev.nr = 10,
191 },
192};
193
194static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
195 {
196 .label = "pwr1",
197 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
198 .mask = BIT(0),
199 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
200 .hpdev.nr = 10,
201 },
202 {
203 .label = "pwr2",
204 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
205 .mask = BIT(1),
206 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
207 .hpdev.nr = 10,
208 },
209};
210
211static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
212 {
213 .label = "fan1",
214 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
215 .mask = BIT(0),
216 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
217 .hpdev.nr = 11,
218 },
219 {
220 .label = "fan2",
221 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
222 .mask = BIT(1),
223 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
224 .hpdev.nr = 12,
225 },
226 {
227 .label = "fan3",
228 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
229 .mask = BIT(2),
230 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
231 .hpdev.nr = 13,
232 },
233 {
234 .label = "fan4",
235 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
236 .mask = BIT(3),
237 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
238 .hpdev.nr = 14,
239 },
240};
241
242static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
243 {
244 .data = mlxplat_mlxcpld_default_psu_items_data,
245 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
246 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
247 .mask = MLXPLAT_CPLD_PSU_MASK,
248 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
249 .inversed = 1,
250 .health = false,
251 },
252 {
253 .data = mlxplat_mlxcpld_default_pwr_items_data,
254 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
255 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
256 .mask = MLXPLAT_CPLD_PWR_MASK,
257 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
258 .inversed = 0,
259 .health = false,
260 },
261 {
262 .data = mlxplat_mlxcpld_default_fan_items_data,
263 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
264 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
265 .mask = MLXPLAT_CPLD_FAN_MASK,
266 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
267 .inversed = 1,
268 .health = false,
269 },
270};
271
Vadim Pasternakafc47152016-10-27 19:55:54 +0000272static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800273struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
274 .items = mlxplat_mlxcpld_default_items,
275 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
276 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
277 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000278};
279
280/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800281static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
282 {
283 .data = mlxplat_mlxcpld_default_pwr_items_data,
284 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
285 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
286 .mask = MLXPLAT_CPLD_PWR_MASK,
287 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
288 .inversed = 0,
289 .health = false,
290 },
291};
292
Vadim Pasternakafc47152016-10-27 19:55:54 +0000293static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800294struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
295 .items = mlxplat_mlxcpld_msn21xx_items,
296 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
297 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
298 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
299};
300
301struct mlxplat_mlxcpld_regmap_context {
302 void __iomem *base;
303};
304
305static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
306
307static int
308mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
309{
310 struct mlxplat_mlxcpld_regmap_context *ctx = context;
311
312 *val = ioread8(ctx->base + reg);
313 return 0;
314}
315
316static int
317mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
318{
319 struct mlxplat_mlxcpld_regmap_context *ctx = context;
320
321 iowrite8(val, ctx->base + reg);
322 return 0;
323}
324
325static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
326 .reg_bits = 8,
327 .val_bits = 8,
328 .max_register = 255,
329 .reg_read = mlxplat_mlxcpld_reg_read,
330 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000331};
332
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000333static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000334 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000335};
336
Colin Ian King36c282b2017-10-05 11:42:11 +0100337static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800338static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000339
340static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
341{
342 int i;
343
344 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
345 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
346 mlxplat_mux_data[i].n_values =
347 ARRAY_SIZE(mlxplat_default_channels[i]);
348 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000349 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000350
351 return 1;
352};
353
354static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
355{
356 int i;
357
358 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
359 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
360 mlxplat_mux_data[i].n_values =
361 ARRAY_SIZE(mlxplat_msn21xx_channels);
362 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000363 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000364
365 return 1;
366};
367
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200368static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000369 {
370 .callback = mlxplat_dmi_default_matched,
371 .matches = {
372 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
373 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
374 },
375 },
376 {
377 .callback = mlxplat_dmi_default_matched,
378 .matches = {
379 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
380 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
381 },
382 },
383 {
384 .callback = mlxplat_dmi_default_matched,
385 .matches = {
386 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
387 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
388 },
389 },
390 {
391 .callback = mlxplat_dmi_default_matched,
392 .matches = {
393 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
394 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
395 },
396 },
397 {
398 .callback = mlxplat_dmi_msn21xx_matched,
399 .matches = {
400 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
401 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
402 },
403 },
404 { }
405};
406
407static int __init mlxplat_init(void)
408{
409 struct mlxplat_priv *priv;
410 int i, err;
411
412 if (!dmi_check_system(mlxplat_dmi_table))
413 return -ENODEV;
414
415 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
416 mlxplat_lpc_resources,
417 ARRAY_SIZE(mlxplat_lpc_resources));
418
Wei Yongjun65f74222016-09-24 11:48:13 +0000419 if (IS_ERR(mlxplat_dev))
420 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000421
422 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
423 GFP_KERNEL);
424 if (!priv) {
425 err = -ENOMEM;
426 goto fail_alloc;
427 }
428 platform_set_drvdata(mlxplat_dev, priv);
429
430 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
431 NULL, 0);
432 if (IS_ERR(priv->pdev_i2c)) {
433 err = PTR_ERR(priv->pdev_i2c);
434 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800435 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000436
437 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
438 priv->pdev_mux[i] = platform_device_register_resndata(
439 &mlxplat_dev->dev,
440 "i2c-mux-reg", i, NULL,
441 0, &mlxplat_mux_data[i],
442 sizeof(mlxplat_mux_data[i]));
443 if (IS_ERR(priv->pdev_mux[i])) {
444 err = PTR_ERR(priv->pdev_mux[i]);
445 goto fail_platform_mux_register;
446 }
447 }
448
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800449 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
450 mlxplat_lpc_resources[1].start, 1);
451 if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) {
452 err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base);
453 goto fail_platform_mux_register;
454 }
455
456 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
457 &mlxplat_mlxcpld_regmap_ctx,
458 &mlxplat_mlxcpld_regmap_config);
459 if (IS_ERR(mlxplat_hotplug->regmap)) {
460 err = PTR_ERR(mlxplat_hotplug->regmap);
461 goto fail_platform_mux_register;
462 }
463
Vadim Pasternakafc47152016-10-27 19:55:54 +0000464 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000465 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000466 PLATFORM_DEVID_NONE,
467 mlxplat_mlxcpld_resources,
468 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000469 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
470 if (IS_ERR(priv->pdev_hotplug)) {
471 err = PTR_ERR(priv->pdev_hotplug);
472 goto fail_platform_mux_register;
473 }
474
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000475 return 0;
476
477fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300478 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000479 platform_device_unregister(priv->pdev_mux[i]);
480 platform_device_unregister(priv->pdev_i2c);
481fail_alloc:
482 platform_device_unregister(mlxplat_dev);
483
484 return err;
485}
486module_init(mlxplat_init);
487
488static void __exit mlxplat_exit(void)
489{
490 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
491 int i;
492
Vadim Pasternakafc47152016-10-27 19:55:54 +0000493 platform_device_unregister(priv->pdev_hotplug);
494
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000495 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
496 platform_device_unregister(priv->pdev_mux[i]);
497
498 platform_device_unregister(priv->pdev_i2c);
499 platform_device_unregister(mlxplat_dev);
500}
501module_exit(mlxplat_exit);
502
503MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
504MODULE_DESCRIPTION("Mellanox platform driver");
505MODULE_LICENSE("Dual BSD/GPL");
506MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
507MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
508MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
509MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
510MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");