.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Renesas R-Car Gen3 for USB2.0 PHY driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * This is based on the phy-rcar-gen2 driver: |
---|
7 | 8 | * Copyright (C) 2014 Renesas Solutions Corp. |
---|
8 | 9 | * Copyright (C) 2014 Cogent Embedded, Inc. |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify |
---|
11 | | - * it under the terms of the GNU General Public License version 2 as |
---|
12 | | - * published by the Free Software Foundation. |
---|
13 | 10 | */ |
---|
14 | 11 | |
---|
15 | 12 | #include <linux/extcon-provider.h> |
---|
16 | 13 | #include <linux/interrupt.h> |
---|
17 | 14 | #include <linux/io.h> |
---|
18 | 15 | #include <linux/module.h> |
---|
| 16 | +#include <linux/mutex.h> |
---|
19 | 17 | #include <linux/of.h> |
---|
20 | 18 | #include <linux/of_address.h> |
---|
21 | 19 | #include <linux/of_device.h> |
---|
.. | .. |
---|
41 | 39 | |
---|
42 | 40 | /* INT_ENABLE */ |
---|
43 | 41 | #define USB2_INT_ENABLE_UCOM_INTEN BIT(3) |
---|
44 | | -#define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) |
---|
45 | | -#define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) |
---|
46 | | -#define USB2_INT_ENABLE_INIT (USB2_INT_ENABLE_UCOM_INTEN | \ |
---|
47 | | - USB2_INT_ENABLE_USBH_INTB_EN | \ |
---|
48 | | - USB2_INT_ENABLE_USBH_INTA_EN) |
---|
| 42 | +#define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) /* For EHCI */ |
---|
| 43 | +#define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) /* For OHCI */ |
---|
49 | 44 | |
---|
50 | 45 | /* USBCTR */ |
---|
51 | 46 | #define USB2_USBCTR_DIRPD BIT(2) |
---|
.. | .. |
---|
83 | 78 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ |
---|
84 | 79 | #define USB2_ADPCTRL_DRVVBUS BIT(4) |
---|
85 | 80 | |
---|
86 | | -#define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1 |
---|
| 81 | +#define NUM_OF_PHYS 4 |
---|
| 82 | +enum rcar_gen3_phy_index { |
---|
| 83 | + PHY_INDEX_BOTH_HC, |
---|
| 84 | + PHY_INDEX_OHCI, |
---|
| 85 | + PHY_INDEX_EHCI, |
---|
| 86 | + PHY_INDEX_HSUSB |
---|
| 87 | +}; |
---|
| 88 | + |
---|
| 89 | +static const u32 rcar_gen3_int_enable[NUM_OF_PHYS] = { |
---|
| 90 | + USB2_INT_ENABLE_USBH_INTB_EN | USB2_INT_ENABLE_USBH_INTA_EN, |
---|
| 91 | + USB2_INT_ENABLE_USBH_INTA_EN, |
---|
| 92 | + USB2_INT_ENABLE_USBH_INTB_EN, |
---|
| 93 | + 0 |
---|
| 94 | +}; |
---|
| 95 | + |
---|
| 96 | +struct rcar_gen3_phy { |
---|
| 97 | + struct phy *phy; |
---|
| 98 | + struct rcar_gen3_chan *ch; |
---|
| 99 | + u32 int_enable_bits; |
---|
| 100 | + bool initialized; |
---|
| 101 | + bool otg_initialized; |
---|
| 102 | + bool powered; |
---|
| 103 | +}; |
---|
87 | 104 | |
---|
88 | 105 | struct rcar_gen3_chan { |
---|
89 | 106 | void __iomem *base; |
---|
| 107 | + struct device *dev; /* platform_device's device */ |
---|
90 | 108 | struct extcon_dev *extcon; |
---|
91 | | - struct phy *phy; |
---|
| 109 | + struct rcar_gen3_phy rphys[NUM_OF_PHYS]; |
---|
92 | 110 | struct regulator *vbus; |
---|
93 | 111 | struct work_struct work; |
---|
| 112 | + struct mutex lock; /* protects rphys[...].powered */ |
---|
| 113 | + enum usb_dr_mode dr_mode; |
---|
| 114 | + int irq; |
---|
94 | 115 | bool extcon_host; |
---|
95 | | - bool has_otg_pins; |
---|
| 116 | + bool is_otg_channel; |
---|
| 117 | + bool uses_otg_pins; |
---|
96 | 118 | }; |
---|
| 119 | + |
---|
| 120 | +/* |
---|
| 121 | + * Combination about is_otg_channel and uses_otg_pins: |
---|
| 122 | + * |
---|
| 123 | + * Parameters || Behaviors |
---|
| 124 | + * is_otg_channel | uses_otg_pins || irqs | role sysfs |
---|
| 125 | + * ---------------------+---------------++--------------+------------ |
---|
| 126 | + * true | true || enabled | enabled |
---|
| 127 | + * true | false || disabled | enabled |
---|
| 128 | + * false | any || disabled | disabled |
---|
| 129 | + */ |
---|
97 | 130 | |
---|
98 | 131 | static void rcar_gen3_phy_usb2_work(struct work_struct *work) |
---|
99 | 132 | { |
---|
.. | .. |
---|
114 | 147 | void __iomem *usb2_base = ch->base; |
---|
115 | 148 | u32 val = readl(usb2_base + USB2_COMMCTRL); |
---|
116 | 149 | |
---|
117 | | - dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); |
---|
| 150 | + dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, host); |
---|
118 | 151 | if (host) |
---|
119 | 152 | val &= ~USB2_COMMCTRL_OTG_PERI; |
---|
120 | 153 | else |
---|
.. | .. |
---|
127 | 160 | void __iomem *usb2_base = ch->base; |
---|
128 | 161 | u32 val = readl(usb2_base + USB2_LINECTRL1); |
---|
129 | 162 | |
---|
130 | | - dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); |
---|
| 163 | + dev_vdbg(ch->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); |
---|
131 | 164 | val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); |
---|
132 | 165 | if (dp) |
---|
133 | 166 | val |= USB2_LINECTRL1_DP_RPD; |
---|
.. | .. |
---|
141 | 174 | void __iomem *usb2_base = ch->base; |
---|
142 | 175 | u32 val = readl(usb2_base + USB2_ADPCTRL); |
---|
143 | 176 | |
---|
144 | | - dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); |
---|
| 177 | + dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); |
---|
145 | 178 | if (vbus) |
---|
146 | 179 | val |= USB2_ADPCTRL_DRVVBUS; |
---|
147 | 180 | else |
---|
148 | 181 | val &= ~USB2_ADPCTRL_DRVVBUS; |
---|
149 | 182 | writel(val, usb2_base + USB2_ADPCTRL); |
---|
| 183 | +} |
---|
| 184 | + |
---|
| 185 | +static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) |
---|
| 186 | +{ |
---|
| 187 | + void __iomem *usb2_base = ch->base; |
---|
| 188 | + u32 val = readl(usb2_base + USB2_OBINTEN); |
---|
| 189 | + |
---|
| 190 | + if (ch->uses_otg_pins && enable) |
---|
| 191 | + val |= USB2_OBINT_BITS; |
---|
| 192 | + else |
---|
| 193 | + val &= ~USB2_OBINT_BITS; |
---|
| 194 | + writel(val, usb2_base + USB2_OBINTEN); |
---|
150 | 195 | } |
---|
151 | 196 | |
---|
152 | 197 | static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) |
---|
.. | .. |
---|
194 | 239 | |
---|
195 | 240 | static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch) |
---|
196 | 241 | { |
---|
197 | | - void __iomem *usb2_base = ch->base; |
---|
198 | | - u32 val; |
---|
199 | | - |
---|
200 | | - val = readl(usb2_base + USB2_OBINTEN); |
---|
201 | | - writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); |
---|
| 242 | + rcar_gen3_control_otg_irq(ch, 0); |
---|
202 | 243 | |
---|
203 | 244 | rcar_gen3_enable_vbus_ctrl(ch, 1); |
---|
204 | 245 | rcar_gen3_init_for_host(ch); |
---|
205 | 246 | |
---|
206 | | - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); |
---|
| 247 | + rcar_gen3_control_otg_irq(ch, 1); |
---|
207 | 248 | } |
---|
208 | 249 | |
---|
209 | 250 | static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) |
---|
210 | 251 | { |
---|
| 252 | + if (!ch->uses_otg_pins) |
---|
| 253 | + return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; |
---|
| 254 | + |
---|
211 | 255 | return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); |
---|
212 | 256 | } |
---|
213 | 257 | |
---|
.. | .. |
---|
232 | 276 | return PHY_MODE_USB_DEVICE; |
---|
233 | 277 | } |
---|
234 | 278 | |
---|
| 279 | +static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch) |
---|
| 280 | +{ |
---|
| 281 | + int i; |
---|
| 282 | + |
---|
| 283 | + for (i = 0; i < NUM_OF_PHYS; i++) { |
---|
| 284 | + if (ch->rphys[i].initialized) |
---|
| 285 | + return true; |
---|
| 286 | + } |
---|
| 287 | + |
---|
| 288 | + return false; |
---|
| 289 | +} |
---|
| 290 | + |
---|
| 291 | +static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch) |
---|
| 292 | +{ |
---|
| 293 | + int i; |
---|
| 294 | + |
---|
| 295 | + for (i = 0; i < NUM_OF_PHYS; i++) { |
---|
| 296 | + if (ch->rphys[i].otg_initialized) |
---|
| 297 | + return false; |
---|
| 298 | + } |
---|
| 299 | + |
---|
| 300 | + return true; |
---|
| 301 | +} |
---|
| 302 | + |
---|
| 303 | +static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch) |
---|
| 304 | +{ |
---|
| 305 | + int i; |
---|
| 306 | + |
---|
| 307 | + for (i = 0; i < NUM_OF_PHYS; i++) { |
---|
| 308 | + if (ch->rphys[i].powered) |
---|
| 309 | + return false; |
---|
| 310 | + } |
---|
| 311 | + |
---|
| 312 | + return true; |
---|
| 313 | +} |
---|
| 314 | + |
---|
235 | 315 | static ssize_t role_store(struct device *dev, struct device_attribute *attr, |
---|
236 | 316 | const char *buf, size_t count) |
---|
237 | 317 | { |
---|
.. | .. |
---|
239 | 319 | bool is_b_device; |
---|
240 | 320 | enum phy_mode cur_mode, new_mode; |
---|
241 | 321 | |
---|
242 | | - if (!ch->has_otg_pins || !ch->phy->init_count) |
---|
| 322 | + if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) |
---|
243 | 323 | return -EIO; |
---|
244 | 324 | |
---|
245 | 325 | if (sysfs_streq(buf, "host")) |
---|
.. | .. |
---|
277 | 357 | { |
---|
278 | 358 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); |
---|
279 | 359 | |
---|
280 | | - if (!ch->has_otg_pins || !ch->phy->init_count) |
---|
| 360 | + if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) |
---|
281 | 361 | return -EIO; |
---|
282 | 362 | |
---|
283 | 363 | return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : |
---|
.. | .. |
---|
290 | 370 | void __iomem *usb2_base = ch->base; |
---|
291 | 371 | u32 val; |
---|
292 | 372 | |
---|
| 373 | + /* Should not use functions of read-modify-write a register */ |
---|
| 374 | + val = readl(usb2_base + USB2_LINECTRL1); |
---|
| 375 | + val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN | |
---|
| 376 | + USB2_LINECTRL1_DMRPD_EN | USB2_LINECTRL1_DM_RPD; |
---|
| 377 | + writel(val, usb2_base + USB2_LINECTRL1); |
---|
| 378 | + |
---|
293 | 379 | val = readl(usb2_base + USB2_VBCTRL); |
---|
294 | 380 | val &= ~USB2_VBCTRL_OCCLREN; |
---|
295 | 381 | writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); |
---|
296 | | - writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); |
---|
297 | | - val = readl(usb2_base + USB2_OBINTEN); |
---|
298 | | - writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); |
---|
299 | 382 | val = readl(usb2_base + USB2_ADPCTRL); |
---|
300 | 383 | writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); |
---|
301 | | - val = readl(usb2_base + USB2_LINECTRL1); |
---|
302 | | - rcar_gen3_set_linectrl(ch, 0, 0); |
---|
303 | | - writel(val | USB2_LINECTRL1_DPRPD_EN | USB2_LINECTRL1_DMRPD_EN, |
---|
304 | | - usb2_base + USB2_LINECTRL1); |
---|
| 384 | + |
---|
| 385 | + msleep(20); |
---|
| 386 | + |
---|
| 387 | + writel(0xffffffff, usb2_base + USB2_OBINTSTA); |
---|
| 388 | + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); |
---|
305 | 389 | |
---|
306 | 390 | rcar_gen3_device_recognition(ch); |
---|
307 | 391 | } |
---|
308 | 392 | |
---|
| 393 | +static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) |
---|
| 394 | +{ |
---|
| 395 | + struct rcar_gen3_chan *ch = _ch; |
---|
| 396 | + void __iomem *usb2_base = ch->base; |
---|
| 397 | + u32 status = readl(usb2_base + USB2_OBINTSTA); |
---|
| 398 | + irqreturn_t ret = IRQ_NONE; |
---|
| 399 | + |
---|
| 400 | + if (status & USB2_OBINT_BITS) { |
---|
| 401 | + dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); |
---|
| 402 | + writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); |
---|
| 403 | + rcar_gen3_device_recognition(ch); |
---|
| 404 | + ret = IRQ_HANDLED; |
---|
| 405 | + } |
---|
| 406 | + |
---|
| 407 | + return ret; |
---|
| 408 | +} |
---|
| 409 | + |
---|
309 | 410 | static int rcar_gen3_phy_usb2_init(struct phy *p) |
---|
310 | 411 | { |
---|
311 | | - struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
---|
| 412 | + struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
---|
| 413 | + struct rcar_gen3_chan *channel = rphy->ch; |
---|
312 | 414 | void __iomem *usb2_base = channel->base; |
---|
| 415 | + u32 val; |
---|
| 416 | + int ret; |
---|
| 417 | + |
---|
| 418 | + if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) { |
---|
| 419 | + INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); |
---|
| 420 | + ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq, |
---|
| 421 | + IRQF_SHARED, dev_name(channel->dev), channel); |
---|
| 422 | + if (ret < 0) { |
---|
| 423 | + dev_err(channel->dev, "No irq handler (%d)\n", channel->irq); |
---|
| 424 | + return ret; |
---|
| 425 | + } |
---|
| 426 | + } |
---|
313 | 427 | |
---|
314 | 428 | /* Initialize USB2 part */ |
---|
315 | | - writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); |
---|
| 429 | + val = readl(usb2_base + USB2_INT_ENABLE); |
---|
| 430 | + val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits; |
---|
| 431 | + writel(val, usb2_base + USB2_INT_ENABLE); |
---|
316 | 432 | writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); |
---|
317 | 433 | writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); |
---|
318 | 434 | |
---|
319 | 435 | /* Initialize otg part */ |
---|
320 | | - if (channel->has_otg_pins) |
---|
321 | | - rcar_gen3_init_otg(channel); |
---|
| 436 | + if (channel->is_otg_channel) { |
---|
| 437 | + if (rcar_gen3_needs_init_otg(channel)) |
---|
| 438 | + rcar_gen3_init_otg(channel); |
---|
| 439 | + rphy->otg_initialized = true; |
---|
| 440 | + } |
---|
| 441 | + |
---|
| 442 | + rphy->initialized = true; |
---|
322 | 443 | |
---|
323 | 444 | return 0; |
---|
324 | 445 | } |
---|
325 | 446 | |
---|
326 | 447 | static int rcar_gen3_phy_usb2_exit(struct phy *p) |
---|
327 | 448 | { |
---|
328 | | - struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
---|
| 449 | + struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
---|
| 450 | + struct rcar_gen3_chan *channel = rphy->ch; |
---|
| 451 | + void __iomem *usb2_base = channel->base; |
---|
| 452 | + u32 val; |
---|
329 | 453 | |
---|
330 | | - writel(0, channel->base + USB2_INT_ENABLE); |
---|
| 454 | + rphy->initialized = false; |
---|
| 455 | + |
---|
| 456 | + if (channel->is_otg_channel) |
---|
| 457 | + rphy->otg_initialized = false; |
---|
| 458 | + |
---|
| 459 | + val = readl(usb2_base + USB2_INT_ENABLE); |
---|
| 460 | + val &= ~rphy->int_enable_bits; |
---|
| 461 | + if (!rcar_gen3_is_any_rphy_initialized(channel)) |
---|
| 462 | + val &= ~USB2_INT_ENABLE_UCOM_INTEN; |
---|
| 463 | + writel(val, usb2_base + USB2_INT_ENABLE); |
---|
| 464 | + |
---|
| 465 | + if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel)) |
---|
| 466 | + free_irq(channel->irq, channel); |
---|
331 | 467 | |
---|
332 | 468 | return 0; |
---|
333 | 469 | } |
---|
334 | 470 | |
---|
335 | 471 | static int rcar_gen3_phy_usb2_power_on(struct phy *p) |
---|
336 | 472 | { |
---|
337 | | - struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
---|
| 473 | + struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
---|
| 474 | + struct rcar_gen3_chan *channel = rphy->ch; |
---|
338 | 475 | void __iomem *usb2_base = channel->base; |
---|
339 | 476 | u32 val; |
---|
340 | | - int ret; |
---|
| 477 | + int ret = 0; |
---|
| 478 | + |
---|
| 479 | + mutex_lock(&channel->lock); |
---|
| 480 | + if (!rcar_gen3_are_all_rphys_power_off(channel)) |
---|
| 481 | + goto out; |
---|
341 | 482 | |
---|
342 | 483 | if (channel->vbus) { |
---|
343 | 484 | ret = regulator_enable(channel->vbus); |
---|
344 | 485 | if (ret) |
---|
345 | | - return ret; |
---|
| 486 | + goto out; |
---|
346 | 487 | } |
---|
347 | 488 | |
---|
348 | 489 | val = readl(usb2_base + USB2_USBCTR); |
---|
.. | .. |
---|
351 | 492 | val &= ~USB2_USBCTR_PLL_RST; |
---|
352 | 493 | writel(val, usb2_base + USB2_USBCTR); |
---|
353 | 494 | |
---|
| 495 | +out: |
---|
| 496 | + /* The powered flag should be set for any other phys anyway */ |
---|
| 497 | + rphy->powered = true; |
---|
| 498 | + mutex_unlock(&channel->lock); |
---|
| 499 | + |
---|
354 | 500 | return 0; |
---|
355 | 501 | } |
---|
356 | 502 | |
---|
357 | 503 | static int rcar_gen3_phy_usb2_power_off(struct phy *p) |
---|
358 | 504 | { |
---|
359 | | - struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
---|
| 505 | + struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
---|
| 506 | + struct rcar_gen3_chan *channel = rphy->ch; |
---|
360 | 507 | int ret = 0; |
---|
| 508 | + |
---|
| 509 | + mutex_lock(&channel->lock); |
---|
| 510 | + rphy->powered = false; |
---|
| 511 | + |
---|
| 512 | + if (!rcar_gen3_are_all_rphys_power_off(channel)) |
---|
| 513 | + goto out; |
---|
361 | 514 | |
---|
362 | 515 | if (channel->vbus) |
---|
363 | 516 | ret = regulator_disable(channel->vbus); |
---|
| 517 | + |
---|
| 518 | +out: |
---|
| 519 | + mutex_unlock(&channel->lock); |
---|
364 | 520 | |
---|
365 | 521 | return ret; |
---|
366 | 522 | } |
---|
.. | .. |
---|
373 | 529 | .owner = THIS_MODULE, |
---|
374 | 530 | }; |
---|
375 | 531 | |
---|
376 | | -static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) |
---|
377 | | -{ |
---|
378 | | - struct rcar_gen3_chan *ch = _ch; |
---|
379 | | - void __iomem *usb2_base = ch->base; |
---|
380 | | - u32 status = readl(usb2_base + USB2_OBINTSTA); |
---|
381 | | - irqreturn_t ret = IRQ_NONE; |
---|
382 | | - |
---|
383 | | - if (status & USB2_OBINT_BITS) { |
---|
384 | | - dev_vdbg(&ch->phy->dev, "%s: %08x\n", __func__, status); |
---|
385 | | - writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); |
---|
386 | | - rcar_gen3_device_recognition(ch); |
---|
387 | | - ret = IRQ_HANDLED; |
---|
388 | | - } |
---|
389 | | - |
---|
390 | | - return ret; |
---|
391 | | -} |
---|
| 532 | +static const struct phy_ops rz_g1c_phy_usb2_ops = { |
---|
| 533 | + .init = rcar_gen3_phy_usb2_init, |
---|
| 534 | + .exit = rcar_gen3_phy_usb2_exit, |
---|
| 535 | + .owner = THIS_MODULE, |
---|
| 536 | +}; |
---|
392 | 537 | |
---|
393 | 538 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { |
---|
394 | 539 | { |
---|
| 540 | + .compatible = "renesas,usb2-phy-r8a77470", |
---|
| 541 | + .data = &rz_g1c_phy_usb2_ops, |
---|
| 542 | + }, |
---|
| 543 | + { |
---|
395 | 544 | .compatible = "renesas,usb2-phy-r8a7795", |
---|
396 | | - .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, |
---|
| 545 | + .data = &rcar_gen3_phy_usb2_ops, |
---|
397 | 546 | }, |
---|
398 | 547 | { |
---|
399 | 548 | .compatible = "renesas,usb2-phy-r8a7796", |
---|
400 | | - .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, |
---|
| 549 | + .data = &rcar_gen3_phy_usb2_ops, |
---|
401 | 550 | }, |
---|
402 | 551 | { |
---|
403 | 552 | .compatible = "renesas,usb2-phy-r8a77965", |
---|
404 | | - .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, |
---|
| 553 | + .data = &rcar_gen3_phy_usb2_ops, |
---|
405 | 554 | }, |
---|
406 | 555 | { |
---|
407 | 556 | .compatible = "renesas,rcar-gen3-usb2-phy", |
---|
| 557 | + .data = &rcar_gen3_phy_usb2_ops, |
---|
408 | 558 | }, |
---|
409 | | - { } |
---|
| 559 | + { /* sentinel */ }, |
---|
410 | 560 | }; |
---|
411 | 561 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); |
---|
412 | 562 | |
---|
.. | .. |
---|
416 | 566 | EXTCON_NONE, |
---|
417 | 567 | }; |
---|
418 | 568 | |
---|
| 569 | +static struct phy *rcar_gen3_phy_usb2_xlate(struct device *dev, |
---|
| 570 | + struct of_phandle_args *args) |
---|
| 571 | +{ |
---|
| 572 | + struct rcar_gen3_chan *ch = dev_get_drvdata(dev); |
---|
| 573 | + |
---|
| 574 | + if (args->args_count == 0) /* For old version dts */ |
---|
| 575 | + return ch->rphys[PHY_INDEX_BOTH_HC].phy; |
---|
| 576 | + else if (args->args_count > 1) /* Prevent invalid args count */ |
---|
| 577 | + return ERR_PTR(-ENODEV); |
---|
| 578 | + |
---|
| 579 | + if (args->args[0] >= NUM_OF_PHYS) |
---|
| 580 | + return ERR_PTR(-ENODEV); |
---|
| 581 | + |
---|
| 582 | + return ch->rphys[args->args[0]].phy; |
---|
| 583 | +} |
---|
| 584 | + |
---|
| 585 | +static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) |
---|
| 586 | +{ |
---|
| 587 | + enum usb_dr_mode candidate = USB_DR_MODE_UNKNOWN; |
---|
| 588 | + int i; |
---|
| 589 | + |
---|
| 590 | + /* |
---|
| 591 | + * If one of device nodes has other dr_mode except UNKNOWN, |
---|
| 592 | + * this function returns UNKNOWN. To achieve backward compatibility, |
---|
| 593 | + * this loop starts the index as 0. |
---|
| 594 | + */ |
---|
| 595 | + for (i = 0; i < NUM_OF_PHYS; i++) { |
---|
| 596 | + enum usb_dr_mode mode = of_usb_get_dr_mode_by_phy(np, i); |
---|
| 597 | + |
---|
| 598 | + if (mode != USB_DR_MODE_UNKNOWN) { |
---|
| 599 | + if (candidate == USB_DR_MODE_UNKNOWN) |
---|
| 600 | + candidate = mode; |
---|
| 601 | + else if (candidate != mode) |
---|
| 602 | + return USB_DR_MODE_UNKNOWN; |
---|
| 603 | + } |
---|
| 604 | + } |
---|
| 605 | + |
---|
| 606 | + return candidate; |
---|
| 607 | +} |
---|
| 608 | + |
---|
419 | 609 | static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) |
---|
420 | 610 | { |
---|
421 | 611 | struct device *dev = &pdev->dev; |
---|
422 | 612 | struct rcar_gen3_chan *channel; |
---|
423 | 613 | struct phy_provider *provider; |
---|
424 | 614 | struct resource *res; |
---|
425 | | - int irq, ret = 0; |
---|
| 615 | + const struct phy_ops *phy_usb2_ops; |
---|
| 616 | + int ret = 0, i; |
---|
426 | 617 | |
---|
427 | 618 | if (!dev->of_node) { |
---|
428 | 619 | dev_err(dev, "This driver needs device tree\n"); |
---|
.. | .. |
---|
438 | 629 | if (IS_ERR(channel->base)) |
---|
439 | 630 | return PTR_ERR(channel->base); |
---|
440 | 631 | |
---|
441 | | - /* call request_irq for OTG */ |
---|
442 | | - irq = platform_get_irq(pdev, 0); |
---|
443 | | - if (irq >= 0) { |
---|
444 | | - INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); |
---|
445 | | - irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, |
---|
446 | | - IRQF_SHARED, dev_name(dev), channel); |
---|
447 | | - if (irq < 0) |
---|
448 | | - dev_err(dev, "No irq handler (%d)\n", irq); |
---|
449 | | - } |
---|
450 | | - |
---|
451 | | - if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) { |
---|
| 632 | + /* get irq number here and request_irq for OTG in phy_init */ |
---|
| 633 | + channel->irq = platform_get_irq_optional(pdev, 0); |
---|
| 634 | + channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); |
---|
| 635 | + if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { |
---|
452 | 636 | int ret; |
---|
453 | 637 | |
---|
454 | | - channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev); |
---|
| 638 | + channel->is_otg_channel = true; |
---|
| 639 | + channel->uses_otg_pins = !of_property_read_bool(dev->of_node, |
---|
| 640 | + "renesas,no-otg-pins"); |
---|
455 | 641 | channel->extcon = devm_extcon_dev_allocate(dev, |
---|
456 | 642 | rcar_gen3_phy_cable); |
---|
457 | 643 | if (IS_ERR(channel->extcon)) |
---|
.. | .. |
---|
469 | 655 | * And then, phy-core will manage runtime pm for this device. |
---|
470 | 656 | */ |
---|
471 | 657 | pm_runtime_enable(dev); |
---|
472 | | - channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops); |
---|
473 | | - if (IS_ERR(channel->phy)) { |
---|
474 | | - dev_err(dev, "Failed to create USB2 PHY\n"); |
---|
475 | | - ret = PTR_ERR(channel->phy); |
---|
| 658 | + phy_usb2_ops = of_device_get_match_data(dev); |
---|
| 659 | + if (!phy_usb2_ops) { |
---|
| 660 | + ret = -EINVAL; |
---|
476 | 661 | goto error; |
---|
| 662 | + } |
---|
| 663 | + |
---|
| 664 | + mutex_init(&channel->lock); |
---|
| 665 | + for (i = 0; i < NUM_OF_PHYS; i++) { |
---|
| 666 | + channel->rphys[i].phy = devm_phy_create(dev, NULL, |
---|
| 667 | + phy_usb2_ops); |
---|
| 668 | + if (IS_ERR(channel->rphys[i].phy)) { |
---|
| 669 | + dev_err(dev, "Failed to create USB2 PHY\n"); |
---|
| 670 | + ret = PTR_ERR(channel->rphys[i].phy); |
---|
| 671 | + goto error; |
---|
| 672 | + } |
---|
| 673 | + channel->rphys[i].ch = channel; |
---|
| 674 | + channel->rphys[i].int_enable_bits = rcar_gen3_int_enable[i]; |
---|
| 675 | + phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); |
---|
477 | 676 | } |
---|
478 | 677 | |
---|
479 | 678 | channel->vbus = devm_regulator_get_optional(dev, "vbus"); |
---|
.. | .. |
---|
486 | 685 | } |
---|
487 | 686 | |
---|
488 | 687 | platform_set_drvdata(pdev, channel); |
---|
489 | | - phy_set_drvdata(channel->phy, channel); |
---|
| 688 | + channel->dev = dev; |
---|
490 | 689 | |
---|
491 | | - provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
---|
| 690 | + provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate); |
---|
492 | 691 | if (IS_ERR(provider)) { |
---|
493 | 692 | dev_err(dev, "Failed to register PHY provider\n"); |
---|
494 | 693 | ret = PTR_ERR(provider); |
---|
495 | 694 | goto error; |
---|
496 | | - } else if (channel->has_otg_pins) { |
---|
| 695 | + } else if (channel->is_otg_channel) { |
---|
497 | 696 | int ret; |
---|
498 | 697 | |
---|
499 | 698 | ret = device_create_file(dev, &dev_attr_role); |
---|
.. | .. |
---|
513 | 712 | { |
---|
514 | 713 | struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); |
---|
515 | 714 | |
---|
516 | | - if (channel->has_otg_pins) |
---|
| 715 | + if (channel->is_otg_channel) |
---|
517 | 716 | device_remove_file(&pdev->dev, &dev_attr_role); |
---|
518 | 717 | |
---|
519 | 718 | pm_runtime_disable(&pdev->dev); |
---|