blob: 2e9f9e4302b2c3fae4c8e06f352a6ed70f8adbe1 [file] [log] [blame]
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00001/*
Vadim Pasternak58cbbee2016-09-22 21:13:42 +00002 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
3 * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the names of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <linux/device.h>
35#include <linux/dmi.h>
36#include <linux/i2c.h>
37#include <linux/i2c-mux.h>
Vadim Pasternakc6acad62018-01-22 19:55:11 -080038#include <linux/io.h>
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000039#include <linux/module.h>
40#include <linux/platform_device.h>
41#include <linux/platform_data/i2c-mux-reg.h>
Vadim Pasternak1f976f62018-01-17 18:21:53 +000042#include <linux/platform_data/mlxreg.h>
Vadim Pasternakc6acad62018-01-22 19:55:11 -080043#include <linux/regmap.h>
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000044
45#define MLX_PLAT_DEVICE_NAME "mlxplat"
46
47/* LPC bus IO offsets */
48#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
49#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
Vadim Pasternakc6acad62018-01-22 19:55:11 -080050#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000051#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
52#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
53#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
Vadim Pasternakc6acad62018-01-22 19:55:11 -080054#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000055#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59
56#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a
Vadim Pasternakc6acad62018-01-22 19:55:11 -080057#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000058#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65
59#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66
Vadim Pasternakc6acad62018-01-22 19:55:11 -080060#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +000061#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
62#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000063#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
64#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
65#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
66#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
67#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
68 MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
69 MLXPLAT_CPLD_LPC_PIO_OFFSET)
70#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
71 MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
72 MLXPLAT_CPLD_LPC_PIO_OFFSET)
73
Vadim Pasternak9a38b672016-12-14 12:05:15 +000074/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
75#define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08
76#define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08
77#define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40
78#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \
79 MLXPLAT_CPLD_AGGR_FAN_MASK_DEF)
80#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04
81#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
82#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
83#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
84
Vadim Pasternak58cbbee2016-09-22 21:13:42 +000085/* Start channel numbers */
86#define MLXPLAT_CPLD_CH1 2
87#define MLXPLAT_CPLD_CH2 10
88
89/* Number of LPC attached MUX platform devices */
90#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
91
Vadim Pasternakba814fd2018-02-02 08:45:45 +000092/* Hotplug devices adapter numbers */
Vadim Pasternak17785672018-02-02 08:45:46 +000093#define MLXPLAT_CPLD_NR_NONE -1
Vadim Pasternakba814fd2018-02-02 08:45:45 +000094#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
95#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11
96#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12
97#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13
98#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14
99
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000100/* mlxplat_priv - platform private data
101 * @pdev_i2c - i2c controller platform device
102 * @pdev_mux - array of mux platform devices
Vadim Pasternakb4d3dbc2018-01-25 14:02:53 -0800103 * @pdev_hotplug - hotplug platform devices
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000104 */
105struct mlxplat_priv {
106 struct platform_device *pdev_i2c;
107 struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
Vadim Pasternakafc47152016-10-27 19:55:54 +0000108 struct platform_device *pdev_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000109};
110
111/* Regions for LPC I2C controller and LPC base register space */
112static const struct resource mlxplat_lpc_resources[] = {
113 [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
114 MLXPLAT_CPLD_LPC_IO_RANGE,
115 "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
116 [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
117 MLXPLAT_CPLD_LPC_IO_RANGE,
118 "mlxplat_cpld_lpc_regs",
119 IORESOURCE_IO),
120};
121
122/* Platform default channels */
123static const int mlxplat_default_channels[][8] = {
124 {
125 MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
126 MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
127 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
128 },
129 {
130 MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
131 MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
132 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
133 },
134};
135
136/* Platform channels for MSN21xx system family */
137static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
138
139/* Platform mux data */
140static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
141 {
142 .parent = 1,
143 .base_nr = MLXPLAT_CPLD_CH1,
144 .write_only = 1,
145 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
146 .reg_size = 1,
147 .idle_in_use = 1,
148 },
149 {
150 .parent = 1,
151 .base_nr = MLXPLAT_CPLD_CH2,
152 .write_only = 1,
153 .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
154 .reg_size = 1,
155 .idle_in_use = 1,
156 },
157
158};
159
Vadim Pasternakafc47152016-10-27 19:55:54 +0000160/* Platform hotplug devices */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800161static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000162 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800163 I2C_BOARD_INFO("24c02", 0x51),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000164 },
165 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800166 I2C_BOARD_INFO("24c02", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000167 },
168};
169
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800170static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000171 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800172 I2C_BOARD_INFO("dps460", 0x59),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000173 },
174 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800175 I2C_BOARD_INFO("dps460", 0x58),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000176 },
177};
178
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800179static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
Vadim Pasternakafc47152016-10-27 19:55:54 +0000180 {
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800181 I2C_BOARD_INFO("24c32", 0x50),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000182 },
183 {
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};
193
194/* Platform hotplug default data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800195static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
196 {
197 .label = "psu1",
198 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
199 .mask = BIT(0),
200 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000201 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800202 },
203 {
204 .label = "psu2",
205 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
206 .mask = BIT(1),
207 .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000208 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800209 },
210};
211
212static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
213 {
214 .label = "pwr1",
215 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
216 .mask = BIT(0),
217 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000218 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800219 },
220 {
221 .label = "pwr2",
222 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
223 .mask = BIT(1),
224 .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000225 .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800226 },
227};
228
229static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
230 {
231 .label = "fan1",
232 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
233 .mask = BIT(0),
234 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000235 .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800236 },
237 {
238 .label = "fan2",
239 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
240 .mask = BIT(1),
241 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000242 .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800243 },
244 {
245 .label = "fan3",
246 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
247 .mask = BIT(2),
248 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000249 .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800250 },
251 {
252 .label = "fan4",
253 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
254 .mask = BIT(3),
255 .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
Vadim Pasternakba814fd2018-02-02 08:45:45 +0000256 .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800257 },
258};
259
260static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
261 {
262 .data = mlxplat_mlxcpld_default_psu_items_data,
263 .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
264 .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
265 .mask = MLXPLAT_CPLD_PSU_MASK,
266 .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
267 .inversed = 1,
268 .health = false,
269 },
270 {
271 .data = mlxplat_mlxcpld_default_pwr_items_data,
272 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
273 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
274 .mask = MLXPLAT_CPLD_PWR_MASK,
275 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
276 .inversed = 0,
277 .health = false,
278 },
279 {
280 .data = mlxplat_mlxcpld_default_fan_items_data,
281 .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
282 .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
283 .mask = MLXPLAT_CPLD_FAN_MASK,
284 .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
285 .inversed = 1,
286 .health = false,
287 },
288};
289
Vadim Pasternakafc47152016-10-27 19:55:54 +0000290static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800291struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
292 .items = mlxplat_mlxcpld_default_items,
293 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
294 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
295 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000296};
297
298/* Platform hotplug MSN21xx system family data */
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800299static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
300 {
301 .data = mlxplat_mlxcpld_default_pwr_items_data,
302 .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
303 .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
304 .mask = MLXPLAT_CPLD_PWR_MASK,
305 .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
306 .inversed = 0,
307 .health = false,
308 },
309};
310
Vadim Pasternakafc47152016-10-27 19:55:54 +0000311static
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800312struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
313 .items = mlxplat_mlxcpld_msn21xx_items,
314 .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
315 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
316 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
317};
318
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000319static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
320{
321 switch (reg) {
322 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
323 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
324 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
325 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
326 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
327 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
328 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
329 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
330 return true;
331 }
332 return false;
333}
334
335static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
336{
337 switch (reg) {
338 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
339 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
340 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
341 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
342 case MLXPLAT_CPLD_LPC_REG_PSU_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_OFFSET:
346 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
347 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
348 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
349 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
350 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
351 return true;
352 }
353 return false;
354}
355
356static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
357{
358 switch (reg) {
359 case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
360 case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
361 case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
362 case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
363 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET:
364 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
365 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET:
366 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET:
367 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET:
368 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
369 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
370 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
371 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
372 return true;
373 }
374 return false;
375}
376
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800377struct mlxplat_mlxcpld_regmap_context {
378 void __iomem *base;
379};
380
381static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
382
383static int
384mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
385{
386 struct mlxplat_mlxcpld_regmap_context *ctx = context;
387
388 *val = ioread8(ctx->base + reg);
389 return 0;
390}
391
392static int
393mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
394{
395 struct mlxplat_mlxcpld_regmap_context *ctx = context;
396
397 iowrite8(val, ctx->base + reg);
398 return 0;
399}
400
401static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
402 .reg_bits = 8,
403 .val_bits = 8,
404 .max_register = 255,
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000405 .cache_type = REGCACHE_FLAT,
406 .writeable_reg = mlxplat_mlxcpld_writeable_reg,
407 .readable_reg = mlxplat_mlxcpld_readable_reg,
408 .volatile_reg = mlxplat_mlxcpld_volatile_reg,
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800409 .reg_read = mlxplat_mlxcpld_reg_read,
410 .reg_write = mlxplat_mlxcpld_reg_write,
Vadim Pasternakafc47152016-10-27 19:55:54 +0000411};
412
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000413static struct resource mlxplat_mlxcpld_resources[] = {
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000414 [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000415};
416
Colin Ian King36c282b2017-10-05 11:42:11 +0100417static struct platform_device *mlxplat_dev;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800418static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000419
420static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
421{
422 int i;
423
424 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
425 mlxplat_mux_data[i].values = mlxplat_default_channels[i];
426 mlxplat_mux_data[i].n_values =
427 ARRAY_SIZE(mlxplat_default_channels[i]);
428 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000429 mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000430
431 return 1;
432};
433
434static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
435{
436 int i;
437
438 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
439 mlxplat_mux_data[i].values = mlxplat_msn21xx_channels;
440 mlxplat_mux_data[i].n_values =
441 ARRAY_SIZE(mlxplat_msn21xx_channels);
442 }
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000443 mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000444
445 return 1;
446};
447
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200448static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000449 {
450 .callback = mlxplat_dmi_default_matched,
451 .matches = {
452 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
453 DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
454 },
455 },
456 {
457 .callback = mlxplat_dmi_default_matched,
458 .matches = {
459 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
460 DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
461 },
462 },
463 {
464 .callback = mlxplat_dmi_default_matched,
465 .matches = {
466 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
467 DMI_MATCH(DMI_PRODUCT_NAME, "MSB"),
468 },
469 },
470 {
471 .callback = mlxplat_dmi_default_matched,
472 .matches = {
473 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
474 DMI_MATCH(DMI_PRODUCT_NAME, "MSX"),
475 },
476 },
477 {
478 .callback = mlxplat_dmi_msn21xx_matched,
479 .matches = {
480 DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
481 DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"),
482 },
483 },
484 { }
485};
486
Ivan Vecera580d8342018-01-22 15:20:43 +0100487MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
488
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000489static int __init mlxplat_init(void)
490{
491 struct mlxplat_priv *priv;
492 int i, err;
493
494 if (!dmi_check_system(mlxplat_dmi_table))
495 return -ENODEV;
496
497 mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
498 mlxplat_lpc_resources,
499 ARRAY_SIZE(mlxplat_lpc_resources));
500
Wei Yongjun65f74222016-09-24 11:48:13 +0000501 if (IS_ERR(mlxplat_dev))
502 return PTR_ERR(mlxplat_dev);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000503
504 priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
505 GFP_KERNEL);
506 if (!priv) {
507 err = -ENOMEM;
508 goto fail_alloc;
509 }
510 platform_set_drvdata(mlxplat_dev, priv);
511
512 priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
513 NULL, 0);
514 if (IS_ERR(priv->pdev_i2c)) {
515 err = PTR_ERR(priv->pdev_i2c);
516 goto fail_alloc;
kbuild test robotc3886c92016-10-28 01:26:50 +0800517 }
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000518
519 for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
520 priv->pdev_mux[i] = platform_device_register_resndata(
521 &mlxplat_dev->dev,
522 "i2c-mux-reg", i, NULL,
523 0, &mlxplat_mux_data[i],
524 sizeof(mlxplat_mux_data[i]));
525 if (IS_ERR(priv->pdev_mux[i])) {
526 err = PTR_ERR(priv->pdev_mux[i]);
527 goto fail_platform_mux_register;
528 }
529 }
530
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800531 mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
532 mlxplat_lpc_resources[1].start, 1);
Dan Carpenter8a0f5b62018-02-06 15:45:36 +0300533 if (!mlxplat_mlxcpld_regmap_ctx.base) {
534 err = -ENOMEM;
Vadim Pasternakc6acad62018-01-22 19:55:11 -0800535 goto fail_platform_mux_register;
536 }
537
538 mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
539 &mlxplat_mlxcpld_regmap_ctx,
540 &mlxplat_mlxcpld_regmap_config);
541 if (IS_ERR(mlxplat_hotplug->regmap)) {
542 err = PTR_ERR(mlxplat_hotplug->regmap);
543 goto fail_platform_mux_register;
544 }
545
Vadim Pasternakafc47152016-10-27 19:55:54 +0000546 priv->pdev_hotplug = platform_device_register_resndata(
Vadim Pasternak1f976f62018-01-17 18:21:53 +0000547 &mlxplat_dev->dev, "mlxreg-hotplug",
Vadim Pasternak9a38b672016-12-14 12:05:15 +0000548 PLATFORM_DEVID_NONE,
549 mlxplat_mlxcpld_resources,
550 ARRAY_SIZE(mlxplat_mlxcpld_resources),
Vadim Pasternakafc47152016-10-27 19:55:54 +0000551 mlxplat_hotplug, sizeof(*mlxplat_hotplug));
552 if (IS_ERR(priv->pdev_hotplug)) {
553 err = PTR_ERR(priv->pdev_hotplug);
554 goto fail_platform_mux_register;
555 }
556
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000557 /* Sync registers with hardware. */
558 regcache_mark_dirty(mlxplat_hotplug->regmap);
559 err = regcache_sync(mlxplat_hotplug->regmap);
560 if (err)
Vadim Pasternak47260982018-01-31 21:55:13 +0000561 goto fail_platform_hotplug_register;
Vadim Pasternak0b78b1c2018-01-26 19:03:44 +0000562
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000563 return 0;
564
Vadim Pasternak47260982018-01-31 21:55:13 +0000565fail_platform_hotplug_register:
566 platform_device_unregister(priv->pdev_hotplug);
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000567fail_platform_mux_register:
Dan Carpenter63d762b2017-01-07 09:33:34 +0300568 while (--i >= 0)
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000569 platform_device_unregister(priv->pdev_mux[i]);
570 platform_device_unregister(priv->pdev_i2c);
571fail_alloc:
572 platform_device_unregister(mlxplat_dev);
573
574 return err;
575}
576module_init(mlxplat_init);
577
578static void __exit mlxplat_exit(void)
579{
580 struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
581 int i;
582
Vadim Pasternakafc47152016-10-27 19:55:54 +0000583 platform_device_unregister(priv->pdev_hotplug);
584
Vadim Pasternak58cbbee2016-09-22 21:13:42 +0000585 for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
586 platform_device_unregister(priv->pdev_mux[i]);
587
588 platform_device_unregister(priv->pdev_i2c);
589 platform_device_unregister(mlxplat_dev);
590}
591module_exit(mlxplat_exit);
592
593MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
594MODULE_DESCRIPTION("Mellanox platform driver");
595MODULE_LICENSE("Dual BSD/GPL");