Lines Matching +full:hsic +full:- +full:mode
1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2014-2015 Hans de Goede <[email protected]>
18 #include <linux/extcon-provider.h>
27 #include <linux/phy/phy-sun4i-usb.h>
84 /* A83T specific control bits for PHY2 HSIC */
145 container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
153 iscr = readl(data->base + REG_ISCR); in sun4i_usb_phy0_update_iscr()
156 writel(iscr, data->base + REG_ISCR); in sun4i_usb_phy0_update_iscr()
183 u32 temp, usbc_bit = BIT(phy->index * 2); in sun4i_usb_phy_write()
184 void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset; in sun4i_usb_phy_write()
188 spin_lock_irqsave(&phy_data->reg_lock, flags); in sun4i_usb_phy_write()
190 if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) { in sun4i_usb_phy_write()
226 spin_unlock_irqrestore(&phy_data->reg_lock, flags); in sun4i_usb_phy_write()
234 if (!phy->pmu) in sun4i_usb_phy_passby()
240 /* A83T USB2 is HSIC */ in sun4i_usb_phy_passby()
241 if (phy_data->cfg->hsic_index && in sun4i_usb_phy_passby()
242 phy->index == phy_data->cfg->hsic_index) in sun4i_usb_phy_passby()
246 reg_value = readl(phy->pmu); in sun4i_usb_phy_passby()
253 writel(reg_value, phy->pmu); in sun4i_usb_phy_passby()
263 ret = clk_prepare_enable(phy->clk); in sun4i_usb_phy_init()
267 ret = clk_prepare_enable(phy->clk2); in sun4i_usb_phy_init()
269 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
273 ret = reset_control_deassert(phy->reset); in sun4i_usb_phy_init()
275 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
276 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
281 if (data->cfg->needs_phy2_siddq && phy->index != 2) { in sun4i_usb_phy_init()
282 struct sun4i_usb_phy *phy2 = &data->phys[2]; in sun4i_usb_phy_init()
284 ret = clk_prepare_enable(phy2->clk); in sun4i_usb_phy_init()
286 reset_control_assert(phy->reset); in sun4i_usb_phy_init()
287 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
288 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
292 ret = reset_control_deassert(phy2->reset); in sun4i_usb_phy_init()
294 clk_disable_unprepare(phy2->clk); in sun4i_usb_phy_init()
295 reset_control_assert(phy->reset); in sun4i_usb_phy_init()
296 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
297 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
305 ret = clk_prepare_enable(phy2->clk2); in sun4i_usb_phy_init()
307 reset_control_assert(phy2->reset); in sun4i_usb_phy_init()
308 clk_disable_unprepare(phy2->clk); in sun4i_usb_phy_init()
309 reset_control_assert(phy->reset); in sun4i_usb_phy_init()
310 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
311 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_init()
315 if (phy2->pmu && data->cfg->hci_phy_ctl_clear) { in sun4i_usb_phy_init()
316 val = readl(phy2->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
317 val &= ~data->cfg->hci_phy_ctl_clear; in sun4i_usb_phy_init()
318 writel(val, phy2->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
321 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_init()
324 if (phy->pmu && data->cfg->hci_phy_ctl_clear) { in sun4i_usb_phy_init()
325 val = readl(phy->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
326 val &= ~data->cfg->hci_phy_ctl_clear; in sun4i_usb_phy_init()
327 writel(val, phy->pmu + REG_HCI_PHY_CTL); in sun4i_usb_phy_init()
330 if (data->cfg->siddq_in_base) { in sun4i_usb_phy_init()
331 if (phy->index == 0) { in sun4i_usb_phy_init()
332 val = readl(data->base + data->cfg->phyctl_offset); in sun4i_usb_phy_init()
335 writel(val, data->base + data->cfg->phyctl_offset); in sun4i_usb_phy_init()
339 if (phy->index == 0) in sun4i_usb_phy_init()
347 data->cfg->disc_thresh, 2); in sun4i_usb_phy_init()
352 if (phy->index == 0) { in sun4i_usb_phy_init()
353 data->phy0_init = true; in sun4i_usb_phy_init()
355 /* Enable pull-ups */ in sun4i_usb_phy_init()
360 data->id_det = -1; in sun4i_usb_phy_init()
361 data->vbus_det = -1; in sun4i_usb_phy_init()
362 queue_delayed_work(system_wq, &data->detect, 0); in sun4i_usb_phy_init()
373 if (phy->index == 0) { in sun4i_usb_phy_exit()
374 if (data->cfg->siddq_in_base) { in sun4i_usb_phy_exit()
375 void __iomem *phyctl = data->base + in sun4i_usb_phy_exit()
376 data->cfg->phyctl_offset; in sun4i_usb_phy_exit()
381 /* Disable pull-ups */ in sun4i_usb_phy_exit()
384 data->phy0_init = false; in sun4i_usb_phy_exit()
387 if (data->cfg->needs_phy2_siddq && phy->index != 2) { in sun4i_usb_phy_exit()
388 struct sun4i_usb_phy *phy2 = &data->phys[2]; in sun4i_usb_phy_exit()
390 clk_disable_unprepare(phy2->clk); in sun4i_usb_phy_exit()
391 reset_control_assert(phy2->reset); in sun4i_usb_phy_exit()
395 reset_control_assert(phy->reset); in sun4i_usb_phy_exit()
396 clk_disable_unprepare(phy->clk2); in sun4i_usb_phy_exit()
397 clk_disable_unprepare(phy->clk); in sun4i_usb_phy_exit()
404 switch (data->dr_mode) { in sun4i_usb_phy0_get_id_det()
406 if (data->id_det_gpio) in sun4i_usb_phy0_get_id_det()
407 return gpiod_get_value_cansleep(data->id_det_gpio); in sun4i_usb_phy0_get_id_det()
409 return 1; /* Fallback to peripheral mode */ in sun4i_usb_phy0_get_id_det()
420 if (data->vbus_det_gpio) in sun4i_usb_phy0_get_vbus_det()
421 return gpiod_get_value_cansleep(data->vbus_det_gpio); in sun4i_usb_phy0_get_vbus_det()
423 if (data->vbus_power_supply) { in sun4i_usb_phy0_get_vbus_det()
427 r = power_supply_get_property(data->vbus_power_supply, in sun4i_usb_phy0_get_vbus_det()
439 return data->vbus_det_gpio || data->vbus_power_supply; in sun4i_usb_phy0_have_vbus_det()
444 if ((data->id_det_gpio && data->id_det_irq <= 0) || in sun4i_usb_phy0_poll()
445 (data->vbus_det_gpio && data->vbus_det_irq <= 0)) in sun4i_usb_phy0_poll()
452 * when using the pmic for vbus-det _and_ we're driving vbus. in sun4i_usb_phy0_poll()
454 if (data->cfg->poll_vbusen && data->vbus_power_supply && in sun4i_usb_phy0_poll()
455 data->phys[0].regulator_on) in sun4i_usb_phy0_poll()
467 if (!phy->vbus || phy->regulator_on) in sun4i_usb_phy_power_on()
471 if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) && in sun4i_usb_phy_power_on()
472 data->vbus_det) { in sun4i_usb_phy_power_on()
473 dev_warn(&_phy->dev, "External vbus detected, not enabling our own vbus\n"); in sun4i_usb_phy_power_on()
477 ret = regulator_enable(phy->vbus); in sun4i_usb_phy_power_on()
481 phy->regulator_on = true; in sun4i_usb_phy_power_on()
484 if (phy->index == 0 && sun4i_usb_phy0_poll(data)) in sun4i_usb_phy_power_on()
485 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); in sun4i_usb_phy_power_on()
495 if (!phy->vbus || !phy->regulator_on) in sun4i_usb_phy_power_off()
498 regulator_disable(phy->vbus); in sun4i_usb_phy_power_off()
499 phy->regulator_on = false; in sun4i_usb_phy_power_off()
505 if (phy->index == 0 && !sun4i_usb_phy0_poll(data)) in sun4i_usb_phy_power_off()
506 mod_delayed_work(system_wq, &data->detect, POLL_TIME); in sun4i_usb_phy_power_off()
512 enum phy_mode mode, int submode) in sun4i_usb_phy_set_mode() argument
518 if (phy->index != 0) { in sun4i_usb_phy_set_mode()
519 if (mode == PHY_MODE_USB_HOST) in sun4i_usb_phy_set_mode()
521 return -EINVAL; in sun4i_usb_phy_set_mode()
524 switch (mode) { in sun4i_usb_phy_set_mode()
535 return -EINVAL; in sun4i_usb_phy_set_mode()
538 if (new_mode != data->dr_mode) { in sun4i_usb_phy_set_mode()
539 dev_info(&_phy->dev, "Changing dr_mode to %d\n", new_mode); in sun4i_usb_phy_set_mode()
540 data->dr_mode = new_mode; in sun4i_usb_phy_set_mode()
543 data->id_det = -1; /* Force reprocessing of id */ in sun4i_usb_phy_set_mode()
544 data->force_session_end = true; in sun4i_usb_phy_set_mode()
545 queue_delayed_work(system_wq, &data->detect, 0); in sun4i_usb_phy_set_mode()
571 regval = readl(data->base + REG_PHY_OTGCTL); in sun4i_usb_phy0_reroute()
573 /* Host mode. Route phy0 to EHCI/OHCI */ in sun4i_usb_phy0_reroute()
576 /* Peripheral mode. Route phy0 to MUSB */ in sun4i_usb_phy0_reroute()
579 writel(regval, data->base + REG_PHY_OTGCTL); in sun4i_usb_phy0_reroute()
586 struct phy *phy0 = data->phys[0].phy; in sun4i_usb_phy0_id_vbus_det_scan()
598 mutex_lock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
600 if (!data->phy0_init) { in sun4i_usb_phy0_id_vbus_det_scan()
601 mutex_unlock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
605 force_session_end = data->force_session_end; in sun4i_usb_phy0_id_vbus_det_scan()
606 data->force_session_end = false; in sun4i_usb_phy0_id_vbus_det_scan()
608 if (id_det != data->id_det) { in sun4i_usb_phy0_id_vbus_det_scan()
609 /* id-change, force session end if we've no vbus detection */ in sun4i_usb_phy0_id_vbus_det_scan()
610 if (data->dr_mode == USB_DR_MODE_OTG && in sun4i_usb_phy0_id_vbus_det_scan()
614 /* When entering host mode (id = 0) force end the session now */ in sun4i_usb_phy0_id_vbus_det_scan()
621 data->id_det = id_det; in sun4i_usb_phy0_id_vbus_det_scan()
625 if (vbus_det != data->vbus_det) { in sun4i_usb_phy0_id_vbus_det_scan()
627 data->vbus_det = vbus_det; in sun4i_usb_phy0_id_vbus_det_scan()
631 mutex_unlock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
634 extcon_set_state_sync(data->extcon, EXTCON_USB_HOST, in sun4i_usb_phy0_id_vbus_det_scan()
636 /* When leaving host mode force end the session here */ in sun4i_usb_phy0_id_vbus_det_scan()
638 mutex_lock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
642 mutex_unlock(&phy0->mutex); in sun4i_usb_phy0_id_vbus_det_scan()
645 /* Enable PHY0 passby for host mode only. */ in sun4i_usb_phy0_id_vbus_det_scan()
648 /* Re-route PHY0 if necessary */ in sun4i_usb_phy0_id_vbus_det_scan()
649 if (data->cfg->phy0_dual_route) in sun4i_usb_phy0_id_vbus_det_scan()
654 extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det); in sun4i_usb_phy0_id_vbus_det_scan()
657 queue_delayed_work(system_wq, &data->detect, POLL_TIME); in sun4i_usb_phy0_id_vbus_det_scan()
665 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); in sun4i_usb_phy0_id_vbus_det_irq()
678 if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply) in sun4i_usb_phy0_vbus_notify()
679 mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); in sun4i_usb_phy0_vbus_notify()
689 if (args->args[0] >= data->cfg->num_phys) in sun4i_usb_phy_xlate()
690 return ERR_PTR(-ENODEV); in sun4i_usb_phy_xlate()
692 if (data->cfg->missing_phys & BIT(args->args[0])) in sun4i_usb_phy_xlate()
693 return ERR_PTR(-ENODEV); in sun4i_usb_phy_xlate()
695 return data->phys[args->args[0]].phy; in sun4i_usb_phy_xlate()
700 struct device *dev = &pdev->dev; in sun4i_usb_phy_remove()
703 if (data->vbus_power_nb_registered) in sun4i_usb_phy_remove()
704 power_supply_unreg_notifier(&data->vbus_power_nb); in sun4i_usb_phy_remove()
705 if (data->id_det_irq > 0) in sun4i_usb_phy_remove()
706 devm_free_irq(dev, data->id_det_irq, data); in sun4i_usb_phy_remove()
707 if (data->vbus_det_irq > 0) in sun4i_usb_phy_remove()
708 devm_free_irq(dev, data->vbus_det_irq, data); in sun4i_usb_phy_remove()
710 cancel_delayed_work_sync(&data->detect); in sun4i_usb_phy_remove()
722 struct device *dev = &pdev->dev; in sun4i_usb_phy_probe()
723 struct device_node *np = dev->of_node; in sun4i_usb_phy_probe()
729 return -ENOMEM; in sun4i_usb_phy_probe()
731 spin_lock_init(&data->reg_lock); in sun4i_usb_phy_probe()
732 INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); in sun4i_usb_phy_probe()
734 data->cfg = of_device_get_match_data(dev); in sun4i_usb_phy_probe()
735 if (!data->cfg) in sun4i_usb_phy_probe()
736 return -EINVAL; in sun4i_usb_phy_probe()
738 data->base = devm_platform_ioremap_resource_byname(pdev, "phy_ctrl"); in sun4i_usb_phy_probe()
739 if (IS_ERR(data->base)) in sun4i_usb_phy_probe()
740 return PTR_ERR(data->base); in sun4i_usb_phy_probe()
742 data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det", in sun4i_usb_phy_probe()
744 if (IS_ERR(data->id_det_gpio)) { in sun4i_usb_phy_probe()
746 return PTR_ERR(data->id_det_gpio); in sun4i_usb_phy_probe()
749 data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det", in sun4i_usb_phy_probe()
751 if (IS_ERR(data->vbus_det_gpio)) { in sun4i_usb_phy_probe()
753 return PTR_ERR(data->vbus_det_gpio); in sun4i_usb_phy_probe()
756 if (of_property_present(np, "usb0_vbus_power-supply")) { in sun4i_usb_phy_probe()
757 data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, in sun4i_usb_phy_probe()
758 "usb0_vbus_power-supply"); in sun4i_usb_phy_probe()
759 if (IS_ERR(data->vbus_power_supply)) { in sun4i_usb_phy_probe()
761 return PTR_ERR(data->vbus_power_supply); in sun4i_usb_phy_probe()
764 if (!data->vbus_power_supply) in sun4i_usb_phy_probe()
765 return -EPROBE_DEFER; in sun4i_usb_phy_probe()
768 data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0); in sun4i_usb_phy_probe()
770 data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable); in sun4i_usb_phy_probe()
771 if (IS_ERR(data->extcon)) { in sun4i_usb_phy_probe()
773 return PTR_ERR(data->extcon); in sun4i_usb_phy_probe()
776 ret = devm_extcon_dev_register(dev, data->extcon); in sun4i_usb_phy_probe()
782 for (i = 0; i < data->cfg->num_phys; i++) { in sun4i_usb_phy_probe()
783 struct sun4i_usb_phy *phy = data->phys + i; in sun4i_usb_phy_probe()
786 if (data->cfg->missing_phys & BIT(i)) in sun4i_usb_phy_probe()
790 phy->vbus = devm_regulator_get_optional(dev, name); in sun4i_usb_phy_probe()
791 if (IS_ERR(phy->vbus)) { in sun4i_usb_phy_probe()
792 if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) { in sun4i_usb_phy_probe()
796 return -EPROBE_DEFER; in sun4i_usb_phy_probe()
799 phy->vbus = NULL; in sun4i_usb_phy_probe()
802 if (data->cfg->dedicated_clocks) in sun4i_usb_phy_probe()
807 phy->clk = devm_clk_get(dev, name); in sun4i_usb_phy_probe()
808 if (IS_ERR(phy->clk)) { in sun4i_usb_phy_probe()
810 return PTR_ERR(phy->clk); in sun4i_usb_phy_probe()
813 /* The first PHY is always tied to OTG, and never HSIC */ in sun4i_usb_phy_probe()
814 if (data->cfg->hsic_index && i == data->cfg->hsic_index) { in sun4i_usb_phy_probe()
815 /* HSIC needs secondary clock */ in sun4i_usb_phy_probe()
817 phy->clk2 = devm_clk_get(dev, name); in sun4i_usb_phy_probe()
818 if (IS_ERR(phy->clk2)) { in sun4i_usb_phy_probe()
820 return PTR_ERR(phy->clk2); in sun4i_usb_phy_probe()
824 phy->clk2 = devm_clk_get_optional(dev, name); in sun4i_usb_phy_probe()
825 if (IS_ERR(phy->clk2)) { in sun4i_usb_phy_probe()
827 return PTR_ERR(phy->clk2); in sun4i_usb_phy_probe()
832 phy->reset = devm_reset_control_get(dev, name); in sun4i_usb_phy_probe()
833 if (IS_ERR(phy->reset)) { in sun4i_usb_phy_probe()
835 return PTR_ERR(phy->reset); in sun4i_usb_phy_probe()
838 if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */ in sun4i_usb_phy_probe()
840 phy->pmu = devm_platform_ioremap_resource_byname(pdev, name); in sun4i_usb_phy_probe()
841 if (IS_ERR(phy->pmu)) in sun4i_usb_phy_probe()
842 return PTR_ERR(phy->pmu); in sun4i_usb_phy_probe()
845 phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops); in sun4i_usb_phy_probe()
846 if (IS_ERR(phy->phy)) { in sun4i_usb_phy_probe()
848 return PTR_ERR(phy->phy); in sun4i_usb_phy_probe()
851 phy->index = i; in sun4i_usb_phy_probe()
852 phy_set_drvdata(phy->phy, &data->phys[i]); in sun4i_usb_phy_probe()
855 data->id_det_irq = gpiod_to_irq(data->id_det_gpio); in sun4i_usb_phy_probe()
856 if (data->id_det_irq > 0) { in sun4i_usb_phy_probe()
857 ret = devm_request_irq(dev, data->id_det_irq, in sun4i_usb_phy_probe()
860 "usb0-id-det", data); in sun4i_usb_phy_probe()
862 dev_err(dev, "Err requesting id-det-irq: %d\n", ret); in sun4i_usb_phy_probe()
867 data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); in sun4i_usb_phy_probe()
868 if (data->vbus_det_irq > 0) { in sun4i_usb_phy_probe()
869 ret = devm_request_irq(dev, data->vbus_det_irq, in sun4i_usb_phy_probe()
872 "usb0-vbus-det", data); in sun4i_usb_phy_probe()
874 dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret); in sun4i_usb_phy_probe()
875 data->vbus_det_irq = -1; in sun4i_usb_phy_probe()
881 if (data->vbus_power_supply) { in sun4i_usb_phy_probe()
882 data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify; in sun4i_usb_phy_probe()
883 data->vbus_power_nb.priority = 0; in sun4i_usb_phy_probe()
884 ret = power_supply_reg_notifier(&data->vbus_power_nb); in sun4i_usb_phy_probe()
889 data->vbus_power_nb_registered = true; in sun4i_usb_phy_probe()
1029 { .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
1030 { .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
1031 { .compatible = "allwinner,sun6i-a31-usb-phy", .data = &sun6i_a31_cfg },
1032 { .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
1033 { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
1034 { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
1035 { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg },
1036 { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
1037 { .compatible = "allwinner,sun8i-r40-usb-phy", .data = &sun8i_r40_cfg },
1038 { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
1039 { .compatible = "allwinner,sun20i-d1-usb-phy", .data = &sun20i_d1_cfg },
1040 { .compatible = "allwinner,sun50i-a64-usb-phy",
1042 { .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
1043 { .compatible = "allwinner,sun50i-h616-usb-phy", .data = &sun50i_h616_cfg },
1044 { .compatible = "allwinner,suniv-f1c100s-usb-phy",
1055 .name = "sun4i-usb-phy",