1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Nvidia sn2201 driver |
4 | * |
5 | * Copyright (C) 2022 Nvidia Technologies Ltd. |
6 | */ |
7 | |
8 | #include <linux/device.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/irq.h> |
12 | #include <linux/gpio.h> |
13 | #include <linux/module.h> |
14 | #include <linux/platform_data/mlxcpld.h> |
15 | #include <linux/platform_data/mlxreg.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/regmap.h> |
18 | |
19 | /* SN2201 CPLD register offset. */ |
20 | #define NVSW_SN2201_CPLD_LPC_I2C_BASE_ADRR 0x2000 |
21 | #define NVSW_SN2201_CPLD_LPC_IO_RANGE 0x100 |
22 | #define NVSW_SN2201_HW_VER_ID_OFFSET 0x00 |
23 | #define NVSW_SN2201_BOARD_ID_OFFSET 0x01 |
24 | #define NVSW_SN2201_CPLD_VER_OFFSET 0x02 |
25 | #define NVSW_SN2201_CPLD_MVER_OFFSET 0x03 |
26 | #define NVSW_SN2201_CPLD_ID_OFFSET 0x04 |
27 | #define NVSW_SN2201_CPLD_PN_OFFSET 0x05 |
28 | #define NVSW_SN2201_CPLD_PN1_OFFSET 0x06 |
29 | #define NVSW_SN2201_PSU_CTRL_OFFSET 0x0a |
30 | #define NVSW_SN2201_QSFP28_STATUS_OFFSET 0x0b |
31 | #define NVSW_SN2201_QSFP28_INT_STATUS_OFFSET 0x0c |
32 | #define NVSW_SN2201_QSFP28_LP_STATUS_OFFSET 0x0d |
33 | #define NVSW_SN2201_QSFP28_RST_STATUS_OFFSET 0x0e |
34 | #define NVSW_SN2201_SYS_STATUS_OFFSET 0x0f |
35 | #define NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET 0x10 |
36 | #define NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET 0x12 |
37 | #define NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET 0x13 |
38 | #define NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET 0x14 |
39 | #define NVSW_SN2201_SYS_RST_STATUS_OFFSET 0x15 |
40 | #define NVSW_SN2201_SYS_INT_STATUS_OFFSET 0x21 |
41 | #define NVSW_SN2201_SYS_INT_MASK_OFFSET 0x22 |
42 | #define NVSW_SN2201_ASIC_STATUS_OFFSET 0x24 |
43 | #define NVSW_SN2201_ASIC_EVENT_OFFSET 0x25 |
44 | #define NVSW_SN2201_ASIC_MAKS_OFFSET 0x26 |
45 | #define NVSW_SN2201_THML_STATUS_OFFSET 0x27 |
46 | #define NVSW_SN2201_THML_EVENT_OFFSET 0x28 |
47 | #define NVSW_SN2201_THML_MASK_OFFSET 0x29 |
48 | #define NVSW_SN2201_PS_ALT_STATUS_OFFSET 0x2a |
49 | #define NVSW_SN2201_PS_ALT_EVENT_OFFSET 0x2b |
50 | #define NVSW_SN2201_PS_ALT_MASK_OFFSET 0x2c |
51 | #define NVSW_SN2201_PS_PRSNT_STATUS_OFFSET 0x30 |
52 | #define NVSW_SN2201_PS_PRSNT_EVENT_OFFSET 0x31 |
53 | #define NVSW_SN2201_PS_PRSNT_MASK_OFFSET 0x32 |
54 | #define NVSW_SN2201_PS_DC_OK_STATUS_OFFSET 0x33 |
55 | #define NVSW_SN2201_PS_DC_OK_EVENT_OFFSET 0x34 |
56 | #define NVSW_SN2201_PS_DC_OK_MASK_OFFSET 0x35 |
57 | #define NVSW_SN2201_RST_CAUSE1_OFFSET 0x36 |
58 | #define NVSW_SN2201_RST_CAUSE2_OFFSET 0x37 |
59 | #define NVSW_SN2201_RST_SW_CTRL_OFFSET 0x38 |
60 | #define NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET 0x3a |
61 | #define NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET 0x3b |
62 | #define NVSW_SN2201_FAN_PRSNT_MASK_OFFSET 0x3c |
63 | #define NVSW_SN2201_WD_TMR_OFFSET_LSB 0x40 |
64 | #define NVSW_SN2201_WD_TMR_OFFSET_MSB 0x41 |
65 | #define NVSW_SN2201_WD_ACT_OFFSET 0x42 |
66 | #define NVSW_SN2201_FAN_LED1_CTRL_OFFSET 0x50 |
67 | #define NVSW_SN2201_FAN_LED2_CTRL_OFFSET 0x51 |
68 | #define NVSW_SN2201_REG_MAX 0x52 |
69 | |
70 | /* Number of physical I2C busses. */ |
71 | #define NVSW_SN2201_PHY_I2C_BUS_NUM 2 |
72 | /* Number of main mux channels. */ |
73 | #define NVSW_SN2201_MAIN_MUX_CHNL_NUM 8 |
74 | |
75 | #define NVSW_SN2201_MAIN_NR 0 |
76 | #define NVSW_SN2201_MAIN_MUX_NR 1 |
77 | #define NVSW_SN2201_MAIN_MUX_DEFER_NR (NVSW_SN2201_PHY_I2C_BUS_NUM + \ |
78 | NVSW_SN2201_MAIN_MUX_CHNL_NUM - 1) |
79 | |
80 | #define NVSW_SN2201_MAIN_MUX_CH0_NR NVSW_SN2201_PHY_I2C_BUS_NUM |
81 | #define NVSW_SN2201_MAIN_MUX_CH1_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 1) |
82 | #define NVSW_SN2201_MAIN_MUX_CH2_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 2) |
83 | #define NVSW_SN2201_MAIN_MUX_CH3_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 3) |
84 | #define NVSW_SN2201_MAIN_MUX_CH5_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 5) |
85 | #define NVSW_SN2201_MAIN_MUX_CH6_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 6) |
86 | #define NVSW_SN2201_MAIN_MUX_CH7_NR (NVSW_SN2201_MAIN_MUX_CH0_NR + 7) |
87 | #define NVSW_SN2201_2ND_MUX_CH0_NR (NVSW_SN2201_MAIN_MUX_CH7_NR + 1) |
88 | #define NVSW_SN2201_2ND_MUX_CH1_NR (NVSW_SN2201_MAIN_MUX_CH7_NR + 2) |
89 | #define NVSW_SN2201_2ND_MUX_CH2_NR (NVSW_SN2201_MAIN_MUX_CH7_NR + 3) |
90 | #define NVSW_SN2201_2ND_MUX_CH3_NR (NVSW_SN2201_MAIN_MUX_CH7_NR + 4) |
91 | |
92 | #define NVSW_SN2201_CPLD_NR NVSW_SN2201_MAIN_MUX_CH0_NR |
93 | #define NVSW_SN2201_NR_NONE -1 |
94 | |
95 | /* Masks for aggregation, PSU presence and power, ASIC events |
96 | * in CPLD related registers. |
97 | */ |
98 | #define NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF 0xe0 |
99 | #define NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF 0x04 |
100 | #define NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF 0x02 |
101 | #define NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF 0x10 |
102 | #define NVSW_SN2201_CPLD_AGGR_MASK_DEF \ |
103 | (NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF \ |
104 | | NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF \ |
105 | | NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF \ |
106 | | NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF) |
107 | |
108 | #define NVSW_SN2201_CPLD_ASIC_MASK GENMASK(3, 1) |
109 | #define NVSW_SN2201_CPLD_PSU_MASK GENMASK(1, 0) |
110 | #define NVSW_SN2201_CPLD_PWR_MASK GENMASK(1, 0) |
111 | #define NVSW_SN2201_CPLD_FAN_MASK GENMASK(3, 0) |
112 | |
113 | #define NVSW_SN2201_CPLD_SYSIRQ 26 |
114 | #define NVSW_SN2201_LPC_SYSIRQ 28 |
115 | #define NVSW_SN2201_CPLD_I2CADDR 0x41 |
116 | |
117 | #define NVSW_SN2201_WD_DFLT_TIMEOUT 600 |
118 | |
119 | /* nvsw_sn2201 - device private data |
120 | * @dev: platform device; |
121 | * @io_data: register access platform data; |
122 | * @led_data: LED platform data; |
123 | * @hotplug_data: hotplug platform data; |
124 | * @i2c_data: I2C controller platform data; |
125 | * @led: LED device; |
126 | * @io_regs: register access device; |
127 | * @pdev_hotplug: hotplug device; |
128 | * @sn2201_devs: I2C devices for sn2201 devices; |
129 | * @sn2201_devs_num: number of I2C devices for sn2201 device; |
130 | * @main_mux_devs: I2C devices for main mux; |
131 | * @main_mux_devs_num: number of I2C devices for main mux; |
132 | * @cpld_devs: I2C devices for cpld; |
133 | * @cpld_devs_num: number of I2C devices for cpld; |
134 | * @main_mux_deferred_nr: I2C adapter number must be exist prior creating devices execution; |
135 | */ |
136 | struct nvsw_sn2201 { |
137 | struct device *dev; |
138 | struct mlxreg_core_platform_data *io_data; |
139 | struct mlxreg_core_platform_data *led_data; |
140 | struct mlxreg_core_platform_data *wd_data; |
141 | struct mlxreg_core_hotplug_platform_data *hotplug_data; |
142 | struct mlxreg_core_hotplug_platform_data *i2c_data; |
143 | struct platform_device *led; |
144 | struct platform_device *wd; |
145 | struct platform_device *io_regs; |
146 | struct platform_device *pdev_hotplug; |
147 | struct platform_device *pdev_i2c; |
148 | struct mlxreg_hotplug_device *sn2201_devs; |
149 | int sn2201_devs_num; |
150 | struct mlxreg_hotplug_device *main_mux_devs; |
151 | int main_mux_devs_num; |
152 | struct mlxreg_hotplug_device *cpld_devs; |
153 | int cpld_devs_num; |
154 | int main_mux_deferred_nr; |
155 | }; |
156 | |
157 | static bool nvsw_sn2201_writeable_reg(struct device *dev, unsigned int reg) |
158 | { |
159 | switch (reg) { |
160 | case NVSW_SN2201_PSU_CTRL_OFFSET: |
161 | case NVSW_SN2201_QSFP28_LP_STATUS_OFFSET: |
162 | case NVSW_SN2201_QSFP28_RST_STATUS_OFFSET: |
163 | case NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET: |
164 | case NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET: |
165 | case NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET: |
166 | case NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET: |
167 | case NVSW_SN2201_SYS_RST_STATUS_OFFSET: |
168 | case NVSW_SN2201_SYS_INT_MASK_OFFSET: |
169 | case NVSW_SN2201_ASIC_EVENT_OFFSET: |
170 | case NVSW_SN2201_ASIC_MAKS_OFFSET: |
171 | case NVSW_SN2201_THML_EVENT_OFFSET: |
172 | case NVSW_SN2201_THML_MASK_OFFSET: |
173 | case NVSW_SN2201_PS_ALT_EVENT_OFFSET: |
174 | case NVSW_SN2201_PS_ALT_MASK_OFFSET: |
175 | case NVSW_SN2201_PS_PRSNT_EVENT_OFFSET: |
176 | case NVSW_SN2201_PS_PRSNT_MASK_OFFSET: |
177 | case NVSW_SN2201_PS_DC_OK_EVENT_OFFSET: |
178 | case NVSW_SN2201_PS_DC_OK_MASK_OFFSET: |
179 | case NVSW_SN2201_RST_SW_CTRL_OFFSET: |
180 | case NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET: |
181 | case NVSW_SN2201_FAN_PRSNT_MASK_OFFSET: |
182 | case NVSW_SN2201_WD_TMR_OFFSET_LSB: |
183 | case NVSW_SN2201_WD_TMR_OFFSET_MSB: |
184 | case NVSW_SN2201_WD_ACT_OFFSET: |
185 | case NVSW_SN2201_FAN_LED1_CTRL_OFFSET: |
186 | case NVSW_SN2201_FAN_LED2_CTRL_OFFSET: |
187 | return true; |
188 | } |
189 | return false; |
190 | } |
191 | |
192 | static bool nvsw_sn2201_readable_reg(struct device *dev, unsigned int reg) |
193 | { |
194 | switch (reg) { |
195 | case NVSW_SN2201_HW_VER_ID_OFFSET: |
196 | case NVSW_SN2201_BOARD_ID_OFFSET: |
197 | case NVSW_SN2201_CPLD_VER_OFFSET: |
198 | case NVSW_SN2201_CPLD_MVER_OFFSET: |
199 | case NVSW_SN2201_CPLD_ID_OFFSET: |
200 | case NVSW_SN2201_CPLD_PN_OFFSET: |
201 | case NVSW_SN2201_CPLD_PN1_OFFSET: |
202 | case NVSW_SN2201_PSU_CTRL_OFFSET: |
203 | case NVSW_SN2201_QSFP28_STATUS_OFFSET: |
204 | case NVSW_SN2201_QSFP28_INT_STATUS_OFFSET: |
205 | case NVSW_SN2201_QSFP28_LP_STATUS_OFFSET: |
206 | case NVSW_SN2201_QSFP28_RST_STATUS_OFFSET: |
207 | case NVSW_SN2201_SYS_STATUS_OFFSET: |
208 | case NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET: |
209 | case NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET: |
210 | case NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET: |
211 | case NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET: |
212 | case NVSW_SN2201_SYS_RST_STATUS_OFFSET: |
213 | case NVSW_SN2201_RST_CAUSE1_OFFSET: |
214 | case NVSW_SN2201_RST_CAUSE2_OFFSET: |
215 | case NVSW_SN2201_SYS_INT_STATUS_OFFSET: |
216 | case NVSW_SN2201_SYS_INT_MASK_OFFSET: |
217 | case NVSW_SN2201_ASIC_STATUS_OFFSET: |
218 | case NVSW_SN2201_ASIC_EVENT_OFFSET: |
219 | case NVSW_SN2201_ASIC_MAKS_OFFSET: |
220 | case NVSW_SN2201_THML_STATUS_OFFSET: |
221 | case NVSW_SN2201_THML_EVENT_OFFSET: |
222 | case NVSW_SN2201_THML_MASK_OFFSET: |
223 | case NVSW_SN2201_PS_ALT_STATUS_OFFSET: |
224 | case NVSW_SN2201_PS_ALT_EVENT_OFFSET: |
225 | case NVSW_SN2201_PS_ALT_MASK_OFFSET: |
226 | case NVSW_SN2201_PS_PRSNT_STATUS_OFFSET: |
227 | case NVSW_SN2201_PS_PRSNT_EVENT_OFFSET: |
228 | case NVSW_SN2201_PS_PRSNT_MASK_OFFSET: |
229 | case NVSW_SN2201_PS_DC_OK_STATUS_OFFSET: |
230 | case NVSW_SN2201_PS_DC_OK_EVENT_OFFSET: |
231 | case NVSW_SN2201_PS_DC_OK_MASK_OFFSET: |
232 | case NVSW_SN2201_RST_SW_CTRL_OFFSET: |
233 | case NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET: |
234 | case NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET: |
235 | case NVSW_SN2201_FAN_PRSNT_MASK_OFFSET: |
236 | case NVSW_SN2201_WD_TMR_OFFSET_LSB: |
237 | case NVSW_SN2201_WD_TMR_OFFSET_MSB: |
238 | case NVSW_SN2201_WD_ACT_OFFSET: |
239 | case NVSW_SN2201_FAN_LED1_CTRL_OFFSET: |
240 | case NVSW_SN2201_FAN_LED2_CTRL_OFFSET: |
241 | return true; |
242 | } |
243 | return false; |
244 | } |
245 | |
246 | static bool nvsw_sn2201_volatile_reg(struct device *dev, unsigned int reg) |
247 | { |
248 | switch (reg) { |
249 | case NVSW_SN2201_HW_VER_ID_OFFSET: |
250 | case NVSW_SN2201_BOARD_ID_OFFSET: |
251 | case NVSW_SN2201_CPLD_VER_OFFSET: |
252 | case NVSW_SN2201_CPLD_MVER_OFFSET: |
253 | case NVSW_SN2201_CPLD_ID_OFFSET: |
254 | case NVSW_SN2201_CPLD_PN_OFFSET: |
255 | case NVSW_SN2201_CPLD_PN1_OFFSET: |
256 | case NVSW_SN2201_PSU_CTRL_OFFSET: |
257 | case NVSW_SN2201_QSFP28_STATUS_OFFSET: |
258 | case NVSW_SN2201_QSFP28_INT_STATUS_OFFSET: |
259 | case NVSW_SN2201_QSFP28_LP_STATUS_OFFSET: |
260 | case NVSW_SN2201_QSFP28_RST_STATUS_OFFSET: |
261 | case NVSW_SN2201_SYS_STATUS_OFFSET: |
262 | case NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET: |
263 | case NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET: |
264 | case NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET: |
265 | case NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET: |
266 | case NVSW_SN2201_SYS_RST_STATUS_OFFSET: |
267 | case NVSW_SN2201_RST_CAUSE1_OFFSET: |
268 | case NVSW_SN2201_RST_CAUSE2_OFFSET: |
269 | case NVSW_SN2201_SYS_INT_STATUS_OFFSET: |
270 | case NVSW_SN2201_SYS_INT_MASK_OFFSET: |
271 | case NVSW_SN2201_ASIC_STATUS_OFFSET: |
272 | case NVSW_SN2201_ASIC_EVENT_OFFSET: |
273 | case NVSW_SN2201_ASIC_MAKS_OFFSET: |
274 | case NVSW_SN2201_THML_STATUS_OFFSET: |
275 | case NVSW_SN2201_THML_EVENT_OFFSET: |
276 | case NVSW_SN2201_THML_MASK_OFFSET: |
277 | case NVSW_SN2201_PS_ALT_STATUS_OFFSET: |
278 | case NVSW_SN2201_PS_ALT_EVENT_OFFSET: |
279 | case NVSW_SN2201_PS_ALT_MASK_OFFSET: |
280 | case NVSW_SN2201_PS_PRSNT_STATUS_OFFSET: |
281 | case NVSW_SN2201_PS_PRSNT_EVENT_OFFSET: |
282 | case NVSW_SN2201_PS_PRSNT_MASK_OFFSET: |
283 | case NVSW_SN2201_PS_DC_OK_STATUS_OFFSET: |
284 | case NVSW_SN2201_PS_DC_OK_EVENT_OFFSET: |
285 | case NVSW_SN2201_PS_DC_OK_MASK_OFFSET: |
286 | case NVSW_SN2201_RST_SW_CTRL_OFFSET: |
287 | case NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET: |
288 | case NVSW_SN2201_FAN_PRSNT_EVENT_OFFSET: |
289 | case NVSW_SN2201_FAN_PRSNT_MASK_OFFSET: |
290 | case NVSW_SN2201_WD_TMR_OFFSET_LSB: |
291 | case NVSW_SN2201_WD_TMR_OFFSET_MSB: |
292 | case NVSW_SN2201_FAN_LED1_CTRL_OFFSET: |
293 | case NVSW_SN2201_FAN_LED2_CTRL_OFFSET: |
294 | return true; |
295 | } |
296 | return false; |
297 | } |
298 | |
299 | static const struct reg_default nvsw_sn2201_regmap_default[] = { |
300 | { NVSW_SN2201_QSFP28_LED_TEST_STATUS_OFFSET, 0x00 }, |
301 | { NVSW_SN2201_WD_ACT_OFFSET, 0x00 }, |
302 | }; |
303 | |
304 | /* Configuration for the register map of a device with 1 bytes address space. */ |
305 | static const struct regmap_config nvsw_sn2201_regmap_conf = { |
306 | .reg_bits = 8, |
307 | .val_bits = 8, |
308 | .max_register = NVSW_SN2201_REG_MAX, |
309 | .cache_type = REGCACHE_FLAT, |
310 | .writeable_reg = nvsw_sn2201_writeable_reg, |
311 | .readable_reg = nvsw_sn2201_readable_reg, |
312 | .volatile_reg = nvsw_sn2201_volatile_reg, |
313 | .reg_defaults = nvsw_sn2201_regmap_default, |
314 | .num_reg_defaults = ARRAY_SIZE(nvsw_sn2201_regmap_default), |
315 | }; |
316 | |
317 | /* Regions for LPC I2C controller and LPC base register space. */ |
318 | static const struct resource nvsw_sn2201_lpc_io_resources[] = { |
319 | [0] = DEFINE_RES_NAMED(NVSW_SN2201_CPLD_LPC_I2C_BASE_ADRR, |
320 | NVSW_SN2201_CPLD_LPC_IO_RANGE, |
321 | "mlxplat_cpld_lpc_i2c_ctrl" , IORESOURCE_IO), |
322 | }; |
323 | |
324 | static struct resource nvsw_sn2201_cpld_res[] = { |
325 | [0] = DEFINE_RES_IRQ_NAMED(NVSW_SN2201_CPLD_SYSIRQ, "mlxreg-hotplug" ), |
326 | }; |
327 | |
328 | static struct resource nvsw_sn2201_lpc_res[] = { |
329 | [0] = DEFINE_RES_IRQ_NAMED(NVSW_SN2201_LPC_SYSIRQ, "i2c-mlxcpld" ), |
330 | }; |
331 | |
332 | /* SN2201 I2C platform data. */ |
333 | static struct mlxreg_core_hotplug_platform_data nvsw_sn2201_i2c_data = { |
334 | .irq = NVSW_SN2201_CPLD_SYSIRQ, |
335 | }; |
336 | |
337 | /* SN2201 CPLD device. */ |
338 | static struct i2c_board_info nvsw_sn2201_cpld_devices[] = { |
339 | { |
340 | I2C_BOARD_INFO("nvsw-sn2201" , 0x41), |
341 | }, |
342 | }; |
343 | |
344 | /* SN2201 CPLD board info. */ |
345 | static struct mlxreg_hotplug_device nvsw_sn2201_cpld_brdinfo[] = { |
346 | { |
347 | .brdinfo = &nvsw_sn2201_cpld_devices[0], |
348 | .nr = NVSW_SN2201_CPLD_NR, |
349 | }, |
350 | }; |
351 | |
352 | /* SN2201 main mux device. */ |
353 | static struct i2c_board_info nvsw_sn2201_main_mux_devices[] = { |
354 | { |
355 | I2C_BOARD_INFO("pca9548" , 0x70), |
356 | }, |
357 | }; |
358 | |
359 | /* SN2201 main mux board info. */ |
360 | static struct mlxreg_hotplug_device nvsw_sn2201_main_mux_brdinfo[] = { |
361 | { |
362 | .brdinfo = &nvsw_sn2201_main_mux_devices[0], |
363 | .nr = NVSW_SN2201_MAIN_MUX_NR, |
364 | }, |
365 | }; |
366 | |
367 | /* SN2201 power devices. */ |
368 | static struct i2c_board_info nvsw_sn2201_pwr_devices[] = { |
369 | { |
370 | I2C_BOARD_INFO("pmbus" , 0x58), |
371 | }, |
372 | { |
373 | I2C_BOARD_INFO("pmbus" , 0x58), |
374 | }, |
375 | }; |
376 | |
377 | /* SN2201 fan devices. */ |
378 | static struct i2c_board_info nvsw_sn2201_fan_devices[] = { |
379 | { |
380 | I2C_BOARD_INFO("24c02" , 0x50), |
381 | }, |
382 | { |
383 | I2C_BOARD_INFO("24c02" , 0x51), |
384 | }, |
385 | { |
386 | I2C_BOARD_INFO("24c02" , 0x52), |
387 | }, |
388 | { |
389 | I2C_BOARD_INFO("24c02" , 0x53), |
390 | }, |
391 | }; |
392 | |
393 | /* SN2201 hotplug default data. */ |
394 | static struct mlxreg_core_data nvsw_sn2201_psu_items_data[] = { |
395 | { |
396 | .label = "psu1" , |
397 | .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, |
398 | .mask = BIT(0), |
399 | .hpdev.nr = NVSW_SN2201_NR_NONE, |
400 | }, |
401 | { |
402 | .label = "psu2" , |
403 | .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, |
404 | .mask = BIT(1), |
405 | .hpdev.nr = NVSW_SN2201_NR_NONE, |
406 | }, |
407 | }; |
408 | |
409 | static struct mlxreg_core_data nvsw_sn2201_pwr_items_data[] = { |
410 | { |
411 | .label = "pwr1" , |
412 | .reg = NVSW_SN2201_PS_DC_OK_STATUS_OFFSET, |
413 | .mask = BIT(0), |
414 | .hpdev.brdinfo = &nvsw_sn2201_pwr_devices[0], |
415 | .hpdev.nr = NVSW_SN2201_MAIN_MUX_CH1_NR, |
416 | }, |
417 | { |
418 | .label = "pwr2" , |
419 | .reg = NVSW_SN2201_PS_DC_OK_STATUS_OFFSET, |
420 | .mask = BIT(1), |
421 | .hpdev.brdinfo = &nvsw_sn2201_pwr_devices[1], |
422 | .hpdev.nr = NVSW_SN2201_MAIN_MUX_CH2_NR, |
423 | }, |
424 | }; |
425 | |
426 | static struct mlxreg_core_data nvsw_sn2201_fan_items_data[] = { |
427 | { |
428 | .label = "fan1" , |
429 | .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, |
430 | .mask = BIT(0), |
431 | .hpdev.brdinfo = &nvsw_sn2201_fan_devices[0], |
432 | .hpdev.nr = NVSW_SN2201_2ND_MUX_CH0_NR, |
433 | }, |
434 | { |
435 | .label = "fan2" , |
436 | .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, |
437 | .mask = BIT(1), |
438 | .hpdev.brdinfo = &nvsw_sn2201_fan_devices[1], |
439 | .hpdev.nr = NVSW_SN2201_2ND_MUX_CH1_NR, |
440 | }, |
441 | { |
442 | .label = "fan3" , |
443 | .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, |
444 | .mask = BIT(2), |
445 | .hpdev.brdinfo = &nvsw_sn2201_fan_devices[2], |
446 | .hpdev.nr = NVSW_SN2201_2ND_MUX_CH2_NR, |
447 | }, |
448 | { |
449 | .label = "fan4" , |
450 | .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, |
451 | .mask = BIT(3), |
452 | .hpdev.brdinfo = &nvsw_sn2201_fan_devices[3], |
453 | .hpdev.nr = NVSW_SN2201_2ND_MUX_CH3_NR, |
454 | }, |
455 | }; |
456 | |
457 | static struct mlxreg_core_data nvsw_sn2201_sys_items_data[] = { |
458 | { |
459 | .label = "nic_smb_alert" , |
460 | .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, |
461 | .mask = BIT(1), |
462 | .hpdev.nr = NVSW_SN2201_NR_NONE, |
463 | }, |
464 | { |
465 | .label = "cpu_sd" , |
466 | .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, |
467 | .mask = BIT(2), |
468 | .hpdev.nr = NVSW_SN2201_NR_NONE, |
469 | }, |
470 | { |
471 | .label = "mac_health" , |
472 | .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, |
473 | .mask = BIT(3), |
474 | .hpdev.nr = NVSW_SN2201_NR_NONE, |
475 | }, |
476 | }; |
477 | |
478 | static struct mlxreg_core_item nvsw_sn2201_items[] = { |
479 | { |
480 | .data = nvsw_sn2201_psu_items_data, |
481 | .aggr_mask = NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF, |
482 | .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, |
483 | .mask = NVSW_SN2201_CPLD_PSU_MASK, |
484 | .count = ARRAY_SIZE(nvsw_sn2201_psu_items_data), |
485 | .inversed = 1, |
486 | .health = false, |
487 | }, |
488 | { |
489 | .data = nvsw_sn2201_pwr_items_data, |
490 | .aggr_mask = NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF, |
491 | .reg = NVSW_SN2201_PS_DC_OK_STATUS_OFFSET, |
492 | .mask = NVSW_SN2201_CPLD_PWR_MASK, |
493 | .count = ARRAY_SIZE(nvsw_sn2201_pwr_items_data), |
494 | .inversed = 0, |
495 | .health = false, |
496 | }, |
497 | { |
498 | .data = nvsw_sn2201_fan_items_data, |
499 | .aggr_mask = NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF, |
500 | .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, |
501 | .mask = NVSW_SN2201_CPLD_FAN_MASK, |
502 | .count = ARRAY_SIZE(nvsw_sn2201_fan_items_data), |
503 | .inversed = 1, |
504 | .health = false, |
505 | }, |
506 | { |
507 | .data = nvsw_sn2201_sys_items_data, |
508 | .aggr_mask = NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF, |
509 | .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, |
510 | .mask = NVSW_SN2201_CPLD_ASIC_MASK, |
511 | .count = ARRAY_SIZE(nvsw_sn2201_sys_items_data), |
512 | .inversed = 1, |
513 | .health = false, |
514 | }, |
515 | }; |
516 | |
517 | static |
518 | struct mlxreg_core_hotplug_platform_data nvsw_sn2201_hotplug = { |
519 | .items = nvsw_sn2201_items, |
520 | .counter = ARRAY_SIZE(nvsw_sn2201_items), |
521 | .cell = NVSW_SN2201_SYS_INT_STATUS_OFFSET, |
522 | .mask = NVSW_SN2201_CPLD_AGGR_MASK_DEF, |
523 | }; |
524 | |
525 | /* SN2201 static devices. */ |
526 | static struct i2c_board_info nvsw_sn2201_static_devices[] = { |
527 | { |
528 | I2C_BOARD_INFO("24c02" , 0x57), |
529 | }, |
530 | { |
531 | I2C_BOARD_INFO("lm75" , 0x4b), |
532 | }, |
533 | { |
534 | I2C_BOARD_INFO("24c64" , 0x56), |
535 | }, |
536 | { |
537 | I2C_BOARD_INFO("ads1015" , 0x49), |
538 | }, |
539 | { |
540 | I2C_BOARD_INFO("pca9546" , 0x71), |
541 | }, |
542 | { |
543 | I2C_BOARD_INFO("emc2305" , 0x4d), |
544 | }, |
545 | { |
546 | I2C_BOARD_INFO("lm75" , 0x49), |
547 | }, |
548 | { |
549 | I2C_BOARD_INFO("pca9555" , 0x27), |
550 | }, |
551 | { |
552 | I2C_BOARD_INFO("powr1014" , 0x37), |
553 | }, |
554 | { |
555 | I2C_BOARD_INFO("lm75" , 0x4f), |
556 | }, |
557 | { |
558 | I2C_BOARD_INFO("pmbus" , 0x40), |
559 | }, |
560 | }; |
561 | |
562 | /* SN2201 default static board info. */ |
563 | static struct mlxreg_hotplug_device nvsw_sn2201_static_brdinfo[] = { |
564 | { |
565 | .brdinfo = &nvsw_sn2201_static_devices[0], |
566 | .nr = NVSW_SN2201_MAIN_NR, |
567 | }, |
568 | { |
569 | .brdinfo = &nvsw_sn2201_static_devices[1], |
570 | .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, |
571 | }, |
572 | { |
573 | .brdinfo = &nvsw_sn2201_static_devices[2], |
574 | .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, |
575 | }, |
576 | { |
577 | .brdinfo = &nvsw_sn2201_static_devices[3], |
578 | .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, |
579 | }, |
580 | { |
581 | .brdinfo = &nvsw_sn2201_static_devices[4], |
582 | .nr = NVSW_SN2201_MAIN_MUX_CH3_NR, |
583 | }, |
584 | { |
585 | .brdinfo = &nvsw_sn2201_static_devices[5], |
586 | .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, |
587 | }, |
588 | { |
589 | .brdinfo = &nvsw_sn2201_static_devices[6], |
590 | .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, |
591 | }, |
592 | { |
593 | .brdinfo = &nvsw_sn2201_static_devices[7], |
594 | .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, |
595 | }, |
596 | { |
597 | .brdinfo = &nvsw_sn2201_static_devices[8], |
598 | .nr = NVSW_SN2201_MAIN_MUX_CH6_NR, |
599 | }, |
600 | { |
601 | .brdinfo = &nvsw_sn2201_static_devices[9], |
602 | .nr = NVSW_SN2201_MAIN_MUX_CH6_NR, |
603 | }, |
604 | { |
605 | .brdinfo = &nvsw_sn2201_static_devices[10], |
606 | .nr = NVSW_SN2201_MAIN_MUX_CH7_NR, |
607 | }, |
608 | }; |
609 | |
610 | /* LED default data. */ |
611 | static struct mlxreg_core_data nvsw_sn2201_led_data[] = { |
612 | { |
613 | .label = "status:green" , |
614 | .reg = NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET, |
615 | .mask = GENMASK(7, 4), |
616 | }, |
617 | { |
618 | .label = "status:orange" , |
619 | .reg = NVSW_SN2201_FRONT_SYS_LED_CTRL_OFFSET, |
620 | .mask = GENMASK(7, 4), |
621 | }, |
622 | { |
623 | .label = "psu:green" , |
624 | .reg = NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET, |
625 | .mask = GENMASK(7, 4), |
626 | }, |
627 | { |
628 | .label = "psu:orange" , |
629 | .reg = NVSW_SN2201_FRONT_PSU_LED_CTRL_OFFSET, |
630 | .mask = GENMASK(7, 4), |
631 | }, |
632 | { |
633 | .label = "uid:blue" , |
634 | .reg = NVSW_SN2201_FRONT_UID_LED_CTRL_OFFSET, |
635 | .mask = GENMASK(7, 4), |
636 | }, |
637 | { |
638 | .label = "fan1:green" , |
639 | .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, |
640 | .mask = GENMASK(7, 4), |
641 | }, |
642 | { |
643 | .label = "fan1:orange" , |
644 | .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, |
645 | .mask = GENMASK(7, 4), |
646 | }, |
647 | { |
648 | .label = "fan2:green" , |
649 | .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, |
650 | .mask = GENMASK(3, 0), |
651 | }, |
652 | { |
653 | .label = "fan2:orange" , |
654 | .reg = NVSW_SN2201_FAN_LED1_CTRL_OFFSET, |
655 | .mask = GENMASK(3, 0), |
656 | }, |
657 | { |
658 | .label = "fan3:green" , |
659 | .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, |
660 | .mask = GENMASK(7, 4), |
661 | }, |
662 | { |
663 | .label = "fan3:orange" , |
664 | .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, |
665 | .mask = GENMASK(7, 4), |
666 | }, |
667 | { |
668 | .label = "fan4:green" , |
669 | .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, |
670 | .mask = GENMASK(3, 0), |
671 | }, |
672 | { |
673 | .label = "fan4:orange" , |
674 | .reg = NVSW_SN2201_FAN_LED2_CTRL_OFFSET, |
675 | .mask = GENMASK(3, 0), |
676 | }, |
677 | }; |
678 | |
679 | static struct mlxreg_core_platform_data nvsw_sn2201_led = { |
680 | .data = nvsw_sn2201_led_data, |
681 | .counter = ARRAY_SIZE(nvsw_sn2201_led_data), |
682 | }; |
683 | |
684 | /* Default register access data. */ |
685 | static struct mlxreg_core_data nvsw_sn2201_io_data[] = { |
686 | { |
687 | .label = "cpld1_version" , |
688 | .reg = NVSW_SN2201_CPLD_VER_OFFSET, |
689 | .bit = GENMASK(7, 0), |
690 | .mode = 0444, |
691 | }, |
692 | { |
693 | .label = "cpld1_version_min" , |
694 | .reg = NVSW_SN2201_CPLD_MVER_OFFSET, |
695 | .bit = GENMASK(7, 0), |
696 | .mode = 0444, |
697 | }, |
698 | { |
699 | .label = "cpld1_pn" , |
700 | .reg = NVSW_SN2201_CPLD_PN_OFFSET, |
701 | .bit = GENMASK(15, 0), |
702 | .mode = 0444, |
703 | .regnum = 2, |
704 | }, |
705 | { |
706 | .label = "psu1_on" , |
707 | .reg = NVSW_SN2201_PSU_CTRL_OFFSET, |
708 | .mask = GENMASK(7, 0) & ~BIT(0), |
709 | .mode = 0644, |
710 | }, |
711 | { |
712 | .label = "psu2_on" , |
713 | .reg = NVSW_SN2201_PSU_CTRL_OFFSET, |
714 | .mask = GENMASK(7, 0) & ~BIT(1), |
715 | .mode = 0644, |
716 | }, |
717 | { |
718 | .label = "pwr_cycle" , |
719 | .reg = NVSW_SN2201_PSU_CTRL_OFFSET, |
720 | .mask = GENMASK(7, 0) & ~BIT(2), |
721 | .mode = 0644, |
722 | }, |
723 | { |
724 | .label = "asic_health" , |
725 | .reg = NVSW_SN2201_SYS_STATUS_OFFSET, |
726 | .mask = GENMASK(4, 3), |
727 | .bit = 4, |
728 | .mode = 0444, |
729 | }, |
730 | { |
731 | .label = "qsfp_pwr_good" , |
732 | .reg = NVSW_SN2201_SYS_STATUS_OFFSET, |
733 | .mask = GENMASK(7, 0) & ~BIT(0), |
734 | .mode = 0444, |
735 | }, |
736 | { |
737 | .label = "phy_reset" , |
738 | .reg = NVSW_SN2201_SYS_RST_STATUS_OFFSET, |
739 | .mask = GENMASK(7, 0) & ~BIT(3), |
740 | .mode = 0644, |
741 | }, |
742 | { |
743 | .label = "mac_reset" , |
744 | .reg = NVSW_SN2201_SYS_RST_STATUS_OFFSET, |
745 | .mask = GENMASK(7, 0) & ~BIT(2), |
746 | .mode = 0644, |
747 | }, |
748 | { |
749 | .label = "pwr_down" , |
750 | .reg = NVSW_SN2201_RST_SW_CTRL_OFFSET, |
751 | .mask = GENMASK(7, 0) & ~BIT(0), |
752 | .mode = 0644, |
753 | }, |
754 | { |
755 | .label = "reset_long_pb" , |
756 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
757 | .mask = GENMASK(7, 0) & ~BIT(0), |
758 | .mode = 0444, |
759 | }, |
760 | { |
761 | .label = "reset_short_pb" , |
762 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
763 | .mask = GENMASK(7, 0) & ~BIT(1), |
764 | .mode = 0444, |
765 | }, |
766 | { |
767 | .label = "reset_aux_pwr_or_fu" , |
768 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
769 | .mask = GENMASK(7, 0) & ~BIT(2), |
770 | .mode = 0444, |
771 | }, |
772 | { |
773 | .label = "reset_swb_dc_dc_pwr_fail" , |
774 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
775 | .mask = GENMASK(7, 0) & ~BIT(3), |
776 | .mode = 0444, |
777 | }, |
778 | { |
779 | .label = "reset_sw_reset" , |
780 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
781 | .mask = GENMASK(7, 0) & ~BIT(4), |
782 | .mode = 0444, |
783 | }, |
784 | { |
785 | .label = "reset_fw_reset" , |
786 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
787 | .mask = GENMASK(7, 0) & ~BIT(5), |
788 | .mode = 0444, |
789 | }, |
790 | { |
791 | .label = "reset_swb_wd" , |
792 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
793 | .mask = GENMASK(7, 0) & ~BIT(6), |
794 | .mode = 0444, |
795 | }, |
796 | { |
797 | .label = "reset_asic_thermal" , |
798 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
799 | .mask = GENMASK(7, 0) & ~BIT(7), |
800 | .mode = 0444, |
801 | }, |
802 | { |
803 | .label = "reset_system" , |
804 | .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, |
805 | .mask = GENMASK(7, 0) & ~BIT(1), |
806 | .mode = 0444, |
807 | }, |
808 | { |
809 | .label = "reset_sw_pwr_off" , |
810 | .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, |
811 | .mask = GENMASK(7, 0) & ~BIT(2), |
812 | .mode = 0444, |
813 | }, |
814 | { |
815 | .label = "reset_cpu_pwr_fail_thermal" , |
816 | .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, |
817 | .mask = GENMASK(7, 0) & ~BIT(4), |
818 | .mode = 0444, |
819 | }, |
820 | { |
821 | .label = "reset_reload_bios" , |
822 | .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, |
823 | .mask = GENMASK(7, 0) & ~BIT(5), |
824 | .mode = 0444, |
825 | }, |
826 | { |
827 | .label = "reset_ac_pwr_fail" , |
828 | .reg = NVSW_SN2201_RST_CAUSE2_OFFSET, |
829 | .mask = GENMASK(7, 0) & ~BIT(6), |
830 | .mode = 0444, |
831 | }, |
832 | { |
833 | .label = "psu1" , |
834 | .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, |
835 | .mask = GENMASK(7, 0) & ~BIT(0), |
836 | .mode = 0444, |
837 | }, |
838 | { |
839 | .label = "psu2" , |
840 | .reg = NVSW_SN2201_PS_PRSNT_STATUS_OFFSET, |
841 | .mask = GENMASK(7, 0) & ~BIT(1), |
842 | .mode = 0444, |
843 | }, |
844 | }; |
845 | |
846 | static struct mlxreg_core_platform_data nvsw_sn2201_regs_io = { |
847 | .data = nvsw_sn2201_io_data, |
848 | .counter = ARRAY_SIZE(nvsw_sn2201_io_data), |
849 | }; |
850 | |
851 | /* Default watchdog data. */ |
852 | static struct mlxreg_core_data nvsw_sn2201_wd_data[] = { |
853 | { |
854 | .label = "action" , |
855 | .reg = NVSW_SN2201_WD_ACT_OFFSET, |
856 | .mask = GENMASK(7, 1), |
857 | .bit = 0, |
858 | }, |
859 | { |
860 | .label = "timeout" , |
861 | .reg = NVSW_SN2201_WD_TMR_OFFSET_LSB, |
862 | .mask = 0, |
863 | .health_cntr = NVSW_SN2201_WD_DFLT_TIMEOUT, |
864 | }, |
865 | { |
866 | .label = "timeleft" , |
867 | .reg = NVSW_SN2201_WD_TMR_OFFSET_LSB, |
868 | .mask = 0, |
869 | }, |
870 | { |
871 | .label = "ping" , |
872 | .reg = NVSW_SN2201_WD_ACT_OFFSET, |
873 | .mask = GENMASK(7, 1), |
874 | .bit = 0, |
875 | }, |
876 | { |
877 | .label = "reset" , |
878 | .reg = NVSW_SN2201_RST_CAUSE1_OFFSET, |
879 | .mask = GENMASK(7, 0) & ~BIT(6), |
880 | .bit = 6, |
881 | }, |
882 | }; |
883 | |
884 | static struct mlxreg_core_platform_data nvsw_sn2201_wd = { |
885 | .data = nvsw_sn2201_wd_data, |
886 | .counter = ARRAY_SIZE(nvsw_sn2201_wd_data), |
887 | .version = MLX_WDT_TYPE3, |
888 | .identity = "mlx-wdt-main" , |
889 | }; |
890 | |
891 | static int |
892 | nvsw_sn2201_create_static_devices(struct nvsw_sn2201 *nvsw_sn2201, |
893 | struct mlxreg_hotplug_device *devs, |
894 | int size) |
895 | { |
896 | struct mlxreg_hotplug_device *dev = devs; |
897 | int ret; |
898 | int i; |
899 | |
900 | /* Create I2C static devices. */ |
901 | for (i = 0; i < size; i++, dev++) { |
902 | dev->client = i2c_new_client_device(adap: dev->adapter, info: dev->brdinfo); |
903 | if (IS_ERR(ptr: dev->client)) { |
904 | dev_err(nvsw_sn2201->dev, "Failed to create client %s at bus %d at addr 0x%02x\n" , |
905 | dev->brdinfo->type, |
906 | dev->nr, dev->brdinfo->addr); |
907 | |
908 | dev->adapter = NULL; |
909 | ret = PTR_ERR(ptr: dev->client); |
910 | goto fail_create_static_devices; |
911 | } |
912 | } |
913 | |
914 | return 0; |
915 | |
916 | fail_create_static_devices: |
917 | while (--i >= 0) { |
918 | dev = devs + i; |
919 | i2c_unregister_device(client: dev->client); |
920 | dev->client = NULL; |
921 | dev->adapter = NULL; |
922 | } |
923 | return ret; |
924 | } |
925 | |
926 | static void nvsw_sn2201_destroy_static_devices(struct nvsw_sn2201 *nvsw_sn2201, |
927 | struct mlxreg_hotplug_device *devs, int size) |
928 | { |
929 | struct mlxreg_hotplug_device *dev = devs; |
930 | int i; |
931 | |
932 | /* Destroy static I2C device for SN2201 static devices. */ |
933 | for (i = 0; i < size; i++, dev++) { |
934 | if (dev->client) { |
935 | i2c_unregister_device(client: dev->client); |
936 | dev->client = NULL; |
937 | i2c_put_adapter(adap: dev->adapter); |
938 | dev->adapter = NULL; |
939 | } |
940 | } |
941 | } |
942 | |
943 | static int nvsw_sn2201_config_post_init(struct nvsw_sn2201 *nvsw_sn2201) |
944 | { |
945 | struct mlxreg_hotplug_device *sn2201_dev; |
946 | struct i2c_adapter *adap; |
947 | struct device *dev; |
948 | int i, err; |
949 | |
950 | dev = nvsw_sn2201->dev; |
951 | adap = i2c_get_adapter(nr: nvsw_sn2201->main_mux_deferred_nr); |
952 | if (!adap) { |
953 | dev_err(dev, "Failed to get adapter for bus %d\n" , |
954 | nvsw_sn2201->main_mux_deferred_nr); |
955 | return -ENODEV; |
956 | } |
957 | i2c_put_adapter(adap); |
958 | |
959 | /* Update board info. */ |
960 | sn2201_dev = nvsw_sn2201->sn2201_devs; |
961 | for (i = 0; i < nvsw_sn2201->sn2201_devs_num; i++, sn2201_dev++) { |
962 | sn2201_dev->adapter = i2c_get_adapter(nr: sn2201_dev->nr); |
963 | if (!sn2201_dev->adapter) |
964 | return -ENODEV; |
965 | i2c_put_adapter(adap: sn2201_dev->adapter); |
966 | } |
967 | |
968 | err = nvsw_sn2201_create_static_devices(nvsw_sn2201, devs: nvsw_sn2201->sn2201_devs, |
969 | size: nvsw_sn2201->sn2201_devs_num); |
970 | if (err) |
971 | dev_err(dev, "Failed to create static devices\n" ); |
972 | |
973 | return err; |
974 | } |
975 | |
976 | static int nvsw_sn2201_config_init(struct nvsw_sn2201 *nvsw_sn2201, void *regmap) |
977 | { |
978 | struct device *dev = nvsw_sn2201->dev; |
979 | int err; |
980 | |
981 | nvsw_sn2201->io_data = &nvsw_sn2201_regs_io; |
982 | nvsw_sn2201->led_data = &nvsw_sn2201_led; |
983 | nvsw_sn2201->wd_data = &nvsw_sn2201_wd; |
984 | nvsw_sn2201->hotplug_data = &nvsw_sn2201_hotplug; |
985 | |
986 | /* Register IO access driver. */ |
987 | if (nvsw_sn2201->io_data) { |
988 | nvsw_sn2201->io_data->regmap = regmap; |
989 | nvsw_sn2201->io_regs = |
990 | platform_device_register_resndata(parent: dev, name: "mlxreg-io" , PLATFORM_DEVID_NONE, NULL, num: 0, |
991 | data: nvsw_sn2201->io_data, |
992 | size: sizeof(*nvsw_sn2201->io_data)); |
993 | if (IS_ERR(ptr: nvsw_sn2201->io_regs)) { |
994 | err = PTR_ERR(ptr: nvsw_sn2201->io_regs); |
995 | goto fail_register_io; |
996 | } |
997 | } |
998 | |
999 | /* Register LED driver. */ |
1000 | if (nvsw_sn2201->led_data) { |
1001 | nvsw_sn2201->led_data->regmap = regmap; |
1002 | nvsw_sn2201->led = |
1003 | platform_device_register_resndata(parent: dev, name: "leds-mlxreg" , PLATFORM_DEVID_NONE, NULL, num: 0, |
1004 | data: nvsw_sn2201->led_data, |
1005 | size: sizeof(*nvsw_sn2201->led_data)); |
1006 | if (IS_ERR(ptr: nvsw_sn2201->led)) { |
1007 | err = PTR_ERR(ptr: nvsw_sn2201->led); |
1008 | goto fail_register_led; |
1009 | } |
1010 | } |
1011 | |
1012 | /* Register WD driver. */ |
1013 | if (nvsw_sn2201->wd_data) { |
1014 | nvsw_sn2201->wd_data->regmap = regmap; |
1015 | nvsw_sn2201->wd = |
1016 | platform_device_register_resndata(parent: dev, name: "mlx-wdt" , PLATFORM_DEVID_NONE, NULL, num: 0, |
1017 | data: nvsw_sn2201->wd_data, |
1018 | size: sizeof(*nvsw_sn2201->wd_data)); |
1019 | if (IS_ERR(ptr: nvsw_sn2201->wd)) { |
1020 | err = PTR_ERR(ptr: nvsw_sn2201->wd); |
1021 | goto fail_register_wd; |
1022 | } |
1023 | } |
1024 | |
1025 | /* Register hotplug driver. */ |
1026 | if (nvsw_sn2201->hotplug_data) { |
1027 | nvsw_sn2201->hotplug_data->regmap = regmap; |
1028 | nvsw_sn2201->pdev_hotplug = |
1029 | platform_device_register_resndata(parent: dev, name: "mlxreg-hotplug" , PLATFORM_DEVID_NONE, |
1030 | res: nvsw_sn2201_cpld_res, |
1031 | ARRAY_SIZE(nvsw_sn2201_cpld_res), |
1032 | data: nvsw_sn2201->hotplug_data, |
1033 | size: sizeof(*nvsw_sn2201->hotplug_data)); |
1034 | if (IS_ERR(ptr: nvsw_sn2201->pdev_hotplug)) { |
1035 | err = PTR_ERR(ptr: nvsw_sn2201->pdev_hotplug); |
1036 | goto fail_register_hotplug; |
1037 | } |
1038 | } |
1039 | |
1040 | return nvsw_sn2201_config_post_init(nvsw_sn2201); |
1041 | |
1042 | fail_register_hotplug: |
1043 | if (nvsw_sn2201->wd) |
1044 | platform_device_unregister(nvsw_sn2201->wd); |
1045 | fail_register_wd: |
1046 | if (nvsw_sn2201->led) |
1047 | platform_device_unregister(nvsw_sn2201->led); |
1048 | fail_register_led: |
1049 | if (nvsw_sn2201->io_regs) |
1050 | platform_device_unregister(nvsw_sn2201->io_regs); |
1051 | fail_register_io: |
1052 | |
1053 | return err; |
1054 | } |
1055 | |
1056 | static void nvsw_sn2201_config_exit(struct nvsw_sn2201 *nvsw_sn2201) |
1057 | { |
1058 | /* Unregister hotplug driver. */ |
1059 | if (nvsw_sn2201->pdev_hotplug) |
1060 | platform_device_unregister(nvsw_sn2201->pdev_hotplug); |
1061 | /* Unregister WD driver. */ |
1062 | if (nvsw_sn2201->wd) |
1063 | platform_device_unregister(nvsw_sn2201->wd); |
1064 | /* Unregister LED driver. */ |
1065 | if (nvsw_sn2201->led) |
1066 | platform_device_unregister(nvsw_sn2201->led); |
1067 | /* Unregister IO access driver. */ |
1068 | if (nvsw_sn2201->io_regs) |
1069 | platform_device_unregister(nvsw_sn2201->io_regs); |
1070 | } |
1071 | |
1072 | /* |
1073 | * Initialization is divided into two parts: |
1074 | * - I2C main bus init. |
1075 | * - Mux creation and attaching devices to the mux, |
1076 | * which assumes that the main bus is already created. |
1077 | * This separation is required for synchronization between these two parts. |
1078 | * Completion notify callback is used to make this flow synchronized. |
1079 | */ |
1080 | static int nvsw_sn2201_i2c_completion_notify(void *handle, int id) |
1081 | { |
1082 | struct nvsw_sn2201 *nvsw_sn2201 = handle; |
1083 | void *regmap; |
1084 | int i, err; |
1085 | |
1086 | /* Create main mux. */ |
1087 | nvsw_sn2201->main_mux_devs->adapter = i2c_get_adapter(nr: nvsw_sn2201->main_mux_devs->nr); |
1088 | if (!nvsw_sn2201->main_mux_devs->adapter) { |
1089 | err = -ENODEV; |
1090 | dev_err(nvsw_sn2201->dev, "Failed to get adapter for bus %d\n" , |
1091 | nvsw_sn2201->cpld_devs->nr); |
1092 | goto i2c_get_adapter_main_fail; |
1093 | } |
1094 | |
1095 | nvsw_sn2201->main_mux_devs_num = ARRAY_SIZE(nvsw_sn2201_main_mux_brdinfo); |
1096 | err = nvsw_sn2201_create_static_devices(nvsw_sn2201, devs: nvsw_sn2201->main_mux_devs, |
1097 | size: nvsw_sn2201->main_mux_devs_num); |
1098 | if (err) { |
1099 | dev_err(nvsw_sn2201->dev, "Failed to create main mux devices\n" ); |
1100 | goto nvsw_sn2201_create_static_devices_fail; |
1101 | } |
1102 | |
1103 | nvsw_sn2201->cpld_devs->adapter = i2c_get_adapter(nr: nvsw_sn2201->cpld_devs->nr); |
1104 | if (!nvsw_sn2201->cpld_devs->adapter) { |
1105 | err = -ENODEV; |
1106 | dev_err(nvsw_sn2201->dev, "Failed to get adapter for bus %d\n" , |
1107 | nvsw_sn2201->cpld_devs->nr); |
1108 | goto i2c_get_adapter_fail; |
1109 | } |
1110 | |
1111 | /* Create CPLD device. */ |
1112 | nvsw_sn2201->cpld_devs->client = i2c_new_dummy_device(adapter: nvsw_sn2201->cpld_devs->adapter, |
1113 | NVSW_SN2201_CPLD_I2CADDR); |
1114 | if (IS_ERR(ptr: nvsw_sn2201->cpld_devs->client)) { |
1115 | err = PTR_ERR(ptr: nvsw_sn2201->cpld_devs->client); |
1116 | dev_err(nvsw_sn2201->dev, "Failed to create %s cpld device at bus %d at addr 0x%02x\n" , |
1117 | nvsw_sn2201->cpld_devs->brdinfo->type, nvsw_sn2201->cpld_devs->nr, |
1118 | nvsw_sn2201->cpld_devs->brdinfo->addr); |
1119 | goto i2c_new_dummy_fail; |
1120 | } |
1121 | |
1122 | regmap = devm_regmap_init_i2c(nvsw_sn2201->cpld_devs->client, &nvsw_sn2201_regmap_conf); |
1123 | if (IS_ERR(ptr: regmap)) { |
1124 | err = PTR_ERR(ptr: regmap); |
1125 | dev_err(nvsw_sn2201->dev, "Failed to initialise managed register map\n" ); |
1126 | goto devm_regmap_init_i2c_fail; |
1127 | } |
1128 | |
1129 | /* Set default registers. */ |
1130 | for (i = 0; i < nvsw_sn2201_regmap_conf.num_reg_defaults; i++) { |
1131 | err = regmap_write(map: regmap, reg: nvsw_sn2201_regmap_default[i].reg, |
1132 | val: nvsw_sn2201_regmap_default[i].def); |
1133 | if (err) { |
1134 | dev_err(nvsw_sn2201->dev, "Failed to set register at offset 0x%02x to default value: 0x%02x\n" , |
1135 | nvsw_sn2201_regmap_default[i].reg, |
1136 | nvsw_sn2201_regmap_default[i].def); |
1137 | goto regmap_write_fail; |
1138 | } |
1139 | } |
1140 | |
1141 | /* Sync registers with hardware. */ |
1142 | regcache_mark_dirty(map: regmap); |
1143 | err = regcache_sync(map: regmap); |
1144 | if (err) { |
1145 | dev_err(nvsw_sn2201->dev, "Failed to Sync registers with hardware\n" ); |
1146 | goto regcache_sync_fail; |
1147 | } |
1148 | |
1149 | /* Configure SN2201 board. */ |
1150 | err = nvsw_sn2201_config_init(nvsw_sn2201, regmap); |
1151 | if (err) { |
1152 | dev_err(nvsw_sn2201->dev, "Failed to configure board\n" ); |
1153 | goto nvsw_sn2201_config_init_fail; |
1154 | } |
1155 | |
1156 | return 0; |
1157 | |
1158 | nvsw_sn2201_config_init_fail: |
1159 | nvsw_sn2201_config_exit(nvsw_sn2201); |
1160 | regcache_sync_fail: |
1161 | regmap_write_fail: |
1162 | devm_regmap_init_i2c_fail: |
1163 | i2c_new_dummy_fail: |
1164 | i2c_put_adapter(adap: nvsw_sn2201->cpld_devs->adapter); |
1165 | nvsw_sn2201->cpld_devs->adapter = NULL; |
1166 | i2c_get_adapter_fail: |
1167 | /* Destroy SN2201 static I2C devices. */ |
1168 | nvsw_sn2201_destroy_static_devices(nvsw_sn2201, devs: nvsw_sn2201->sn2201_devs, |
1169 | size: nvsw_sn2201->sn2201_devs_num); |
1170 | /* Destroy main mux device. */ |
1171 | nvsw_sn2201_destroy_static_devices(nvsw_sn2201, devs: nvsw_sn2201->main_mux_devs, |
1172 | size: nvsw_sn2201->main_mux_devs_num); |
1173 | nvsw_sn2201_create_static_devices_fail: |
1174 | i2c_put_adapter(adap: nvsw_sn2201->main_mux_devs->adapter); |
1175 | i2c_get_adapter_main_fail: |
1176 | return err; |
1177 | } |
1178 | |
1179 | static int nvsw_sn2201_config_pre_init(struct nvsw_sn2201 *nvsw_sn2201) |
1180 | { |
1181 | nvsw_sn2201->i2c_data = &nvsw_sn2201_i2c_data; |
1182 | |
1183 | /* Register I2C controller. */ |
1184 | nvsw_sn2201->i2c_data->handle = nvsw_sn2201; |
1185 | nvsw_sn2201->i2c_data->completion_notify = nvsw_sn2201_i2c_completion_notify; |
1186 | nvsw_sn2201->pdev_i2c = platform_device_register_resndata(parent: nvsw_sn2201->dev, name: "i2c_mlxcpld" , |
1187 | NVSW_SN2201_MAIN_MUX_NR, |
1188 | res: nvsw_sn2201_lpc_res, |
1189 | ARRAY_SIZE(nvsw_sn2201_lpc_res), |
1190 | data: nvsw_sn2201->i2c_data, |
1191 | size: sizeof(*nvsw_sn2201->i2c_data)); |
1192 | if (IS_ERR(ptr: nvsw_sn2201->pdev_i2c)) |
1193 | return PTR_ERR(ptr: nvsw_sn2201->pdev_i2c); |
1194 | |
1195 | return 0; |
1196 | } |
1197 | |
1198 | static int nvsw_sn2201_probe(struct platform_device *pdev) |
1199 | { |
1200 | struct nvsw_sn2201 *nvsw_sn2201; |
1201 | |
1202 | nvsw_sn2201 = devm_kzalloc(dev: &pdev->dev, size: sizeof(*nvsw_sn2201), GFP_KERNEL); |
1203 | if (!nvsw_sn2201) |
1204 | return -ENOMEM; |
1205 | |
1206 | nvsw_sn2201->dev = &pdev->dev; |
1207 | platform_set_drvdata(pdev, data: nvsw_sn2201); |
1208 | platform_device_add_resources(pdev, res: nvsw_sn2201_lpc_io_resources, |
1209 | ARRAY_SIZE(nvsw_sn2201_lpc_io_resources)); |
1210 | |
1211 | nvsw_sn2201->main_mux_deferred_nr = NVSW_SN2201_MAIN_MUX_DEFER_NR; |
1212 | nvsw_sn2201->main_mux_devs = nvsw_sn2201_main_mux_brdinfo; |
1213 | nvsw_sn2201->cpld_devs = nvsw_sn2201_cpld_brdinfo; |
1214 | nvsw_sn2201->sn2201_devs = nvsw_sn2201_static_brdinfo; |
1215 | nvsw_sn2201->sn2201_devs_num = ARRAY_SIZE(nvsw_sn2201_static_brdinfo); |
1216 | |
1217 | return nvsw_sn2201_config_pre_init(nvsw_sn2201); |
1218 | } |
1219 | |
1220 | static void nvsw_sn2201_remove(struct platform_device *pdev) |
1221 | { |
1222 | struct nvsw_sn2201 *nvsw_sn2201 = platform_get_drvdata(pdev); |
1223 | |
1224 | /* Unregister underlying drivers. */ |
1225 | nvsw_sn2201_config_exit(nvsw_sn2201); |
1226 | |
1227 | /* Destroy SN2201 static I2C devices. */ |
1228 | nvsw_sn2201_destroy_static_devices(nvsw_sn2201, |
1229 | devs: nvsw_sn2201->sn2201_devs, |
1230 | size: nvsw_sn2201->sn2201_devs_num); |
1231 | |
1232 | i2c_put_adapter(adap: nvsw_sn2201->cpld_devs->adapter); |
1233 | nvsw_sn2201->cpld_devs->adapter = NULL; |
1234 | /* Destroy main mux device. */ |
1235 | nvsw_sn2201_destroy_static_devices(nvsw_sn2201, |
1236 | devs: nvsw_sn2201->main_mux_devs, |
1237 | size: nvsw_sn2201->main_mux_devs_num); |
1238 | |
1239 | /* Unregister I2C controller. */ |
1240 | if (nvsw_sn2201->pdev_i2c) |
1241 | platform_device_unregister(nvsw_sn2201->pdev_i2c); |
1242 | } |
1243 | |
1244 | static const struct acpi_device_id nvsw_sn2201_acpi_ids[] = { |
1245 | {"NVSN2201" , 0}, |
1246 | {} |
1247 | }; |
1248 | |
1249 | MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids); |
1250 | |
1251 | static struct platform_driver nvsw_sn2201_driver = { |
1252 | .probe = nvsw_sn2201_probe, |
1253 | .remove_new = nvsw_sn2201_remove, |
1254 | .driver = { |
1255 | .name = "nvsw-sn2201" , |
1256 | .acpi_match_table = nvsw_sn2201_acpi_ids, |
1257 | }, |
1258 | }; |
1259 | |
1260 | module_platform_driver(nvsw_sn2201_driver); |
1261 | |
1262 | MODULE_AUTHOR("Nvidia" ); |
1263 | MODULE_DESCRIPTION("Nvidia sn2201 platform driver" ); |
1264 | MODULE_LICENSE("Dual BSD/GPL" ); |
1265 | MODULE_ALIAS("platform:nvsw-sn2201" ); |
1266 | |