blob: 67f3c6d3698873e39267133602f31a4943b4f9b9 [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)
Vadim Pasternak6016f7d2018-02-02 08:45:47 +000080#define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04
81#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0
Vadim Pasternak9a38b672016-12-14 12:05:15 +000082#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)
Vadim Pasternak1bd42d92018-02-09 23:59:32 +000086#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0)
Vadim Pasternak9a38b672016-12-14 12:05:15 +000087
Vadim Pasternakd066f142018-02-13 22:09:33 +000088/* Number of channels in group */
89#define MLXPLAT_CPLD_GRP_CHNL_NUM 8
90
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000091/* Start channel numbers */
92#define MLXPLAT_CPLD_CH1 2
93#define MLXPLAT_CPLD_CH2 10
94
95/* Number of LPC attached MUX platform devices */
96#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
97
Vadim Pasternakba814fd2018-02-02 08:45:45 +000098/* Hotplug devices adapter numbers */
Vadim Pasternak17785672018-02-02 08:45:46 +000099#define MLXPLAT_CPLD_NR_NONE -1
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000100#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
Vadim Pasternakef08e142018-02-09 23:59:30 +0000101#define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000102#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
103#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
104#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
105#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
106
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000107/* mlxplat_priv - platform private data
108 * @pdev_i2c - i2c controller platform device
109 * @pdev_mux - array of mux platform devices
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -0800110 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000111 */
112struct mlxplat_priv {
113 struct platform_device *pdev_i2c;
114 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +0000115 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000116};
117
118/* Regions for LPC I2C controller and LPC base register space */
119static const struct resource mlxplat_lpc_resources[] = {
120 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
121 MLXPLAT_CPLD_LPC_IO_RANGE,
122 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
123 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
124 MLXPLAT_CPLD_LPC_IO_RANGE,
125 "mlxplat_cpld_lpc_regs",
126 IORESOURCE_IO),
127};
128
129/* Platform default channels */
Vadim Pasternakd066f142018-02-13 22:09:33 +0000130static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000131 {
132 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
133 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
134 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
135 },
136 {
137 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
138 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
139 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
140 },
141};
142
143/* Platform channels for MSN21xx system family */
144static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
145
146/* Platform mux data */
147static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
148 {
149 .parent = 1,
150 .base_nr = MLXPLAT_CPLD_CH1,
151 .write_only = 1,
152 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
153 .reg_size = 1,
154 .idle_in_use = 1,
155 },
156 {
157 .parent = 1,
158 .base_nr = MLXPLAT_CPLD_CH2,
159 .write_only = 1,
160 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
161 .reg_size = 1,
162 .idle_in_use = 1,
163 },
164
165};
166
Vadim Pasternakafc47152016-10-27 19:55:54 +0000167/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800168static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000169 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800170 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000171 },
172 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800173 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000174 },
175};
176
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000177static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = {
178 {
179 I2C_BOARD_INFO("24c32", 0x51),
180 },
181 {
182 I2C_BOARD_INFO("24c32", 0x50),
183 },
184};
185
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800186static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000187 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800188 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000189 },
190 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800191 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000192 },
193};
194
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800195static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000196 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800197 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000198 },
199 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800200 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000201 },
202 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800203 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000204 },
205 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800206 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000207 },
208};
209
210/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800211static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
212 {
213 .label = "psu1",
214 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
215 .mask = BIT(0),
216 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000217 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800218 },
219 {
220 .label = "psu2",
221 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
222 .mask = BIT(1),
223 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000224 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800225 },
226};
227
228static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
229 {
230 .label = "pwr1",
231 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
232 .mask = BIT(0),
233 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000234 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800235 },
236 {
237 .label = "pwr2",
238 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
239 .mask = BIT(1),
240 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000241 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800242 },
243};
244
245static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
246 {
247 .label = "fan1",
248 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
249 .mask = BIT(0),
250 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000251 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800252 },
253 {
254 .label = "fan2",
255 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
256 .mask = BIT(1),
257 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000258 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800259 },
260 {
261 .label = "fan3",
262 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
263 .mask = BIT(2),
264 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000265 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800266 },
267 {
268 .label = "fan4",
269 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
270 .mask = BIT(3),
271 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000272 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800273 },
274};
275
276static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
277 {
278 .data = mlxplat_mlxcpld_default_psu_items_data,
279 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
280 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
281 .mask = MLXPLAT_CPLD_PSU_MASK,
282 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
283 .inversed = 1,
284 .health = false,
285 },
286 {
287 .data = mlxplat_mlxcpld_default_pwr_items_data,
288 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
289 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
290 .mask = MLXPLAT_CPLD_PWR_MASK,
291 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
292 .inversed = 0,
293 .health = false,
294 },
295 {
296 .data = mlxplat_mlxcpld_default_fan_items_data,
297 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
298 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
299 .mask = MLXPLAT_CPLD_FAN_MASK,
300 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
301 .inversed = 1,
302 .health = false,
303 },
304};
305
Vadim Pasternakafc47152016-10-27 19:55:54 +0000306static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800307struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
308 .items = mlxplat_mlxcpld_default_items,
309 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
310 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
311 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000312};
313
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000314static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
315 {
316 .label = "pwr1",
317 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
318 .mask = BIT(0),
319 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
320 },
321 {
322 .label = "pwr2",
323 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
324 .mask = BIT(1),
325 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
326 },
327};
328
Vadim Pasternakafc47152016-10-27 19:55:54 +0000329/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800330static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
331 {
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000332 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800333 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
334 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
335 .mask = MLXPLAT_CPLD_PWR_MASK,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000336 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800337 .inversed = 0,
338 .health = false,
339 },
340};
341
Vadim Pasternakafc47152016-10-27 19:55:54 +0000342static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800343struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
344 .items = mlxplat_mlxcpld_msn21xx_items,
345 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
346 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
347 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000348 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
349 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800350};
351
Vadim Pasternakef08e142018-02-09 23:59:30 +0000352/* Platform hotplug msn274x system family data */
353static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
354 {
355 .label = "psu1",
356 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
357 .mask = BIT(0),
358 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
359 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
360 },
361 {
362 .label = "psu2",
363 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
364 .mask = BIT(1),
365 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
366 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
367 },
368};
369
370static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
371 {
372 .label = "pwr1",
373 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
374 .mask = BIT(0),
375 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
376 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
377 },
378 {
379 .label = "pwr2",
380 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
381 .mask = BIT(1),
382 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
383 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
384 },
385};
386
387static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
388 {
389 .label = "fan1",
390 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
391 .mask = BIT(0),
392 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
393 },
394 {
395 .label = "fan2",
396 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
397 .mask = BIT(1),
398 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
399 },
400 {
401 .label = "fan3",
402 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
403 .mask = BIT(2),
404 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
405 },
406 {
407 .label = "fan4",
408 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
409 .mask = BIT(3),
410 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
411 },
412};
413
414static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
415 {
416 .data = mlxplat_mlxcpld_msn274x_psu_items_data,
417 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
418 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
419 .mask = MLXPLAT_CPLD_PSU_MASK,
420 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data),
421 .inversed = 1,
422 .health = false,
423 },
424 {
425 .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
426 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
427 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
428 .mask = MLXPLAT_CPLD_PWR_MASK,
429 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
430 .inversed = 0,
431 .health = false,
432 },
433 {
434 .data = mlxplat_mlxcpld_msn274x_fan_items_data,
435 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
436 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
437 .mask = MLXPLAT_CPLD_FAN_MASK,
438 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data),
439 .inversed = 1,
440 .health = false,
441 },
442};
443
444static
445struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = {
446 .items = mlxplat_mlxcpld_msn274x_items,
447 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items),
448 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
449 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
450 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
451 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
452};
453
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000454/* Platform hotplug MSN201x system family data */
455static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = {
456 {
457 .label = "pwr1",
458 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
459 .mask = BIT(0),
460 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
461 },
462 {
463 .label = "pwr2",
464 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
465 .mask = BIT(1),
466 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
467 },
468};
469
470static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
471 {
472 .data = mlxplat_mlxcpld_msn201x_pwr_items_data,
473 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
474 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
475 .mask = MLXPLAT_CPLD_PWR_MASK,
476 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data),
477 .inversed = 0,
478 .health = false,
479 },
480};
481
482static
483struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = {
484 .items = mlxplat_mlxcpld_msn21xx_items,
485 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items),
486 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
487 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
488 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
489 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
490};
491
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000492/* Platform hotplug next generation system family data */
493static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = {
494 {
495 .label = "psu1",
496 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
497 .mask = BIT(0),
498 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0],
499 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
500 },
501 {
502 .label = "psu2",
503 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
504 .mask = BIT(1),
505 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1],
506 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
507 },
508};
509
510static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
511 {
512 .label = "fan1",
513 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
514 .mask = BIT(0),
515 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
516 },
517 {
518 .label = "fan2",
519 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
520 .mask = BIT(1),
521 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
522 },
523 {
524 .label = "fan3",
525 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
526 .mask = BIT(2),
527 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
528 },
529 {
530 .label = "fan4",
531 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
532 .mask = BIT(3),
533 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
534 },
535 {
536 .label = "fan5",
537 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
538 .mask = BIT(4),
539 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
540 },
541 {
542 .label = "fan6",
543 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
544 .mask = BIT(5),
545 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
546 },
547};
548
549static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = {
550 {
551 .data = mlxplat_mlxcpld_default_ng_psu_items_data,
552 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
553 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
554 .mask = MLXPLAT_CPLD_PSU_MASK,
555 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data),
556 .inversed = 1,
557 .health = false,
558 },
559 {
560 .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
561 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
562 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
563 .mask = MLXPLAT_CPLD_PWR_MASK,
564 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
565 .inversed = 0,
566 .health = false,
567 },
568 {
569 .data = mlxplat_mlxcpld_default_ng_fan_items_data,
570 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
571 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
572 .mask = MLXPLAT_CPLD_FAN_NG_MASK,
573 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
574 .inversed = 1,
575 .health = false,
576 },
577};
578
579static
580struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
581 .items = mlxplat_mlxcpld_default_ng_items,
582 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items),
583 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
584 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
585 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
586 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
587};
588
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000589static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
590{
591 switch (reg) {
592 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
593 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
594 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
595 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
596 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
597 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
598 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
599 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
600 return true;
601 }
602 return false;
603}
604
605static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
606{
607 switch (reg) {
608 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
609 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
610 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
611 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
612 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
613 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
614 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
615 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
616 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
617 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
618 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
619 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
620 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
621 return true;
622 }
623 return false;
624}
625
626static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
627{
628 switch (reg) {
629 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
630 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
631 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
632 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
633 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
634 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
635 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
636 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
637 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
638 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
639 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
640 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
641 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
642 return true;
643 }
644 return false;
645}
646
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800647struct mlxplat_mlxcpld_regmap_context {
648 void __iomem *base;
649};
650
651static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
652
653static int
654mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
655{
656 struct mlxplat_mlxcpld_regmap_context *ctx = context;
657
658 *val = ioread8(ctx->base + reg);
659 return 0;
660}
661
662static int
663mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
664{
665 struct mlxplat_mlxcpld_regmap_context *ctx = context;
666
667 iowrite8(val, ctx->base + reg);
668 return 0;
669}
670
671static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
672 .reg_bits = 8,
673 .val_bits = 8,
674 .max_register = 255,
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000675 .cache_type = REGCACHE_FLAT,
676 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
677 .readable_reg = mlxplat_mlxcpld_readable_reg,
678 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800679 .reg_read = mlxplat_mlxcpld_reg_read,
680 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000681};
682
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000683static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000684 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000685};
686
Colin Ian King36c282b2017-10-05 11:42:11 +0100687static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800688static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000689
690static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
691{
692 int i;
693
694 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
695 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
696 mlxplat_mux_data[i].n_values =
697 ARRAY_SIZE(mlxplat_default_channels[i]);
698 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000699 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000700 mlxplat_hotplug->deferred_nr =
701 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000702
703 return 1;
704};
705
706static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
707{
708 int i;
709
710 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
711 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
712 mlxplat_mux_data[i].n_values =
713 ARRAY_SIZE(mlxplat_msn21xx_channels);
714 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000715 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000716 mlxplat_hotplug->deferred_nr =
717 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000718
719 return 1;
720};
721
Vadim Pasternakef08e142018-02-09 23:59:30 +0000722static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
723{
724 int i;
725
726 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
727 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
728 mlxplat_mux_data[i].n_values =
729 ARRAY_SIZE(mlxplat_msn21xx_channels);
730 }
731 mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000732 mlxplat_hotplug->deferred_nr =
733 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternakef08e142018-02-09 23:59:30 +0000734
735 return 1;
736};
737
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000738static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
739{
740 int i;
741
742 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
743 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
744 mlxplat_mux_data[i].n_values =
745 ARRAY_SIZE(mlxplat_msn21xx_channels);
746 }
747 mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000748 mlxplat_hotplug->deferred_nr =
749 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000750
751 return 1;
752};
753
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000754static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
755{
756 int i;
757
758 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
759 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
760 mlxplat_mux_data[i].n_values =
761 ARRAY_SIZE(mlxplat_msn21xx_channels);
762 }
763 mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000764 mlxplat_hotplug->deferred_nr =
765 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000766
767 return 1;
768};
769
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200770static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000771 {
Vadim Pasternakef08e142018-02-09 23:59:30 +0000772 .callback = mlxplat_dmi_msn274x_matched,
773 .matches = {
774 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
775 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
776 },
777 },
778 {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000779 .callback = mlxplat_dmi_default_matched,
780 .matches = {
781 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
782 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
783 },
784 },
785 {
786 .callback = mlxplat_dmi_default_matched,
787 .matches = {
788 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
789 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
790 },
791 },
792 {
793 .callback = mlxplat_dmi_default_matched,
794 .matches = {
795 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
796 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
797 },
798 },
799 {
800 .callback = mlxplat_dmi_default_matched,
801 .matches = {
802 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
803 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
804 },
805 },
806 {
807 .callback = mlxplat_dmi_msn21xx_matched,
808 .matches = {
809 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
810 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
811 },
812 },
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000813 {
814 .callback = mlxplat_dmi_msn201x_matched,
815 .matches = {
816 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
817 DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
818 },
819 },
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000820 {
821 .callback = mlxplat_dmi_qmb7xx_matched,
822 .matches = {
823 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
824 DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
825 },
826 },
827 {
828 .callback = mlxplat_dmi_qmb7xx_matched,
829 .matches = {
830 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
831 DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
832 },
833 },
834 {
835 .callback = mlxplat_dmi_qmb7xx_matched,
836 .matches = {
837 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
838 DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
839 },
840 },
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000841 { }
842};
843
Ivan Vecera580d8342018-01-22 15:20:43 +0100844MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
845
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000846static int __init mlxplat_init(void)
847{
848 struct mlxplat_priv *priv;
849 int i, err;
850
851 if (!dmi_check_system(mlxplat_dmi_table))
852 return -ENODEV;
853
854 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
855 mlxplat_lpc_resources,
856 ARRAY_SIZE(mlxplat_lpc_resources));
857
Wei Yongjun65f74222016-09-24 11:48:13 +0000858 if (IS_ERR(mlxplat_dev))
859 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000860
861 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
862 GFP_KERNEL);
863 if (!priv) {
864 err = -ENOMEM;
865 goto fail_alloc;
866 }
867 platform_set_drvdata(mlxplat_dev, priv);
868
869 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
870 NULL, 0);
871 if (IS_ERR(priv->pdev_i2c)) {
872 err = PTR_ERR(priv->pdev_i2c);
873 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800874 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000875
876 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
877 priv->pdev_mux[i] = platform_device_register_resndata(
878 &mlxplat_dev->dev,
879 "i2c-mux-reg", i, NULL,
880 0, &mlxplat_mux_data[i],
881 sizeof(mlxplat_mux_data[i]));
882 if (IS_ERR(priv->pdev_mux[i])) {
883 err = PTR_ERR(priv->pdev_mux[i]);
884 goto fail_platform_mux_register;
885 }
886 }
887
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800888 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
889 mlxplat_lpc_resources[1].start, 1);
Dan Carpenter8a0f5b62018-02-06 15:45:36 +0300890 if (!mlxplat_mlxcpld_regmap_ctx.base) {
891 err = -ENOMEM;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800892 goto fail_platform_mux_register;
893 }
894
895 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
896 &mlxplat_mlxcpld_regmap_ctx,
897 &mlxplat_mlxcpld_regmap_config);
898 if (IS_ERR(mlxplat_hotplug->regmap)) {
899 err = PTR_ERR(mlxplat_hotplug->regmap);
900 goto fail_platform_mux_register;
901 }
902
Vadim Pasternakafc47152016-10-27 19:55:54 +0000903 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000904 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000905 PLATFORM_DEVID_NONE,
906 mlxplat_mlxcpld_resources,
907 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000908 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
909 if (IS_ERR(priv->pdev_hotplug)) {
910 err = PTR_ERR(priv->pdev_hotplug);
911 goto fail_platform_mux_register;
912 }
913
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000914 /* Sync registers with hardware. */
915 regcache_mark_dirty(mlxplat_hotplug->regmap);
916 err = regcache_sync(mlxplat_hotplug->regmap);
917 if (err)
Vadim Pasternak47260982018-01-31 21:55:13 +0000918 goto fail_platform_hotplug_register;
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000919
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000920 return 0;
921
Vadim Pasternak47260982018-01-31 21:55:13 +0000922fail_platform_hotplug_register:
923 platform_device_unregister(priv->pdev_hotplug);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000924fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300925 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000926 platform_device_unregister(priv->pdev_mux[i]);
927 platform_device_unregister(priv->pdev_i2c);
928fail_alloc:
929 platform_device_unregister(mlxplat_dev);
930
931 return err;
932}
933module_init(mlxplat_init);
934
935static void __exit mlxplat_exit(void)
936{
937 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
938 int i;
939
Vadim Pasternakafc47152016-10-27 19:55:54 +0000940 platform_device_unregister(priv->pdev_hotplug);
941
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000942 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
943 platform_device_unregister(priv->pdev_mux[i]);
944
945 platform_device_unregister(priv->pdev_i2c);
946 platform_device_unregister(mlxplat_dev);
947}
948module_exit(mlxplat_exit);
949
950MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
951MODULE_DESCRIPTION("Mellanox platform driver");
952MODULE_LICENSE("Dual BSD/GPL");