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