blob: 3a13285d1aa8734ce69aced0b12f932b0cb52a04 [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
Vadim Pasternakef08e142018-02-09 23:59:30 +000097#define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
Vadim Pasternakba814fd2018-02-02 08:45:45 +000098#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
99#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
100#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
101#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
102
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000103/* mlxplat_priv - platform private data
104 * @pdev_i2c - i2c controller platform device
105 * @pdev_mux - array of mux platform devices
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -0800106 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000107 */
108struct mlxplat_priv {
109 struct platform_device *pdev_i2c;
110 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +0000111 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000112};
113
114/* Regions for LPC I2C controller and LPC base register space */
115static const struct resource mlxplat_lpc_resources[] = {
116 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
117 MLXPLAT_CPLD_LPC_IO_RANGE,
118 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
119 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
120 MLXPLAT_CPLD_LPC_IO_RANGE,
121 "mlxplat_cpld_lpc_regs",
122 IORESOURCE_IO),
123};
124
125/* Platform default channels */
126static const int mlxplat_default_channels[][8] = {
127 {
128 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
129 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
130 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
131 },
132 {
133 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
134 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
135 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
136 },
137};
138
139/* Platform channels for MSN21xx system family */
140static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
141
142/* Platform mux data */
143static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
144 {
145 .parent = 1,
146 .base_nr = MLXPLAT_CPLD_CH1,
147 .write_only = 1,
148 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
149 .reg_size = 1,
150 .idle_in_use = 1,
151 },
152 {
153 .parent = 1,
154 .base_nr = MLXPLAT_CPLD_CH2,
155 .write_only = 1,
156 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
157 .reg_size = 1,
158 .idle_in_use = 1,
159 },
160
161};
162
Vadim Pasternakafc47152016-10-27 19:55:54 +0000163/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800164static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000165 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800166 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000167 },
168 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800169 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000170 },
171};
172
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800173static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000174 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800175 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000176 },
177 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800178 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000179 },
180};
181
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800182static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000183 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800184 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000185 },
186 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800187 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000188 },
189 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800190 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000191 },
192 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800193 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000194 },
195};
196
197/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800198static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
199 {
200 .label = "psu1",
201 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
202 .mask = BIT(0),
203 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000204 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800205 },
206 {
207 .label = "psu2",
208 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
209 .mask = BIT(1),
210 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000211 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800212 },
213};
214
215static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
216 {
217 .label = "pwr1",
218 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
219 .mask = BIT(0),
220 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000221 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800222 },
223 {
224 .label = "pwr2",
225 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
226 .mask = BIT(1),
227 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000228 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800229 },
230};
231
232static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
233 {
234 .label = "fan1",
235 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
236 .mask = BIT(0),
237 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000238 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800239 },
240 {
241 .label = "fan2",
242 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
243 .mask = BIT(1),
244 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000245 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800246 },
247 {
248 .label = "fan3",
249 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
250 .mask = BIT(2),
251 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000252 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800253 },
254 {
255 .label = "fan4",
256 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
257 .mask = BIT(3),
258 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000259 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800260 },
261};
262
263static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
264 {
265 .data = mlxplat_mlxcpld_default_psu_items_data,
266 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
267 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
268 .mask = MLXPLAT_CPLD_PSU_MASK,
269 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
270 .inversed = 1,
271 .health = false,
272 },
273 {
274 .data = mlxplat_mlxcpld_default_pwr_items_data,
275 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
276 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
277 .mask = MLXPLAT_CPLD_PWR_MASK,
278 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
279 .inversed = 0,
280 .health = false,
281 },
282 {
283 .data = mlxplat_mlxcpld_default_fan_items_data,
284 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
285 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
286 .mask = MLXPLAT_CPLD_FAN_MASK,
287 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
288 .inversed = 1,
289 .health = false,
290 },
291};
292
Vadim Pasternakafc47152016-10-27 19:55:54 +0000293static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800294struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
295 .items = mlxplat_mlxcpld_default_items,
296 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
297 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
298 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000299};
300
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000301static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = {
302 {
303 .label = "pwr1",
304 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
305 .mask = BIT(0),
306 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
307 },
308 {
309 .label = "pwr2",
310 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
311 .mask = BIT(1),
312 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
313 },
314};
315
Vadim Pasternakafc47152016-10-27 19:55:54 +0000316/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800317static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
318 {
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000319 .data = mlxplat_mlxcpld_msn21xx_pwr_items_data,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800320 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
321 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
322 .mask = MLXPLAT_CPLD_PWR_MASK,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000323 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data),
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800324 .inversed = 0,
325 .health = false,
326 },
327};
328
Vadim Pasternakafc47152016-10-27 19:55:54 +0000329static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800330struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
331 .items = mlxplat_mlxcpld_msn21xx_items,
332 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
333 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
334 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternak6016f7d2018-02-02 08:45:47 +0000335 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
336 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800337};
338
Vadim Pasternakef08e142018-02-09 23:59:30 +0000339/* Platform hotplug msn274x system family data */
340static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = {
341 {
342 .label = "psu1",
343 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
344 .mask = BIT(0),
345 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
346 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
347 },
348 {
349 .label = "psu2",
350 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
351 .mask = BIT(1),
352 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
353 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
354 },
355};
356
357static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = {
358 {
359 .label = "pwr1",
360 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
361 .mask = BIT(0),
362 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
363 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
364 },
365 {
366 .label = "pwr2",
367 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
368 .mask = BIT(1),
369 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
370 .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
371 },
372};
373
374static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = {
375 {
376 .label = "fan1",
377 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
378 .mask = BIT(0),
379 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
380 },
381 {
382 .label = "fan2",
383 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
384 .mask = BIT(1),
385 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
386 },
387 {
388 .label = "fan3",
389 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
390 .mask = BIT(2),
391 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
392 },
393 {
394 .label = "fan4",
395 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
396 .mask = BIT(3),
397 .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
398 },
399};
400
401static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = {
402 {
403 .data = mlxplat_mlxcpld_msn274x_psu_items_data,
404 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
405 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
406 .mask = MLXPLAT_CPLD_PSU_MASK,
407 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data),
408 .inversed = 1,
409 .health = false,
410 },
411 {
412 .data = mlxplat_mlxcpld_default_ng_pwr_items_data,
413 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
414 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
415 .mask = MLXPLAT_CPLD_PWR_MASK,
416 .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data),
417 .inversed = 0,
418 .health = false,
419 },
420 {
421 .data = mlxplat_mlxcpld_msn274x_fan_items_data,
422 .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
423 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
424 .mask = MLXPLAT_CPLD_FAN_MASK,
425 .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data),
426 .inversed = 1,
427 .health = false,
428 },
429};
430
431static
432struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = {
433 .items = mlxplat_mlxcpld_msn274x_items,
434 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items),
435 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
436 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
437 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
438 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
439};
440
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000441static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
442{
443 switch (reg) {
444 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
445 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
446 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
447 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
448 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
449 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
450 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
451 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
452 return true;
453 }
454 return false;
455}
456
457static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
458{
459 switch (reg) {
460 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
461 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
462 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
463 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
464 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
465 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
466 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
467 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
468 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
469 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
470 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
471 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
472 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
473 return true;
474 }
475 return false;
476}
477
478static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
479{
480 switch (reg) {
481 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
482 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
483 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
484 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
485 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
486 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
487 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
488 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
489 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
490 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
491 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
492 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
493 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
494 return true;
495 }
496 return false;
497}
498
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800499struct mlxplat_mlxcpld_regmap_context {
500 void __iomem *base;
501};
502
503static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
504
505static int
506mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
507{
508 struct mlxplat_mlxcpld_regmap_context *ctx = context;
509
510 *val = ioread8(ctx->base + reg);
511 return 0;
512}
513
514static int
515mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
516{
517 struct mlxplat_mlxcpld_regmap_context *ctx = context;
518
519 iowrite8(val, ctx->base + reg);
520 return 0;
521}
522
523static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
524 .reg_bits = 8,
525 .val_bits = 8,
526 .max_register = 255,
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000527 .cache_type = REGCACHE_FLAT,
528 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
529 .readable_reg = mlxplat_mlxcpld_readable_reg,
530 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800531 .reg_read = mlxplat_mlxcpld_reg_read,
532 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000533};
534
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000535static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000536 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000537};
538
Colin Ian King36c282b2017-10-05 11:42:11 +0100539static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800540static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000541
542static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
543{
544 int i;
545
546 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
547 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
548 mlxplat_mux_data[i].n_values =
549 ARRAY_SIZE(mlxplat_default_channels[i]);
550 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000551 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000552
553 return 1;
554};
555
556static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
557{
558 int i;
559
560 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
561 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
562 mlxplat_mux_data[i].n_values =
563 ARRAY_SIZE(mlxplat_msn21xx_channels);
564 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000565 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000566
567 return 1;
568};
569
Vadim Pasternakef08e142018-02-09 23:59:30 +0000570static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
571{
572 int i;
573
574 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
575 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
576 mlxplat_mux_data[i].n_values =
577 ARRAY_SIZE(mlxplat_msn21xx_channels);
578 }
579 mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
580
581 return 1;
582};
583
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200584static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000585 {
Vadim Pasternakef08e142018-02-09 23:59:30 +0000586 .callback = mlxplat_dmi_msn274x_matched,
587 .matches = {
588 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
589 DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"),
590 },
591 },
592 {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000593 .callback = mlxplat_dmi_default_matched,
594 .matches = {
595 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
596 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
597 },
598 },
599 {
600 .callback = mlxplat_dmi_default_matched,
601 .matches = {
602 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
603 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
604 },
605 },
606 {
607 .callback = mlxplat_dmi_default_matched,
608 .matches = {
609 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
610 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
611 },
612 },
613 {
614 .callback = mlxplat_dmi_default_matched,
615 .matches = {
616 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
617 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
618 },
619 },
620 {
621 .callback = mlxplat_dmi_msn21xx_matched,
622 .matches = {
623 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
624 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
625 },
626 },
627 { }
628};
629
Ivan Vecera580d8342018-01-22 15:20:43 +0100630MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
631
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000632static int __init mlxplat_init(void)
633{
634 struct mlxplat_priv *priv;
635 int i, err;
636
637 if (!dmi_check_system(mlxplat_dmi_table))
638 return -ENODEV;
639
640 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
641 mlxplat_lpc_resources,
642 ARRAY_SIZE(mlxplat_lpc_resources));
643
Wei Yongjun65f74222016-09-24 11:48:13 +0000644 if (IS_ERR(mlxplat_dev))
645 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000646
647 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
648 GFP_KERNEL);
649 if (!priv) {
650 err = -ENOMEM;
651 goto fail_alloc;
652 }
653 platform_set_drvdata(mlxplat_dev, priv);
654
655 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
656 NULL, 0);
657 if (IS_ERR(priv->pdev_i2c)) {
658 err = PTR_ERR(priv->pdev_i2c);
659 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800660 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000661
662 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
663 priv->pdev_mux[i] = platform_device_register_resndata(
664 &mlxplat_dev->dev,
665 "i2c-mux-reg", i, NULL,
666 0, &mlxplat_mux_data[i],
667 sizeof(mlxplat_mux_data[i]));
668 if (IS_ERR(priv->pdev_mux[i])) {
669 err = PTR_ERR(priv->pdev_mux[i]);
670 goto fail_platform_mux_register;
671 }
672 }
673
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800674 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
675 mlxplat_lpc_resources[1].start, 1);
Dan Carpenter8a0f5b62018-02-06 15:45:36 +0300676 if (!mlxplat_mlxcpld_regmap_ctx.base) {
677 err = -ENOMEM;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800678 goto fail_platform_mux_register;
679 }
680
681 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
682 &mlxplat_mlxcpld_regmap_ctx,
683 &mlxplat_mlxcpld_regmap_config);
684 if (IS_ERR(mlxplat_hotplug->regmap)) {
685 err = PTR_ERR(mlxplat_hotplug->regmap);
686 goto fail_platform_mux_register;
687 }
688
Vadim Pasternakafc47152016-10-27 19:55:54 +0000689 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000690 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000691 PLATFORM_DEVID_NONE,
692 mlxplat_mlxcpld_resources,
693 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000694 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
695 if (IS_ERR(priv->pdev_hotplug)) {
696 err = PTR_ERR(priv->pdev_hotplug);
697 goto fail_platform_mux_register;
698 }
699
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000700 /* Sync registers with hardware. */
701 regcache_mark_dirty(mlxplat_hotplug->regmap);
702 err = regcache_sync(mlxplat_hotplug->regmap);
703 if (err)
Vadim Pasternak47260982018-01-31 21:55:13 +0000704 goto fail_platform_hotplug_register;
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000705
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000706 return 0;
707
Vadim Pasternak47260982018-01-31 21:55:13 +0000708fail_platform_hotplug_register:
709 platform_device_unregister(priv->pdev_hotplug);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000710fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300711 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000712 platform_device_unregister(priv->pdev_mux[i]);
713 platform_device_unregister(priv->pdev_i2c);
714fail_alloc:
715 platform_device_unregister(mlxplat_dev);
716
717 return err;
718}
719module_init(mlxplat_init);
720
721static void __exit mlxplat_exit(void)
722{
723 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
724 int i;
725
Vadim Pasternakafc47152016-10-27 19:55:54 +0000726 platform_device_unregister(priv->pdev_hotplug);
727
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000728 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
729 platform_device_unregister(priv->pdev_mux[i]);
730
731 platform_device_unregister(priv->pdev_i2c);
732 platform_device_unregister(mlxplat_dev);
733}
734module_exit(mlxplat_exit);
735
736MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
737MODULE_DESCRIPTION("Mellanox platform driver");
738MODULE_LICENSE("Dual BSD/GPL");