1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Driver for the NXP ISP1760 chip |
4 | * |
5 | * Copyright 2021 Linaro, Rui Miguel Silva |
6 | * Copyright 2014 Laurent Pinchart |
7 | * Copyright 2007 Sebastian Siewior |
8 | * |
9 | * Contacts: |
10 | * Sebastian Siewior <bigeasy@linutronix.de> |
11 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
12 | * Rui Miguel Silva <rui.silva@linaro.org> |
13 | */ |
14 | |
15 | #include <linux/delay.h> |
16 | #include <linux/gpio/consumer.h> |
17 | #include <linux/io.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/slab.h> |
22 | #include <linux/usb.h> |
23 | |
24 | #include "isp1760-core.h" |
25 | #include "isp1760-hcd.h" |
26 | #include "isp1760-regs.h" |
27 | #include "isp1760-udc.h" |
28 | |
29 | static int isp1760_init_core(struct isp1760_device *isp) |
30 | { |
31 | struct isp1760_hcd *hcd = &isp->hcd; |
32 | struct isp1760_udc *udc = &isp->udc; |
33 | u32 otg_ctrl; |
34 | |
35 | /* Low-level chip reset */ |
36 | if (isp->rst_gpio) { |
37 | gpiod_set_value_cansleep(desc: isp->rst_gpio, value: 1); |
38 | msleep(msecs: 50); |
39 | gpiod_set_value_cansleep(desc: isp->rst_gpio, value: 0); |
40 | } |
41 | |
42 | /* |
43 | * Reset the host controller, including the CPU interface |
44 | * configuration. |
45 | */ |
46 | isp1760_field_set(fields: hcd->fields, field: SW_RESET_RESET_ALL); |
47 | msleep(msecs: 100); |
48 | |
49 | /* Setup HW Mode Control: This assumes a level active-low interrupt */ |
50 | if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) { |
51 | dev_err(isp->dev, "isp1763 analog overcurrent not available\n" ); |
52 | return -EINVAL; |
53 | } |
54 | |
55 | if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16) |
56 | isp1760_field_clear(fields: hcd->fields, field: HW_DATA_BUS_WIDTH); |
57 | if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8) |
58 | isp1760_field_set(fields: hcd->fields, field: HW_DATA_BUS_WIDTH); |
59 | if (isp->devflags & ISP1760_FLAG_ANALOG_OC) |
60 | isp1760_field_set(fields: hcd->fields, field: HW_ANA_DIGI_OC); |
61 | if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH) |
62 | isp1760_field_set(fields: hcd->fields, field: HW_DACK_POL_HIGH); |
63 | if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH) |
64 | isp1760_field_set(fields: hcd->fields, field: HW_DREQ_POL_HIGH); |
65 | if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH) |
66 | isp1760_field_set(fields: hcd->fields, field: HW_INTR_HIGH_ACT); |
67 | if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) |
68 | isp1760_field_set(fields: hcd->fields, field: HW_INTR_EDGE_TRIG); |
69 | |
70 | /* |
71 | * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC |
72 | * IRQ line for both the host and device controllers. Hardcode IRQ |
73 | * sharing for now and disable the DC interrupts globally to avoid |
74 | * spurious interrupts during HCD registration. |
75 | */ |
76 | if (isp->devflags & ISP1760_FLAG_ISP1761) { |
77 | isp1760_reg_write(regs: udc->regs, ISP176x_DC_MODE, val: 0); |
78 | isp1760_field_set(fields: hcd->fields, field: HW_COMN_IRQ); |
79 | } |
80 | |
81 | /* |
82 | * PORT 1 Control register of the ISP1760 is the OTG control register |
83 | * on ISP1761. |
84 | * |
85 | * TODO: Really support OTG. For now we configure port 1 in device mode |
86 | */ |
87 | if (isp->devflags & ISP1760_FLAG_ISP1761) { |
88 | if (isp->devflags & ISP1760_FLAG_PERIPHERAL_EN) { |
89 | otg_ctrl = (ISP176x_HW_DM_PULLDOWN_CLEAR | |
90 | ISP176x_HW_DP_PULLDOWN_CLEAR | |
91 | ISP176x_HW_OTG_DISABLE); |
92 | } else { |
93 | otg_ctrl = (ISP176x_HW_SW_SEL_HC_DC_CLEAR | |
94 | ISP176x_HW_VBUS_DRV | |
95 | ISP176x_HW_SEL_CP_EXT); |
96 | } |
97 | isp1760_reg_write(regs: hcd->regs, ISP176x_HC_OTG_CTRL, val: otg_ctrl); |
98 | } |
99 | |
100 | dev_info(isp->dev, "%s bus width: %u, oc: %s\n" , |
101 | hcd->is_isp1763 ? "isp1763" : "isp1760" , |
102 | isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 : |
103 | isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32, |
104 | hcd->is_isp1763 ? "not available" : |
105 | isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital" ); |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | void isp1760_set_pullup(struct isp1760_device *isp, bool enable) |
111 | { |
112 | struct isp1760_udc *udc = &isp->udc; |
113 | |
114 | if (enable) |
115 | isp1760_field_set(fields: udc->fields, field: HW_DP_PULLUP); |
116 | else |
117 | isp1760_field_set(fields: udc->fields, field: HW_DP_PULLUP_CLEAR); |
118 | } |
119 | |
120 | /* |
121 | * ISP1760/61: |
122 | * |
123 | * 60kb divided in: |
124 | * - 32 blocks @ 256 bytes |
125 | * - 20 blocks @ 1024 bytes |
126 | * - 4 blocks @ 8192 bytes |
127 | */ |
128 | static const struct isp1760_memory_layout isp176x_memory_conf = { |
129 | .blocks[0] = 32, |
130 | .blocks_size[0] = 256, |
131 | .blocks[1] = 20, |
132 | .blocks_size[1] = 1024, |
133 | .blocks[2] = 4, |
134 | .blocks_size[2] = 8192, |
135 | |
136 | .slot_num = 32, |
137 | .payload_blocks = 32 + 20 + 4, |
138 | .payload_area_size = 0xf000, |
139 | }; |
140 | |
141 | /* |
142 | * ISP1763: |
143 | * |
144 | * 20kb divided in: |
145 | * - 8 blocks @ 256 bytes |
146 | * - 2 blocks @ 1024 bytes |
147 | * - 4 blocks @ 4096 bytes |
148 | */ |
149 | static const struct isp1760_memory_layout isp1763_memory_conf = { |
150 | .blocks[0] = 8, |
151 | .blocks_size[0] = 256, |
152 | .blocks[1] = 2, |
153 | .blocks_size[1] = 1024, |
154 | .blocks[2] = 4, |
155 | .blocks_size[2] = 4096, |
156 | |
157 | .slot_num = 16, |
158 | .payload_blocks = 8 + 2 + 4, |
159 | .payload_area_size = 0x5000, |
160 | }; |
161 | |
162 | static const struct regmap_range isp176x_hc_volatile_ranges[] = { |
163 | regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD), |
164 | regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY), |
165 | regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_OTG_CTRL_CLEAR), |
166 | }; |
167 | |
168 | static const struct regmap_access_table isp176x_hc_volatile_table = { |
169 | .yes_ranges = isp176x_hc_volatile_ranges, |
170 | .n_yes_ranges = ARRAY_SIZE(isp176x_hc_volatile_ranges), |
171 | }; |
172 | |
173 | static const struct regmap_config isp1760_hc_regmap_conf = { |
174 | .name = "isp1760-hc" , |
175 | .reg_bits = 16, |
176 | .reg_stride = 4, |
177 | .val_bits = 32, |
178 | .fast_io = true, |
179 | .max_register = ISP176x_HC_OTG_CTRL_CLEAR, |
180 | .volatile_table = &isp176x_hc_volatile_table, |
181 | }; |
182 | |
183 | static const struct reg_field isp1760_hc_reg_fields[] = { |
184 | [HCS_PPC] = REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4), |
185 | [HCS_N_PORTS] = REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3), |
186 | [HCC_ISOC_CACHE] = REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7), |
187 | [HCC_ISOC_THRES] = REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6), |
188 | [CMD_LRESET] = REG_FIELD(ISP176x_HC_USBCMD, 7, 7), |
189 | [CMD_RESET] = REG_FIELD(ISP176x_HC_USBCMD, 1, 1), |
190 | [CMD_RUN] = REG_FIELD(ISP176x_HC_USBCMD, 0, 0), |
191 | [STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2), |
192 | [HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13), |
193 | [FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0), |
194 | [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31), |
195 | [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31), |
196 | [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31), |
197 | [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31), |
198 | [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31), |
199 | [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31), |
200 | [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31), |
201 | [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31), |
202 | [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31), |
203 | [PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13), |
204 | [PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12), |
205 | [PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11), |
206 | [PORT_RESET] = REG_FIELD(ISP176x_HC_PORTSC1, 8, 8), |
207 | [PORT_SUSPEND] = REG_FIELD(ISP176x_HC_PORTSC1, 7, 7), |
208 | [PORT_RESUME] = REG_FIELD(ISP176x_HC_PORTSC1, 6, 6), |
209 | [PORT_PE] = REG_FIELD(ISP176x_HC_PORTSC1, 2, 2), |
210 | [PORT_CSC] = REG_FIELD(ISP176x_HC_PORTSC1, 1, 1), |
211 | [PORT_CONNECT] = REG_FIELD(ISP176x_HC_PORTSC1, 0, 0), |
212 | [ALL_ATX_RESET] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31), |
213 | [HW_ANA_DIGI_OC] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15), |
214 | [HW_COMN_IRQ] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10), |
215 | [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8), |
216 | [HW_DACK_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6), |
217 | [HW_DREQ_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5), |
218 | [HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2), |
219 | [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1), |
220 | [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0), |
221 | [HC_CHIP_REV] = REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31), |
222 | [HC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15), |
223 | [HC_CHIP_ID_LOW] = REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7), |
224 | [HC_SCRATCH] = REG_FIELD(ISP176x_HC_SCRATCH, 0, 31), |
225 | [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0), |
226 | [ISO_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2), |
227 | [INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1), |
228 | [ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0), |
229 | [MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17), |
230 | [MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15), |
231 | [HC_INTERRUPT] = REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9), |
232 | [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8), |
233 | [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7), |
234 | [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31), |
235 | [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31), |
236 | [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31), |
237 | [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31), |
238 | [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31), |
239 | [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31), |
240 | [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 26, 26), |
241 | [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 23, 23), |
242 | [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 20, 20), |
243 | [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 19, 19), |
244 | [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 18, 18), |
245 | [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 17, 17), |
246 | [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 16, 16), |
247 | [HW_OTG_DISABLE] = REG_FIELD(ISP176x_HC_OTG_CTRL, 10, 10), |
248 | [HW_SW_SEL_HC_DC] = REG_FIELD(ISP176x_HC_OTG_CTRL, 7, 7), |
249 | [HW_VBUS_DRV] = REG_FIELD(ISP176x_HC_OTG_CTRL, 4, 4), |
250 | [HW_SEL_CP_EXT] = REG_FIELD(ISP176x_HC_OTG_CTRL, 3, 3), |
251 | [HW_DM_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL, 2, 2), |
252 | [HW_DP_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL, 1, 1), |
253 | [HW_DP_PULLUP] = REG_FIELD(ISP176x_HC_OTG_CTRL, 0, 0), |
254 | /* Make sure the array is sized properly during compilation */ |
255 | [HC_FIELD_MAX] = {}, |
256 | }; |
257 | |
258 | static const struct reg_field isp1763_hc_reg_fields[] = { |
259 | [CMD_LRESET] = REG_FIELD(ISP1763_HC_USBCMD, 7, 7), |
260 | [CMD_RESET] = REG_FIELD(ISP1763_HC_USBCMD, 1, 1), |
261 | [CMD_RUN] = REG_FIELD(ISP1763_HC_USBCMD, 0, 0), |
262 | [STS_PCD] = REG_FIELD(ISP1763_HC_USBSTS, 2, 2), |
263 | [HC_FRINDEX] = REG_FIELD(ISP1763_HC_FRINDEX, 0, 13), |
264 | [FLAG_CF] = REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0), |
265 | [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15), |
266 | [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15), |
267 | [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15), |
268 | [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15), |
269 | [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15), |
270 | [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15), |
271 | [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15), |
272 | [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15), |
273 | [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15), |
274 | [PORT_OWNER] = REG_FIELD(ISP1763_HC_PORTSC1, 13, 13), |
275 | [PORT_POWER] = REG_FIELD(ISP1763_HC_PORTSC1, 12, 12), |
276 | [PORT_LSTATUS] = REG_FIELD(ISP1763_HC_PORTSC1, 10, 11), |
277 | [PORT_RESET] = REG_FIELD(ISP1763_HC_PORTSC1, 8, 8), |
278 | [PORT_SUSPEND] = REG_FIELD(ISP1763_HC_PORTSC1, 7, 7), |
279 | [PORT_RESUME] = REG_FIELD(ISP1763_HC_PORTSC1, 6, 6), |
280 | [PORT_PE] = REG_FIELD(ISP1763_HC_PORTSC1, 2, 2), |
281 | [PORT_CSC] = REG_FIELD(ISP1763_HC_PORTSC1, 1, 1), |
282 | [PORT_CONNECT] = REG_FIELD(ISP1763_HC_PORTSC1, 0, 0), |
283 | [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4), |
284 | [HW_DACK_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6), |
285 | [HW_DREQ_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5), |
286 | [HW_INTF_LOCK] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3), |
287 | [HW_INTR_HIGH_ACT] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2), |
288 | [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1), |
289 | [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0), |
290 | [SW_RESET_RESET_ATX] = REG_FIELD(ISP1763_HC_RESET, 3, 3), |
291 | [SW_RESET_RESET_ALL] = REG_FIELD(ISP1763_HC_RESET, 0, 0), |
292 | [HC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15), |
293 | [HC_CHIP_ID_LOW] = REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15), |
294 | [HC_CHIP_REV] = REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7), |
295 | [HC_SCRATCH] = REG_FIELD(ISP1763_HC_SCRATCH, 0, 15), |
296 | [ISO_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2), |
297 | [INT_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1), |
298 | [ATL_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0), |
299 | [MEM_START_ADDR] = REG_FIELD(ISP1763_HC_MEMORY, 0, 15), |
300 | [HC_DATA] = REG_FIELD(ISP1763_HC_DATA, 0, 15), |
301 | [HC_INTERRUPT] = REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10), |
302 | [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8), |
303 | [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7), |
304 | [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15), |
305 | [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15), |
306 | [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15), |
307 | [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15), |
308 | [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15), |
309 | [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15), |
310 | [HW_HC_2_DIS] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15), |
311 | [HW_OTG_DISABLE] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10), |
312 | [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7), |
313 | [HW_VBUS_DRV] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4), |
314 | [HW_SEL_CP_EXT] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3), |
315 | [HW_DM_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2), |
316 | [HW_DP_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1), |
317 | [HW_DP_PULLUP] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0), |
318 | [HW_HC_2_DIS_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15), |
319 | [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10), |
320 | [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7), |
321 | [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4), |
322 | [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3), |
323 | [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2), |
324 | [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1), |
325 | [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0), |
326 | /* Make sure the array is sized properly during compilation */ |
327 | [HC_FIELD_MAX] = {}, |
328 | }; |
329 | |
330 | static const struct regmap_range isp1763_hc_volatile_ranges[] = { |
331 | regmap_reg_range(ISP1763_HC_USBCMD, ISP1763_HC_ATL_PTD_LASTPTD), |
332 | regmap_reg_range(ISP1763_HC_BUFFER_STATUS, ISP1763_HC_DATA), |
333 | regmap_reg_range(ISP1763_HC_INTERRUPT, ISP1763_HC_OTG_CTRL_CLEAR), |
334 | }; |
335 | |
336 | static const struct regmap_access_table isp1763_hc_volatile_table = { |
337 | .yes_ranges = isp1763_hc_volatile_ranges, |
338 | .n_yes_ranges = ARRAY_SIZE(isp1763_hc_volatile_ranges), |
339 | }; |
340 | |
341 | static const struct regmap_config isp1763_hc_regmap_conf = { |
342 | .name = "isp1763-hc" , |
343 | .reg_bits = 8, |
344 | .reg_stride = 2, |
345 | .val_bits = 16, |
346 | .fast_io = true, |
347 | .max_register = ISP1763_HC_OTG_CTRL_CLEAR, |
348 | .volatile_table = &isp1763_hc_volatile_table, |
349 | }; |
350 | |
351 | static const struct regmap_range isp176x_dc_volatile_ranges[] = { |
352 | regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE), |
353 | regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX), |
354 | }; |
355 | |
356 | static const struct regmap_access_table isp176x_dc_volatile_table = { |
357 | .yes_ranges = isp176x_dc_volatile_ranges, |
358 | .n_yes_ranges = ARRAY_SIZE(isp176x_dc_volatile_ranges), |
359 | }; |
360 | |
361 | static const struct regmap_config isp1761_dc_regmap_conf = { |
362 | .name = "isp1761-dc" , |
363 | .reg_bits = 16, |
364 | .reg_stride = 4, |
365 | .val_bits = 32, |
366 | .fast_io = true, |
367 | .max_register = ISP176x_DC_TESTMODE, |
368 | .volatile_table = &isp176x_dc_volatile_table, |
369 | }; |
370 | |
371 | static const struct reg_field isp1761_dc_reg_fields[] = { |
372 | [DC_DEVEN] = REG_FIELD(ISP176x_DC_ADDRESS, 7, 7), |
373 | [DC_DEVADDR] = REG_FIELD(ISP176x_DC_ADDRESS, 0, 6), |
374 | [DC_VBUSSTAT] = REG_FIELD(ISP176x_DC_MODE, 8, 8), |
375 | [DC_SFRESET] = REG_FIELD(ISP176x_DC_MODE, 4, 4), |
376 | [DC_GLINTENA] = REG_FIELD(ISP176x_DC_MODE, 3, 3), |
377 | [DC_CDBGMOD_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 6, 6), |
378 | [DC_DDBGMODIN_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 4, 4), |
379 | [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 2, 2), |
380 | [DC_INTPOL] = REG_FIELD(ISP176x_DC_INTCONF, 0, 0), |
381 | [DC_IEPRXTX_7] = REG_FIELD(ISP176x_DC_INTENABLE, 25, 25), |
382 | [DC_IEPRXTX_6] = REG_FIELD(ISP176x_DC_INTENABLE, 23, 23), |
383 | [DC_IEPRXTX_5] = REG_FIELD(ISP176x_DC_INTENABLE, 21, 21), |
384 | [DC_IEPRXTX_4] = REG_FIELD(ISP176x_DC_INTENABLE, 19, 19), |
385 | [DC_IEPRXTX_3] = REG_FIELD(ISP176x_DC_INTENABLE, 17, 17), |
386 | [DC_IEPRXTX_2] = REG_FIELD(ISP176x_DC_INTENABLE, 15, 15), |
387 | [DC_IEPRXTX_1] = REG_FIELD(ISP176x_DC_INTENABLE, 13, 13), |
388 | [DC_IEPRXTX_0] = REG_FIELD(ISP176x_DC_INTENABLE, 11, 11), |
389 | [DC_IEP0SETUP] = REG_FIELD(ISP176x_DC_INTENABLE, 8, 8), |
390 | [DC_IEVBUS] = REG_FIELD(ISP176x_DC_INTENABLE, 7, 7), |
391 | [DC_IEHS_STA] = REG_FIELD(ISP176x_DC_INTENABLE, 5, 5), |
392 | [DC_IERESM] = REG_FIELD(ISP176x_DC_INTENABLE, 4, 4), |
393 | [DC_IESUSP] = REG_FIELD(ISP176x_DC_INTENABLE, 3, 3), |
394 | [DC_IEBRST] = REG_FIELD(ISP176x_DC_INTENABLE, 0, 0), |
395 | [DC_EP0SETUP] = REG_FIELD(ISP176x_DC_EPINDEX, 5, 5), |
396 | [DC_ENDPIDX] = REG_FIELD(ISP176x_DC_EPINDEX, 1, 4), |
397 | [DC_EPDIR] = REG_FIELD(ISP176x_DC_EPINDEX, 0, 0), |
398 | [DC_CLBUF] = REG_FIELD(ISP176x_DC_CTRLFUNC, 4, 4), |
399 | [DC_VENDP] = REG_FIELD(ISP176x_DC_CTRLFUNC, 3, 3), |
400 | [DC_DSEN] = REG_FIELD(ISP176x_DC_CTRLFUNC, 2, 2), |
401 | [DC_STATUS] = REG_FIELD(ISP176x_DC_CTRLFUNC, 1, 1), |
402 | [DC_STALL] = REG_FIELD(ISP176x_DC_CTRLFUNC, 0, 0), |
403 | [DC_BUFLEN] = REG_FIELD(ISP176x_DC_BUFLEN, 0, 15), |
404 | [DC_FFOSZ] = REG_FIELD(ISP176x_DC_EPMAXPKTSZ, 0, 10), |
405 | [DC_EPENABLE] = REG_FIELD(ISP176x_DC_EPTYPE, 3, 3), |
406 | [DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1), |
407 | [DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13), |
408 | [DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10), |
409 | [DC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_DC_CHIPID, 16, 31), |
410 | [DC_CHIP_ID_LOW] = REG_FIELD(ISP176x_DC_CHIPID, 0, 15), |
411 | [DC_SCRATCH] = REG_FIELD(ISP176x_DC_SCRATCH, 0, 15), |
412 | /* Make sure the array is sized properly during compilation */ |
413 | [DC_FIELD_MAX] = {}, |
414 | }; |
415 | |
416 | static const struct regmap_range isp1763_dc_volatile_ranges[] = { |
417 | regmap_reg_range(ISP1763_DC_EPMAXPKTSZ, ISP1763_DC_EPTYPE), |
418 | regmap_reg_range(ISP1763_DC_BUFLEN, ISP1763_DC_EPINDEX), |
419 | }; |
420 | |
421 | static const struct regmap_access_table isp1763_dc_volatile_table = { |
422 | .yes_ranges = isp1763_dc_volatile_ranges, |
423 | .n_yes_ranges = ARRAY_SIZE(isp1763_dc_volatile_ranges), |
424 | }; |
425 | |
426 | static const struct reg_field isp1763_dc_reg_fields[] = { |
427 | [DC_DEVEN] = REG_FIELD(ISP1763_DC_ADDRESS, 7, 7), |
428 | [DC_DEVADDR] = REG_FIELD(ISP1763_DC_ADDRESS, 0, 6), |
429 | [DC_VBUSSTAT] = REG_FIELD(ISP1763_DC_MODE, 8, 8), |
430 | [DC_SFRESET] = REG_FIELD(ISP1763_DC_MODE, 4, 4), |
431 | [DC_GLINTENA] = REG_FIELD(ISP1763_DC_MODE, 3, 3), |
432 | [DC_CDBGMOD_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 6, 6), |
433 | [DC_DDBGMODIN_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 4, 4), |
434 | [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 2, 2), |
435 | [DC_INTPOL] = REG_FIELD(ISP1763_DC_INTCONF, 0, 0), |
436 | [DC_IEPRXTX_7] = REG_FIELD(ISP1763_DC_INTENABLE, 25, 25), |
437 | [DC_IEPRXTX_6] = REG_FIELD(ISP1763_DC_INTENABLE, 23, 23), |
438 | [DC_IEPRXTX_5] = REG_FIELD(ISP1763_DC_INTENABLE, 21, 21), |
439 | [DC_IEPRXTX_4] = REG_FIELD(ISP1763_DC_INTENABLE, 19, 19), |
440 | [DC_IEPRXTX_3] = REG_FIELD(ISP1763_DC_INTENABLE, 17, 17), |
441 | [DC_IEPRXTX_2] = REG_FIELD(ISP1763_DC_INTENABLE, 15, 15), |
442 | [DC_IEPRXTX_1] = REG_FIELD(ISP1763_DC_INTENABLE, 13, 13), |
443 | [DC_IEPRXTX_0] = REG_FIELD(ISP1763_DC_INTENABLE, 11, 11), |
444 | [DC_IEP0SETUP] = REG_FIELD(ISP1763_DC_INTENABLE, 8, 8), |
445 | [DC_IEVBUS] = REG_FIELD(ISP1763_DC_INTENABLE, 7, 7), |
446 | [DC_IEHS_STA] = REG_FIELD(ISP1763_DC_INTENABLE, 5, 5), |
447 | [DC_IERESM] = REG_FIELD(ISP1763_DC_INTENABLE, 4, 4), |
448 | [DC_IESUSP] = REG_FIELD(ISP1763_DC_INTENABLE, 3, 3), |
449 | [DC_IEBRST] = REG_FIELD(ISP1763_DC_INTENABLE, 0, 0), |
450 | [DC_EP0SETUP] = REG_FIELD(ISP1763_DC_EPINDEX, 5, 5), |
451 | [DC_ENDPIDX] = REG_FIELD(ISP1763_DC_EPINDEX, 1, 4), |
452 | [DC_EPDIR] = REG_FIELD(ISP1763_DC_EPINDEX, 0, 0), |
453 | [DC_CLBUF] = REG_FIELD(ISP1763_DC_CTRLFUNC, 4, 4), |
454 | [DC_VENDP] = REG_FIELD(ISP1763_DC_CTRLFUNC, 3, 3), |
455 | [DC_DSEN] = REG_FIELD(ISP1763_DC_CTRLFUNC, 2, 2), |
456 | [DC_STATUS] = REG_FIELD(ISP1763_DC_CTRLFUNC, 1, 1), |
457 | [DC_STALL] = REG_FIELD(ISP1763_DC_CTRLFUNC, 0, 0), |
458 | [DC_BUFLEN] = REG_FIELD(ISP1763_DC_BUFLEN, 0, 15), |
459 | [DC_FFOSZ] = REG_FIELD(ISP1763_DC_EPMAXPKTSZ, 0, 10), |
460 | [DC_EPENABLE] = REG_FIELD(ISP1763_DC_EPTYPE, 3, 3), |
461 | [DC_ENDPTYP] = REG_FIELD(ISP1763_DC_EPTYPE, 0, 1), |
462 | [DC_UFRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 11, 13), |
463 | [DC_FRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 0, 10), |
464 | [DC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_DC_CHIPID_HIGH, 0, 15), |
465 | [DC_CHIP_ID_LOW] = REG_FIELD(ISP1763_DC_CHIPID_LOW, 0, 15), |
466 | [DC_SCRATCH] = REG_FIELD(ISP1763_DC_SCRATCH, 0, 15), |
467 | /* Make sure the array is sized properly during compilation */ |
468 | [DC_FIELD_MAX] = {}, |
469 | }; |
470 | |
471 | static const struct regmap_config isp1763_dc_regmap_conf = { |
472 | .name = "isp1763-dc" , |
473 | .reg_bits = 8, |
474 | .reg_stride = 2, |
475 | .val_bits = 16, |
476 | .fast_io = true, |
477 | .max_register = ISP1763_DC_TESTMODE, |
478 | .volatile_table = &isp1763_dc_volatile_table, |
479 | }; |
480 | |
481 | int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, |
482 | struct device *dev, unsigned int devflags) |
483 | { |
484 | const struct regmap_config *hc_regmap; |
485 | const struct reg_field *hc_reg_fields; |
486 | const struct regmap_config *dc_regmap; |
487 | const struct reg_field *dc_reg_fields; |
488 | struct isp1760_device *isp; |
489 | struct isp1760_hcd *hcd; |
490 | struct isp1760_udc *udc; |
491 | struct regmap_field *f; |
492 | bool udc_enabled; |
493 | int ret; |
494 | int i; |
495 | |
496 | /* |
497 | * If neither the HCD not the UDC is enabled return an error, as no |
498 | * device would be registered. |
499 | */ |
500 | udc_enabled = ((devflags & ISP1760_FLAG_ISP1763) || |
501 | (devflags & ISP1760_FLAG_ISP1761)); |
502 | |
503 | if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) && |
504 | (!udc_enabled || !IS_ENABLED(CONFIG_USB_ISP1761_UDC))) |
505 | return -ENODEV; |
506 | |
507 | isp = devm_kzalloc(dev, size: sizeof(*isp), GFP_KERNEL); |
508 | if (!isp) |
509 | return -ENOMEM; |
510 | |
511 | isp->dev = dev; |
512 | isp->devflags = devflags; |
513 | hcd = &isp->hcd; |
514 | udc = &isp->udc; |
515 | |
516 | hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763); |
517 | udc->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763); |
518 | |
519 | if (!hcd->is_isp1763 && (devflags & ISP1760_FLAG_BUS_WIDTH_8)) { |
520 | dev_err(dev, "isp1760/61 do not support data width 8\n" ); |
521 | return -EINVAL; |
522 | } |
523 | |
524 | if (hcd->is_isp1763) { |
525 | hc_regmap = &isp1763_hc_regmap_conf; |
526 | hc_reg_fields = &isp1763_hc_reg_fields[0]; |
527 | dc_regmap = &isp1763_dc_regmap_conf; |
528 | dc_reg_fields = &isp1763_dc_reg_fields[0]; |
529 | } else { |
530 | hc_regmap = &isp1760_hc_regmap_conf; |
531 | hc_reg_fields = &isp1760_hc_reg_fields[0]; |
532 | dc_regmap = &isp1761_dc_regmap_conf; |
533 | dc_reg_fields = &isp1761_dc_reg_fields[0]; |
534 | } |
535 | |
536 | isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, flags: GPIOD_OUT_HIGH); |
537 | if (IS_ERR(ptr: isp->rst_gpio)) |
538 | return PTR_ERR(ptr: isp->rst_gpio); |
539 | |
540 | hcd->base = devm_ioremap_resource(dev, res: mem); |
541 | if (IS_ERR(ptr: hcd->base)) |
542 | return PTR_ERR(ptr: hcd->base); |
543 | |
544 | hcd->regs = devm_regmap_init_mmio(dev, hcd->base, hc_regmap); |
545 | if (IS_ERR(ptr: hcd->regs)) |
546 | return PTR_ERR(ptr: hcd->regs); |
547 | |
548 | for (i = 0; i < HC_FIELD_MAX; i++) { |
549 | f = devm_regmap_field_alloc(dev, regmap: hcd->regs, reg_field: hc_reg_fields[i]); |
550 | if (IS_ERR(ptr: f)) |
551 | return PTR_ERR(ptr: f); |
552 | |
553 | hcd->fields[i] = f; |
554 | } |
555 | |
556 | udc->regs = devm_regmap_init_mmio(dev, hcd->base, dc_regmap); |
557 | if (IS_ERR(ptr: udc->regs)) |
558 | return PTR_ERR(ptr: udc->regs); |
559 | |
560 | for (i = 0; i < DC_FIELD_MAX; i++) { |
561 | f = devm_regmap_field_alloc(dev, regmap: udc->regs, reg_field: dc_reg_fields[i]); |
562 | if (IS_ERR(ptr: f)) |
563 | return PTR_ERR(ptr: f); |
564 | |
565 | udc->fields[i] = f; |
566 | } |
567 | |
568 | if (hcd->is_isp1763) |
569 | hcd->memory_layout = &isp1763_memory_conf; |
570 | else |
571 | hcd->memory_layout = &isp176x_memory_conf; |
572 | |
573 | ret = isp1760_init_core(isp); |
574 | if (ret < 0) |
575 | return ret; |
576 | |
577 | if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) { |
578 | ret = isp1760_hcd_register(priv: hcd, mem, irq, |
579 | irqflags: irqflags | IRQF_SHARED, dev); |
580 | if (ret < 0) |
581 | return ret; |
582 | } |
583 | |
584 | if (udc_enabled && IS_ENABLED(CONFIG_USB_ISP1761_UDC)) { |
585 | ret = isp1760_udc_register(isp, irq, irqflags); |
586 | if (ret < 0) { |
587 | isp1760_hcd_unregister(priv: hcd); |
588 | return ret; |
589 | } |
590 | } |
591 | |
592 | dev_set_drvdata(dev, data: isp); |
593 | |
594 | return 0; |
595 | } |
596 | |
597 | void isp1760_unregister(struct device *dev) |
598 | { |
599 | struct isp1760_device *isp = dev_get_drvdata(dev); |
600 | |
601 | isp1760_udc_unregister(isp); |
602 | isp1760_hcd_unregister(priv: &isp->hcd); |
603 | } |
604 | |
605 | MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP" ); |
606 | MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>" ); |
607 | MODULE_LICENSE("GPL v2" ); |
608 | |