| .. | .. |
|---|
| 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); |
|---|