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

usb: ohci-exynos: Add facility to use phy provided by the generic phy framework

Add support to consume phy provided by Generic phy framework.
Keeping the support for older usb-phy intact right now, in order
to prevent any functionality break in absence of relevant
device tree side change for ohci-exynos.
Once we move to new phy in the device nodes for ohci, we can
remove the support for older phys.

Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
Cc: Jingoo Han <jg1.han@samsung.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vivek Gautam and committed by
Greg Kroah-Hartman
7d28e54b 91a9677a

+118 -16
+16
Documentation/devicetree/bindings/usb/exynos-usb.txt
··· 38 38 - interrupts: interrupt number to the cpu. 39 39 - clocks: from common clock binding: handle to usb clock. 40 40 - clock-names: from common clock binding: Shall be "usbhost". 41 + - port: if in the SoC there are OHCI phys, they should be listed here. 42 + One phy per port. Each port should have following entries: 43 + - reg: port number on OHCI controller, e.g 44 + On Exynos5250, port 0 is USB2.0 otg phy 45 + port 1 is HSIC phy0 46 + port 2 is HSIC phy1 47 + - phys: from the *Generic PHY* bindings, specifying phy used by port. 41 48 42 49 Example: 43 50 usb@12120000 { ··· 54 47 55 48 clocks = <&clock 285>; 56 49 clock-names = "usbhost"; 50 + 51 + #address-cells = <1>; 52 + #size-cells = <0>; 53 + port@0 { 54 + reg = <0>; 55 + phys = <&usb2phy 1>; 56 + status = "disabled"; 57 + }; 58 + 57 59 }; 58 60 59 61 DWC3
+102 -16
drivers/usb/host/ohci-exynos.c
··· 18 18 #include <linux/module.h> 19 19 #include <linux/of.h> 20 20 #include <linux/platform_device.h> 21 + #include <linux/phy/phy.h> 21 22 #include <linux/usb/phy.h> 22 23 #include <linux/usb/samsung_usb_phy.h> 23 24 #include <linux/usb.h> ··· 34 33 35 34 #define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv) 36 35 36 + #define PHY_NUMBER 3 37 + 37 38 struct exynos_ohci_hcd { 38 39 struct clk *clk; 39 40 struct usb_phy *phy; 40 41 struct usb_otg *otg; 42 + struct phy *phy_g[PHY_NUMBER]; 41 43 }; 42 44 43 - static void exynos_ohci_phy_enable(struct device *dev) 45 + static int exynos_ohci_get_phy(struct device *dev, 46 + struct exynos_ohci_hcd *exynos_ohci) 47 + { 48 + struct device_node *child; 49 + struct phy *phy; 50 + int phy_number; 51 + int ret = 0; 52 + 53 + exynos_ohci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 54 + if (IS_ERR(exynos_ohci->phy)) { 55 + ret = PTR_ERR(exynos_ohci->phy); 56 + if (ret != -ENXIO && ret != -ENODEV) { 57 + dev_err(dev, "no usb2 phy configured\n"); 58 + return ret; 59 + } 60 + dev_dbg(dev, "Failed to get usb2 phy\n"); 61 + } else { 62 + exynos_ohci->otg = exynos_ohci->phy->otg; 63 + } 64 + 65 + /* 66 + * Getting generic phy: 67 + * We are keeping both types of phys as a part of transiting OHCI 68 + * to generic phy framework, so as to maintain backward compatibilty 69 + * with old DTB. 70 + * If there are existing devices using DTB files built from them, 71 + * to remove the support for old bindings in this driver, 72 + * we need to make sure that such devices have their DTBs 73 + * updated to ones built from new DTS. 74 + */ 75 + for_each_available_child_of_node(dev->of_node, child) { 76 + ret = of_property_read_u32(child, "reg", &phy_number); 77 + if (ret) { 78 + dev_err(dev, "Failed to parse device tree\n"); 79 + of_node_put(child); 80 + return ret; 81 + } 82 + 83 + if (phy_number >= PHY_NUMBER) { 84 + dev_err(dev, "Invalid number of PHYs\n"); 85 + of_node_put(child); 86 + return -EINVAL; 87 + } 88 + 89 + phy = devm_of_phy_get(dev, child, 0); 90 + of_node_put(child); 91 + if (IS_ERR(phy)) { 92 + ret = PTR_ERR(phy); 93 + if (ret != -ENOSYS && ret != -ENODEV) { 94 + dev_err(dev, "no usb2 phy configured\n"); 95 + return ret; 96 + } 97 + dev_dbg(dev, "Failed to get usb2 phy\n"); 98 + } 99 + exynos_ohci->phy_g[phy_number] = phy; 100 + } 101 + 102 + return ret; 103 + } 104 + 105 + static int exynos_ohci_phy_enable(struct device *dev) 44 106 { 45 107 struct usb_hcd *hcd = dev_get_drvdata(dev); 46 108 struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); 109 + int i; 110 + int ret = 0; 47 111 48 - if (exynos_ohci->phy) 49 - usb_phy_init(exynos_ohci->phy); 112 + if (!IS_ERR(exynos_ohci->phy)) 113 + return usb_phy_init(exynos_ohci->phy); 114 + 115 + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) 116 + if (!IS_ERR(exynos_ohci->phy_g[i])) 117 + ret = phy_power_on(exynos_ohci->phy_g[i]); 118 + if (ret) 119 + for (i--; i >= 0; i--) 120 + if (!IS_ERR(exynos_ohci->phy_g[i])) 121 + phy_power_off(exynos_ohci->phy_g[i]); 122 + 123 + return ret; 50 124 } 51 125 52 126 static void exynos_ohci_phy_disable(struct device *dev) 53 127 { 54 128 struct usb_hcd *hcd = dev_get_drvdata(dev); 55 129 struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); 130 + int i; 56 131 57 - if (exynos_ohci->phy) 132 + if (!IS_ERR(exynos_ohci->phy)) { 58 133 usb_phy_shutdown(exynos_ohci->phy); 134 + return; 135 + } 136 + 137 + for (i = 0; i < PHY_NUMBER; i++) 138 + if (!IS_ERR(exynos_ohci->phy_g[i])) 139 + phy_power_off(exynos_ohci->phy_g[i]); 59 140 } 60 141 61 142 static int exynos_ohci_probe(struct platform_device *pdev) ··· 145 62 struct exynos_ohci_hcd *exynos_ohci; 146 63 struct usb_hcd *hcd; 147 64 struct resource *res; 148 - struct usb_phy *phy; 149 65 int irq; 150 66 int err; 151 67 ··· 170 88 "samsung,exynos5440-ohci")) 171 89 goto skip_phy; 172 90 173 - phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 174 - if (IS_ERR(phy)) { 175 - usb_put_hcd(hcd); 176 - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); 177 - return -EPROBE_DEFER; 178 - } else { 179 - exynos_ohci->phy = phy; 180 - exynos_ohci->otg = phy->otg; 181 - } 91 + err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); 92 + if (err) 93 + goto fail_clk; 182 94 183 95 skip_phy: 184 96 exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); ··· 215 139 216 140 platform_set_drvdata(pdev, hcd); 217 141 218 - exynos_ohci_phy_enable(&pdev->dev); 142 + err = exynos_ohci_phy_enable(&pdev->dev); 143 + if (err) { 144 + dev_err(&pdev->dev, "Failed to enable USB phy\n"); 145 + goto fail_io; 146 + } 219 147 220 148 err = usb_add_hcd(hcd, irq, IRQF_SHARED); 221 149 if (err) { ··· 290 210 { 291 211 struct usb_hcd *hcd = dev_get_drvdata(dev); 292 212 struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); 213 + int ret; 293 214 294 215 clk_prepare_enable(exynos_ohci->clk); 295 216 296 217 if (exynos_ohci->otg) 297 218 exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); 298 219 299 - exynos_ohci_phy_enable(dev); 220 + ret = exynos_ohci_phy_enable(dev); 221 + if (ret) { 222 + dev_err(dev, "Failed to enable USB phy\n"); 223 + clk_disable_unprepare(exynos_ohci->clk); 224 + return ret; 225 + } 300 226 301 227 ohci_resume(hcd, false); 302 228