blob: e87fe34eadf5bf5a2750f1758bb3274806494d56 [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)
86
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000087/* Start channel numbers */
88#define MLXPLAT_CPLD_CH1 2
89#define MLXPLAT_CPLD_CH2 10
90
91/* Number of LPC attached MUX platform devices */
92#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
93
Vadim Pasternakba814fd2018-02-02 08:45:45 +000094/* Hotplug devices adapter numbers */
Vadim Pasternak17785672018-02-02 08:45:46 +000095#define MLXPLAT_CPLD_NR_NONE -1
Vadim Pasternakba814fd2018-02-02 08:45:45 +000096#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
97#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
98#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
99#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
100#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
101
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000102/* mlxplat_priv - platform private data
103 * @pdev_i2c - i2c controller platform device
104 * @pdev_mux - array of mux platform devices
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -0800105 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000106 */
107struct mlxplat_priv {
108 struct platform_device *pdev_i2c;
109 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +0000110 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000111};
112
113/* Regions for LPC I2C controller and LPC base register space */
114static const struct resource mlxplat_lpc_resources[] = {
115 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
116 MLXPLAT_CPLD_LPC_IO_RANGE,
117 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
118 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
119 MLXPLAT_CPLD_LPC_IO_RANGE,
120 "mlxplat_cpld_lpc_regs",
121 IORESOURCE_IO),
122};
123
124/* Platform default channels */
125static const int mlxplat_default_channels[][8] = {
126 {
127 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
128 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
129 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
130 },
131 {
132 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
133 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
134 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
135 },
136};
137
138/* Platform channels for MSN21xx system family */
139static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
140
141/* Platform mux data */
142static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
143 {
144 .parent = 1,
145 .base_nr = MLXPLAT_CPLD_CH1,
146 .write_only = 1,
147 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
148 .reg_size = 1,
149 .idle_in_use = 1,
150 },
151 {
152 .parent = 1,
153 .base_nr = MLXPLAT_CPLD_CH2,
154 .write_only = 1,
155 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
156 .reg_size = 1,
157 .idle_in_use = 1,
158 },
159
160};
161
Vadim Pasternakafc47152016-10-27 19:55:54 +0000162/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800163static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000164 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800165 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000166 },
167 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800168 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000169 },
170};
171
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800172static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000173 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800174 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000175 },
176 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800177 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000178 },
179};
180
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800181static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000182 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800183 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000184 },
185 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800186 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000187 },
188 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800189 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000190 },
191 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800192 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000193 },
194};
195
196/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800197static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
198 {
199 .label = "psu1",
200 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
201 .mask = BIT(0),
202 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000203 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800204 },
205 {
206 .label = "psu2",
207 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
208 .mask = BIT(1),
209 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000210 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800211 },
212};
213
214static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
215 {
216 .label = "pwr1",
217 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
218 .mask = BIT(0),
219 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000220 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800221 },
222 {
223 .label = "pwr2",
224 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
225 .mask = BIT(1),
226 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000227 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800228 },
229};
230
231static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
232 {
233 .label = "fan1",
234 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
235 .mask = BIT(0),
236 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000237 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800238 },
239 {
240 .label = "fan2",
241 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
242 .mask = BIT(1),
243 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000244 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800245 },
246 {
247 .label = "fan3",
248 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
249 .mask = BIT(2),
250 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000251 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800252 },
253 {
254 .label = "fan4",
255 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
256 .mask = BIT(3),
257 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000258 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800259 },
260};
261
262static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
263 {
264 .data = mlxplat_mlxcpld_default_psu_items_data,
265 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
266 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
267 .mask = MLXPLAT_CPLD_PSU_MASK,
268 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
269 .inversed = 1,
270 .health = false,
271 },
272 {
273 .data = mlxplat_mlxcpld_default_pwr_items_data,
274 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
275 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
276 .mask = MLXPLAT_CPLD_PWR_MASK,
277 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
278 .inversed = 0,
279 .health = false,
280 },
281 {
282 .data = mlxplat_mlxcpld_default_fan_items_data,
283 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
284 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
285 .mask = MLXPLAT_CPLD_FAN_MASK,
286 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
287 .inversed = 1,
288 .health = false,
289 },
290};
291
Vadim Pasternakafc47152016-10-27 19:55:54 +0000292static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800293struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
294 .items = mlxplat_mlxcpld_default_items,
295 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
296 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
297 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000298};
299
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000300static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
301 {
302 .label = "pwr1",
303 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
304 .mask = BIT(0),
305 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
306 },
307 {
308 .label = "pwr2",
309 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
310 .mask = BIT(1),
311 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
312 },
313};
314
Vadim Pasternakafc47152016-10-27 19:55:54 +0000315/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800316static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
317 {
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000318 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800319 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
320 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
321 .mask = MLXPLAT_CPLD_PWR_MASK,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000322 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800323 .inversed = 0,
324 .health = false,
325 },
326};
327
Vadim Pasternakafc47152016-10-27 19:55:54 +0000328static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800329struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
330 .items = mlxplat_mlxcpld_msn21xx_items,
331 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
332 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
333 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000334 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
335 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800336};
337
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000338static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
339{
340 switch (reg) {
341 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
342 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
343 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
344 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
345 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
346 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
347 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
348 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
349 return true;
350 }
351 return false;
352}
353
354static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
355{
356 switch (reg) {
357 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
358 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
359 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
360 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
361 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
362 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
363 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
364 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
365 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
366 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
367 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
368 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
369 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
370 return true;
371 }
372 return false;
373}
374
375static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
376{
377 switch (reg) {
378 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
379 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
380 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
381 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
382 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
383 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
384 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
385 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
386 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
387 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
388 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
389 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
390 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
391 return true;
392 }
393 return false;
394}
395
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800396struct mlxplat_mlxcpld_regmap_context {
397 void __iomem *base;
398};
399
400static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
401
402static int
403mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
404{
405 struct mlxplat_mlxcpld_regmap_context *ctx = context;
406
407 *val = ioread8(ctx->base + reg);
408 return 0;
409}
410
411static int
412mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
413{
414 struct mlxplat_mlxcpld_regmap_context *ctx = context;
415
416 iowrite8(val, ctx->base + reg);
417 return 0;
418}
419
420static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
421 .reg_bits = 8,
422 .val_bits = 8,
423 .max_register = 255,
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000424 .cache_type = REGCACHE_FLAT,
425 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
426 .readable_reg = mlxplat_mlxcpld_readable_reg,
427 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800428 .reg_read = mlxplat_mlxcpld_reg_read,
429 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000430};
431
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000432static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000433 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000434};
435
Colin Ian King36c282b2017-10-05 11:42:11 +0100436static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800437static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000438
439static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
440{
441 int i;
442
443 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
444 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
445 mlxplat_mux_data[i].n_values =
446 ARRAY_SIZE(mlxplat_default_channels[i]);
447 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000448 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000449
450 return 1;
451};
452
453static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
454{
455 int i;
456
457 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
458 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
459 mlxplat_mux_data[i].n_values =
460 ARRAY_SIZE(mlxplat_msn21xx_channels);
461 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000462 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000463
464 return 1;
465};
466
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200467static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000468 {
469 .callback = mlxplat_dmi_default_matched,
470 .matches = {
471 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
472 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
473 },
474 },
475 {
476 .callback = mlxplat_dmi_default_matched,
477 .matches = {
478 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
479 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
480 },
481 },
482 {
483 .callback = mlxplat_dmi_default_matched,
484 .matches = {
485 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
486 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
487 },
488 },
489 {
490 .callback = mlxplat_dmi_default_matched,
491 .matches = {
492 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
493 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
494 },
495 },
496 {
497 .callback = mlxplat_dmi_msn21xx_matched,
498 .matches = {
499 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
500 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
501 },
502 },
503 { }
504};
505
Ivan Vecera580d8342018-01-22 15:20:43 +0100506MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
507
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000508static int __init mlxplat_init(void)
509{
510 struct mlxplat_priv *priv;
511 int i, err;
512
513 if (!dmi_check_system(mlxplat_dmi_table))
514 return -ENODEV;
515
516 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
517 mlxplat_lpc_resources,
518 ARRAY_SIZE(mlxplat_lpc_resources));
519
Wei Yongjun65f74222016-09-24 11:48:13 +0000520 if (IS_ERR(mlxplat_dev))
521 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000522
523 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
524 GFP_KERNEL);
525 if (!priv) {
526 err = -ENOMEM;
527 goto fail_alloc;
528 }
529 platform_set_drvdata(mlxplat_dev, priv);
530
531 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
532 NULL, 0);
533 if (IS_ERR(priv->pdev_i2c)) {
534 err = PTR_ERR(priv->pdev_i2c);
535 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800536 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000537
538 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
539 priv->pdev_mux[i] = platform_device_register_resndata(
540 &mlxplat_dev->dev,
541 "i2c-mux-reg", i, NULL,
542 0, &mlxplat_mux_data[i],
543 sizeof(mlxplat_mux_data[i]));
544 if (IS_ERR(priv->pdev_mux[i])) {
545 err = PTR_ERR(priv->pdev_mux[i]);
546 goto fail_platform_mux_register;
547 }
548 }
549
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800550 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
551 mlxplat_lpc_resources[1].start, 1);
Dan Carpenter8a0f5b62018-02-06 15:45:36 +0300552 if (!mlxplat_mlxcpld_regmap_ctx.base) {
553 err = -ENOMEM;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800554 goto fail_platform_mux_register;
555 }
556
557 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
558 &mlxplat_mlxcpld_regmap_ctx,
559 &mlxplat_mlxcpld_regmap_config);
560 if (IS_ERR(mlxplat_hotplug->regmap)) {
561 err = PTR_ERR(mlxplat_hotplug->regmap);
562 goto fail_platform_mux_register;
563 }
564
Vadim Pasternakafc47152016-10-27 19:55:54 +0000565 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000566 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000567 PLATFORM_DEVID_NONE,
568 mlxplat_mlxcpld_resources,
569 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000570 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
571 if (IS_ERR(priv->pdev_hotplug)) {
572 err = PTR_ERR(priv->pdev_hotplug);
573 goto fail_platform_mux_register;
574 }
575
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000576 /* Sync registers with hardware. */
577 regcache_mark_dirty(mlxplat_hotplug->regmap);
578 err = regcache_sync(mlxplat_hotplug->regmap);
579 if (err)
Vadim Pasternak47260982018-01-31 21:55:13 +0000580 goto fail_platform_hotplug_register;
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000581
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000582 return 0;
583
Vadim Pasternak47260982018-01-31 21:55:13 +0000584fail_platform_hotplug_register:
585 platform_device_unregister(priv->pdev_hotplug);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000586fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300587 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000588 platform_device_unregister(priv->pdev_mux[i]);
589 platform_device_unregister(priv->pdev_i2c);
590fail_alloc:
591 platform_device_unregister(mlxplat_dev);
592
593 return err;
594}
595module_init(mlxplat_init);
596
597static void __exit mlxplat_exit(void)
598{
599 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
600 int i;
601
Vadim Pasternakafc47152016-10-27 19:55:54 +0000602 platform_device_unregister(priv->pdev_hotplug);
603
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000604 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
605 platform_device_unregister(priv->pdev_mux[i]);
606
607 platform_device_unregister(priv->pdev_i2c);
608 platform_device_unregister(mlxplat_dev);
609}
610module_exit(mlxplat_exit);
611
612MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
613MODULE_DESCRIPTION("Mellanox platform driver");
614MODULE_LICENSE("Dual BSD/GPL");