blob: 912f844713ab4cc88d1afadca68bc19ce8831b86 [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 Pasternakef0f6222018-02-13 22:09:36 +000088/* Default I2C parent bus number */
89#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
90
91/* Maximum number of possible physical buses equipped on system */
92#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
93
Vadim Pasternakd066f142018-02-13 22:09:33 +000094/* Number of channels in group */
95#define MLXPLAT_CPLD_GRP_CHNL_NUM 8
96
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000097/* Start channel numbers */
98#define MLXPLAT_CPLD_CH1 2
99#define MLXPLAT_CPLD_CH2 10
100
101/* Number of LPC attached MUX platform devices */
102#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
103
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000104/* Hotplug devices adapter numbers */
Vadim Pasternak1778567a2018-02-02 08:45:46 +0000105#define MLXPLAT_CPLD_NR_NONE -1
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000106#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
Vadim Pasternakef08e142018-02-09 23:59:30 +0000107#define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000108#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
109#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
110#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
111#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
112
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000113/* mlxplat_priv - platform private data
114 * @pdev_i2c - i2c controller platform device
115 * @pdev_mux - array of mux platform devices
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -0800116 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000117 */
118struct mlxplat_priv {
119 struct platform_device *pdev_i2c;
120 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +0000121 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000122};
123
124/* Regions for LPC I2C controller and LPC base register space */
125static const struct resource mlxplat_lpc_resources[] = {
126 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
127 MLXPLAT_CPLD_LPC_IO_RANGE,
128 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
129 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
130 MLXPLAT_CPLD_LPC_IO_RANGE,
131 "mlxplat_cpld_lpc_regs",
132 IORESOURCE_IO),
133};
134
135/* Platform default channels */
Vadim Pasternakd066f142018-02-13 22:09:33 +0000136static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000137 {
138 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
139 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
140 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
141 },
142 {
143 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
144 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
145 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
146 },
147};
148
149/* Platform channels for MSN21xx system family */
150static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
151
152/* Platform mux data */
153static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
154 {
155 .parent = 1,
156 .base_nr = MLXPLAT_CPLD_CH1,
157 .write_only = 1,
158 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
159 .reg_size = 1,
160 .idle_in_use = 1,
161 },
162 {
163 .parent = 1,
164 .base_nr = MLXPLAT_CPLD_CH2,
165 .write_only = 1,
166 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
167 .reg_size = 1,
168 .idle_in_use = 1,
169 },
170
171};
172
Vadim Pasternakafc47152016-10-27 19:55:54 +0000173/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800174static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000175 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800176 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000177 },
178 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800179 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000180 },
181};
182
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000183static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = {
184 {
185 I2C_BOARD_INFO("24c32", 0x51),
186 },
187 {
188 I2C_BOARD_INFO("24c32", 0x50),
189 },
190};
191
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800192static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000193 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800194 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000195 },
196 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800197 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000198 },
199};
200
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800201static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000202 {
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 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800209 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000210 },
211 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800212 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000213 },
214};
215
216/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800217static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
218 {
219 .label = "psu1",
220 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
221 .mask = BIT(0),
222 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000223 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800224 },
225 {
226 .label = "psu2",
227 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
228 .mask = BIT(1),
229 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000230 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800231 },
232};
233
234static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
235 {
236 .label = "pwr1",
237 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
238 .mask = BIT(0),
239 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000240 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800241 },
242 {
243 .label = "pwr2",
244 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
245 .mask = BIT(1),
246 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000247 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800248 },
249};
250
251static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
252 {
253 .label = "fan1",
254 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
255 .mask = BIT(0),
256 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000257 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800258 },
259 {
260 .label = "fan2",
261 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
262 .mask = BIT(1),
263 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000264 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800265 },
266 {
267 .label = "fan3",
268 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
269 .mask = BIT(2),
270 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000271 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800272 },
273 {
274 .label = "fan4",
275 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
276 .mask = BIT(3),
277 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000278 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800279 },
280};
281
282static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
283 {
284 .data = mlxplat_mlxcpld_default_psu_items_data,
285 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
286 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
287 .mask = MLXPLAT_CPLD_PSU_MASK,
288 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
289 .inversed = 1,
290 .health = false,
291 },
292 {
293 .data = mlxplat_mlxcpld_default_pwr_items_data,
294 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
295 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
296 .mask = MLXPLAT_CPLD_PWR_MASK,
297 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
298 .inversed = 0,
299 .health = false,
300 },
301 {
302 .data = mlxplat_mlxcpld_default_fan_items_data,
303 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
304 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
305 .mask = MLXPLAT_CPLD_FAN_MASK,
306 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
307 .inversed = 1,
308 .health = false,
309 },
310};
311
Vadim Pasternakafc47152016-10-27 19:55:54 +0000312static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800313struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
314 .items = mlxplat_mlxcpld_default_items,
315 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
316 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
317 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000318};
319
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000320static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
321 {
322 .label = "pwr1",
323 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
324 .mask = BIT(0),
325 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
326 },
327 {
328 .label = "pwr2",
329 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
330 .mask = BIT(1),
331 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
332 },
333};
334
Vadim Pasternakafc47152016-10-27 19:55:54 +0000335/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800336static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
337 {
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000338 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800339 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
340 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
341 .mask = MLXPLAT_CPLD_PWR_MASK,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000342 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800343 .inversed = 0,
344 .health = false,
345 },
346};
347
Vadim Pasternakafc47152016-10-27 19:55:54 +0000348static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800349struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
350 .items = mlxplat_mlxcpld_msn21xx_items,
351 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
352 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
353 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000354 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
355 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800356};
357
Vadim Pasternakef08e142018-02-09 23:59:30 +0000358/* Platform hotplug msn274x system family data */
359static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
360 {
361 .label = "psu1",
362 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
363 .mask = BIT(0),
364 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
365 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
366 },
367 {
368 .label = "psu2",
369 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
370 .mask = BIT(1),
371 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
372 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
373 },
374};
375
376static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
377 {
378 .label = "pwr1",
379 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
380 .mask = BIT(0),
381 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
382 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
383 },
384 {
385 .label = "pwr2",
386 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
387 .mask = BIT(1),
388 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
389 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
390 },
391};
392
393static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
394 {
395 .label = "fan1",
396 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
397 .mask = BIT(0),
398 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
399 },
400 {
401 .label = "fan2",
402 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
403 .mask = BIT(1),
404 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
405 },
406 {
407 .label = "fan3",
408 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
409 .mask = BIT(2),
410 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
411 },
412 {
413 .label = "fan4",
414 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
415 .mask = BIT(3),
416 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
417 },
418};
419
420static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
421 {
422 .data = mlxplat_mlxcpld_msn274x_psu_items_data,
423 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
424 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
425 .mask = MLXPLAT_CPLD_PSU_MASK,
426 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data),
427 .inversed = 1,
428 .health = false,
429 },
430 {
431 .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
432 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
433 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
434 .mask = MLXPLAT_CPLD_PWR_MASK,
435 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
436 .inversed = 0,
437 .health = false,
438 },
439 {
440 .data = mlxplat_mlxcpld_msn274x_fan_items_data,
441 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
442 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
443 .mask = MLXPLAT_CPLD_FAN_MASK,
444 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data),
445 .inversed = 1,
446 .health = false,
447 },
448};
449
450static
451struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = {
452 .items = mlxplat_mlxcpld_msn274x_items,
453 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items),
454 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
455 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
456 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
457 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
458};
459
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000460/* Platform hotplug MSN201x system family data */
461static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = {
462 {
463 .label = "pwr1",
464 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
465 .mask = BIT(0),
466 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
467 },
468 {
469 .label = "pwr2",
470 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
471 .mask = BIT(1),
472 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
473 },
474};
475
476static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = {
477 {
478 .data = mlxplat_mlxcpld_msn201x_pwr_items_data,
479 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
480 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
481 .mask = MLXPLAT_CPLD_PWR_MASK,
482 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data),
483 .inversed = 0,
484 .health = false,
485 },
486};
487
488static
489struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = {
490 .items = mlxplat_mlxcpld_msn21xx_items,
491 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items),
492 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
493 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
494 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
495 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
496};
497
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000498/* Platform hotplug next generation system family data */
499static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = {
500 {
501 .label = "psu1",
502 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
503 .mask = BIT(0),
504 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0],
505 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
506 },
507 {
508 .label = "psu2",
509 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
510 .mask = BIT(1),
511 .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1],
512 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
513 },
514};
515
516static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
517 {
518 .label = "fan1",
519 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
520 .mask = BIT(0),
521 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
522 },
523 {
524 .label = "fan2",
525 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
526 .mask = BIT(1),
527 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
528 },
529 {
530 .label = "fan3",
531 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
532 .mask = BIT(2),
533 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
534 },
535 {
536 .label = "fan4",
537 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
538 .mask = BIT(3),
539 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
540 },
541 {
542 .label = "fan5",
543 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
544 .mask = BIT(4),
545 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
546 },
547 {
548 .label = "fan6",
549 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
550 .mask = BIT(5),
551 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
552 },
553};
554
555static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = {
556 {
557 .data = mlxplat_mlxcpld_default_ng_psu_items_data,
558 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
559 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
560 .mask = MLXPLAT_CPLD_PSU_MASK,
561 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data),
562 .inversed = 1,
563 .health = false,
564 },
565 {
566 .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
567 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
568 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
569 .mask = MLXPLAT_CPLD_PWR_MASK,
570 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
571 .inversed = 0,
572 .health = false,
573 },
574 {
575 .data = mlxplat_mlxcpld_default_ng_fan_items_data,
576 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
577 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
578 .mask = MLXPLAT_CPLD_FAN_NG_MASK,
579 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
580 .inversed = 1,
581 .health = false,
582 },
583};
584
585static
586struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
587 .items = mlxplat_mlxcpld_default_ng_items,
588 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items),
589 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
590 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
591 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
592 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
593};
594
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000595static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
596{
597 switch (reg) {
598 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
599 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
600 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
601 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
602 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
603 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
604 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
605 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
606 return true;
607 }
608 return false;
609}
610
611static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
612{
613 switch (reg) {
614 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
615 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
616 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
617 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
618 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
619 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
620 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
621 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
622 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
623 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
624 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
625 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
626 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
627 return true;
628 }
629 return false;
630}
631
632static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
633{
634 switch (reg) {
635 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
636 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
637 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
638 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
639 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
640 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
641 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
642 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
643 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
644 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
645 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
646 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
647 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
648 return true;
649 }
650 return false;
651}
652
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800653struct mlxplat_mlxcpld_regmap_context {
654 void __iomem *base;
655};
656
657static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
658
659static int
660mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
661{
662 struct mlxplat_mlxcpld_regmap_context *ctx = context;
663
664 *val = ioread8(ctx->base + reg);
665 return 0;
666}
667
668static int
669mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
670{
671 struct mlxplat_mlxcpld_regmap_context *ctx = context;
672
673 iowrite8(val, ctx->base + reg);
674 return 0;
675}
676
677static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
678 .reg_bits = 8,
679 .val_bits = 8,
680 .max_register = 255,
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000681 .cache_type = REGCACHE_FLAT,
682 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
683 .readable_reg = mlxplat_mlxcpld_readable_reg,
684 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800685 .reg_read = mlxplat_mlxcpld_reg_read,
686 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000687};
688
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000689static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000690 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000691};
692
Colin Ian King36c282b2017-10-05 11:42:11 +0100693static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800694static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000695
696static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
697{
698 int i;
699
700 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
701 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
702 mlxplat_mux_data[i].n_values =
703 ARRAY_SIZE(mlxplat_default_channels[i]);
704 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000705 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000706 mlxplat_hotplug->deferred_nr =
707 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000708
709 return 1;
710};
711
712static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
713{
714 int i;
715
716 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
717 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
718 mlxplat_mux_data[i].n_values =
719 ARRAY_SIZE(mlxplat_msn21xx_channels);
720 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000721 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000722 mlxplat_hotplug->deferred_nr =
723 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000724
725 return 1;
726};
727
Vadim Pasternakef08e142018-02-09 23:59:30 +0000728static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
729{
730 int i;
731
732 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
733 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
734 mlxplat_mux_data[i].n_values =
735 ARRAY_SIZE(mlxplat_msn21xx_channels);
736 }
737 mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000738 mlxplat_hotplug->deferred_nr =
739 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternakef08e142018-02-09 23:59:30 +0000740
741 return 1;
742};
743
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000744static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
745{
746 int i;
747
748 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
749 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
750 mlxplat_mux_data[i].n_values =
751 ARRAY_SIZE(mlxplat_msn21xx_channels);
752 }
753 mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000754 mlxplat_hotplug->deferred_nr =
755 mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000756
757 return 1;
758};
759
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000760static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
761{
762 int i;
763
764 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
765 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
766 mlxplat_mux_data[i].n_values =
767 ARRAY_SIZE(mlxplat_msn21xx_channels);
768 }
769 mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
Vadim Pasternakd726f6b2018-02-13 22:09:34 +0000770 mlxplat_hotplug->deferred_nr =
771 mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000772
773 return 1;
774};
775
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200776static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000777 {
Vadim Pasternakef08e142018-02-09 23:59:30 +0000778 .callback = mlxplat_dmi_msn274x_matched,
779 .matches = {
780 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
781 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
782 },
783 },
784 {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000785 .callback = mlxplat_dmi_default_matched,
786 .matches = {
787 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
788 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
789 },
790 },
791 {
792 .callback = mlxplat_dmi_default_matched,
793 .matches = {
794 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
795 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
796 },
797 },
798 {
799 .callback = mlxplat_dmi_default_matched,
800 .matches = {
801 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
802 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
803 },
804 },
805 {
806 .callback = mlxplat_dmi_default_matched,
807 .matches = {
808 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
809 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
810 },
811 },
812 {
813 .callback = mlxplat_dmi_msn21xx_matched,
814 .matches = {
815 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
816 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
817 },
818 },
Vadim Pasternaka49a4142018-02-09 23:59:31 +0000819 {
820 .callback = mlxplat_dmi_msn201x_matched,
821 .matches = {
822 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
823 DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"),
824 },
825 },
Vadim Pasternak1bd42d92018-02-09 23:59:32 +0000826 {
827 .callback = mlxplat_dmi_qmb7xx_matched,
828 .matches = {
829 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
830 DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"),
831 },
832 },
833 {
834 .callback = mlxplat_dmi_qmb7xx_matched,
835 .matches = {
836 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
837 DMI_MATCH(DMI_PRODUCT_NAME, "SN37"),
838 },
839 },
840 {
841 .callback = mlxplat_dmi_qmb7xx_matched,
842 .matches = {
843 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
844 DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
845 },
846 },
Vadim Pasternakcbf7ff82018-05-07 06:48:52 +0000847 {
848 .callback = mlxplat_dmi_default_matched,
849 .matches = {
850 DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"),
851 },
852 },
853 {
854 .callback = mlxplat_dmi_msn21xx_matched,
855 .matches = {
856 DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"),
857 },
858 },
859 {
860 .callback = mlxplat_dmi_msn274x_matched,
861 .matches = {
862 DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"),
863 },
864 },
865 {
866 .callback = mlxplat_dmi_msn201x_matched,
867 .matches = {
868 DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"),
869 },
870 },
871 {
872 .callback = mlxplat_dmi_qmb7xx_matched,
873 .matches = {
874 DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"),
875 },
876 },
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000877 { }
878};
879
Ivan Vecera580d8342018-01-22 15:20:43 +0100880MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
881
Vadim Pasternakef0f6222018-02-13 22:09:36 +0000882static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
883{
884 struct i2c_adapter *search_adap;
885 int shift, i;
886
887 /* Scan adapters from expected id to verify it is free. */
888 *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
889 for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
890 MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
891 search_adap = i2c_get_adapter(i);
892 if (search_adap) {
893 i2c_put_adapter(search_adap);
894 continue;
895 }
896
897 /* Return if expected parent adapter is free. */
898 if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
899 return 0;
900 break;
901 }
902
903 /* Return with error if free id for adapter is not found. */
904 if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
905 return -ENODEV;
906
907 /* Shift adapter ids, since expected parent adapter is not free. */
908 *nr = i;
909 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
910 shift = *nr - mlxplat_mux_data[i].parent;
911 mlxplat_mux_data[i].parent = *nr;
912 mlxplat_mux_data[i].base_nr += shift;
913 if (shift > 0)
914 mlxplat_hotplug->shift_nr = shift;
915 }
916
917 return 0;
918}
919
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000920static int __init mlxplat_init(void)
921{
922 struct mlxplat_priv *priv;
Vadim Pasternakef0f6222018-02-13 22:09:36 +0000923 int i, nr, err;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000924
925 if (!dmi_check_system(mlxplat_dmi_table))
926 return -ENODEV;
927
928 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
929 mlxplat_lpc_resources,
930 ARRAY_SIZE(mlxplat_lpc_resources));
931
Wei Yongjun65f74222016-09-24 11:48:13 +0000932 if (IS_ERR(mlxplat_dev))
933 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000934
935 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
936 GFP_KERNEL);
937 if (!priv) {
938 err = -ENOMEM;
939 goto fail_alloc;
940 }
941 platform_set_drvdata(mlxplat_dev, priv);
942
Vadim Pasternakef0f6222018-02-13 22:09:36 +0000943 err = mlxplat_mlxcpld_verify_bus_topology(&nr);
944 if (nr < 0)
945 goto fail_alloc;
946
947 nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
948 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000949 NULL, 0);
950 if (IS_ERR(priv->pdev_i2c)) {
951 err = PTR_ERR(priv->pdev_i2c);
952 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800953 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000954
955 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
956 priv->pdev_mux[i] = platform_device_register_resndata(
957 &mlxplat_dev->dev,
958 "i2c-mux-reg", i, NULL,
959 0, &mlxplat_mux_data[i],
960 sizeof(mlxplat_mux_data[i]));
961 if (IS_ERR(priv->pdev_mux[i])) {
962 err = PTR_ERR(priv->pdev_mux[i]);
963 goto fail_platform_mux_register;
964 }
965 }
966
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800967 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
968 mlxplat_lpc_resources[1].start, 1);
Dan Carpenter8a0f5b62018-02-06 15:45:36 +0300969 if (!mlxplat_mlxcpld_regmap_ctx.base) {
970 err = -ENOMEM;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800971 goto fail_platform_mux_register;
972 }
973
974 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
975 &mlxplat_mlxcpld_regmap_ctx,
976 &mlxplat_mlxcpld_regmap_config);
977 if (IS_ERR(mlxplat_hotplug->regmap)) {
978 err = PTR_ERR(mlxplat_hotplug->regmap);
979 goto fail_platform_mux_register;
980 }
981
Vadim Pasternakafc47152016-10-27 19:55:54 +0000982 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000983 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000984 PLATFORM_DEVID_NONE,
985 mlxplat_mlxcpld_resources,
986 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000987 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
988 if (IS_ERR(priv->pdev_hotplug)) {
989 err = PTR_ERR(priv->pdev_hotplug);
990 goto fail_platform_mux_register;
991 }
992
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000993 /* Sync registers with hardware. */
994 regcache_mark_dirty(mlxplat_hotplug->regmap);
995 err = regcache_sync(mlxplat_hotplug->regmap);
996 if (err)
Vadim Pasternak47260982018-01-31 21:55:13 +0000997 goto fail_platform_hotplug_register;
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000998
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000999 return 0;
1000
Vadim Pasternak47260982018-01-31 21:55:13 +00001001fail_platform_hotplug_register:
1002 platform_device_unregister(priv->pdev_hotplug);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00001003fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +03001004 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00001005 platform_device_unregister(priv->pdev_mux[i]);
1006 platform_device_unregister(priv->pdev_i2c);
1007fail_alloc:
1008 platform_device_unregister(mlxplat_dev);
1009
1010 return err;
1011}
1012module_init(mlxplat_init);
1013
1014static void __exit mlxplat_exit(void)
1015{
1016 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
1017 int i;
1018
Vadim Pasternakafc47152016-10-27 19:55:54 +00001019 platform_device_unregister(priv->pdev_hotplug);
1020
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00001021 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
1022 platform_device_unregister(priv->pdev_mux[i]);
1023
1024 platform_device_unregister(priv->pdev_i2c);
1025 platform_device_unregister(mlxplat_dev);
1026}
1027module_exit(mlxplat_exit);
1028
1029MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
1030MODULE_DESCRIPTION("Mellanox platform driver");
1031MODULE_LICENSE("Dual BSD/GPL");