blob: 752476e83da4a33a773f32cd5486f7b7600fb560 [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
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000051#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
Vadim Pasternakc6acad62018-01-22 19:55:11 -080054#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000055#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59
56#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a
Vadim Pasternakc6acad62018-01-22 19:55:11 -080057#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000058#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65
59#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66
Vadim Pasternakc6acad62018-01-22 19:55:11 -080060#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000061#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
62#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000063#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
Vadim Pasternak9a38b672016-12-14 12:05:15 +000074/* 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_MSN21XX 0x04
81#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
82#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
83#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
84
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000085/* Start channel numbers */
86#define MLXPLAT_CPLD_CH1 2
87#define MLXPLAT_CPLD_CH2 10
88
89/* Number of LPC attached MUX platform devices */
90#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
91
92/* mlxplat_priv - platform private data
93 * @pdev_i2c - i2c controller platform device
94 * @pdev_mux - array of mux platform devices
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -080095 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000096 */
97struct mlxplat_priv {
98 struct platform_device *pdev_i2c;
99 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +0000100 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000101};
102
103/* Regions for LPC I2C controller and LPC base register space */
104static const struct resource mlxplat_lpc_resources[] = {
105 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
106 MLXPLAT_CPLD_LPC_IO_RANGE,
107 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
108 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
109 MLXPLAT_CPLD_LPC_IO_RANGE,
110 "mlxplat_cpld_lpc_regs",
111 IORESOURCE_IO),
112};
113
114/* Platform default channels */
115static const int mlxplat_default_channels[][8] = {
116 {
117 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
118 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
119 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
120 },
121 {
122 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
123 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
124 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
125 },
126};
127
128/* Platform channels for MSN21xx system family */
129static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
130
131/* Platform mux data */
132static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
133 {
134 .parent = 1,
135 .base_nr = MLXPLAT_CPLD_CH1,
136 .write_only = 1,
137 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
138 .reg_size = 1,
139 .idle_in_use = 1,
140 },
141 {
142 .parent = 1,
143 .base_nr = MLXPLAT_CPLD_CH2,
144 .write_only = 1,
145 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
146 .reg_size = 1,
147 .idle_in_use = 1,
148 },
149
150};
151
Vadim Pasternakafc47152016-10-27 19:55:54 +0000152/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800153static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000154 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800155 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000156 },
157 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800158 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000159 },
160};
161
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800162static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000163 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800164 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000165 },
166 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800167 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000168 },
169};
170
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800171static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000172 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800173 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000174 },
175 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800176 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000177 },
178 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800179 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000180 },
181 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800182 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000183 },
184};
185
186/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800187static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
188 {
189 .label = "psu1",
190 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
191 .mask = BIT(0),
192 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
193 .hpdev.nr = 10,
194 },
195 {
196 .label = "psu2",
197 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
198 .mask = BIT(1),
199 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
200 .hpdev.nr = 10,
201 },
202};
203
204static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
205 {
206 .label = "pwr1",
207 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
208 .mask = BIT(0),
209 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
210 .hpdev.nr = 10,
211 },
212 {
213 .label = "pwr2",
214 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
215 .mask = BIT(1),
216 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
217 .hpdev.nr = 10,
218 },
219};
220
221static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
222 {
223 .label = "fan1",
224 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
225 .mask = BIT(0),
226 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
227 .hpdev.nr = 11,
228 },
229 {
230 .label = "fan2",
231 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
232 .mask = BIT(1),
233 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
234 .hpdev.nr = 12,
235 },
236 {
237 .label = "fan3",
238 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
239 .mask = BIT(2),
240 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
241 .hpdev.nr = 13,
242 },
243 {
244 .label = "fan4",
245 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
246 .mask = BIT(3),
247 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
248 .hpdev.nr = 14,
249 },
250};
251
252static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
253 {
254 .data = mlxplat_mlxcpld_default_psu_items_data,
255 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
256 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
257 .mask = MLXPLAT_CPLD_PSU_MASK,
258 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
259 .inversed = 1,
260 .health = false,
261 },
262 {
263 .data = mlxplat_mlxcpld_default_pwr_items_data,
264 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
265 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
266 .mask = MLXPLAT_CPLD_PWR_MASK,
267 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
268 .inversed = 0,
269 .health = false,
270 },
271 {
272 .data = mlxplat_mlxcpld_default_fan_items_data,
273 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
274 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
275 .mask = MLXPLAT_CPLD_FAN_MASK,
276 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
277 .inversed = 1,
278 .health = false,
279 },
280};
281
Vadim Pasternakafc47152016-10-27 19:55:54 +0000282static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800283struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
284 .items = mlxplat_mlxcpld_default_items,
285 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
286 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
287 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000288};
289
290/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800291static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
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
Vadim Pasternakafc47152016-10-27 19:55:54 +0000303static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800304struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
305 .items = mlxplat_mlxcpld_msn21xx_items,
306 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
307 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
308 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
309};
310
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000311static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
312{
313 switch (reg) {
314 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
315 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
316 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
317 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
318 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
319 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
320 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
321 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
322 return true;
323 }
324 return false;
325}
326
327static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
328{
329 switch (reg) {
330 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
331 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
332 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
333 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
334 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
335 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
336 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
337 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
338 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
339 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
340 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
341 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
342 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
343 return true;
344 }
345 return false;
346}
347
348static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
349{
350 switch (reg) {
351 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
352 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
353 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
354 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
355 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
356 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
357 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
358 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
359 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
360 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
361 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
362 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
363 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
364 return true;
365 }
366 return false;
367}
368
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800369struct mlxplat_mlxcpld_regmap_context {
370 void __iomem *base;
371};
372
373static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
374
375static int
376mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
377{
378 struct mlxplat_mlxcpld_regmap_context *ctx = context;
379
380 *val = ioread8(ctx->base + reg);
381 return 0;
382}
383
384static int
385mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
386{
387 struct mlxplat_mlxcpld_regmap_context *ctx = context;
388
389 iowrite8(val, ctx->base + reg);
390 return 0;
391}
392
393static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
394 .reg_bits = 8,
395 .val_bits = 8,
396 .max_register = 255,
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000397 .cache_type = REGCACHE_FLAT,
398 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
399 .readable_reg = mlxplat_mlxcpld_readable_reg,
400 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800401 .reg_read = mlxplat_mlxcpld_reg_read,
402 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000403};
404
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000405static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000406 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000407};
408
Colin Ian King36c282b2017-10-05 11:42:11 +0100409static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800410static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000411
412static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
413{
414 int i;
415
416 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
417 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
418 mlxplat_mux_data[i].n_values =
419 ARRAY_SIZE(mlxplat_default_channels[i]);
420 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000421 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000422
423 return 1;
424};
425
426static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
427{
428 int i;
429
430 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
431 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
432 mlxplat_mux_data[i].n_values =
433 ARRAY_SIZE(mlxplat_msn21xx_channels);
434 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000435 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000436
437 return 1;
438};
439
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200440static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000441 {
442 .callback = mlxplat_dmi_default_matched,
443 .matches = {
444 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
445 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
446 },
447 },
448 {
449 .callback = mlxplat_dmi_default_matched,
450 .matches = {
451 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
452 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
453 },
454 },
455 {
456 .callback = mlxplat_dmi_default_matched,
457 .matches = {
458 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
459 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
460 },
461 },
462 {
463 .callback = mlxplat_dmi_default_matched,
464 .matches = {
465 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
466 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
467 },
468 },
469 {
470 .callback = mlxplat_dmi_msn21xx_matched,
471 .matches = {
472 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
473 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
474 },
475 },
476 { }
477};
478
Ivan Vecera580d8342018-01-22 15:20:43 +0100479MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
480
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000481static int __init mlxplat_init(void)
482{
483 struct mlxplat_priv *priv;
484 int i, err;
485
486 if (!dmi_check_system(mlxplat_dmi_table))
487 return -ENODEV;
488
489 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
490 mlxplat_lpc_resources,
491 ARRAY_SIZE(mlxplat_lpc_resources));
492
Wei Yongjun65f74222016-09-24 11:48:13 +0000493 if (IS_ERR(mlxplat_dev))
494 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000495
496 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
497 GFP_KERNEL);
498 if (!priv) {
499 err = -ENOMEM;
500 goto fail_alloc;
501 }
502 platform_set_drvdata(mlxplat_dev, priv);
503
504 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
505 NULL, 0);
506 if (IS_ERR(priv->pdev_i2c)) {
507 err = PTR_ERR(priv->pdev_i2c);
508 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800509 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000510
511 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
512 priv->pdev_mux[i] = platform_device_register_resndata(
513 &mlxplat_dev->dev,
514 "i2c-mux-reg", i, NULL,
515 0, &mlxplat_mux_data[i],
516 sizeof(mlxplat_mux_data[i]));
517 if (IS_ERR(priv->pdev_mux[i])) {
518 err = PTR_ERR(priv->pdev_mux[i]);
519 goto fail_platform_mux_register;
520 }
521 }
522
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800523 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
524 mlxplat_lpc_resources[1].start, 1);
525 if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) {
526 err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base);
527 goto fail_platform_mux_register;
528 }
529
530 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
531 &mlxplat_mlxcpld_regmap_ctx,
532 &mlxplat_mlxcpld_regmap_config);
533 if (IS_ERR(mlxplat_hotplug->regmap)) {
534 err = PTR_ERR(mlxplat_hotplug->regmap);
535 goto fail_platform_mux_register;
536 }
537
Vadim Pasternakafc47152016-10-27 19:55:54 +0000538 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000539 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000540 PLATFORM_DEVID_NONE,
541 mlxplat_mlxcpld_resources,
542 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000543 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
544 if (IS_ERR(priv->pdev_hotplug)) {
545 err = PTR_ERR(priv->pdev_hotplug);
546 goto fail_platform_mux_register;
547 }
548
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000549 /* Sync registers with hardware. */
550 regcache_mark_dirty(mlxplat_hotplug->regmap);
551 err = regcache_sync(mlxplat_hotplug->regmap);
552 if (err)
553 goto fail_platform_mux_register;
554
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000555 return 0;
556
557fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300558 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000559 platform_device_unregister(priv->pdev_mux[i]);
560 platform_device_unregister(priv->pdev_i2c);
561fail_alloc:
562 platform_device_unregister(mlxplat_dev);
563
564 return err;
565}
566module_init(mlxplat_init);
567
568static void __exit mlxplat_exit(void)
569{
570 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
571 int i;
572
Vadim Pasternakafc47152016-10-27 19:55:54 +0000573 platform_device_unregister(priv->pdev_hotplug);
574
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000575 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
576 platform_device_unregister(priv->pdev_mux[i]);
577
578 platform_device_unregister(priv->pdev_i2c);
579 platform_device_unregister(mlxplat_dev);
580}
581module_exit(mlxplat_exit);
582
583MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
584MODULE_DESCRIPTION("Mellanox platform driver");
585MODULE_LICENSE("Dual BSD/GPL");