Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: phy: msm: Add D+/D- lines route control

apq8016-sbc board is using Dual SPDT USB Switch (TC7USB40MU),
witch is controlled by GPIO to de/multiplex D+/D- USB lines to
USB2513B Hub and uB connector. Add support for this.

Signed-off-by: Ivan T. Ivanov <ivan.ivanov@linaro.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Ivan T. Ivanov and committed by
Felipe Balbi
6f98f545 736d093b

+58
+4
Documentation/devicetree/bindings/usb/msm-hsusb.txt
··· 52 52 Optional properties: 53 53 - dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" 54 54 55 + - switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual 56 + SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex 57 + D+/D- USB lines between connectors. 58 + 55 59 - qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device 56 60 Mode Eye Diagram test. Start address at which these values will be 57 61 written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
+47
drivers/usb/phy/phy-msm-usb.c
··· 18 18 19 19 #include <linux/module.h> 20 20 #include <linux/device.h> 21 + #include <linux/gpio/consumer.h> 21 22 #include <linux/platform_device.h> 22 23 #include <linux/clk.h> 23 24 #include <linux/slab.h> ··· 33 32 #include <linux/pm_runtime.h> 34 33 #include <linux/of.h> 35 34 #include <linux/of_device.h> 35 + #include <linux/reboot.h> 36 36 #include <linux/reset.h> 37 37 38 38 #include <linux/usb.h> ··· 1473 1471 else 1474 1472 clear_bit(B_SESS_VLD, &motg->inputs); 1475 1473 1474 + if (test_bit(B_SESS_VLD, &motg->inputs)) { 1475 + /* Switch D+/D- lines to Device connector */ 1476 + gpiod_set_value_cansleep(motg->switch_gpio, 0); 1477 + } else { 1478 + /* Switch D+/D- lines to Hub */ 1479 + gpiod_set_value_cansleep(motg->switch_gpio, 1); 1480 + } 1481 + 1476 1482 schedule_work(&motg->sm_work); 1477 1483 1478 1484 return NOTIFY_DONE; ··· 1556 1546 1557 1547 motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup"); 1558 1548 1549 + motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch", 1550 + GPIOD_OUT_LOW); 1551 + if (IS_ERR(motg->switch_gpio)) 1552 + return PTR_ERR(motg->switch_gpio); 1553 + 1559 1554 ext_id = ERR_PTR(-ENODEV); 1560 1555 ext_vbus = ERR_PTR(-ENODEV); 1561 1556 if (of_property_read_bool(node, "extcon")) { ··· 1630 1615 pdata->phy_init_sz = words; 1631 1616 1632 1617 return 0; 1618 + } 1619 + 1620 + static int msm_otg_reboot_notify(struct notifier_block *this, 1621 + unsigned long code, void *unused) 1622 + { 1623 + struct msm_otg *motg = container_of(this, struct msm_otg, reboot); 1624 + 1625 + /* 1626 + * Ensure that D+/D- lines are routed to uB connector, so 1627 + * we could load bootloader/kernel at next reboot 1628 + */ 1629 + gpiod_set_value_cansleep(motg->switch_gpio, 0); 1630 + return NOTIFY_DONE; 1633 1631 } 1634 1632 1635 1633 static int msm_otg_probe(struct platform_device *pdev) ··· 1809 1781 dev_dbg(&pdev->dev, "Can not create mode change file\n"); 1810 1782 } 1811 1783 1784 + if (test_bit(B_SESS_VLD, &motg->inputs)) { 1785 + /* Switch D+/D- lines to Device connector */ 1786 + gpiod_set_value_cansleep(motg->switch_gpio, 0); 1787 + } else { 1788 + /* Switch D+/D- lines to Hub */ 1789 + gpiod_set_value_cansleep(motg->switch_gpio, 1); 1790 + } 1791 + 1792 + motg->reboot.notifier_call = msm_otg_reboot_notify; 1793 + register_reboot_notifier(&motg->reboot); 1794 + 1812 1795 pm_runtime_set_active(&pdev->dev); 1813 1796 pm_runtime_enable(&pdev->dev); 1814 1797 ··· 1845 1806 1846 1807 if (phy->otg->host || phy->otg->gadget) 1847 1808 return -EBUSY; 1809 + 1810 + unregister_reboot_notifier(&motg->reboot); 1811 + 1812 + /* 1813 + * Ensure that D+/D- lines are routed to uB connector, so 1814 + * we could load bootloader/kernel at next reboot 1815 + */ 1816 + gpiod_set_value_cansleep(motg->switch_gpio, 0); 1848 1817 1849 1818 extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); 1850 1819 extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb);
+7
include/linux/usb/msm_hsusb.h
··· 155 155 * starting controller using usbcmd run/stop bit. 156 156 * @vbus: VBUS signal state trakining, using extcon framework 157 157 * @id: ID signal state trakining, using extcon framework 158 + * @switch_gpio: Descriptor for GPIO used to control external Dual 159 + * SPDT USB Switch. 160 + * @reboot: Used to inform the driver to route USB D+/D- line to Device 161 + * connector 158 162 */ 159 163 struct msm_otg { 160 164 struct usb_phy phy; ··· 192 188 193 189 struct msm_usb_cable vbus; 194 190 struct msm_usb_cable id; 191 + 192 + struct gpio_desc *switch_gpio; 193 + struct notifier_block reboot; 195 194 }; 196 195 197 196 #endif