blob: fa27ca8b03bae442da450d0ba3655c230eaec03b [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
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -080086 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000087 */
88struct mlxplat_priv {
89 struct platform_device *pdev_i2c;
90 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +000091 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000092};
93
94/* Regions for LPC I2C controller and LPC base register space */
95static const struct resource mlxplat_lpc_resources[] = {
96 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
97 MLXPLAT_CPLD_LPC_IO_RANGE,
98 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
99 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
100 MLXPLAT_CPLD_LPC_IO_RANGE,
101 "mlxplat_cpld_lpc_regs",
102 IORESOURCE_IO),
103};
104
105/* Platform default channels */
106static const int mlxplat_default_channels[][8] = {
107 {
108 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
109 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
110 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
111 },
112 {
113 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
114 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
115 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
116 },
117};
118
119/* Platform channels for MSN21xx system family */
120static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
121
122/* Platform mux data */
123static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
124 {
125 .parent = 1,
126 .base_nr = MLXPLAT_CPLD_CH1,
127 .write_only = 1,
128 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
129 .reg_size = 1,
130 .idle_in_use = 1,
131 },
132 {
133 .parent = 1,
134 .base_nr = MLXPLAT_CPLD_CH2,
135 .write_only = 1,
136 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
137 .reg_size = 1,
138 .idle_in_use = 1,
139 },
140
141};
142
Vadim Pasternakafc47152016-10-27 19:55:54 +0000143/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800144static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000145 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800146 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000147 },
148 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800149 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000150 },
151};
152
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800153static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000154 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800155 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000156 },
157 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800158 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000159 },
160};
161
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800162static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000163 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800164 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000165 },
166 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800167 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000168 },
169 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800170 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000171 },
172 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800173 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000174 },
175};
176
177/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800178static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
179 {
180 .label = "psu1",
181 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
182 .mask = BIT(0),
183 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
184 .hpdev.nr = 10,
185 },
186 {
187 .label = "psu2",
188 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
189 .mask = BIT(1),
190 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
191 .hpdev.nr = 10,
192 },
193};
194
195static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
196 {
197 .label = "pwr1",
198 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
199 .mask = BIT(0),
200 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
201 .hpdev.nr = 10,
202 },
203 {
204 .label = "pwr2",
205 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
206 .mask = BIT(1),
207 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
208 .hpdev.nr = 10,
209 },
210};
211
212static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
213 {
214 .label = "fan1",
215 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
216 .mask = BIT(0),
217 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
218 .hpdev.nr = 11,
219 },
220 {
221 .label = "fan2",
222 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
223 .mask = BIT(1),
224 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
225 .hpdev.nr = 12,
226 },
227 {
228 .label = "fan3",
229 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
230 .mask = BIT(2),
231 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
232 .hpdev.nr = 13,
233 },
234 {
235 .label = "fan4",
236 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
237 .mask = BIT(3),
238 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
239 .hpdev.nr = 14,
240 },
241};
242
243static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
244 {
245 .data = mlxplat_mlxcpld_default_psu_items_data,
246 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
247 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
248 .mask = MLXPLAT_CPLD_PSU_MASK,
249 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
250 .inversed = 1,
251 .health = false,
252 },
253 {
254 .data = mlxplat_mlxcpld_default_pwr_items_data,
255 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
256 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
257 .mask = MLXPLAT_CPLD_PWR_MASK,
258 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
259 .inversed = 0,
260 .health = false,
261 },
262 {
263 .data = mlxplat_mlxcpld_default_fan_items_data,
264 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
265 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
266 .mask = MLXPLAT_CPLD_FAN_MASK,
267 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
268 .inversed = 1,
269 .health = false,
270 },
271};
272
Vadim Pasternakafc47152016-10-27 19:55:54 +0000273static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800274struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
275 .items = mlxplat_mlxcpld_default_items,
276 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
277 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
278 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000279};
280
281/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800282static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
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
Vadim Pasternakafc47152016-10-27 19:55:54 +0000294static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800295struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
296 .items = mlxplat_mlxcpld_msn21xx_items,
297 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
298 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
299 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
300};
301
302struct mlxplat_mlxcpld_regmap_context {
303 void __iomem *base;
304};
305
306static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
307
308static int
309mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
310{
311 struct mlxplat_mlxcpld_regmap_context *ctx = context;
312
313 *val = ioread8(ctx->base + reg);
314 return 0;
315}
316
317static int
318mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
319{
320 struct mlxplat_mlxcpld_regmap_context *ctx = context;
321
322 iowrite8(val, ctx->base + reg);
323 return 0;
324}
325
326static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
327 .reg_bits = 8,
328 .val_bits = 8,
329 .max_register = 255,
330 .reg_read = mlxplat_mlxcpld_reg_read,
331 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000332};
333
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000334static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000335 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000336};
337
Colin Ian King36c282b2017-10-05 11:42:11 +0100338static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800339static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000340
341static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
342{
343 int i;
344
345 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
346 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
347 mlxplat_mux_data[i].n_values =
348 ARRAY_SIZE(mlxplat_default_channels[i]);
349 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000350 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000351
352 return 1;
353};
354
355static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
356{
357 int i;
358
359 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
360 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
361 mlxplat_mux_data[i].n_values =
362 ARRAY_SIZE(mlxplat_msn21xx_channels);
363 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000364 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000365
366 return 1;
367};
368
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200369static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000370 {
371 .callback = mlxplat_dmi_default_matched,
372 .matches = {
373 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
374 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
375 },
376 },
377 {
378 .callback = mlxplat_dmi_default_matched,
379 .matches = {
380 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
381 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
382 },
383 },
384 {
385 .callback = mlxplat_dmi_default_matched,
386 .matches = {
387 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
388 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
389 },
390 },
391 {
392 .callback = mlxplat_dmi_default_matched,
393 .matches = {
394 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
395 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
396 },
397 },
398 {
399 .callback = mlxplat_dmi_msn21xx_matched,
400 .matches = {
401 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
402 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
403 },
404 },
405 { }
406};
407
408static int __init mlxplat_init(void)
409{
410 struct mlxplat_priv *priv;
411 int i, err;
412
413 if (!dmi_check_system(mlxplat_dmi_table))
414 return -ENODEV;
415
416 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
417 mlxplat_lpc_resources,
418 ARRAY_SIZE(mlxplat_lpc_resources));
419
Wei Yongjun65f74222016-09-24 11:48:13 +0000420 if (IS_ERR(mlxplat_dev))
421 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000422
423 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
424 GFP_KERNEL);
425 if (!priv) {
426 err = -ENOMEM;
427 goto fail_alloc;
428 }
429 platform_set_drvdata(mlxplat_dev, priv);
430
431 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
432 NULL, 0);
433 if (IS_ERR(priv->pdev_i2c)) {
434 err = PTR_ERR(priv->pdev_i2c);
435 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800436 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000437
438 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
439 priv->pdev_mux[i] = platform_device_register_resndata(
440 &mlxplat_dev->dev,
441 "i2c-mux-reg", i, NULL,
442 0, &mlxplat_mux_data[i],
443 sizeof(mlxplat_mux_data[i]));
444 if (IS_ERR(priv->pdev_mux[i])) {
445 err = PTR_ERR(priv->pdev_mux[i]);
446 goto fail_platform_mux_register;
447 }
448 }
449
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800450 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
451 mlxplat_lpc_resources[1].start, 1);
452 if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) {
453 err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base);
454 goto fail_platform_mux_register;
455 }
456
457 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
458 &mlxplat_mlxcpld_regmap_ctx,
459 &mlxplat_mlxcpld_regmap_config);
460 if (IS_ERR(mlxplat_hotplug->regmap)) {
461 err = PTR_ERR(mlxplat_hotplug->regmap);
462 goto fail_platform_mux_register;
463 }
464
Vadim Pasternakafc47152016-10-27 19:55:54 +0000465 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000466 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000467 PLATFORM_DEVID_NONE,
468 mlxplat_mlxcpld_resources,
469 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000470 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
471 if (IS_ERR(priv->pdev_hotplug)) {
472 err = PTR_ERR(priv->pdev_hotplug);
473 goto fail_platform_mux_register;
474 }
475
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000476 return 0;
477
478fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300479 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000480 platform_device_unregister(priv->pdev_mux[i]);
481 platform_device_unregister(priv->pdev_i2c);
482fail_alloc:
483 platform_device_unregister(mlxplat_dev);
484
485 return err;
486}
487module_init(mlxplat_init);
488
489static void __exit mlxplat_exit(void)
490{
491 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
492 int i;
493
Vadim Pasternakafc47152016-10-27 19:55:54 +0000494 platform_device_unregister(priv->pdev_hotplug);
495
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000496 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
497 platform_device_unregister(priv->pdev_mux[i]);
498
499 platform_device_unregister(priv->pdev_i2c);
500 platform_device_unregister(mlxplat_dev);
501}
502module_exit(mlxplat_exit);
503
504MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
505MODULE_DESCRIPTION("Mellanox platform driver");
506MODULE_LICENSE("Dual BSD/GPL");
507MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
508MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
509MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
510MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
511MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");