Lines Matching +full:rcar +full:- +full:gen3 +full:- +full:usb2 +full:- +full:phy
1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas R-Car Gen3 for USB2.0 PHY driver
5 * Copyright (C) 2015-2017 Renesas Electronics Corporation
7 * This is based on the phy-rcar-gen2 driver:
12 #include <linux/extcon-provider.h>
20 #include <linux/phy/phy.h>
28 /******* USB2.0 Host registers (original offset is +0x200) *******/
97 struct phy *phy; member
125 * ---------------------+---------------++--------------+------------
136 if (ch->extcon_host) { in rcar_gen3_phy_usb2_work()
137 extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); in rcar_gen3_phy_usb2_work()
138 extcon_set_state_sync(ch->extcon, EXTCON_USB, false); in rcar_gen3_phy_usb2_work()
140 extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false); in rcar_gen3_phy_usb2_work()
141 extcon_set_state_sync(ch->extcon, EXTCON_USB, true); in rcar_gen3_phy_usb2_work()
147 void __iomem *usb2_base = ch->base; in rcar_gen3_set_host_mode()
150 dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, host); in rcar_gen3_set_host_mode()
160 void __iomem *usb2_base = ch->base; in rcar_gen3_set_linectrl()
163 dev_vdbg(ch->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); in rcar_gen3_set_linectrl()
174 void __iomem *usb2_base = ch->base; in rcar_gen3_enable_vbus_ctrl()
177 dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); in rcar_gen3_enable_vbus_ctrl()
187 void __iomem *usb2_base = ch->base; in rcar_gen3_control_otg_irq()
190 if (ch->uses_otg_pins && enable) in rcar_gen3_control_otg_irq()
203 ch->extcon_host = true; in rcar_gen3_init_for_host()
204 schedule_work(&ch->work); in rcar_gen3_init_for_host()
213 ch->extcon_host = false; in rcar_gen3_init_for_peri()
214 schedule_work(&ch->work); in rcar_gen3_init_for_peri()
219 void __iomem *usb2_base = ch->base; in rcar_gen3_init_for_b_host()
252 if (!ch->uses_otg_pins) in rcar_gen3_check_id()
253 return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; in rcar_gen3_check_id()
255 return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); in rcar_gen3_check_id()
268 return !(readl(ch->base + USB2_COMMCTRL) & USB2_COMMCTRL_OTG_PERI); in rcar_gen3_is_host()
284 if (ch->rphys[i].initialized) in rcar_gen3_is_any_rphy_initialized()
296 if (ch->rphys[i].otg_initialized) in rcar_gen3_needs_init_otg()
308 if (ch->rphys[i].powered) in rcar_gen3_are_all_rphys_power_off()
322 if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) in role_store()
323 return -EIO; in role_store()
330 return -EINVAL; in role_store()
332 /* is_b_device: true is B-Device. false is A-Device. */ in role_store()
338 return -EINVAL; in role_store()
341 if (!is_b_device) /* A-Peripheral */ in role_store()
343 else /* B-Peripheral */ in role_store()
346 if (!is_b_device) /* A-Host */ in role_store()
348 else /* B-Host */ in role_store()
360 if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) in role_show()
361 return -EIO; in role_show()
370 void __iomem *usb2_base = ch->base; in rcar_gen3_init_otg()
373 /* Should not use functions of read-modify-write a register */ in rcar_gen3_init_otg()
396 void __iomem *usb2_base = ch->base; in rcar_gen3_phy_usb2_irq()
401 dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); in rcar_gen3_phy_usb2_irq()
410 static int rcar_gen3_phy_usb2_init(struct phy *p) in rcar_gen3_phy_usb2_init()
413 struct rcar_gen3_chan *channel = rphy->ch; in rcar_gen3_phy_usb2_init()
414 void __iomem *usb2_base = channel->base; in rcar_gen3_phy_usb2_init()
418 if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) { in rcar_gen3_phy_usb2_init()
419 INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); in rcar_gen3_phy_usb2_init()
420 ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq, in rcar_gen3_phy_usb2_init()
421 IRQF_SHARED, dev_name(channel->dev), channel); in rcar_gen3_phy_usb2_init()
423 dev_err(channel->dev, "No irq handler (%d)\n", channel->irq); in rcar_gen3_phy_usb2_init()
428 /* Initialize USB2 part */ in rcar_gen3_phy_usb2_init()
430 val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits; in rcar_gen3_phy_usb2_init()
436 if (channel->is_otg_channel) { in rcar_gen3_phy_usb2_init()
439 rphy->otg_initialized = true; in rcar_gen3_phy_usb2_init()
442 rphy->initialized = true; in rcar_gen3_phy_usb2_init()
447 static int rcar_gen3_phy_usb2_exit(struct phy *p) in rcar_gen3_phy_usb2_exit()
450 struct rcar_gen3_chan *channel = rphy->ch; in rcar_gen3_phy_usb2_exit()
451 void __iomem *usb2_base = channel->base; in rcar_gen3_phy_usb2_exit()
454 rphy->initialized = false; in rcar_gen3_phy_usb2_exit()
456 if (channel->is_otg_channel) in rcar_gen3_phy_usb2_exit()
457 rphy->otg_initialized = false; in rcar_gen3_phy_usb2_exit()
460 val &= ~rphy->int_enable_bits; in rcar_gen3_phy_usb2_exit()
465 if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel)) in rcar_gen3_phy_usb2_exit()
466 free_irq(channel->irq, channel); in rcar_gen3_phy_usb2_exit()
471 static int rcar_gen3_phy_usb2_power_on(struct phy *p) in rcar_gen3_phy_usb2_power_on()
474 struct rcar_gen3_chan *channel = rphy->ch; in rcar_gen3_phy_usb2_power_on()
475 void __iomem *usb2_base = channel->base; in rcar_gen3_phy_usb2_power_on()
479 mutex_lock(&channel->lock); in rcar_gen3_phy_usb2_power_on()
483 if (channel->vbus) { in rcar_gen3_phy_usb2_power_on()
484 ret = regulator_enable(channel->vbus); in rcar_gen3_phy_usb2_power_on()
497 rphy->powered = true; in rcar_gen3_phy_usb2_power_on()
498 mutex_unlock(&channel->lock); in rcar_gen3_phy_usb2_power_on()
503 static int rcar_gen3_phy_usb2_power_off(struct phy *p) in rcar_gen3_phy_usb2_power_off()
506 struct rcar_gen3_chan *channel = rphy->ch; in rcar_gen3_phy_usb2_power_off()
509 mutex_lock(&channel->lock); in rcar_gen3_phy_usb2_power_off()
510 rphy->powered = false; in rcar_gen3_phy_usb2_power_off()
515 if (channel->vbus) in rcar_gen3_phy_usb2_power_off()
516 ret = regulator_disable(channel->vbus); in rcar_gen3_phy_usb2_power_off()
519 mutex_unlock(&channel->lock); in rcar_gen3_phy_usb2_power_off()
540 .compatible = "renesas,usb2-phy-r8a77470",
544 .compatible = "renesas,usb2-phy-r8a7795",
548 .compatible = "renesas,usb2-phy-r8a7796",
552 .compatible = "renesas,usb2-phy-r8a77965",
556 .compatible = "renesas,rcar-gen3-usb2-phy",
569 static struct phy *rcar_gen3_phy_usb2_xlate(struct device *dev, in rcar_gen3_phy_usb2_xlate()
574 if (args->args_count == 0) /* For old version dts */ in rcar_gen3_phy_usb2_xlate()
575 return ch->rphys[PHY_INDEX_BOTH_HC].phy; in rcar_gen3_phy_usb2_xlate()
576 else if (args->args_count > 1) /* Prevent invalid args count */ in rcar_gen3_phy_usb2_xlate()
577 return ERR_PTR(-ENODEV); in rcar_gen3_phy_usb2_xlate()
579 if (args->args[0] >= NUM_OF_PHYS) in rcar_gen3_phy_usb2_xlate()
580 return ERR_PTR(-ENODEV); in rcar_gen3_phy_usb2_xlate()
582 return ch->rphys[args->args[0]].phy; in rcar_gen3_phy_usb2_xlate()
611 struct device *dev = &pdev->dev; in rcar_gen3_phy_usb2_probe()
618 if (!dev->of_node) { in rcar_gen3_phy_usb2_probe()
620 return -EINVAL; in rcar_gen3_phy_usb2_probe()
625 return -ENOMEM; in rcar_gen3_phy_usb2_probe()
628 channel->base = devm_ioremap_resource(dev, res); in rcar_gen3_phy_usb2_probe()
629 if (IS_ERR(channel->base)) in rcar_gen3_phy_usb2_probe()
630 return PTR_ERR(channel->base); in rcar_gen3_phy_usb2_probe()
633 channel->irq = platform_get_irq_optional(pdev, 0); in rcar_gen3_phy_usb2_probe()
634 channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); in rcar_gen3_phy_usb2_probe()
635 if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { in rcar_gen3_phy_usb2_probe()
638 channel->is_otg_channel = true; in rcar_gen3_phy_usb2_probe()
639 channel->uses_otg_pins = !of_property_read_bool(dev->of_node, in rcar_gen3_phy_usb2_probe()
640 "renesas,no-otg-pins"); in rcar_gen3_phy_usb2_probe()
641 channel->extcon = devm_extcon_dev_allocate(dev, in rcar_gen3_phy_usb2_probe()
643 if (IS_ERR(channel->extcon)) in rcar_gen3_phy_usb2_probe()
644 return PTR_ERR(channel->extcon); in rcar_gen3_phy_usb2_probe()
646 ret = devm_extcon_dev_register(dev, channel->extcon); in rcar_gen3_phy_usb2_probe()
654 * devm_phy_create() will call pm_runtime_enable(&phy->dev); in rcar_gen3_phy_usb2_probe()
655 * And then, phy-core will manage runtime pm for this device. in rcar_gen3_phy_usb2_probe()
660 return -EINVAL; in rcar_gen3_phy_usb2_probe()
662 mutex_init(&channel->lock); in rcar_gen3_phy_usb2_probe()
664 channel->rphys[i].phy = devm_phy_create(dev, NULL, in rcar_gen3_phy_usb2_probe()
666 if (IS_ERR(channel->rphys[i].phy)) { in rcar_gen3_phy_usb2_probe()
667 dev_err(dev, "Failed to create USB2 PHY\n"); in rcar_gen3_phy_usb2_probe()
668 ret = PTR_ERR(channel->rphys[i].phy); in rcar_gen3_phy_usb2_probe()
671 channel->rphys[i].ch = channel; in rcar_gen3_phy_usb2_probe()
672 channel->rphys[i].int_enable_bits = rcar_gen3_int_enable[i]; in rcar_gen3_phy_usb2_probe()
673 phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); in rcar_gen3_phy_usb2_probe()
676 channel->vbus = devm_regulator_get_optional(dev, "vbus"); in rcar_gen3_phy_usb2_probe()
677 if (IS_ERR(channel->vbus)) { in rcar_gen3_phy_usb2_probe()
678 if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) { in rcar_gen3_phy_usb2_probe()
679 ret = PTR_ERR(channel->vbus); in rcar_gen3_phy_usb2_probe()
682 channel->vbus = NULL; in rcar_gen3_phy_usb2_probe()
686 channel->dev = dev; in rcar_gen3_phy_usb2_probe()
690 dev_err(dev, "Failed to register PHY provider\n"); in rcar_gen3_phy_usb2_probe()
693 } else if (channel->is_otg_channel) { in rcar_gen3_phy_usb2_probe()
713 if (channel->is_otg_channel) in rcar_gen3_phy_usb2_remove()
714 device_remove_file(&pdev->dev, &dev_attr_role); in rcar_gen3_phy_usb2_remove()
716 pm_runtime_disable(&pdev->dev); in rcar_gen3_phy_usb2_remove()
732 MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 2.0 PHY");