1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * USB Glue for Amlogic G12A SoCs |
4 | * |
5 | * Copyright (c) 2019 BayLibre, SAS |
6 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
7 | */ |
8 | |
9 | /* |
10 | * The USB is organized with a glue around the DWC3 Controller IP as : |
11 | * - Control registers for each USB2 Ports |
12 | * - Control registers for the USB PHY layer |
13 | * - SuperSpeed PHY can be enabled only if port is used |
14 | * - Dynamic OTG switching with ID change interrupt |
15 | */ |
16 | |
17 | #include <linux/module.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/clk.h> |
21 | #include <linux/of.h> |
22 | #include <linux/of_platform.h> |
23 | #include <linux/pm_runtime.h> |
24 | #include <linux/regmap.h> |
25 | #include <linux/bitfield.h> |
26 | #include <linux/bitops.h> |
27 | #include <linux/reset.h> |
28 | #include <linux/phy/phy.h> |
29 | #include <linux/usb/otg.h> |
30 | #include <linux/usb/role.h> |
31 | #include <linux/regulator/consumer.h> |
32 | |
33 | /* USB2 Ports Control Registers, offsets are per-port */ |
34 | |
35 | #define U2P_REG_SIZE 0x20 |
36 | |
37 | #define U2P_R0 0x0 |
38 | #define U2P_R0_HOST_DEVICE BIT(0) |
39 | #define U2P_R0_POWER_OK BIT(1) |
40 | #define U2P_R0_HAST_MODE BIT(2) |
41 | #define U2P_R0_POWER_ON_RESET BIT(3) |
42 | #define U2P_R0_ID_PULLUP BIT(4) |
43 | #define U2P_R0_DRV_VBUS BIT(5) |
44 | |
45 | #define U2P_R1 0x4 |
46 | #define U2P_R1_PHY_READY BIT(0) |
47 | #define U2P_R1_ID_DIG BIT(1) |
48 | #define U2P_R1_OTG_SESSION_VALID BIT(2) |
49 | #define U2P_R1_VBUS_VALID BIT(3) |
50 | |
51 | /* USB Glue Control Registers */ |
52 | |
53 | #define G12A_GLUE_OFFSET 0x80 |
54 | |
55 | #define USB_R0 0x00 |
56 | #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) |
57 | #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) |
58 | #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) |
59 | #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) |
60 | #define USB_R0_U2D_ACT BIT(31) |
61 | |
62 | #define USB_R1 0x04 |
63 | #define USB_R1_U3H_BIGENDIAN_GS BIT(0) |
64 | #define USB_R1_U3H_PME_ENABLE BIT(1) |
65 | #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2) |
66 | #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7) |
67 | #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12) |
68 | #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) |
69 | #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) |
70 | #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) |
71 | #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) |
72 | #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) |
73 | |
74 | #define USB_R2 0x08 |
75 | #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) |
76 | #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) |
77 | |
78 | #define USB_R3 0x0c |
79 | #define USB_R3_P30_SSC_ENABLE BIT(0) |
80 | #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) |
81 | #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) |
82 | #define USB_R3_P30_REF_SSP_EN BIT(13) |
83 | |
84 | #define USB_R4 0x10 |
85 | #define USB_R4_P21_PORT_RESET_0 BIT(0) |
86 | #define USB_R4_P21_SLEEP_M0 BIT(1) |
87 | #define USB_R4_MEM_PD_MASK GENMASK(3, 2) |
88 | #define USB_R4_P21_ONLY BIT(4) |
89 | |
90 | #define USB_R5 0x14 |
91 | #define USB_R5_ID_DIG_SYNC BIT(0) |
92 | #define USB_R5_ID_DIG_REG BIT(1) |
93 | #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) |
94 | #define USB_R5_ID_DIG_EN_0 BIT(4) |
95 | #define USB_R5_ID_DIG_EN_1 BIT(5) |
96 | #define USB_R5_ID_DIG_CURR BIT(6) |
97 | #define USB_R5_ID_DIG_IRQ BIT(7) |
98 | #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) |
99 | #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) |
100 | |
101 | #define PHY_COUNT 3 |
102 | #define USB2_OTG_PHY 1 |
103 | |
104 | static struct clk_bulk_data meson_gxl_clocks[] = { |
105 | { .id = "usb_ctrl" }, |
106 | { .id = "ddr" }, |
107 | }; |
108 | |
109 | static struct clk_bulk_data meson_g12a_clocks[] = { |
110 | { .id = NULL }, |
111 | }; |
112 | |
113 | static struct clk_bulk_data meson_a1_clocks[] = { |
114 | { .id = "usb_ctrl" }, |
115 | { .id = "usb_bus" }, |
116 | { .id = "xtal_usb_ctrl" }, |
117 | }; |
118 | |
119 | static const char * const meson_gxm_phy_names[] = { |
120 | "usb2-phy0" , "usb2-phy1" , "usb2-phy2" , |
121 | }; |
122 | |
123 | static const char * const meson_g12a_phy_names[] = { |
124 | "usb2-phy0" , "usb2-phy1" , "usb3-phy0" , |
125 | }; |
126 | |
127 | /* |
128 | * Amlogic A1 has a single physical PHY, in slot 1, but still has the |
129 | * two U2 PHY controls register blocks like G12A. |
130 | * AXG has the similar scheme, thus needs the same tweak. |
131 | * Handling the first PHY on slot 1 would need a large amount of code |
132 | * changes, and the current management is generic enough to handle it |
133 | * correctly when only the "usb2-phy1" phy is specified on-par with the |
134 | * DT bindings. |
135 | */ |
136 | static const char * const meson_a1_phy_names[] = { |
137 | "usb2-phy0" , "usb2-phy1" |
138 | }; |
139 | |
140 | struct dwc3_meson_g12a; |
141 | |
142 | struct dwc3_meson_g12a_drvdata { |
143 | bool otg_phy_host_port_disable; |
144 | struct clk_bulk_data *clks; |
145 | int num_clks; |
146 | const char * const *phy_names; |
147 | int num_phys; |
148 | int (*setup_regmaps)(struct dwc3_meson_g12a *priv, void __iomem *base); |
149 | int (*usb2_init_phy)(struct dwc3_meson_g12a *priv, int i, |
150 | enum phy_mode mode); |
151 | int (*set_phy_mode)(struct dwc3_meson_g12a *priv, int i, |
152 | enum phy_mode mode); |
153 | int (*usb_init)(struct dwc3_meson_g12a *priv); |
154 | int (*usb_post_init)(struct dwc3_meson_g12a *priv); |
155 | }; |
156 | |
157 | static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv, |
158 | void __iomem *base); |
159 | static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv, |
160 | void __iomem *base); |
161 | |
162 | static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, |
163 | enum phy_mode mode); |
164 | static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, |
165 | enum phy_mode mode); |
166 | |
167 | static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv, |
168 | int i, enum phy_mode mode); |
169 | static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv, |
170 | int i, enum phy_mode mode); |
171 | |
172 | static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv); |
173 | static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv); |
174 | |
175 | static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv); |
176 | |
177 | /* |
178 | * For GXL and GXM SoCs: |
179 | * USB Phy muxing between the DWC2 Device controller and the DWC3 Host |
180 | * controller is buggy when switching from Device to Host when USB port |
181 | * is unpopulated, it causes the DWC3 to hard crash. |
182 | * When populated (including OTG switching with ID pin), the switch works |
183 | * like a charm like on the G12A platforms. |
184 | * In order to still switch from Host to Device on an USB Type-A port, |
185 | * an U2_PORT_DISABLE bit has been added to disconnect the DWC3 Host |
186 | * controller from the port, but when used the DWC3 controller must be |
187 | * reset to recover usage of the port. |
188 | */ |
189 | |
190 | static const struct dwc3_meson_g12a_drvdata gxl_drvdata = { |
191 | .otg_phy_host_port_disable = true, |
192 | .clks = meson_gxl_clocks, |
193 | .num_clks = ARRAY_SIZE(meson_g12a_clocks), |
194 | .phy_names = meson_a1_phy_names, |
195 | .num_phys = ARRAY_SIZE(meson_a1_phy_names), |
196 | .setup_regmaps = dwc3_meson_gxl_setup_regmaps, |
197 | .usb2_init_phy = dwc3_meson_gxl_usb2_init_phy, |
198 | .set_phy_mode = dwc3_meson_gxl_set_phy_mode, |
199 | .usb_init = dwc3_meson_gxl_usb_init, |
200 | .usb_post_init = dwc3_meson_gxl_usb_post_init, |
201 | }; |
202 | |
203 | static const struct dwc3_meson_g12a_drvdata gxm_drvdata = { |
204 | .otg_phy_host_port_disable = true, |
205 | .clks = meson_gxl_clocks, |
206 | .num_clks = ARRAY_SIZE(meson_g12a_clocks), |
207 | .phy_names = meson_gxm_phy_names, |
208 | .num_phys = ARRAY_SIZE(meson_gxm_phy_names), |
209 | .setup_regmaps = dwc3_meson_gxl_setup_regmaps, |
210 | .usb2_init_phy = dwc3_meson_gxl_usb2_init_phy, |
211 | .set_phy_mode = dwc3_meson_gxl_set_phy_mode, |
212 | .usb_init = dwc3_meson_gxl_usb_init, |
213 | .usb_post_init = dwc3_meson_gxl_usb_post_init, |
214 | }; |
215 | |
216 | static const struct dwc3_meson_g12a_drvdata axg_drvdata = { |
217 | .clks = meson_gxl_clocks, |
218 | .num_clks = ARRAY_SIZE(meson_gxl_clocks), |
219 | .phy_names = meson_a1_phy_names, |
220 | .num_phys = ARRAY_SIZE(meson_a1_phy_names), |
221 | .setup_regmaps = dwc3_meson_gxl_setup_regmaps, |
222 | .usb2_init_phy = dwc3_meson_gxl_usb2_init_phy, |
223 | .set_phy_mode = dwc3_meson_gxl_set_phy_mode, |
224 | .usb_init = dwc3_meson_g12a_usb_init, |
225 | .usb_post_init = dwc3_meson_gxl_usb_post_init, |
226 | }; |
227 | |
228 | static const struct dwc3_meson_g12a_drvdata g12a_drvdata = { |
229 | .clks = meson_g12a_clocks, |
230 | .num_clks = ARRAY_SIZE(meson_g12a_clocks), |
231 | .phy_names = meson_g12a_phy_names, |
232 | .num_phys = ARRAY_SIZE(meson_g12a_phy_names), |
233 | .setup_regmaps = dwc3_meson_g12a_setup_regmaps, |
234 | .usb2_init_phy = dwc3_meson_g12a_usb2_init_phy, |
235 | .set_phy_mode = dwc3_meson_g12a_set_phy_mode, |
236 | .usb_init = dwc3_meson_g12a_usb_init, |
237 | }; |
238 | |
239 | static const struct dwc3_meson_g12a_drvdata a1_drvdata = { |
240 | .clks = meson_a1_clocks, |
241 | .num_clks = ARRAY_SIZE(meson_a1_clocks), |
242 | .phy_names = meson_a1_phy_names, |
243 | .num_phys = ARRAY_SIZE(meson_a1_phy_names), |
244 | .setup_regmaps = dwc3_meson_g12a_setup_regmaps, |
245 | .usb2_init_phy = dwc3_meson_g12a_usb2_init_phy, |
246 | .set_phy_mode = dwc3_meson_g12a_set_phy_mode, |
247 | .usb_init = dwc3_meson_g12a_usb_init, |
248 | }; |
249 | |
250 | struct dwc3_meson_g12a { |
251 | struct device *dev; |
252 | struct regmap *u2p_regmap[PHY_COUNT]; |
253 | struct regmap *usb_glue_regmap; |
254 | struct reset_control *reset; |
255 | struct phy *phys[PHY_COUNT]; |
256 | enum usb_dr_mode otg_mode; |
257 | enum phy_mode otg_phy_mode; |
258 | unsigned int usb2_ports; |
259 | unsigned int usb3_ports; |
260 | struct regulator *vbus; |
261 | struct usb_role_switch_desc switch_desc; |
262 | struct usb_role_switch *role_switch; |
263 | const struct dwc3_meson_g12a_drvdata *drvdata; |
264 | }; |
265 | |
266 | static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv, |
267 | int i, enum phy_mode mode) |
268 | { |
269 | return phy_set_mode(priv->phys[i], mode); |
270 | } |
271 | |
272 | static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, |
273 | enum phy_mode mode) |
274 | { |
275 | /* On GXL PHY must be started in device mode for DWC2 init */ |
276 | return priv->drvdata->set_phy_mode(priv, i, |
277 | (i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE |
278 | : PHY_MODE_USB_HOST); |
279 | } |
280 | |
281 | static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv, |
282 | int i, enum phy_mode mode) |
283 | { |
284 | if (mode == PHY_MODE_USB_HOST) |
285 | regmap_update_bits(map: priv->u2p_regmap[i], U2P_R0, |
286 | U2P_R0_HOST_DEVICE, |
287 | U2P_R0_HOST_DEVICE); |
288 | else |
289 | regmap_update_bits(map: priv->u2p_regmap[i], U2P_R0, |
290 | U2P_R0_HOST_DEVICE, val: 0); |
291 | |
292 | return 0; |
293 | } |
294 | |
295 | static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i, |
296 | enum phy_mode mode) |
297 | { |
298 | int ret; |
299 | |
300 | regmap_update_bits(map: priv->u2p_regmap[i], U2P_R0, |
301 | U2P_R0_POWER_ON_RESET, |
302 | U2P_R0_POWER_ON_RESET); |
303 | |
304 | if (i == USB2_OTG_PHY) { |
305 | regmap_update_bits(map: priv->u2p_regmap[i], U2P_R0, |
306 | U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, |
307 | U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS); |
308 | |
309 | ret = priv->drvdata->set_phy_mode(priv, i, mode); |
310 | } else |
311 | ret = priv->drvdata->set_phy_mode(priv, i, |
312 | PHY_MODE_USB_HOST); |
313 | |
314 | if (ret) |
315 | return ret; |
316 | |
317 | regmap_update_bits(map: priv->u2p_regmap[i], U2P_R0, |
318 | U2P_R0_POWER_ON_RESET, val: 0); |
319 | |
320 | return 0; |
321 | } |
322 | |
323 | static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv, |
324 | enum phy_mode mode) |
325 | { |
326 | int i, ret; |
327 | |
328 | for (i = 0; i < priv->drvdata->num_phys; ++i) { |
329 | if (!priv->phys[i]) |
330 | continue; |
331 | |
332 | if (!strstr(priv->drvdata->phy_names[i], "usb2" )) |
333 | continue; |
334 | |
335 | ret = priv->drvdata->usb2_init_phy(priv, i, mode); |
336 | if (ret) |
337 | return ret; |
338 | } |
339 | |
340 | return 0; |
341 | } |
342 | |
343 | static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv) |
344 | { |
345 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R3, |
346 | USB_R3_P30_SSC_RANGE_MASK | |
347 | USB_R3_P30_REF_SSP_EN, |
348 | USB_R3_P30_SSC_ENABLE | |
349 | FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) | |
350 | USB_R3_P30_REF_SSP_EN); |
351 | udelay(2); |
352 | |
353 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R2, |
354 | USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, |
355 | FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15)); |
356 | |
357 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R2, |
358 | USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, |
359 | FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20)); |
360 | |
361 | udelay(2); |
362 | |
363 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R1, |
364 | USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT, |
365 | USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); |
366 | |
367 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R1, |
368 | USB_R1_P30_PCS_TX_SWING_FULL_MASK, |
369 | FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127)); |
370 | } |
371 | |
372 | static void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv, |
373 | enum phy_mode mode) |
374 | { |
375 | if (mode == PHY_MODE_USB_DEVICE) { |
376 | if (priv->otg_mode != USB_DR_MODE_OTG && |
377 | priv->drvdata->otg_phy_host_port_disable) |
378 | /* Isolate the OTG PHY port from the Host Controller */ |
379 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R1, |
380 | USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, |
381 | FIELD_PREP(USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, |
382 | BIT(USB2_OTG_PHY))); |
383 | |
384 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R0, |
385 | USB_R0_U2D_ACT, USB_R0_U2D_ACT); |
386 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R0, |
387 | USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, val: 0); |
388 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R4, |
389 | USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0); |
390 | } else { |
391 | if (priv->otg_mode != USB_DR_MODE_OTG && |
392 | priv->drvdata->otg_phy_host_port_disable) { |
393 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R1, |
394 | USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK, val: 0); |
395 | msleep(msecs: 500); |
396 | } |
397 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R0, |
398 | USB_R0_U2D_ACT, val: 0); |
399 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R4, |
400 | USB_R4_P21_SLEEP_M0, val: 0); |
401 | } |
402 | } |
403 | |
404 | static int dwc3_meson_g12a_usb_init_glue(struct dwc3_meson_g12a *priv, |
405 | enum phy_mode mode) |
406 | { |
407 | int ret; |
408 | |
409 | ret = dwc3_meson_g12a_usb2_init(priv, mode); |
410 | if (ret) |
411 | return ret; |
412 | |
413 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R1, |
414 | USB_R1_U3H_FLADJ_30MHZ_REG_MASK, |
415 | FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20)); |
416 | |
417 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R5, |
418 | USB_R5_ID_DIG_EN_0, |
419 | USB_R5_ID_DIG_EN_0); |
420 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R5, |
421 | USB_R5_ID_DIG_EN_1, |
422 | USB_R5_ID_DIG_EN_1); |
423 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R5, |
424 | USB_R5_ID_DIG_TH_MASK, |
425 | FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff)); |
426 | |
427 | /* If we have an actual SuperSpeed port, initialize it */ |
428 | if (priv->usb3_ports) |
429 | dwc3_meson_g12a_usb3_init(priv); |
430 | |
431 | dwc3_meson_g12a_usb_otg_apply_mode(priv, mode); |
432 | |
433 | return 0; |
434 | } |
435 | |
436 | static const struct regmap_config phy_meson_g12a_usb_glue_regmap_conf = { |
437 | .name = "usb-glue" , |
438 | .reg_bits = 8, |
439 | .val_bits = 32, |
440 | .reg_stride = 4, |
441 | .max_register = USB_R5, |
442 | }; |
443 | |
444 | static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) |
445 | { |
446 | const char *phy_name; |
447 | int i; |
448 | |
449 | for (i = 0 ; i < priv->drvdata->num_phys ; ++i) { |
450 | phy_name = priv->drvdata->phy_names[i]; |
451 | priv->phys[i] = devm_phy_optional_get(dev: priv->dev, string: phy_name); |
452 | if (!priv->phys[i]) |
453 | continue; |
454 | |
455 | if (IS_ERR(ptr: priv->phys[i])) |
456 | return PTR_ERR(ptr: priv->phys[i]); |
457 | |
458 | if (strstr(phy_name, "usb3" )) |
459 | priv->usb3_ports++; |
460 | else |
461 | priv->usb2_ports++; |
462 | } |
463 | |
464 | dev_info(priv->dev, "USB2 ports: %d\n" , priv->usb2_ports); |
465 | dev_info(priv->dev, "USB3 ports: %d\n" , priv->usb3_ports); |
466 | |
467 | return 0; |
468 | } |
469 | |
470 | static enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv) |
471 | { |
472 | u32 reg; |
473 | |
474 | regmap_read(map: priv->usb_glue_regmap, USB_R5, val: ®); |
475 | |
476 | if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG)) |
477 | return PHY_MODE_USB_DEVICE; |
478 | |
479 | return PHY_MODE_USB_HOST; |
480 | } |
481 | |
482 | static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, |
483 | enum phy_mode mode) |
484 | { |
485 | int ret; |
486 | |
487 | if (!priv->phys[USB2_OTG_PHY]) |
488 | return -EINVAL; |
489 | |
490 | if (mode == PHY_MODE_USB_HOST) |
491 | dev_info(priv->dev, "switching to Host Mode\n" ); |
492 | else |
493 | dev_info(priv->dev, "switching to Device Mode\n" ); |
494 | |
495 | if (priv->vbus) { |
496 | if (mode == PHY_MODE_USB_DEVICE) |
497 | ret = regulator_disable(regulator: priv->vbus); |
498 | else |
499 | ret = regulator_enable(regulator: priv->vbus); |
500 | if (ret) |
501 | return ret; |
502 | } |
503 | |
504 | priv->otg_phy_mode = mode; |
505 | |
506 | ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY, mode); |
507 | if (ret) |
508 | return ret; |
509 | |
510 | dwc3_meson_g12a_usb_otg_apply_mode(priv, mode); |
511 | |
512 | return 0; |
513 | } |
514 | |
515 | static int dwc3_meson_g12a_role_set(struct usb_role_switch *sw, |
516 | enum usb_role role) |
517 | { |
518 | struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw); |
519 | enum phy_mode mode; |
520 | |
521 | if (role == USB_ROLE_NONE) |
522 | return 0; |
523 | |
524 | mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST |
525 | : PHY_MODE_USB_DEVICE; |
526 | |
527 | if (mode == priv->otg_phy_mode) |
528 | return 0; |
529 | |
530 | if (priv->drvdata->otg_phy_host_port_disable) |
531 | dev_warn_once(priv->dev, "Broken manual OTG switch\n" ); |
532 | |
533 | return dwc3_meson_g12a_otg_mode_set(priv, mode); |
534 | } |
535 | |
536 | static enum usb_role dwc3_meson_g12a_role_get(struct usb_role_switch *sw) |
537 | { |
538 | struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw); |
539 | |
540 | return priv->otg_phy_mode == PHY_MODE_USB_HOST ? |
541 | USB_ROLE_HOST : USB_ROLE_DEVICE; |
542 | } |
543 | |
544 | static irqreturn_t dwc3_meson_g12a_irq_thread(int irq, void *data) |
545 | { |
546 | struct dwc3_meson_g12a *priv = data; |
547 | enum phy_mode otg_id; |
548 | |
549 | otg_id = dwc3_meson_g12a_get_id(priv); |
550 | if (otg_id != priv->otg_phy_mode) { |
551 | if (dwc3_meson_g12a_otg_mode_set(priv, mode: otg_id)) |
552 | dev_warn(priv->dev, "Failed to switch OTG mode\n" ); |
553 | } |
554 | |
555 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R5, |
556 | USB_R5_ID_DIG_IRQ, val: 0); |
557 | |
558 | return IRQ_HANDLED; |
559 | } |
560 | |
561 | static struct device *dwc3_meson_g12_find_child(struct device *dev, |
562 | const char *compatible) |
563 | { |
564 | struct platform_device *pdev; |
565 | struct device_node *np; |
566 | |
567 | np = of_get_compatible_child(parent: dev->of_node, compatible); |
568 | if (!np) |
569 | return NULL; |
570 | |
571 | pdev = of_find_device_by_node(np); |
572 | of_node_put(node: np); |
573 | if (!pdev) |
574 | return NULL; |
575 | |
576 | return &pdev->dev; |
577 | } |
578 | |
579 | static int dwc3_meson_g12a_otg_init(struct platform_device *pdev, |
580 | struct dwc3_meson_g12a *priv) |
581 | { |
582 | enum phy_mode otg_id; |
583 | int ret, irq; |
584 | struct device *dev = &pdev->dev; |
585 | |
586 | if (priv->otg_mode == USB_DR_MODE_OTG) { |
587 | /* Ack irq before registering */ |
588 | regmap_update_bits(map: priv->usb_glue_regmap, USB_R5, |
589 | USB_R5_ID_DIG_IRQ, val: 0); |
590 | |
591 | irq = platform_get_irq(pdev, 0); |
592 | if (irq < 0) |
593 | return irq; |
594 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq, NULL, |
595 | thread_fn: dwc3_meson_g12a_irq_thread, |
596 | IRQF_ONESHOT, devname: pdev->name, dev_id: priv); |
597 | if (ret) |
598 | return ret; |
599 | } |
600 | |
601 | /* Setup OTG mode corresponding to the ID pin */ |
602 | if (priv->otg_mode == USB_DR_MODE_OTG) { |
603 | otg_id = dwc3_meson_g12a_get_id(priv); |
604 | if (otg_id != priv->otg_phy_mode) { |
605 | if (dwc3_meson_g12a_otg_mode_set(priv, mode: otg_id)) |
606 | dev_warn(dev, "Failed to switch OTG mode\n" ); |
607 | } |
608 | } |
609 | |
610 | /* Setup role switcher */ |
611 | priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, |
612 | compatible: "snps,dwc3" ); |
613 | priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, compatible: "snps,dwc2" ); |
614 | priv->switch_desc.allow_userspace_control = true; |
615 | priv->switch_desc.set = dwc3_meson_g12a_role_set; |
616 | priv->switch_desc.get = dwc3_meson_g12a_role_get; |
617 | priv->switch_desc.driver_data = priv; |
618 | |
619 | priv->role_switch = usb_role_switch_register(parent: dev, desc: &priv->switch_desc); |
620 | if (IS_ERR(ptr: priv->role_switch)) |
621 | dev_warn(dev, "Unable to register Role Switch\n" ); |
622 | |
623 | return 0; |
624 | } |
625 | |
626 | static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv, |
627 | void __iomem *base) |
628 | { |
629 | /* GXL controls the PHY mode in the PHY registers unlike G12A */ |
630 | priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, base, |
631 | &phy_meson_g12a_usb_glue_regmap_conf); |
632 | return PTR_ERR_OR_ZERO(ptr: priv->usb_glue_regmap); |
633 | } |
634 | |
635 | static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv, |
636 | void __iomem *base) |
637 | { |
638 | int i; |
639 | |
640 | priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, |
641 | base + G12A_GLUE_OFFSET, |
642 | &phy_meson_g12a_usb_glue_regmap_conf); |
643 | if (IS_ERR(ptr: priv->usb_glue_regmap)) |
644 | return PTR_ERR(ptr: priv->usb_glue_regmap); |
645 | |
646 | /* Create a regmap for each USB2 PHY control register set */ |
647 | for (i = 0; i < priv->drvdata->num_phys; i++) { |
648 | struct regmap_config u2p_regmap_config = { |
649 | .reg_bits = 8, |
650 | .val_bits = 32, |
651 | .reg_stride = 4, |
652 | .max_register = U2P_R1, |
653 | }; |
654 | |
655 | if (!strstr(priv->drvdata->phy_names[i], "usb2" )) |
656 | continue; |
657 | |
658 | u2p_regmap_config.name = devm_kasprintf(dev: priv->dev, GFP_KERNEL, |
659 | fmt: "u2p-%d" , i); |
660 | if (!u2p_regmap_config.name) |
661 | return -ENOMEM; |
662 | |
663 | priv->u2p_regmap[i] = devm_regmap_init_mmio(priv->dev, |
664 | base + (i * U2P_REG_SIZE), |
665 | &u2p_regmap_config); |
666 | if (IS_ERR(ptr: priv->u2p_regmap[i])) |
667 | return PTR_ERR(ptr: priv->u2p_regmap[i]); |
668 | } |
669 | |
670 | return 0; |
671 | } |
672 | |
673 | static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv) |
674 | { |
675 | return dwc3_meson_g12a_usb_init_glue(priv, mode: priv->otg_phy_mode); |
676 | } |
677 | |
678 | static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv) |
679 | { |
680 | return dwc3_meson_g12a_usb_init_glue(priv, mode: PHY_MODE_USB_DEVICE); |
681 | } |
682 | |
683 | static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv) |
684 | { |
685 | int ret; |
686 | |
687 | ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY, |
688 | priv->otg_phy_mode); |
689 | if (ret) |
690 | return ret; |
691 | |
692 | dwc3_meson_g12a_usb_otg_apply_mode(priv, mode: priv->otg_phy_mode); |
693 | |
694 | return 0; |
695 | } |
696 | |
697 | static int dwc3_meson_g12a_probe(struct platform_device *pdev) |
698 | { |
699 | struct dwc3_meson_g12a *priv; |
700 | struct device *dev = &pdev->dev; |
701 | struct device_node *np = dev->of_node; |
702 | void __iomem *base; |
703 | int ret, i; |
704 | |
705 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
706 | if (!priv) |
707 | return -ENOMEM; |
708 | |
709 | base = devm_platform_ioremap_resource(pdev, index: 0); |
710 | if (IS_ERR(ptr: base)) |
711 | return PTR_ERR(ptr: base); |
712 | |
713 | priv->drvdata = of_device_get_match_data(dev: &pdev->dev); |
714 | priv->dev = dev; |
715 | |
716 | priv->vbus = devm_regulator_get_optional(dev, id: "vbus" ); |
717 | if (IS_ERR(ptr: priv->vbus)) { |
718 | if (PTR_ERR(ptr: priv->vbus) == -EPROBE_DEFER) |
719 | return PTR_ERR(ptr: priv->vbus); |
720 | priv->vbus = NULL; |
721 | } |
722 | |
723 | ret = devm_clk_bulk_get(dev, |
724 | num_clks: priv->drvdata->num_clks, |
725 | clks: priv->drvdata->clks); |
726 | if (ret) |
727 | return ret; |
728 | |
729 | ret = clk_bulk_prepare_enable(num_clks: priv->drvdata->num_clks, |
730 | clks: priv->drvdata->clks); |
731 | if (ret) |
732 | return ret; |
733 | |
734 | platform_set_drvdata(pdev, data: priv); |
735 | |
736 | priv->reset = devm_reset_control_get_shared(dev, NULL); |
737 | if (IS_ERR(ptr: priv->reset)) { |
738 | ret = PTR_ERR(ptr: priv->reset); |
739 | dev_err(dev, "failed to get device reset, err=%d\n" , ret); |
740 | goto err_disable_clks; |
741 | } |
742 | |
743 | ret = reset_control_reset(rstc: priv->reset); |
744 | if (ret) |
745 | goto err_disable_clks; |
746 | |
747 | ret = dwc3_meson_g12a_get_phys(priv); |
748 | if (ret) |
749 | goto err_rearm; |
750 | |
751 | ret = priv->drvdata->setup_regmaps(priv, base); |
752 | if (ret) |
753 | goto err_rearm; |
754 | |
755 | if (priv->vbus) { |
756 | ret = regulator_enable(regulator: priv->vbus); |
757 | if (ret) |
758 | goto err_rearm; |
759 | } |
760 | |
761 | /* Get dr_mode */ |
762 | priv->otg_mode = usb_get_dr_mode(dev); |
763 | |
764 | if (priv->otg_mode == USB_DR_MODE_PERIPHERAL) |
765 | priv->otg_phy_mode = PHY_MODE_USB_DEVICE; |
766 | else |
767 | priv->otg_phy_mode = PHY_MODE_USB_HOST; |
768 | |
769 | ret = priv->drvdata->usb_init(priv); |
770 | if (ret) |
771 | goto err_disable_regulator; |
772 | |
773 | /* Init PHYs */ |
774 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
775 | ret = phy_init(phy: priv->phys[i]); |
776 | if (ret) |
777 | goto err_disable_regulator; |
778 | } |
779 | |
780 | /* Set PHY Power */ |
781 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
782 | ret = phy_power_on(phy: priv->phys[i]); |
783 | if (ret) |
784 | goto err_phys_exit; |
785 | } |
786 | |
787 | if (priv->drvdata->usb_post_init) { |
788 | ret = priv->drvdata->usb_post_init(priv); |
789 | if (ret) |
790 | goto err_phys_power; |
791 | } |
792 | |
793 | ret = of_platform_populate(root: np, NULL, NULL, parent: dev); |
794 | if (ret) |
795 | goto err_phys_power; |
796 | |
797 | ret = dwc3_meson_g12a_otg_init(pdev, priv); |
798 | if (ret) |
799 | goto err_plat_depopulate; |
800 | |
801 | pm_runtime_set_active(dev); |
802 | pm_runtime_enable(dev); |
803 | pm_runtime_get_sync(dev); |
804 | |
805 | return 0; |
806 | |
807 | err_plat_depopulate: |
808 | of_platform_depopulate(parent: dev); |
809 | |
810 | err_phys_power: |
811 | for (i = 0 ; i < PHY_COUNT ; ++i) |
812 | phy_power_off(phy: priv->phys[i]); |
813 | |
814 | err_phys_exit: |
815 | for (i = 0 ; i < PHY_COUNT ; ++i) |
816 | phy_exit(phy: priv->phys[i]); |
817 | |
818 | err_disable_regulator: |
819 | if (priv->vbus) |
820 | regulator_disable(regulator: priv->vbus); |
821 | |
822 | err_rearm: |
823 | reset_control_rearm(rstc: priv->reset); |
824 | |
825 | err_disable_clks: |
826 | clk_bulk_disable_unprepare(num_clks: priv->drvdata->num_clks, |
827 | clks: priv->drvdata->clks); |
828 | |
829 | return ret; |
830 | } |
831 | |
832 | static void dwc3_meson_g12a_remove(struct platform_device *pdev) |
833 | { |
834 | struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev); |
835 | struct device *dev = &pdev->dev; |
836 | int i; |
837 | |
838 | usb_role_switch_unregister(sw: priv->role_switch); |
839 | |
840 | of_platform_depopulate(parent: dev); |
841 | |
842 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
843 | phy_power_off(phy: priv->phys[i]); |
844 | phy_exit(phy: priv->phys[i]); |
845 | } |
846 | |
847 | pm_runtime_disable(dev); |
848 | pm_runtime_put_noidle(dev); |
849 | pm_runtime_set_suspended(dev); |
850 | |
851 | reset_control_rearm(rstc: priv->reset); |
852 | |
853 | clk_bulk_disable_unprepare(num_clks: priv->drvdata->num_clks, |
854 | clks: priv->drvdata->clks); |
855 | } |
856 | |
857 | static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) |
858 | { |
859 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); |
860 | |
861 | clk_bulk_disable_unprepare(num_clks: priv->drvdata->num_clks, |
862 | clks: priv->drvdata->clks); |
863 | |
864 | return 0; |
865 | } |
866 | |
867 | static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) |
868 | { |
869 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); |
870 | |
871 | return clk_bulk_prepare_enable(num_clks: priv->drvdata->num_clks, |
872 | clks: priv->drvdata->clks); |
873 | } |
874 | |
875 | static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) |
876 | { |
877 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); |
878 | int i, ret; |
879 | |
880 | if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) { |
881 | ret = regulator_disable(regulator: priv->vbus); |
882 | if (ret) |
883 | return ret; |
884 | } |
885 | |
886 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
887 | phy_power_off(phy: priv->phys[i]); |
888 | phy_exit(phy: priv->phys[i]); |
889 | } |
890 | |
891 | reset_control_rearm(rstc: priv->reset); |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev) |
897 | { |
898 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); |
899 | int i, ret; |
900 | |
901 | ret = reset_control_reset(rstc: priv->reset); |
902 | if (ret) |
903 | return ret; |
904 | |
905 | ret = priv->drvdata->usb_init(priv); |
906 | if (ret) |
907 | return ret; |
908 | |
909 | /* Init PHYs */ |
910 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
911 | ret = phy_init(phy: priv->phys[i]); |
912 | if (ret) |
913 | return ret; |
914 | } |
915 | |
916 | /* Set PHY Power */ |
917 | for (i = 0 ; i < PHY_COUNT ; ++i) { |
918 | ret = phy_power_on(phy: priv->phys[i]); |
919 | if (ret) |
920 | return ret; |
921 | } |
922 | |
923 | if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) { |
924 | ret = regulator_enable(regulator: priv->vbus); |
925 | if (ret) |
926 | return ret; |
927 | } |
928 | |
929 | if (priv->drvdata->usb_post_init) { |
930 | ret = priv->drvdata->usb_post_init(priv); |
931 | if (ret) |
932 | return ret; |
933 | } |
934 | |
935 | return 0; |
936 | } |
937 | |
938 | static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { |
939 | SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume) |
940 | SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend, |
941 | dwc3_meson_g12a_runtime_resume, NULL) |
942 | }; |
943 | |
944 | static const struct of_device_id dwc3_meson_g12a_match[] = { |
945 | { |
946 | .compatible = "amlogic,meson-gxl-usb-ctrl" , |
947 | .data = &gxl_drvdata, |
948 | }, |
949 | { |
950 | .compatible = "amlogic,meson-gxm-usb-ctrl" , |
951 | .data = &gxm_drvdata, |
952 | }, |
953 | { |
954 | .compatible = "amlogic,meson-axg-usb-ctrl" , |
955 | .data = &axg_drvdata, |
956 | }, |
957 | { |
958 | .compatible = "amlogic,meson-g12a-usb-ctrl" , |
959 | .data = &g12a_drvdata, |
960 | }, |
961 | { |
962 | .compatible = "amlogic,meson-a1-usb-ctrl" , |
963 | .data = &a1_drvdata, |
964 | }, |
965 | { /* Sentinel */ } |
966 | }; |
967 | MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); |
968 | |
969 | static struct platform_driver dwc3_meson_g12a_driver = { |
970 | .probe = dwc3_meson_g12a_probe, |
971 | .remove_new = dwc3_meson_g12a_remove, |
972 | .driver = { |
973 | .name = "dwc3-meson-g12a" , |
974 | .of_match_table = dwc3_meson_g12a_match, |
975 | .pm = &dwc3_meson_g12a_dev_pm_ops, |
976 | }, |
977 | }; |
978 | |
979 | module_platform_driver(dwc3_meson_g12a_driver); |
980 | MODULE_LICENSE("GPL v2" ); |
981 | MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer" ); |
982 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>" ); |
983 | |