1 // SPDX-License-Identifier: GPL-2.0
3 * USB Glue for Amlogic G12A SoCs
5 * Copyright (c) 2019 BayLibre, SAS
6 * Author: Neil Armstrong <narmstrong@baylibre.com>
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
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/platform_device.h>
20 #include <linux/clk.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>
33 /* USB2 Ports Control Registers, offsets are per-port */
35 #define U2P_REG_SIZE 0x20
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)
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)
51 /* USB Glue Control Registers */
53 #define G12A_GLUE_OFFSET 0x80
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)
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)
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)
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)
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)
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)
102 #define USB2_OTG_PHY 1
104 static struct clk_bulk_data meson_gxl_clocks
[] = {
105 { .id
= "usb_ctrl" },
109 static struct clk_bulk_data meson_g12a_clocks
[] = {
113 static struct clk_bulk_data meson_a1_clocks
[] = {
114 { .id
= "usb_ctrl" },
116 { .id
= "xtal_usb_ctrl" },
119 static const char * const meson_gxm_phy_names
[] = {
120 "usb2-phy0", "usb2-phy1", "usb2-phy2",
123 static const char * const meson_g12a_phy_names
[] = {
124 "usb2-phy0", "usb2-phy1", "usb3-phy0",
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
136 static const char * const meson_a1_phy_names
[] = {
137 "usb2-phy0", "usb2-phy1"
140 struct dwc3_meson_g12a
;
142 struct dwc3_meson_g12a_drvdata
{
143 bool otg_switch_supported
;
144 bool otg_phy_host_port_disable
;
145 struct clk_bulk_data
*clks
;
147 const char * const *phy_names
;
149 int (*setup_regmaps
)(struct dwc3_meson_g12a
*priv
, void __iomem
*base
);
150 int (*usb2_init_phy
)(struct dwc3_meson_g12a
*priv
, int i
,
152 int (*set_phy_mode
)(struct dwc3_meson_g12a
*priv
, int i
,
154 int (*usb_init
)(struct dwc3_meson_g12a
*priv
);
155 int (*usb_post_init
)(struct dwc3_meson_g12a
*priv
);
158 static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a
*priv
,
160 static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a
*priv
,
163 static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a
*priv
, int i
,
165 static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a
*priv
, int i
,
168 static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a
*priv
,
169 int i
, enum phy_mode mode
);
170 static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a
*priv
,
171 int i
, enum phy_mode mode
);
173 static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a
*priv
);
174 static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a
*priv
);
176 static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a
*priv
);
179 * For GXL and GXM SoCs:
180 * USB Phy muxing between the DWC2 Device controller and the DWC3 Host
181 * controller is buggy when switching from Device to Host when USB port
182 * is unpopulated, it causes the DWC3 to hard crash.
183 * When populated (including OTG switching with ID pin), the switch works
184 * like a charm like on the G12A platforms.
185 * In order to still switch from Host to Device on an USB Type-A port,
186 * an U2_PORT_DISABLE bit has been added to disconnect the DWC3 Host
187 * controller from the port, but when used the DWC3 controller must be
188 * reset to recover usage of the port.
191 static struct dwc3_meson_g12a_drvdata gxl_drvdata
= {
192 .otg_switch_supported
= true,
193 .otg_phy_host_port_disable
= true,
194 .clks
= meson_gxl_clocks
,
195 .num_clks
= ARRAY_SIZE(meson_g12a_clocks
),
196 .phy_names
= meson_a1_phy_names
,
197 .num_phys
= ARRAY_SIZE(meson_a1_phy_names
),
198 .setup_regmaps
= dwc3_meson_gxl_setup_regmaps
,
199 .usb2_init_phy
= dwc3_meson_gxl_usb2_init_phy
,
200 .set_phy_mode
= dwc3_meson_gxl_set_phy_mode
,
201 .usb_init
= dwc3_meson_gxl_usb_init
,
202 .usb_post_init
= dwc3_meson_gxl_usb_post_init
,
205 static struct dwc3_meson_g12a_drvdata gxm_drvdata
= {
206 .otg_switch_supported
= true,
207 .otg_phy_host_port_disable
= true,
208 .clks
= meson_gxl_clocks
,
209 .num_clks
= ARRAY_SIZE(meson_g12a_clocks
),
210 .phy_names
= meson_gxm_phy_names
,
211 .num_phys
= ARRAY_SIZE(meson_gxm_phy_names
),
212 .setup_regmaps
= dwc3_meson_gxl_setup_regmaps
,
213 .usb2_init_phy
= dwc3_meson_gxl_usb2_init_phy
,
214 .set_phy_mode
= dwc3_meson_gxl_set_phy_mode
,
215 .usb_init
= dwc3_meson_gxl_usb_init
,
216 .usb_post_init
= dwc3_meson_gxl_usb_post_init
,
219 static struct dwc3_meson_g12a_drvdata axg_drvdata
= {
220 .otg_switch_supported
= true,
221 .clks
= meson_gxl_clocks
,
222 .num_clks
= ARRAY_SIZE(meson_gxl_clocks
),
223 .phy_names
= meson_a1_phy_names
,
224 .num_phys
= ARRAY_SIZE(meson_a1_phy_names
),
225 .setup_regmaps
= dwc3_meson_gxl_setup_regmaps
,
226 .usb2_init_phy
= dwc3_meson_gxl_usb2_init_phy
,
227 .set_phy_mode
= dwc3_meson_gxl_set_phy_mode
,
228 .usb_init
= dwc3_meson_g12a_usb_init
,
229 .usb_post_init
= dwc3_meson_gxl_usb_post_init
,
232 static struct dwc3_meson_g12a_drvdata g12a_drvdata
= {
233 .otg_switch_supported
= true,
234 .clks
= meson_g12a_clocks
,
235 .num_clks
= ARRAY_SIZE(meson_g12a_clocks
),
236 .phy_names
= meson_g12a_phy_names
,
237 .num_phys
= ARRAY_SIZE(meson_g12a_phy_names
),
238 .setup_regmaps
= dwc3_meson_g12a_setup_regmaps
,
239 .usb2_init_phy
= dwc3_meson_g12a_usb2_init_phy
,
240 .set_phy_mode
= dwc3_meson_g12a_set_phy_mode
,
241 .usb_init
= dwc3_meson_g12a_usb_init
,
244 static struct dwc3_meson_g12a_drvdata a1_drvdata
= {
245 .otg_switch_supported
= false,
246 .clks
= meson_a1_clocks
,
247 .num_clks
= ARRAY_SIZE(meson_a1_clocks
),
248 .phy_names
= meson_a1_phy_names
,
249 .num_phys
= ARRAY_SIZE(meson_a1_phy_names
),
250 .setup_regmaps
= dwc3_meson_g12a_setup_regmaps
,
251 .usb2_init_phy
= dwc3_meson_g12a_usb2_init_phy
,
252 .set_phy_mode
= dwc3_meson_g12a_set_phy_mode
,
253 .usb_init
= dwc3_meson_g12a_usb_init
,
256 struct dwc3_meson_g12a
{
258 struct regmap
*u2p_regmap
[PHY_COUNT
];
259 struct regmap
*usb_glue_regmap
;
260 struct reset_control
*reset
;
261 struct phy
*phys
[PHY_COUNT
];
262 enum usb_dr_mode otg_mode
;
263 enum phy_mode otg_phy_mode
;
264 unsigned int usb2_ports
;
265 unsigned int usb3_ports
;
266 struct regulator
*vbus
;
267 struct usb_role_switch_desc switch_desc
;
268 struct usb_role_switch
*role_switch
;
269 const struct dwc3_meson_g12a_drvdata
*drvdata
;
272 static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a
*priv
,
273 int i
, enum phy_mode mode
)
275 return phy_set_mode(priv
->phys
[i
], mode
);
278 static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a
*priv
, int i
,
281 /* On GXL PHY must be started in device mode for DWC2 init */
282 return priv
->drvdata
->set_phy_mode(priv
, i
,
283 (i
== USB2_OTG_PHY
) ? PHY_MODE_USB_DEVICE
284 : PHY_MODE_USB_HOST
);
287 static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a
*priv
,
288 int i
, enum phy_mode mode
)
290 if (mode
== PHY_MODE_USB_HOST
)
291 regmap_update_bits(priv
->u2p_regmap
[i
], U2P_R0
,
295 regmap_update_bits(priv
->u2p_regmap
[i
], U2P_R0
,
296 U2P_R0_HOST_DEVICE
, 0);
301 static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a
*priv
, int i
,
306 regmap_update_bits(priv
->u2p_regmap
[i
], U2P_R0
,
307 U2P_R0_POWER_ON_RESET
,
308 U2P_R0_POWER_ON_RESET
);
310 if (priv
->drvdata
->otg_switch_supported
&& i
== USB2_OTG_PHY
) {
311 regmap_update_bits(priv
->u2p_regmap
[i
], U2P_R0
,
312 U2P_R0_ID_PULLUP
| U2P_R0_DRV_VBUS
,
313 U2P_R0_ID_PULLUP
| U2P_R0_DRV_VBUS
);
315 ret
= priv
->drvdata
->set_phy_mode(priv
, i
, mode
);
317 ret
= priv
->drvdata
->set_phy_mode(priv
, i
,
323 regmap_update_bits(priv
->u2p_regmap
[i
], U2P_R0
,
324 U2P_R0_POWER_ON_RESET
, 0);
329 static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a
*priv
,
334 for (i
= 0; i
< priv
->drvdata
->num_phys
; ++i
) {
338 if (!strstr(priv
->drvdata
->phy_names
[i
], "usb2"))
341 ret
= priv
->drvdata
->usb2_init_phy(priv
, i
, mode
);
349 static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a
*priv
)
351 regmap_update_bits(priv
->usb_glue_regmap
, USB_R3
,
352 USB_R3_P30_SSC_RANGE_MASK
|
353 USB_R3_P30_REF_SSP_EN
,
354 USB_R3_P30_SSC_ENABLE
|
355 FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK
, 2) |
356 USB_R3_P30_REF_SSP_EN
);
359 regmap_update_bits(priv
->usb_glue_regmap
, USB_R2
,
360 USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK
,
361 FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK
, 0x15));
363 regmap_update_bits(priv
->usb_glue_regmap
, USB_R2
,
364 USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK
,
365 FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK
, 0x20));
369 regmap_update_bits(priv
->usb_glue_regmap
, USB_R1
,
370 USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT
,
371 USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT
);
373 regmap_update_bits(priv
->usb_glue_regmap
, USB_R1
,
374 USB_R1_P30_PCS_TX_SWING_FULL_MASK
,
375 FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK
, 127));
378 static void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a
*priv
,
381 if (mode
== PHY_MODE_USB_DEVICE
) {
382 if (priv
->otg_mode
!= USB_DR_MODE_OTG
&&
383 priv
->drvdata
->otg_phy_host_port_disable
)
384 /* Isolate the OTG PHY port from the Host Controller */
385 regmap_update_bits(priv
->usb_glue_regmap
, USB_R1
,
386 USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK
,
387 FIELD_PREP(USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK
,
390 regmap_update_bits(priv
->usb_glue_regmap
, USB_R0
,
391 USB_R0_U2D_ACT
, USB_R0_U2D_ACT
);
392 regmap_update_bits(priv
->usb_glue_regmap
, USB_R0
,
393 USB_R0_U2D_SS_SCALEDOWN_MODE_MASK
, 0);
394 regmap_update_bits(priv
->usb_glue_regmap
, USB_R4
,
395 USB_R4_P21_SLEEP_M0
, USB_R4_P21_SLEEP_M0
);
397 if (priv
->otg_mode
!= USB_DR_MODE_OTG
&&
398 priv
->drvdata
->otg_phy_host_port_disable
) {
399 regmap_update_bits(priv
->usb_glue_regmap
, USB_R1
,
400 USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK
, 0);
403 regmap_update_bits(priv
->usb_glue_regmap
, USB_R0
,
405 regmap_update_bits(priv
->usb_glue_regmap
, USB_R4
,
406 USB_R4_P21_SLEEP_M0
, 0);
410 static int dwc3_meson_g12a_usb_init_glue(struct dwc3_meson_g12a
*priv
,
415 ret
= dwc3_meson_g12a_usb2_init(priv
, mode
);
419 regmap_update_bits(priv
->usb_glue_regmap
, USB_R1
,
420 USB_R1_U3H_FLADJ_30MHZ_REG_MASK
,
421 FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK
, 0x20));
423 regmap_update_bits(priv
->usb_glue_regmap
, USB_R5
,
426 regmap_update_bits(priv
->usb_glue_regmap
, USB_R5
,
429 regmap_update_bits(priv
->usb_glue_regmap
, USB_R5
,
430 USB_R5_ID_DIG_TH_MASK
,
431 FIELD_PREP(USB_R5_ID_DIG_TH_MASK
, 0xff));
433 /* If we have an actual SuperSpeed port, initialize it */
434 if (priv
->usb3_ports
)
435 dwc3_meson_g12a_usb3_init(priv
);
437 dwc3_meson_g12a_usb_otg_apply_mode(priv
, mode
);
442 static const struct regmap_config phy_meson_g12a_usb_glue_regmap_conf
= {
447 .max_register
= USB_R5
,
450 static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a
*priv
)
452 const char *phy_name
;
455 for (i
= 0 ; i
< priv
->drvdata
->num_phys
; ++i
) {
456 phy_name
= priv
->drvdata
->phy_names
[i
];
457 priv
->phys
[i
] = devm_phy_optional_get(priv
->dev
, phy_name
);
461 if (IS_ERR(priv
->phys
[i
]))
462 return PTR_ERR(priv
->phys
[i
]);
464 if (strstr(phy_name
, "usb3"))
470 dev_info(priv
->dev
, "USB2 ports: %d\n", priv
->usb2_ports
);
471 dev_info(priv
->dev
, "USB3 ports: %d\n", priv
->usb3_ports
);
476 static enum phy_mode
dwc3_meson_g12a_get_id(struct dwc3_meson_g12a
*priv
)
480 regmap_read(priv
->usb_glue_regmap
, USB_R5
, ®
);
482 if (reg
& (USB_R5_ID_DIG_SYNC
| USB_R5_ID_DIG_REG
))
483 return PHY_MODE_USB_DEVICE
;
485 return PHY_MODE_USB_HOST
;
488 static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a
*priv
,
493 if (!priv
->drvdata
->otg_switch_supported
|| !priv
->phys
[USB2_OTG_PHY
])
496 if (mode
== PHY_MODE_USB_HOST
)
497 dev_info(priv
->dev
, "switching to Host Mode\n");
499 dev_info(priv
->dev
, "switching to Device Mode\n");
502 if (mode
== PHY_MODE_USB_DEVICE
)
503 ret
= regulator_disable(priv
->vbus
);
505 ret
= regulator_enable(priv
->vbus
);
510 priv
->otg_phy_mode
= mode
;
512 ret
= priv
->drvdata
->set_phy_mode(priv
, USB2_OTG_PHY
, mode
);
516 dwc3_meson_g12a_usb_otg_apply_mode(priv
, mode
);
521 static int dwc3_meson_g12a_role_set(struct usb_role_switch
*sw
,
524 struct dwc3_meson_g12a
*priv
= usb_role_switch_get_drvdata(sw
);
527 if (role
== USB_ROLE_NONE
)
530 mode
= (role
== USB_ROLE_HOST
) ? PHY_MODE_USB_HOST
531 : PHY_MODE_USB_DEVICE
;
533 if (mode
== priv
->otg_phy_mode
)
536 if (priv
->drvdata
->otg_phy_host_port_disable
)
537 dev_warn_once(priv
->dev
, "Broken manual OTG switch\n");
539 return dwc3_meson_g12a_otg_mode_set(priv
, mode
);
542 static enum usb_role
dwc3_meson_g12a_role_get(struct usb_role_switch
*sw
)
544 struct dwc3_meson_g12a
*priv
= usb_role_switch_get_drvdata(sw
);
546 return priv
->otg_phy_mode
== PHY_MODE_USB_HOST
?
547 USB_ROLE_HOST
: USB_ROLE_DEVICE
;
550 static irqreturn_t
dwc3_meson_g12a_irq_thread(int irq
, void *data
)
552 struct dwc3_meson_g12a
*priv
= data
;
553 enum phy_mode otg_id
;
555 otg_id
= dwc3_meson_g12a_get_id(priv
);
556 if (otg_id
!= priv
->otg_phy_mode
) {
557 if (dwc3_meson_g12a_otg_mode_set(priv
, otg_id
))
558 dev_warn(priv
->dev
, "Failed to switch OTG mode\n");
561 regmap_update_bits(priv
->usb_glue_regmap
, USB_R5
,
562 USB_R5_ID_DIG_IRQ
, 0);
567 static struct device
*dwc3_meson_g12_find_child(struct device
*dev
,
568 const char *compatible
)
570 struct platform_device
*pdev
;
571 struct device_node
*np
;
573 np
= of_get_compatible_child(dev
->of_node
, compatible
);
577 pdev
= of_find_device_by_node(np
);
585 static int dwc3_meson_g12a_otg_init(struct platform_device
*pdev
,
586 struct dwc3_meson_g12a
*priv
)
588 enum phy_mode otg_id
;
590 struct device
*dev
= &pdev
->dev
;
592 if (!priv
->drvdata
->otg_switch_supported
)
595 if (priv
->otg_mode
== USB_DR_MODE_OTG
) {
596 /* Ack irq before registering */
597 regmap_update_bits(priv
->usb_glue_regmap
, USB_R5
,
598 USB_R5_ID_DIG_IRQ
, 0);
600 irq
= platform_get_irq(pdev
, 0);
601 ret
= devm_request_threaded_irq(&pdev
->dev
, irq
, NULL
,
602 dwc3_meson_g12a_irq_thread
,
603 IRQF_ONESHOT
, pdev
->name
, priv
);
608 /* Setup OTG mode corresponding to the ID pin */
609 if (priv
->otg_mode
== USB_DR_MODE_OTG
) {
610 otg_id
= dwc3_meson_g12a_get_id(priv
);
611 if (otg_id
!= priv
->otg_phy_mode
) {
612 if (dwc3_meson_g12a_otg_mode_set(priv
, otg_id
))
613 dev_warn(dev
, "Failed to switch OTG mode\n");
617 /* Setup role switcher */
618 priv
->switch_desc
.usb2_port
= dwc3_meson_g12_find_child(dev
,
620 priv
->switch_desc
.udc
= dwc3_meson_g12_find_child(dev
, "snps,dwc2");
621 priv
->switch_desc
.allow_userspace_control
= true;
622 priv
->switch_desc
.set
= dwc3_meson_g12a_role_set
;
623 priv
->switch_desc
.get
= dwc3_meson_g12a_role_get
;
624 priv
->switch_desc
.driver_data
= priv
;
626 priv
->role_switch
= usb_role_switch_register(dev
, &priv
->switch_desc
);
627 if (IS_ERR(priv
->role_switch
))
628 dev_warn(dev
, "Unable to register Role Switch\n");
633 static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a
*priv
,
636 /* GXL controls the PHY mode in the PHY registers unlike G12A */
637 priv
->usb_glue_regmap
= devm_regmap_init_mmio(priv
->dev
, base
,
638 &phy_meson_g12a_usb_glue_regmap_conf
);
639 return PTR_ERR_OR_ZERO(priv
->usb_glue_regmap
);
642 static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a
*priv
,
647 priv
->usb_glue_regmap
= devm_regmap_init_mmio(priv
->dev
,
648 base
+ G12A_GLUE_OFFSET
,
649 &phy_meson_g12a_usb_glue_regmap_conf
);
650 if (IS_ERR(priv
->usb_glue_regmap
))
651 return PTR_ERR(priv
->usb_glue_regmap
);
653 /* Create a regmap for each USB2 PHY control register set */
654 for (i
= 0; i
< priv
->drvdata
->num_phys
; i
++) {
655 struct regmap_config u2p_regmap_config
= {
659 .max_register
= U2P_R1
,
662 if (!strstr(priv
->drvdata
->phy_names
[i
], "usb2"))
665 u2p_regmap_config
.name
= devm_kasprintf(priv
->dev
, GFP_KERNEL
,
667 if (!u2p_regmap_config
.name
)
670 priv
->u2p_regmap
[i
] = devm_regmap_init_mmio(priv
->dev
,
671 base
+ (i
* U2P_REG_SIZE
),
673 if (IS_ERR(priv
->u2p_regmap
[i
]))
674 return PTR_ERR(priv
->u2p_regmap
[i
]);
680 static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a
*priv
)
682 return dwc3_meson_g12a_usb_init_glue(priv
, priv
->otg_phy_mode
);
685 static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a
*priv
)
687 return dwc3_meson_g12a_usb_init_glue(priv
, PHY_MODE_USB_DEVICE
);
690 static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a
*priv
)
694 ret
= priv
->drvdata
->set_phy_mode(priv
, USB2_OTG_PHY
,
699 dwc3_meson_g12a_usb_otg_apply_mode(priv
, priv
->otg_phy_mode
);
704 static int dwc3_meson_g12a_probe(struct platform_device
*pdev
)
706 struct dwc3_meson_g12a
*priv
;
707 struct device
*dev
= &pdev
->dev
;
708 struct device_node
*np
= dev
->of_node
;
712 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
716 base
= devm_platform_ioremap_resource(pdev
, 0);
718 return PTR_ERR(base
);
720 priv
->drvdata
= of_device_get_match_data(&pdev
->dev
);
723 priv
->vbus
= devm_regulator_get_optional(dev
, "vbus");
724 if (IS_ERR(priv
->vbus
)) {
725 if (PTR_ERR(priv
->vbus
) == -EPROBE_DEFER
)
726 return PTR_ERR(priv
->vbus
);
730 ret
= devm_clk_bulk_get(dev
,
731 priv
->drvdata
->num_clks
,
732 priv
->drvdata
->clks
);
736 ret
= clk_bulk_prepare_enable(priv
->drvdata
->num_clks
,
737 priv
->drvdata
->clks
);
741 platform_set_drvdata(pdev
, priv
);
743 priv
->reset
= devm_reset_control_get_shared(dev
, NULL
);
744 if (IS_ERR(priv
->reset
)) {
745 ret
= PTR_ERR(priv
->reset
);
746 dev_err(dev
, "failed to get device reset, err=%d\n", ret
);
747 goto err_disable_clks
;
750 ret
= reset_control_reset(priv
->reset
);
752 goto err_disable_clks
;
754 ret
= dwc3_meson_g12a_get_phys(priv
);
756 goto err_disable_clks
;
758 ret
= priv
->drvdata
->setup_regmaps(priv
, base
);
760 goto err_disable_clks
;
763 ret
= regulator_enable(priv
->vbus
);
765 goto err_disable_clks
;
769 priv
->otg_mode
= usb_get_dr_mode(dev
);
771 if (priv
->otg_mode
== USB_DR_MODE_PERIPHERAL
)
772 priv
->otg_phy_mode
= PHY_MODE_USB_DEVICE
;
774 priv
->otg_phy_mode
= PHY_MODE_USB_HOST
;
776 ret
= priv
->drvdata
->usb_init(priv
);
778 goto err_disable_regulator
;
781 for (i
= 0 ; i
< PHY_COUNT
; ++i
) {
782 ret
= phy_init(priv
->phys
[i
]);
784 goto err_disable_regulator
;
788 for (i
= 0 ; i
< PHY_COUNT
; ++i
) {
789 ret
= phy_power_on(priv
->phys
[i
]);
794 if (priv
->drvdata
->usb_post_init
) {
795 ret
= priv
->drvdata
->usb_post_init(priv
);
800 ret
= of_platform_populate(np
, NULL
, NULL
, dev
);
804 ret
= dwc3_meson_g12a_otg_init(pdev
, priv
);
808 pm_runtime_set_active(dev
);
809 pm_runtime_enable(dev
);
810 pm_runtime_get_sync(dev
);
815 for (i
= 0 ; i
< PHY_COUNT
; ++i
)
816 phy_power_off(priv
->phys
[i
]);
819 for (i
= 0 ; i
< PHY_COUNT
; ++i
)
820 phy_exit(priv
->phys
[i
]);
822 err_disable_regulator
:
824 regulator_disable(priv
->vbus
);
827 clk_bulk_disable_unprepare(priv
->drvdata
->num_clks
,
828 priv
->drvdata
->clks
);
833 static int dwc3_meson_g12a_remove(struct platform_device
*pdev
)
835 struct dwc3_meson_g12a
*priv
= platform_get_drvdata(pdev
);
836 struct device
*dev
= &pdev
->dev
;
839 if (priv
->drvdata
->otg_switch_supported
)
840 usb_role_switch_unregister(priv
->role_switch
);
842 of_platform_depopulate(dev
);
844 for (i
= 0 ; i
< PHY_COUNT
; ++i
) {
845 phy_power_off(priv
->phys
[i
]);
846 phy_exit(priv
->phys
[i
]);
849 pm_runtime_disable(dev
);
850 pm_runtime_put_noidle(dev
);
851 pm_runtime_set_suspended(dev
);
853 clk_bulk_disable_unprepare(priv
->drvdata
->num_clks
,
854 priv
->drvdata
->clks
);
859 static int __maybe_unused
dwc3_meson_g12a_runtime_suspend(struct device
*dev
)
861 struct dwc3_meson_g12a
*priv
= dev_get_drvdata(dev
);
863 clk_bulk_disable_unprepare(priv
->drvdata
->num_clks
,
864 priv
->drvdata
->clks
);
869 static int __maybe_unused
dwc3_meson_g12a_runtime_resume(struct device
*dev
)
871 struct dwc3_meson_g12a
*priv
= dev_get_drvdata(dev
);
873 return clk_bulk_prepare_enable(priv
->drvdata
->num_clks
,
874 priv
->drvdata
->clks
);
877 static int __maybe_unused
dwc3_meson_g12a_suspend(struct device
*dev
)
879 struct dwc3_meson_g12a
*priv
= dev_get_drvdata(dev
);
882 if (priv
->vbus
&& priv
->otg_phy_mode
== PHY_MODE_USB_HOST
) {
883 ret
= regulator_disable(priv
->vbus
);
888 for (i
= 0 ; i
< PHY_COUNT
; ++i
) {
889 phy_power_off(priv
->phys
[i
]);
890 phy_exit(priv
->phys
[i
]);
893 reset_control_assert(priv
->reset
);
898 static int __maybe_unused
dwc3_meson_g12a_resume(struct device
*dev
)
900 struct dwc3_meson_g12a
*priv
= dev_get_drvdata(dev
);
903 reset_control_deassert(priv
->reset
);
905 ret
= priv
->drvdata
->usb_init(priv
);
910 for (i
= 0 ; i
< PHY_COUNT
; ++i
) {
911 ret
= phy_init(priv
->phys
[i
]);
917 for (i
= 0 ; i
< PHY_COUNT
; ++i
) {
918 ret
= phy_power_on(priv
->phys
[i
]);
923 if (priv
->vbus
&& priv
->otg_phy_mode
== PHY_MODE_USB_HOST
) {
924 ret
= regulator_enable(priv
->vbus
);
932 static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops
= {
933 SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend
, dwc3_meson_g12a_resume
)
934 SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend
,
935 dwc3_meson_g12a_runtime_resume
, NULL
)
938 static const struct of_device_id dwc3_meson_g12a_match
[] = {
940 .compatible
= "amlogic,meson-gxl-usb-ctrl",
941 .data
= &gxl_drvdata
,
944 .compatible
= "amlogic,meson-gxm-usb-ctrl",
945 .data
= &gxm_drvdata
,
948 .compatible
= "amlogic,meson-axg-usb-ctrl",
949 .data
= &axg_drvdata
,
952 .compatible
= "amlogic,meson-g12a-usb-ctrl",
953 .data
= &g12a_drvdata
,
956 .compatible
= "amlogic,meson-a1-usb-ctrl",
961 MODULE_DEVICE_TABLE(of
, dwc3_meson_g12a_match
);
963 static struct platform_driver dwc3_meson_g12a_driver
= {
964 .probe
= dwc3_meson_g12a_probe
,
965 .remove
= dwc3_meson_g12a_remove
,
967 .name
= "dwc3-meson-g12a",
968 .of_match_table
= dwc3_meson_g12a_match
,
969 .pm
= &dwc3_meson_g12a_dev_pm_ops
,
973 module_platform_driver(dwc3_meson_g12a_driver
);
974 MODULE_LICENSE("GPL v2");
975 MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer");
976 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");