Lines Matching +full:usb2 +full:- +full:phy0

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2014-2015 Hans de Goede <hdegoede@redhat.com>
18 #include <linux/extcon-provider.h>
28 #include <linux/phy/phy-sun4i-usb.h>
80 /* A83T specific control bits for PHY0 */
129 /* phy0 / otg related variables */
146 container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
154 iscr = readl(data->base + REG_ISCR); in sun4i_usb_phy0_update_iscr()
157 writel(iscr, data->base + REG_ISCR); in sun4i_usb_phy0_update_iscr()
184 u32 temp, usbc_bit = BIT(phy->index * 2); in sun4i_usb_phy_write()
185 void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset; in sun4i_usb_phy_write()
189 spin_lock_irqsave(&phy_data->reg_lock, flags); in sun4i_usb_phy_write()
191 if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) { in sun4i_usb_phy_write()
227 spin_unlock_irqrestore(&phy_data->reg_lock, flags); in sun4i_usb_phy_write()
235 if (!phy->pmu) in sun4i_usb_phy_passby()
241 /* A83T USB2 is HSIC */ in sun4i_usb_phy_passby()
242 if (phy_data->cfg->hsic_index && in sun4i_usb_phy_passby()
243 phy->index == phy_data->cfg->hsic_index) in sun4i_usb_phy_passby()
247 reg_value = readl(phy->pmu); in sun4i_usb_phy_passby()
254 writel(reg_value, phy->pmu); in sun4i_usb_phy_passby()
264 ret = clk_prepare_enable(phy->clk); in sun4i_usb_phy_init()
268 ret = clk_prepare_enable(phy->clk2); in sun4i_usb_phy_init()
270 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
274 ret = reset_control_deassert(phy->reset); in sun4i_usb_phy_init()
276 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
277 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
282 if (data->cfg->needs_phy2_siddq && phy->index != 2) { in sun4i_usb_phy_init()
283 struct sun4i_usb_phy *phy2 = &data->phys[2]; in sun4i_usb_phy_init()
285 ret = clk_prepare_enable(phy2->clk); in sun4i_usb_phy_init()
287 reset_control_assert(phy->reset); in sun4i_usb_phy_init()
288 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
289 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
293 ret = reset_control_deassert(phy2->reset); in sun4i_usb_phy_init()
295 clk_disable_unprepare(phy2->clk); in sun4i_usb_phy_init()
296 reset_control_assert(phy->reset); in sun4i_usb_phy_init()
297 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
298 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
306 ret = clk_prepare_enable(phy2->clk2); in sun4i_usb_phy_init()
308 reset_control_assert(phy2->reset); in sun4i_usb_phy_init()
309 clk_disable_unprepare(phy2->clk); in sun4i_usb_phy_init()
310 reset_control_assert(phy->reset); in sun4i_usb_phy_init()
311 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
312 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
316 if (phy2->pmu && data->cfg->hci_phy_ctl_clear) { in sun4i_usb_phy_init()
317 val = readl(phy2->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
318 val &= ~data->cfg->hci_phy_ctl_clear; in sun4i_usb_phy_init()
319 writel(val, phy2->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
322 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
325 if (phy->pmu && data->cfg->hci_phy_ctl_clear) { in sun4i_usb_phy_init()
326 val = readl(phy->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
327 val &= ~data->cfg->hci_phy_ctl_clear; in sun4i_usb_phy_init()
328 writel(val, phy->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
331 if (data->cfg->siddq_in_base) { in sun4i_usb_phy_init()
332 if (phy->index == 0) { in sun4i_usb_phy_init()
333 val = readl(data->base + data->cfg->phyctl_offset); in sun4i_usb_phy_init()
336 writel(val, data->base + data->cfg->phyctl_offset); in sun4i_usb_phy_init()
340 if (phy->index == 0) in sun4i_usb_phy_init()
348 data->cfg->disc_thresh, 2); in sun4i_usb_phy_init()
353 if (phy->index == 0) { in sun4i_usb_phy_init()
354 data->phy0_init = true; in sun4i_usb_phy_init()
356 /* Enable pull-ups */ in sun4i_usb_phy_init()
361 data->id_det = -1; in sun4i_usb_phy_init()
362 data->vbus_det = -1; in sun4i_usb_phy_init()
363 queue_delayed_work(system_wq, &data->detect, 0); in sun4i_usb_phy_init()
374 if (phy->index == 0) { in sun4i_usb_phy_exit()
375 if (data->cfg->siddq_in_base) { in sun4i_usb_phy_exit()
376 void __iomem *phyctl = data->base + in sun4i_usb_phy_exit()
377 data->cfg->phyctl_offset; in sun4i_usb_phy_exit()
382 /* Disable pull-ups */ in sun4i_usb_phy_exit()
385 data->phy0_init = false; in sun4i_usb_phy_exit()
388 if (data->cfg->needs_phy2_siddq && phy->index != 2) { in sun4i_usb_phy_exit()
389 struct sun4i_usb_phy *phy2 = &data->phys[2]; in sun4i_usb_phy_exit()
391 clk_disable_unprepare(phy2->clk); in sun4i_usb_phy_exit()
392 reset_control_assert(phy2->reset); in sun4i_usb_phy_exit()
396 reset_control_assert(phy->reset); in sun4i_usb_phy_exit()
397 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_exit()
398 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_exit()
405 switch (data->dr_mode) { in sun4i_usb_phy0_get_id_det()
407 if (data->id_det_gpio) in sun4i_usb_phy0_get_id_det()
408 return gpiod_get_value_cansleep(data->id_det_gpio); in sun4i_usb_phy0_get_id_det()
421 if (data->vbus_det_gpio) in sun4i_usb_phy0_get_vbus_det()
422 return gpiod_get_value_cansleep(data->vbus_det_gpio); in sun4i_usb_phy0_get_vbus_det()
424 if (data->vbus_power_supply) { in sun4i_usb_phy0_get_vbus_det()
428 r = power_supply_get_property(data->vbus_power_supply, in sun4i_usb_phy0_get_vbus_det()
440 return data->vbus_det_gpio || data->vbus_power_supply; in sun4i_usb_phy0_have_vbus_det()
445 if ((data->id_det_gpio && data->id_det_irq <= 0) || in sun4i_usb_phy0_poll()
446 (data->vbus_det_gpio && data->vbus_det_irq <= 0)) in sun4i_usb_phy0_poll()
453 * when using the pmic for vbus-det _and_ we're driving vbus. in sun4i_usb_phy0_poll()
455 if (data->cfg->poll_vbusen && data->vbus_power_supply && in sun4i_usb_phy0_poll()
456 data->phys[0].regulator_on) in sun4i_usb_phy0_poll()
468 if (!phy->vbus || phy->regulator_on) in sun4i_usb_phy_power_on()
471 /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ in sun4i_usb_phy_power_on()
472 if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) && in sun4i_usb_phy_power_on()
473 data->vbus_det) { in sun4i_usb_phy_power_on()
474 dev_warn(&_phy->dev, "External vbus detected, not enabling our own vbus\n"); in sun4i_usb_phy_power_on()
478 ret = regulator_enable(phy->vbus); in sun4i_usb_phy_power_on()
482 phy->regulator_on = true; in sun4i_usb_phy_power_on()
485 if (phy->index == 0 && sun4i_usb_phy0_poll(data)) in sun4i_usb_phy_power_on()
486 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); in sun4i_usb_phy_power_on()
496 if (!phy->vbus || !phy->regulator_on) in sun4i_usb_phy_power_off()
499 regulator_disable(phy->vbus); in sun4i_usb_phy_power_off()
500 phy->regulator_on = false; in sun4i_usb_phy_power_off()
503 * phy0 vbus typically slowly discharges, sometimes this causes the in sun4i_usb_phy_power_off()
506 if (phy->index == 0 && !sun4i_usb_phy0_poll(data)) in sun4i_usb_phy_power_off()
507 mod_delayed_work(system_wq, &data->detect, POLL_TIME); in sun4i_usb_phy_power_off()
519 if (phy->index != 0) { in sun4i_usb_phy_set_mode()
522 return -EINVAL; in sun4i_usb_phy_set_mode()
536 return -EINVAL; in sun4i_usb_phy_set_mode()
539 if (new_mode != data->dr_mode) { in sun4i_usb_phy_set_mode()
540 dev_info(&_phy->dev, "Changing dr_mode to %d\n", new_mode); in sun4i_usb_phy_set_mode()
541 data->dr_mode = new_mode; in sun4i_usb_phy_set_mode()
544 data->id_det = -1; /* Force reprocessing of id */ in sun4i_usb_phy_set_mode()
545 data->force_session_end = true; in sun4i_usb_phy_set_mode()
546 queue_delayed_work(system_wq, &data->detect, 0); in sun4i_usb_phy_set_mode()
572 regval = readl(data->base + REG_PHY_OTGCTL); in sun4i_usb_phy0_reroute()
574 /* Host mode. Route phy0 to EHCI/OHCI */ in sun4i_usb_phy0_reroute()
577 /* Peripheral mode. Route phy0 to MUSB */ in sun4i_usb_phy0_reroute()
580 writel(regval, data->base + REG_PHY_OTGCTL); in sun4i_usb_phy0_reroute()
587 struct phy *phy0 = data->phys[0].phy; in sun4i_usb_phy0_id_vbus_det_scan() local
592 if (!phy0) in sun4i_usb_phy0_id_vbus_det_scan()
595 phy = phy_get_drvdata(phy0); in sun4i_usb_phy0_id_vbus_det_scan()
599 mutex_lock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
601 if (!data->phy0_init) { in sun4i_usb_phy0_id_vbus_det_scan()
602 mutex_unlock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
606 force_session_end = data->force_session_end; in sun4i_usb_phy0_id_vbus_det_scan()
607 data->force_session_end = false; in sun4i_usb_phy0_id_vbus_det_scan()
609 if (id_det != data->id_det) { in sun4i_usb_phy0_id_vbus_det_scan()
610 /* id-change, force session end if we've no vbus detection */ in sun4i_usb_phy0_id_vbus_det_scan()
611 if (data->dr_mode == USB_DR_MODE_OTG && in sun4i_usb_phy0_id_vbus_det_scan()
617 sun4i_usb_phy0_set_vbus_detect(phy0, 0); in sun4i_usb_phy0_id_vbus_det_scan()
619 sun4i_usb_phy0_set_vbus_detect(phy0, 1); in sun4i_usb_phy0_id_vbus_det_scan()
621 sun4i_usb_phy0_set_id_detect(phy0, id_det); in sun4i_usb_phy0_id_vbus_det_scan()
622 data->id_det = id_det; in sun4i_usb_phy0_id_vbus_det_scan()
626 if (vbus_det != data->vbus_det) { in sun4i_usb_phy0_id_vbus_det_scan()
627 sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); in sun4i_usb_phy0_id_vbus_det_scan()
628 data->vbus_det = vbus_det; in sun4i_usb_phy0_id_vbus_det_scan()
632 mutex_unlock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
635 extcon_set_state_sync(data->extcon, EXTCON_USB_HOST, in sun4i_usb_phy0_id_vbus_det_scan()
639 mutex_lock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
640 sun4i_usb_phy0_set_vbus_detect(phy0, 0); in sun4i_usb_phy0_id_vbus_det_scan()
642 sun4i_usb_phy0_set_vbus_detect(phy0, 1); in sun4i_usb_phy0_id_vbus_det_scan()
643 mutex_unlock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
646 /* Enable PHY0 passby for host mode only. */ in sun4i_usb_phy0_id_vbus_det_scan()
649 /* Re-route PHY0 if necessary */ in sun4i_usb_phy0_id_vbus_det_scan()
650 if (data->cfg->phy0_dual_route) in sun4i_usb_phy0_id_vbus_det_scan()
655 extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det); in sun4i_usb_phy0_id_vbus_det_scan()
658 queue_delayed_work(system_wq, &data->detect, POLL_TIME); in sun4i_usb_phy0_id_vbus_det_scan()
666 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); in sun4i_usb_phy0_id_vbus_det_irq()
679 if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply) in sun4i_usb_phy0_vbus_notify()
680 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); in sun4i_usb_phy0_vbus_notify()
690 if (args->args[0] >= data->cfg->num_phys) in sun4i_usb_phy_xlate()
691 return ERR_PTR(-ENODEV); in sun4i_usb_phy_xlate()
693 if (data->cfg->missing_phys & BIT(args->args[0])) in sun4i_usb_phy_xlate()
694 return ERR_PTR(-ENODEV); in sun4i_usb_phy_xlate()
696 return data->phys[args->args[0]].phy; in sun4i_usb_phy_xlate()
701 struct device *dev = &pdev->dev; in sun4i_usb_phy_remove()
704 if (data->vbus_power_nb_registered) in sun4i_usb_phy_remove()
705 power_supply_unreg_notifier(&data->vbus_power_nb); in sun4i_usb_phy_remove()
706 if (data->id_det_irq > 0) in sun4i_usb_phy_remove()
707 devm_free_irq(dev, data->id_det_irq, data); in sun4i_usb_phy_remove()
708 if (data->vbus_det_irq > 0) in sun4i_usb_phy_remove()
709 devm_free_irq(dev, data->vbus_det_irq, data); in sun4i_usb_phy_remove()
711 cancel_delayed_work_sync(&data->detect); in sun4i_usb_phy_remove()
723 struct device *dev = &pdev->dev; in sun4i_usb_phy_probe()
724 struct device_node *np = dev->of_node; in sun4i_usb_phy_probe()
730 return -ENOMEM; in sun4i_usb_phy_probe()
732 spin_lock_init(&data->reg_lock); in sun4i_usb_phy_probe()
733 INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); in sun4i_usb_phy_probe()
735 data->cfg = of_device_get_match_data(dev); in sun4i_usb_phy_probe()
736 if (!data->cfg) in sun4i_usb_phy_probe()
737 return -EINVAL; in sun4i_usb_phy_probe()
739 data->base = devm_platform_ioremap_resource_byname(pdev, "phy_ctrl"); in sun4i_usb_phy_probe()
740 if (IS_ERR(data->base)) in sun4i_usb_phy_probe()
741 return PTR_ERR(data->base); in sun4i_usb_phy_probe()
743 data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det", in sun4i_usb_phy_probe()
745 if (IS_ERR(data->id_det_gpio)) { in sun4i_usb_phy_probe()
747 return PTR_ERR(data->id_det_gpio); in sun4i_usb_phy_probe()
750 data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det", in sun4i_usb_phy_probe()
752 if (IS_ERR(data->vbus_det_gpio)) { in sun4i_usb_phy_probe()
754 return PTR_ERR(data->vbus_det_gpio); in sun4i_usb_phy_probe()
757 if (of_property_present(np, "usb0_vbus_power-supply")) { in sun4i_usb_phy_probe()
758 data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, in sun4i_usb_phy_probe()
759 "usb0_vbus_power-supply"); in sun4i_usb_phy_probe()
760 if (IS_ERR(data->vbus_power_supply)) { in sun4i_usb_phy_probe()
762 return PTR_ERR(data->vbus_power_supply); in sun4i_usb_phy_probe()
765 if (!data->vbus_power_supply) in sun4i_usb_phy_probe()
766 return -EPROBE_DEFER; in sun4i_usb_phy_probe()
769 data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0); in sun4i_usb_phy_probe()
771 data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable); in sun4i_usb_phy_probe()
772 if (IS_ERR(data->extcon)) { in sun4i_usb_phy_probe()
774 return PTR_ERR(data->extcon); in sun4i_usb_phy_probe()
777 ret = devm_extcon_dev_register(dev, data->extcon); in sun4i_usb_phy_probe()
783 for (i = 0; i < data->cfg->num_phys; i++) { in sun4i_usb_phy_probe()
784 struct sun4i_usb_phy *phy = data->phys + i; in sun4i_usb_phy_probe()
787 if (data->cfg->missing_phys & BIT(i)) in sun4i_usb_phy_probe()
791 phy->vbus = devm_regulator_get_optional(dev, name); in sun4i_usb_phy_probe()
792 if (IS_ERR(phy->vbus)) { in sun4i_usb_phy_probe()
793 if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) { in sun4i_usb_phy_probe()
797 return -EPROBE_DEFER; in sun4i_usb_phy_probe()
800 phy->vbus = NULL; in sun4i_usb_phy_probe()
803 if (data->cfg->dedicated_clocks) in sun4i_usb_phy_probe()
808 phy->clk = devm_clk_get(dev, name); in sun4i_usb_phy_probe()
809 if (IS_ERR(phy->clk)) { in sun4i_usb_phy_probe()
811 return PTR_ERR(phy->clk); in sun4i_usb_phy_probe()
815 if (data->cfg->hsic_index && i == data->cfg->hsic_index) { in sun4i_usb_phy_probe()
818 phy->clk2 = devm_clk_get(dev, name); in sun4i_usb_phy_probe()
819 if (IS_ERR(phy->clk2)) { in sun4i_usb_phy_probe()
821 return PTR_ERR(phy->clk2); in sun4i_usb_phy_probe()
825 phy->clk2 = devm_clk_get_optional(dev, name); in sun4i_usb_phy_probe()
826 if (IS_ERR(phy->clk2)) { in sun4i_usb_phy_probe()
828 return PTR_ERR(phy->clk2); in sun4i_usb_phy_probe()
833 phy->reset = devm_reset_control_get(dev, name); in sun4i_usb_phy_probe()
834 if (IS_ERR(phy->reset)) { in sun4i_usb_phy_probe()
836 return PTR_ERR(phy->reset); in sun4i_usb_phy_probe()
839 if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */ in sun4i_usb_phy_probe()
841 phy->pmu = devm_platform_ioremap_resource_byname(pdev, name); in sun4i_usb_phy_probe()
842 if (IS_ERR(phy->pmu)) in sun4i_usb_phy_probe()
843 return PTR_ERR(phy->pmu); in sun4i_usb_phy_probe()
846 phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops); in sun4i_usb_phy_probe()
847 if (IS_ERR(phy->phy)) { in sun4i_usb_phy_probe()
849 return PTR_ERR(phy->phy); in sun4i_usb_phy_probe()
852 phy->index = i; in sun4i_usb_phy_probe()
853 phy_set_drvdata(phy->phy, &data->phys[i]); in sun4i_usb_phy_probe()
856 data->id_det_irq = gpiod_to_irq(data->id_det_gpio); in sun4i_usb_phy_probe()
857 if (data->id_det_irq > 0) { in sun4i_usb_phy_probe()
858 ret = devm_request_irq(dev, data->id_det_irq, in sun4i_usb_phy_probe()
861 "usb0-id-det", data); in sun4i_usb_phy_probe()
863 dev_err(dev, "Err requesting id-det-irq: %d\n", ret); in sun4i_usb_phy_probe()
868 data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); in sun4i_usb_phy_probe()
869 if (data->vbus_det_irq > 0) { in sun4i_usb_phy_probe()
870 ret = devm_request_irq(dev, data->vbus_det_irq, in sun4i_usb_phy_probe()
873 "usb0-vbus-det", data); in sun4i_usb_phy_probe()
875 dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret); in sun4i_usb_phy_probe()
876 data->vbus_det_irq = -1; in sun4i_usb_phy_probe()
882 if (data->vbus_power_supply) { in sun4i_usb_phy_probe()
883 data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify; in sun4i_usb_phy_probe()
884 data->vbus_power_nb.priority = 0; in sun4i_usb_phy_probe()
885 ret = power_supply_reg_notifier(&data->vbus_power_nb); in sun4i_usb_phy_probe()
890 data->vbus_power_nb_registered = true; in sun4i_usb_phy_probe()
1030 { .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
1031 { .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
1032 { .compatible = "allwinner,sun6i-a31-usb-phy", .data = &sun6i_a31_cfg },
1033 { .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
1034 { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
1035 { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
1036 { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg },
1037 { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
1038 { .compatible = "allwinner,sun8i-r40-usb-phy", .data = &sun8i_r40_cfg },
1039 { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
1040 { .compatible = "allwinner,sun20i-d1-usb-phy", .data = &sun20i_d1_cfg },
1041 { .compatible = "allwinner,sun50i-a64-usb-phy",
1043 { .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
1044 { .compatible = "allwinner,sun50i-h616-usb-phy", .data = &sun50i_h616_cfg },
1045 { .compatible = "allwinner,suniv-f1c100s-usb-phy",
1056 .name = "sun4i-usb-phy",