1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Renesas USB driver R-Car Gen. 3 initialization and power control |
4 | * |
5 | * Copyright (C) 2016-2019 Renesas Electronics Corporation |
6 | */ |
7 | |
8 | #include <linux/delay.h> |
9 | #include <linux/io.h> |
10 | #include "common.h" |
11 | #include "rcar3.h" |
12 | |
13 | #define LPSTS 0x102 |
14 | #define UGCTRL 0x180 /* 32-bit register */ |
15 | #define UGCTRL2 0x184 /* 32-bit register */ |
16 | #define UGSTS 0x188 /* 32-bit register */ |
17 | |
18 | /* Low Power Status register (LPSTS) */ |
19 | #define LPSTS_SUSPM 0x4000 |
20 | |
21 | /* R-Car D3 only: USB General control register (UGCTRL) */ |
22 | #define UGCTRL_PLLRESET 0x00000001 |
23 | #define UGCTRL_CONNECT 0x00000004 |
24 | |
25 | /* |
26 | * USB General control register 2 (UGCTRL2) |
27 | * Remarks: bit[31:11] and bit[9:6] should be 0 |
28 | */ |
29 | #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ |
30 | #define UGCTRL2_USB0SEL_HSUSB 0x00000020 |
31 | #define UGCTRL2_USB0SEL_OTG 0x00000030 |
32 | #define UGCTRL2_VBUSSEL 0x00000400 |
33 | |
34 | /* R-Car D3 only: USB General status register (UGSTS) */ |
35 | #define UGSTS_LOCK 0x00000100 |
36 | |
37 | static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data) |
38 | { |
39 | iowrite32(data, priv->base + reg); |
40 | } |
41 | |
42 | static u32 usbhs_read32(struct usbhs_priv *priv, u32 reg) |
43 | { |
44 | return ioread32(priv->base + reg); |
45 | } |
46 | |
47 | static void usbhs_rcar3_set_ugctrl2(struct usbhs_priv *priv, u32 val) |
48 | { |
49 | usbhs_write32(priv, UGCTRL2, data: val | UGCTRL2_RESERVED_3); |
50 | } |
51 | |
52 | static int usbhs_rcar3_power_ctrl(struct platform_device *pdev, |
53 | void __iomem *base, int enable) |
54 | { |
55 | struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); |
56 | |
57 | usbhs_rcar3_set_ugctrl2(priv, UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL); |
58 | |
59 | if (enable) { |
60 | usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); |
61 | /* The controller on R-Car Gen3 needs to wait up to 45 usec */ |
62 | usleep_range(min: 45, max: 90); |
63 | } else { |
64 | usbhs_bset(priv, LPSTS, LPSTS_SUSPM, data: 0); |
65 | } |
66 | |
67 | return 0; |
68 | } |
69 | |
70 | /* R-Car D3 needs to release UGCTRL.PLLRESET */ |
71 | static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev, |
72 | void __iomem *base, int enable) |
73 | { |
74 | struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); |
75 | u32 val; |
76 | int timeout = 1000; |
77 | |
78 | if (enable) { |
79 | usbhs_write32(priv, UGCTRL, data: 0); /* release PLLRESET */ |
80 | usbhs_rcar3_set_ugctrl2(priv, |
81 | UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL); |
82 | |
83 | usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); |
84 | do { |
85 | val = usbhs_read32(priv, UGSTS); |
86 | udelay(1); |
87 | } while (!(val & UGSTS_LOCK) && timeout--); |
88 | usbhs_write32(priv, UGCTRL, UGCTRL_CONNECT); |
89 | } else { |
90 | usbhs_write32(priv, UGCTRL, data: 0); |
91 | usbhs_bset(priv, LPSTS, LPSTS_SUSPM, data: 0); |
92 | usbhs_write32(priv, UGCTRL, UGCTRL_PLLRESET); |
93 | } |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | const struct renesas_usbhs_platform_info usbhs_rcar_gen3_plat_info = { |
99 | .platform_callback = { |
100 | .power_ctrl = usbhs_rcar3_power_ctrl, |
101 | .get_id = usbhs_get_id_as_gadget, |
102 | }, |
103 | .driver_param = { |
104 | .has_usb_dmac = 1, |
105 | .multi_clks = 1, |
106 | .has_new_pipe_configs = 1, |
107 | }, |
108 | }; |
109 | |
110 | const struct renesas_usbhs_platform_info usbhs_rcar_gen3_with_pll_plat_info = { |
111 | .platform_callback = { |
112 | .power_ctrl = usbhs_rcar3_power_and_pll_ctrl, |
113 | .get_id = usbhs_get_id_as_gadget, |
114 | }, |
115 | .driver_param = { |
116 | .has_usb_dmac = 1, |
117 | .multi_clks = 1, |
118 | .has_new_pipe_configs = 1, |
119 | }, |
120 | }; |
121 | |