Commit | Line | Data |
---|---|---|
eee0e5da | 1 | // SPDX-License-Identifier: GPL-2.0 |
f3b5a8d9 YS |
2 | /* |
3 | * Renesas R-Car Gen3 for USB2.0 PHY driver | |
4 | * | |
7e0540f4 | 5 | * Copyright (C) 2015-2017 Renesas Electronics Corporation |
f3b5a8d9 YS |
6 | * |
7 | * This is based on the phy-rcar-gen2 driver: | |
8 | * Copyright (C) 2014 Renesas Solutions Corp. | |
9 | * Copyright (C) 2014 Cogent Embedded, Inc. | |
f3b5a8d9 YS |
10 | */ |
11 | ||
176aa360 | 12 | #include <linux/extcon-provider.h> |
9f391c57 | 13 | #include <linux/interrupt.h> |
f3b5a8d9 YS |
14 | #include <linux/io.h> |
15 | #include <linux/module.h> | |
5c9dc637 | 16 | #include <linux/mutex.h> |
f3b5a8d9 | 17 | #include <linux/of.h> |
f3b5a8d9 YS |
18 | #include <linux/phy/phy.h> |
19 | #include <linux/platform_device.h> | |
441a681b | 20 | #include <linux/pm_runtime.h> |
6dcfd7c3 | 21 | #include <linux/regulator/consumer.h> |
4bd5ead8 | 22 | #include <linux/string.h> |
7e0540f4 | 23 | #include <linux/usb/of.h> |
c14f8a40 | 24 | #include <linux/workqueue.h> |
f3b5a8d9 YS |
25 | |
26 | /******* USB2.0 Host registers (original offset is +0x200) *******/ | |
27 | #define USB2_INT_ENABLE 0x000 | |
28 | #define USB2_USBCTR 0x00c | |
29 | #define USB2_SPD_RSM_TIMSET 0x10c | |
30 | #define USB2_OC_TIMSET 0x110 | |
1114e2d3 | 31 | #define USB2_COMMCTRL 0x600 |
9f391c57 YS |
32 | #define USB2_OBINTSTA 0x604 |
33 | #define USB2_OBINTEN 0x608 | |
1114e2d3 YS |
34 | #define USB2_VBCTRL 0x60c |
35 | #define USB2_LINECTRL1 0x610 | |
36 | #define USB2_ADPCTRL 0x630 | |
f3b5a8d9 YS |
37 | |
38 | /* INT_ENABLE */ | |
9f391c57 | 39 | #define USB2_INT_ENABLE_UCOM_INTEN BIT(3) |
549b6b55 YS |
40 | #define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) /* For EHCI */ |
41 | #define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) /* For OHCI */ | |
f3b5a8d9 YS |
42 | |
43 | /* USBCTR */ | |
44 | #define USB2_USBCTR_DIRPD BIT(2) | |
45 | #define USB2_USBCTR_PLL_RST BIT(1) | |
46 | ||
47 | /* SPD_RSM_TIMSET */ | |
48 | #define USB2_SPD_RSM_TIMSET_INIT 0x014e029b | |
49 | ||
50 | /* OC_TIMSET */ | |
51 | #define USB2_OC_TIMSET_INIT 0x000209ab | |
52 | ||
1114e2d3 YS |
53 | /* COMMCTRL */ |
54 | #define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */ | |
55 | ||
9f391c57 YS |
56 | /* OBINTSTA and OBINTEN */ |
57 | #define USB2_OBINT_SESSVLDCHG BIT(12) | |
58 | #define USB2_OBINT_IDDIGCHG BIT(11) | |
59 | #define USB2_OBINT_BITS (USB2_OBINT_SESSVLDCHG | \ | |
60 | USB2_OBINT_IDDIGCHG) | |
61 | ||
1114e2d3 | 62 | /* VBCTRL */ |
e6839c31 | 63 | #define USB2_VBCTRL_OCCLREN BIT(16) |
1114e2d3 | 64 | #define USB2_VBCTRL_DRVVBUSSEL BIT(8) |
b0512a6e | 65 | #define USB2_VBCTRL_VBOUT BIT(0) |
1114e2d3 YS |
66 | |
67 | /* LINECTRL1 */ | |
68 | #define USB2_LINECTRL1_DPRPD_EN BIT(19) | |
69 | #define USB2_LINECTRL1_DP_RPD BIT(18) | |
70 | #define USB2_LINECTRL1_DMRPD_EN BIT(17) | |
71 | #define USB2_LINECTRL1_DM_RPD BIT(16) | |
9bb86777 | 72 | #define USB2_LINECTRL1_OPMODE_NODRV BIT(6) |
1114e2d3 YS |
73 | |
74 | /* ADPCTRL */ | |
75 | #define USB2_ADPCTRL_OTGSESSVLD BIT(20) | |
76 | #define USB2_ADPCTRL_IDDIG BIT(19) | |
77 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ | |
78 | #define USB2_ADPCTRL_DRVVBUS BIT(4) | |
79 | ||
b0512a6e BD |
80 | /* RZ/G2L specific */ |
81 | #define USB2_OBINT_IDCHG_EN BIT(0) | |
82 | #define USB2_LINECTRL1_USB2_IDMON BIT(0) | |
83 | ||
549b6b55 YS |
84 | #define NUM_OF_PHYS 4 |
85 | enum rcar_gen3_phy_index { | |
86 | PHY_INDEX_BOTH_HC, | |
87 | PHY_INDEX_OHCI, | |
88 | PHY_INDEX_EHCI, | |
89 | PHY_INDEX_HSUSB | |
90 | }; | |
91 | ||
92 | static const u32 rcar_gen3_int_enable[NUM_OF_PHYS] = { | |
93 | USB2_INT_ENABLE_USBH_INTB_EN | USB2_INT_ENABLE_USBH_INTA_EN, | |
94 | USB2_INT_ENABLE_USBH_INTA_EN, | |
95 | USB2_INT_ENABLE_USBH_INTB_EN, | |
96 | 0 | |
97 | }; | |
98 | ||
99 | struct rcar_gen3_phy { | |
100 | struct phy *phy; | |
101 | struct rcar_gen3_chan *ch; | |
102 | u32 int_enable_bits; | |
103 | bool initialized; | |
104 | bool otg_initialized; | |
105 | bool powered; | |
106 | }; | |
107 | ||
f3b5a8d9 | 108 | struct rcar_gen3_chan { |
801a69c7 | 109 | void __iomem *base; |
92fec1c2 | 110 | struct device *dev; /* platform_device's device */ |
2b38543c | 111 | struct extcon_dev *extcon; |
549b6b55 | 112 | struct rcar_gen3_phy rphys[NUM_OF_PHYS]; |
6dcfd7c3 | 113 | struct regulator *vbus; |
c14f8a40 | 114 | struct work_struct work; |
5c9dc637 | 115 | struct mutex lock; /* protects rphys[...].powered */ |
73801b90 | 116 | enum usb_dr_mode dr_mode; |
08b0ad37 | 117 | int irq; |
b0512a6e | 118 | u32 obint_enable_bits; |
c14f8a40 | 119 | bool extcon_host; |
979b519c | 120 | bool is_otg_channel; |
cfdc6634 | 121 | bool uses_otg_pins; |
b0512a6e BD |
122 | bool soc_no_adp_ctrl; |
123 | }; | |
124 | ||
125 | struct rcar_gen3_phy_drv_data { | |
126 | const struct phy_ops *phy_usb2_ops; | |
127 | bool no_adp_ctrl; | |
f3b5a8d9 YS |
128 | }; |
129 | ||
979b519c YS |
130 | /* |
131 | * Combination about is_otg_channel and uses_otg_pins: | |
132 | * | |
133 | * Parameters || Behaviors | |
134 | * is_otg_channel | uses_otg_pins || irqs | role sysfs | |
135 | * ---------------------+---------------++--------------+------------ | |
136 | * true | true || enabled | enabled | |
137 | * true | false || disabled | enabled | |
138 | * false | any || disabled | disabled | |
139 | */ | |
140 | ||
c14f8a40 YS |
141 | static void rcar_gen3_phy_usb2_work(struct work_struct *work) |
142 | { | |
143 | struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, | |
144 | work); | |
145 | ||
146 | if (ch->extcon_host) { | |
c6f30a5b CC |
147 | extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); |
148 | extcon_set_state_sync(ch->extcon, EXTCON_USB, false); | |
c14f8a40 | 149 | } else { |
c6f30a5b CC |
150 | extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false); |
151 | extcon_set_state_sync(ch->extcon, EXTCON_USB, true); | |
c14f8a40 YS |
152 | } |
153 | } | |
154 | ||
1114e2d3 YS |
155 | static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) |
156 | { | |
801a69c7 | 157 | void __iomem *usb2_base = ch->base; |
1114e2d3 YS |
158 | u32 val = readl(usb2_base + USB2_COMMCTRL); |
159 | ||
92fec1c2 | 160 | dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, host); |
1114e2d3 YS |
161 | if (host) |
162 | val &= ~USB2_COMMCTRL_OTG_PERI; | |
163 | else | |
164 | val |= USB2_COMMCTRL_OTG_PERI; | |
165 | writel(val, usb2_base + USB2_COMMCTRL); | |
166 | } | |
167 | ||
168 | static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) | |
169 | { | |
801a69c7 | 170 | void __iomem *usb2_base = ch->base; |
1114e2d3 YS |
171 | u32 val = readl(usb2_base + USB2_LINECTRL1); |
172 | ||
92fec1c2 | 173 | dev_vdbg(ch->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); |
1114e2d3 YS |
174 | val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); |
175 | if (dp) | |
176 | val |= USB2_LINECTRL1_DP_RPD; | |
177 | if (dm) | |
178 | val |= USB2_LINECTRL1_DM_RPD; | |
179 | writel(val, usb2_base + USB2_LINECTRL1); | |
180 | } | |
181 | ||
182 | static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) | |
183 | { | |
801a69c7 | 184 | void __iomem *usb2_base = ch->base; |
b0512a6e BD |
185 | u32 vbus_ctrl_reg = USB2_ADPCTRL; |
186 | u32 vbus_ctrl_val = USB2_ADPCTRL_DRVVBUS; | |
187 | u32 val; | |
1114e2d3 | 188 | |
92fec1c2 | 189 | dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); |
b0512a6e BD |
190 | if (ch->soc_no_adp_ctrl) { |
191 | vbus_ctrl_reg = USB2_VBCTRL; | |
192 | vbus_ctrl_val = USB2_VBCTRL_VBOUT; | |
193 | } | |
194 | ||
195 | val = readl(usb2_base + vbus_ctrl_reg); | |
1114e2d3 | 196 | if (vbus) |
b0512a6e | 197 | val |= vbus_ctrl_val; |
1114e2d3 | 198 | else |
b0512a6e BD |
199 | val &= ~vbus_ctrl_val; |
200 | writel(val, usb2_base + vbus_ctrl_reg); | |
1114e2d3 YS |
201 | } |
202 | ||
7ab0305d YS |
203 | static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) |
204 | { | |
205 | void __iomem *usb2_base = ch->base; | |
206 | u32 val = readl(usb2_base + USB2_OBINTEN); | |
207 | ||
a602152c | 208 | if (ch->uses_otg_pins && enable) |
b0512a6e | 209 | val |= ch->obint_enable_bits; |
7ab0305d | 210 | else |
b0512a6e | 211 | val &= ~ch->obint_enable_bits; |
7ab0305d YS |
212 | writel(val, usb2_base + USB2_OBINTEN); |
213 | } | |
214 | ||
1114e2d3 YS |
215 | static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) |
216 | { | |
217 | rcar_gen3_set_linectrl(ch, 1, 1); | |
218 | rcar_gen3_set_host_mode(ch, 1); | |
219 | rcar_gen3_enable_vbus_ctrl(ch, 1); | |
2b38543c | 220 | |
c14f8a40 YS |
221 | ch->extcon_host = true; |
222 | schedule_work(&ch->work); | |
1114e2d3 YS |
223 | } |
224 | ||
225 | static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) | |
226 | { | |
227 | rcar_gen3_set_linectrl(ch, 0, 1); | |
228 | rcar_gen3_set_host_mode(ch, 0); | |
229 | rcar_gen3_enable_vbus_ctrl(ch, 0); | |
2b38543c | 230 | |
c14f8a40 YS |
231 | ch->extcon_host = false; |
232 | schedule_work(&ch->work); | |
1114e2d3 YS |
233 | } |
234 | ||
9bb86777 YS |
235 | static void rcar_gen3_init_for_b_host(struct rcar_gen3_chan *ch) |
236 | { | |
237 | void __iomem *usb2_base = ch->base; | |
238 | u32 val; | |
239 | ||
240 | val = readl(usb2_base + USB2_LINECTRL1); | |
241 | writel(val | USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1); | |
242 | ||
243 | rcar_gen3_set_linectrl(ch, 1, 1); | |
244 | rcar_gen3_set_host_mode(ch, 1); | |
245 | rcar_gen3_enable_vbus_ctrl(ch, 0); | |
246 | ||
247 | val = readl(usb2_base + USB2_LINECTRL1); | |
248 | writel(val & ~USB2_LINECTRL1_OPMODE_NODRV, usb2_base + USB2_LINECTRL1); | |
249 | } | |
250 | ||
251 | static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch) | |
252 | { | |
253 | rcar_gen3_set_linectrl(ch, 0, 1); | |
254 | rcar_gen3_set_host_mode(ch, 0); | |
255 | rcar_gen3_enable_vbus_ctrl(ch, 1); | |
256 | } | |
257 | ||
258 | static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) | |
259 | { | |
7ab0305d | 260 | rcar_gen3_control_otg_irq(ch, 0); |
9bb86777 | 261 | |
09938ea9 | 262 | rcar_gen3_enable_vbus_ctrl(ch, 1); |
9bb86777 YS |
263 | rcar_gen3_init_for_host(ch); |
264 | ||
7ab0305d | 265 | rcar_gen3_control_otg_irq(ch, 1); |
9bb86777 YS |
266 | } |
267 | ||
1114e2d3 YS |
268 | static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) |
269 | { | |
a602152c YS |
270 | if (!ch->uses_otg_pins) |
271 | return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; | |
272 | ||
b0512a6e BD |
273 | if (ch->soc_no_adp_ctrl) |
274 | return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON); | |
275 | ||
801a69c7 | 276 | return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); |
1114e2d3 YS |
277 | } |
278 | ||
279 | static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) | |
280 | { | |
6762925d | 281 | if (!rcar_gen3_check_id(ch)) |
1114e2d3 YS |
282 | rcar_gen3_init_for_host(ch); |
283 | else | |
284 | rcar_gen3_init_for_peri(ch); | |
285 | } | |
286 | ||
9bb86777 YS |
287 | static bool rcar_gen3_is_host(struct rcar_gen3_chan *ch) |
288 | { | |
289 | return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI); | |
290 | } | |
291 | ||
b56acc82 YS |
292 | static enum phy_mode rcar_gen3_get_phy_mode(struct rcar_gen3_chan *ch) |
293 | { | |
294 | if (rcar_gen3_is_host(ch)) | |
295 | return PHY_MODE_USB_HOST; | |
296 | ||
297 | return PHY_MODE_USB_DEVICE; | |
298 | } | |
299 | ||
549b6b55 YS |
300 | static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch) |
301 | { | |
302 | int i; | |
303 | ||
304 | for (i = 0; i < NUM_OF_PHYS; i++) { | |
305 | if (ch->rphys[i].initialized) | |
306 | return true; | |
307 | } | |
308 | ||
309 | return false; | |
310 | } | |
311 | ||
312 | static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch) | |
313 | { | |
314 | int i; | |
315 | ||
316 | for (i = 0; i < NUM_OF_PHYS; i++) { | |
317 | if (ch->rphys[i].otg_initialized) | |
318 | return false; | |
319 | } | |
320 | ||
321 | return true; | |
322 | } | |
323 | ||
324 | static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch) | |
325 | { | |
326 | int i; | |
327 | ||
328 | for (i = 0; i < NUM_OF_PHYS; i++) { | |
329 | if (ch->rphys[i].powered) | |
330 | return false; | |
331 | } | |
332 | ||
333 | return true; | |
334 | } | |
335 | ||
9bb86777 YS |
336 | static ssize_t role_store(struct device *dev, struct device_attribute *attr, |
337 | const char *buf, size_t count) | |
338 | { | |
339 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); | |
b56acc82 YS |
340 | bool is_b_device; |
341 | enum phy_mode cur_mode, new_mode; | |
9bb86777 | 342 | |
549b6b55 | 343 | if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) |
9bb86777 YS |
344 | return -EIO; |
345 | ||
4bd5ead8 | 346 | if (sysfs_streq(buf, "host")) |
b56acc82 | 347 | new_mode = PHY_MODE_USB_HOST; |
4bd5ead8 | 348 | else if (sysfs_streq(buf, "peripheral")) |
b56acc82 | 349 | new_mode = PHY_MODE_USB_DEVICE; |
9bb86777 YS |
350 | else |
351 | return -EINVAL; | |
352 | ||
b56acc82 YS |
353 | /* is_b_device: true is B-Device. false is A-Device. */ |
354 | is_b_device = rcar_gen3_check_id(ch); | |
355 | cur_mode = rcar_gen3_get_phy_mode(ch); | |
356 | ||
9bb86777 | 357 | /* If current and new mode is the same, this returns the error */ |
b56acc82 | 358 | if (cur_mode == new_mode) |
9bb86777 YS |
359 | return -EINVAL; |
360 | ||
b56acc82 | 361 | if (new_mode == PHY_MODE_USB_HOST) { /* And is_host must be false */ |
9bb86777 YS |
362 | if (!is_b_device) /* A-Peripheral */ |
363 | rcar_gen3_init_from_a_peri_to_a_host(ch); | |
364 | else /* B-Peripheral */ | |
365 | rcar_gen3_init_for_b_host(ch); | |
366 | } else { /* And is_host must be true */ | |
367 | if (!is_b_device) /* A-Host */ | |
368 | rcar_gen3_init_for_a_peri(ch); | |
369 | else /* B-Host */ | |
370 | rcar_gen3_init_for_peri(ch); | |
371 | } | |
372 | ||
373 | return count; | |
374 | } | |
375 | ||
376 | static ssize_t role_show(struct device *dev, struct device_attribute *attr, | |
377 | char *buf) | |
378 | { | |
379 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); | |
380 | ||
549b6b55 | 381 | if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) |
9bb86777 YS |
382 | return -EIO; |
383 | ||
384 | return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : | |
385 | "peripheral"); | |
386 | } | |
387 | static DEVICE_ATTR_RW(role); | |
388 | ||
1114e2d3 YS |
389 | static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) |
390 | { | |
801a69c7 | 391 | void __iomem *usb2_base = ch->base; |
1114e2d3 YS |
392 | u32 val; |
393 | ||
72c0339c YS |
394 | /* Should not use functions of read-modify-write a register */ |
395 | val = readl(usb2_base + USB2_LINECTRL1); | |
396 | val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN | | |
397 | USB2_LINECTRL1_DMRPD_EN | USB2_LINECTRL1_DM_RPD; | |
398 | writel(val, usb2_base + USB2_LINECTRL1); | |
399 | ||
b0512a6e BD |
400 | if (!ch->soc_no_adp_ctrl) { |
401 | val = readl(usb2_base + USB2_VBCTRL); | |
402 | val &= ~USB2_VBCTRL_OCCLREN; | |
403 | writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); | |
404 | val = readl(usb2_base + USB2_ADPCTRL); | |
405 | writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); | |
406 | } | |
72c0339c YS |
407 | msleep(20); |
408 | ||
409 | writel(0xffffffff, usb2_base + USB2_OBINTSTA); | |
b0512a6e | 410 | writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN); |
1114e2d3 YS |
411 | |
412 | rcar_gen3_device_recognition(ch); | |
413 | } | |
414 | ||
08b0ad37 YS |
415 | static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) |
416 | { | |
417 | struct rcar_gen3_chan *ch = _ch; | |
418 | void __iomem *usb2_base = ch->base; | |
419 | u32 status = readl(usb2_base + USB2_OBINTSTA); | |
420 | irqreturn_t ret = IRQ_NONE; | |
421 | ||
b0512a6e | 422 | if (status & ch->obint_enable_bits) { |
08b0ad37 | 423 | dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); |
b0512a6e | 424 | writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); |
08b0ad37 YS |
425 | rcar_gen3_device_recognition(ch); |
426 | ret = IRQ_HANDLED; | |
427 | } | |
428 | ||
429 | return ret; | |
430 | } | |
431 | ||
f3b5a8d9 YS |
432 | static int rcar_gen3_phy_usb2_init(struct phy *p) |
433 | { | |
549b6b55 YS |
434 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
435 | struct rcar_gen3_chan *channel = rphy->ch; | |
801a69c7 | 436 | void __iomem *usb2_base = channel->base; |
549b6b55 | 437 | u32 val; |
08b0ad37 YS |
438 | int ret; |
439 | ||
440 | if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) { | |
441 | INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); | |
442 | ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq, | |
443 | IRQF_SHARED, dev_name(channel->dev), channel); | |
b59aeb1a | 444 | if (ret < 0) { |
08b0ad37 | 445 | dev_err(channel->dev, "No irq handler (%d)\n", channel->irq); |
b59aeb1a YS |
446 | return ret; |
447 | } | |
08b0ad37 | 448 | } |
f3b5a8d9 YS |
449 | |
450 | /* Initialize USB2 part */ | |
549b6b55 YS |
451 | val = readl(usb2_base + USB2_INT_ENABLE); |
452 | val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits; | |
453 | writel(val, usb2_base + USB2_INT_ENABLE); | |
f3b5a8d9 YS |
454 | writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); |
455 | writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); | |
456 | ||
b9564016 | 457 | /* Initialize otg part */ |
549b6b55 YS |
458 | if (channel->is_otg_channel) { |
459 | if (rcar_gen3_needs_init_otg(channel)) | |
460 | rcar_gen3_init_otg(channel); | |
461 | rphy->otg_initialized = true; | |
462 | } | |
463 | ||
464 | rphy->initialized = true; | |
f3b5a8d9 YS |
465 | |
466 | return 0; | |
467 | } | |
468 | ||
469 | static int rcar_gen3_phy_usb2_exit(struct phy *p) | |
470 | { | |
549b6b55 YS |
471 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
472 | struct rcar_gen3_chan *channel = rphy->ch; | |
473 | void __iomem *usb2_base = channel->base; | |
474 | u32 val; | |
f3b5a8d9 | 475 | |
549b6b55 YS |
476 | rphy->initialized = false; |
477 | ||
478 | if (channel->is_otg_channel) | |
479 | rphy->otg_initialized = false; | |
480 | ||
481 | val = readl(usb2_base + USB2_INT_ENABLE); | |
482 | val &= ~rphy->int_enable_bits; | |
483 | if (!rcar_gen3_is_any_rphy_initialized(channel)) | |
484 | val &= ~USB2_INT_ENABLE_UCOM_INTEN; | |
485 | writel(val, usb2_base + USB2_INT_ENABLE); | |
f3b5a8d9 | 486 | |
08b0ad37 YS |
487 | if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel)) |
488 | free_irq(channel->irq, channel); | |
489 | ||
f3b5a8d9 YS |
490 | return 0; |
491 | } | |
492 | ||
493 | static int rcar_gen3_phy_usb2_power_on(struct phy *p) | |
494 | { | |
549b6b55 YS |
495 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
496 | struct rcar_gen3_chan *channel = rphy->ch; | |
801a69c7 | 497 | void __iomem *usb2_base = channel->base; |
f3b5a8d9 | 498 | u32 val; |
5c9dc637 | 499 | int ret = 0; |
6dcfd7c3 | 500 | |
5c9dc637 | 501 | mutex_lock(&channel->lock); |
549b6b55 | 502 | if (!rcar_gen3_are_all_rphys_power_off(channel)) |
5c9dc637 | 503 | goto out; |
549b6b55 | 504 | |
6dcfd7c3 YS |
505 | if (channel->vbus) { |
506 | ret = regulator_enable(channel->vbus); | |
507 | if (ret) | |
5c9dc637 | 508 | goto out; |
6dcfd7c3 | 509 | } |
f3b5a8d9 YS |
510 | |
511 | val = readl(usb2_base + USB2_USBCTR); | |
512 | val |= USB2_USBCTR_PLL_RST; | |
513 | writel(val, usb2_base + USB2_USBCTR); | |
514 | val &= ~USB2_USBCTR_PLL_RST; | |
515 | writel(val, usb2_base + USB2_USBCTR); | |
516 | ||
5c9dc637 YS |
517 | out: |
518 | /* The powered flag should be set for any other phys anyway */ | |
549b6b55 | 519 | rphy->powered = true; |
5c9dc637 | 520 | mutex_unlock(&channel->lock); |
549b6b55 | 521 | |
f3b5a8d9 YS |
522 | return 0; |
523 | } | |
524 | ||
6dcfd7c3 YS |
525 | static int rcar_gen3_phy_usb2_power_off(struct phy *p) |
526 | { | |
549b6b55 YS |
527 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
528 | struct rcar_gen3_chan *channel = rphy->ch; | |
6dcfd7c3 YS |
529 | int ret = 0; |
530 | ||
5c9dc637 | 531 | mutex_lock(&channel->lock); |
549b6b55 YS |
532 | rphy->powered = false; |
533 | ||
534 | if (!rcar_gen3_are_all_rphys_power_off(channel)) | |
5c9dc637 | 535 | goto out; |
549b6b55 | 536 | |
6dcfd7c3 YS |
537 | if (channel->vbus) |
538 | ret = regulator_disable(channel->vbus); | |
539 | ||
5c9dc637 YS |
540 | out: |
541 | mutex_unlock(&channel->lock); | |
542 | ||
6dcfd7c3 YS |
543 | return ret; |
544 | } | |
545 | ||
a8df2768 | 546 | static const struct phy_ops rcar_gen3_phy_usb2_ops = { |
f3b5a8d9 YS |
547 | .init = rcar_gen3_phy_usb2_init, |
548 | .exit = rcar_gen3_phy_usb2_exit, | |
549 | .power_on = rcar_gen3_phy_usb2_power_on, | |
6dcfd7c3 | 550 | .power_off = rcar_gen3_phy_usb2_power_off, |
f3b5a8d9 YS |
551 | .owner = THIS_MODULE, |
552 | }; | |
553 | ||
5d8042e9 BD |
554 | static const struct phy_ops rz_g1c_phy_usb2_ops = { |
555 | .init = rcar_gen3_phy_usb2_init, | |
556 | .exit = rcar_gen3_phy_usb2_exit, | |
557 | .owner = THIS_MODULE, | |
558 | }; | |
559 | ||
b0512a6e BD |
560 | static const struct rcar_gen3_phy_drv_data rcar_gen3_phy_usb2_data = { |
561 | .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, | |
562 | .no_adp_ctrl = false, | |
563 | }; | |
564 | ||
565 | static const struct rcar_gen3_phy_drv_data rz_g1c_phy_usb2_data = { | |
566 | .phy_usb2_ops = &rz_g1c_phy_usb2_ops, | |
567 | .no_adp_ctrl = false, | |
568 | }; | |
569 | ||
570 | static const struct rcar_gen3_phy_drv_data rz_g2l_phy_usb2_data = { | |
571 | .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, | |
572 | .no_adp_ctrl = true, | |
573 | }; | |
574 | ||
f3b5a8d9 | 575 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { |
5d8042e9 BD |
576 | { |
577 | .compatible = "renesas,usb2-phy-r8a77470", | |
b0512a6e | 578 | .data = &rz_g1c_phy_usb2_data, |
5d8042e9 BD |
579 | }, |
580 | { | |
581 | .compatible = "renesas,usb2-phy-r8a7795", | |
b0512a6e | 582 | .data = &rcar_gen3_phy_usb2_data, |
5d8042e9 BD |
583 | }, |
584 | { | |
585 | .compatible = "renesas,usb2-phy-r8a7796", | |
b0512a6e | 586 | .data = &rcar_gen3_phy_usb2_data, |
5d8042e9 BD |
587 | }, |
588 | { | |
589 | .compatible = "renesas,usb2-phy-r8a77965", | |
b0512a6e BD |
590 | .data = &rcar_gen3_phy_usb2_data, |
591 | }, | |
592 | { | |
593 | .compatible = "renesas,rzg2l-usb2-phy", | |
594 | .data = &rz_g2l_phy_usb2_data, | |
5d8042e9 BD |
595 | }, |
596 | { | |
597 | .compatible = "renesas,rcar-gen3-usb2-phy", | |
b0512a6e | 598 | .data = &rcar_gen3_phy_usb2_data, |
5d8042e9 BD |
599 | }, |
600 | { /* sentinel */ }, | |
f3b5a8d9 YS |
601 | }; |
602 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); | |
603 | ||
2b38543c YS |
604 | static const unsigned int rcar_gen3_phy_cable[] = { |
605 | EXTCON_USB, | |
606 | EXTCON_USB_HOST, | |
607 | EXTCON_NONE, | |
608 | }; | |
609 | ||
549b6b55 YS |
610 | static struct phy *rcar_gen3_phy_usb2_xlate(struct device *dev, |
611 | struct of_phandle_args *args) | |
612 | { | |
613 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); | |
614 | ||
615 | if (args->args_count == 0) /* For old version dts */ | |
616 | return ch->rphys[PHY_INDEX_BOTH_HC].phy; | |
617 | else if (args->args_count > 1) /* Prevent invalid args count */ | |
618 | return ERR_PTR(-ENODEV); | |
619 | ||
620 | if (args->args[0] >= NUM_OF_PHYS) | |
621 | return ERR_PTR(-ENODEV); | |
622 | ||
623 | return ch->rphys[args->args[0]].phy; | |
624 | } | |
625 | ||
626 | static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) | |
627 | { | |
628 | enum usb_dr_mode candidate = USB_DR_MODE_UNKNOWN; | |
629 | int i; | |
630 | ||
631 | /* | |
632 | * If one of device nodes has other dr_mode except UNKNOWN, | |
633 | * this function returns UNKNOWN. To achieve backward compatibility, | |
634 | * this loop starts the index as 0. | |
635 | */ | |
636 | for (i = 0; i < NUM_OF_PHYS; i++) { | |
637 | enum usb_dr_mode mode = of_usb_get_dr_mode_by_phy(np, i); | |
638 | ||
639 | if (mode != USB_DR_MODE_UNKNOWN) { | |
640 | if (candidate == USB_DR_MODE_UNKNOWN) | |
641 | candidate = mode; | |
642 | else if (candidate != mode) | |
643 | return USB_DR_MODE_UNKNOWN; | |
644 | } | |
645 | } | |
646 | ||
647 | return candidate; | |
648 | } | |
649 | ||
f3b5a8d9 YS |
650 | static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) |
651 | { | |
b0512a6e | 652 | const struct rcar_gen3_phy_drv_data *phy_data; |
f3b5a8d9 YS |
653 | struct device *dev = &pdev->dev; |
654 | struct rcar_gen3_chan *channel; | |
655 | struct phy_provider *provider; | |
08b0ad37 | 656 | int ret = 0, i; |
f3b5a8d9 YS |
657 | |
658 | if (!dev->of_node) { | |
659 | dev_err(dev, "This driver needs device tree\n"); | |
660 | return -EINVAL; | |
661 | } | |
662 | ||
663 | channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); | |
664 | if (!channel) | |
665 | return -ENOMEM; | |
666 | ||
0b5604af | 667 | channel->base = devm_platform_ioremap_resource(pdev, 0); |
801a69c7 YS |
668 | if (IS_ERR(channel->base)) |
669 | return PTR_ERR(channel->base); | |
f3b5a8d9 | 670 | |
b0512a6e | 671 | channel->obint_enable_bits = USB2_OBINT_BITS; |
08b0ad37 YS |
672 | /* get irq number here and request_irq for OTG in phy_init */ |
673 | channel->irq = platform_get_irq_optional(pdev, 0); | |
549b6b55 | 674 | channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); |
73801b90 | 675 | if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { |
979b519c | 676 | channel->is_otg_channel = true; |
8dde0008 YS |
677 | channel->uses_otg_pins = !of_property_read_bool(dev->of_node, |
678 | "renesas,no-otg-pins"); | |
2b38543c YS |
679 | channel->extcon = devm_extcon_dev_allocate(dev, |
680 | rcar_gen3_phy_cable); | |
681 | if (IS_ERR(channel->extcon)) | |
682 | return PTR_ERR(channel->extcon); | |
683 | ||
684 | ret = devm_extcon_dev_register(dev, channel->extcon); | |
685 | if (ret < 0) { | |
686 | dev_err(dev, "Failed to register extcon\n"); | |
687 | return ret; | |
688 | } | |
f3b5a8d9 YS |
689 | } |
690 | ||
441a681b YS |
691 | /* |
692 | * devm_phy_create() will call pm_runtime_enable(&phy->dev); | |
693 | * And then, phy-core will manage runtime pm for this device. | |
694 | */ | |
695 | pm_runtime_enable(dev); | |
b0512a6e BD |
696 | |
697 | phy_data = of_device_get_match_data(dev); | |
698 | if (!phy_data) { | |
51e339de WL |
699 | ret = -EINVAL; |
700 | goto error; | |
701 | } | |
5d8042e9 | 702 | |
b0512a6e BD |
703 | channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; |
704 | if (phy_data->no_adp_ctrl) | |
705 | channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; | |
706 | ||
5c9dc637 | 707 | mutex_init(&channel->lock); |
549b6b55 YS |
708 | for (i = 0; i < NUM_OF_PHYS; i++) { |
709 | channel->rphys[i].phy = devm_phy_create(dev, NULL, | |
b0512a6e | 710 | phy_data->phy_usb2_ops); |
549b6b55 YS |
711 | if (IS_ERR(channel->rphys[i].phy)) { |
712 | dev_err(dev, "Failed to create USB2 PHY\n"); | |
713 | ret = PTR_ERR(channel->rphys[i].phy); | |
714 | goto error; | |
715 | } | |
716 | channel->rphys[i].ch = channel; | |
717 | channel->rphys[i].int_enable_bits = rcar_gen3_int_enable[i]; | |
718 | phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); | |
f3b5a8d9 YS |
719 | } |
720 | ||
6dcfd7c3 YS |
721 | channel->vbus = devm_regulator_get_optional(dev, "vbus"); |
722 | if (IS_ERR(channel->vbus)) { | |
441a681b YS |
723 | if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) { |
724 | ret = PTR_ERR(channel->vbus); | |
725 | goto error; | |
726 | } | |
6dcfd7c3 YS |
727 | channel->vbus = NULL; |
728 | } | |
729 | ||
9bb86777 | 730 | platform_set_drvdata(pdev, channel); |
92fec1c2 | 731 | channel->dev = dev; |
f3b5a8d9 | 732 | |
549b6b55 | 733 | provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate); |
9bb86777 | 734 | if (IS_ERR(provider)) { |
f3b5a8d9 | 735 | dev_err(dev, "Failed to register PHY provider\n"); |
441a681b YS |
736 | ret = PTR_ERR(provider); |
737 | goto error; | |
979b519c | 738 | } else if (channel->is_otg_channel) { |
9bb86777 YS |
739 | ret = device_create_file(dev, &dev_attr_role); |
740 | if (ret < 0) | |
441a681b | 741 | goto error; |
9bb86777 | 742 | } |
f3b5a8d9 | 743 | |
441a681b YS |
744 | return 0; |
745 | ||
746 | error: | |
747 | pm_runtime_disable(dev); | |
748 | ||
749 | return ret; | |
f3b5a8d9 YS |
750 | } |
751 | ||
c7ac6dff | 752 | static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) |
9bb86777 YS |
753 | { |
754 | struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); | |
755 | ||
979b519c | 756 | if (channel->is_otg_channel) |
9bb86777 YS |
757 | device_remove_file(&pdev->dev, &dev_attr_role); |
758 | ||
441a681b | 759 | pm_runtime_disable(&pdev->dev); |
9bb86777 YS |
760 | }; |
761 | ||
f3b5a8d9 YS |
762 | static struct platform_driver rcar_gen3_phy_usb2_driver = { |
763 | .driver = { | |
764 | .name = "phy_rcar_gen3_usb2", | |
765 | .of_match_table = rcar_gen3_phy_usb2_match_table, | |
766 | }, | |
767 | .probe = rcar_gen3_phy_usb2_probe, | |
c7ac6dff | 768 | .remove_new = rcar_gen3_phy_usb2_remove, |
f3b5a8d9 YS |
769 | }; |
770 | module_platform_driver(rcar_gen3_phy_usb2_driver); | |
771 | ||
772 | MODULE_LICENSE("GPL v2"); | |
773 | MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY"); | |
774 | MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>"); |