| .. | .. |
|---|
| 19 | 19 | |
|---|
| 20 | 20 | #include "ohci.h" |
|---|
| 21 | 21 | |
|---|
| 22 | | -#define DRIVER_DESC "OHCI EXYNOS driver" |
|---|
| 22 | +#define DRIVER_DESC "OHCI Exynos driver" |
|---|
| 23 | 23 | |
|---|
| 24 | 24 | static const char hcd_name[] = "ohci-exynos"; |
|---|
| 25 | 25 | static struct hc_driver __read_mostly exynos_ohci_hc_driver; |
|---|
| .. | .. |
|---|
| 30 | 30 | |
|---|
| 31 | 31 | struct exynos_ohci_hcd { |
|---|
| 32 | 32 | struct clk *clk; |
|---|
| 33 | + struct device_node *of_node; |
|---|
| 33 | 34 | struct phy *phy[PHY_NUMBER]; |
|---|
| 35 | + bool legacy_phy; |
|---|
| 34 | 36 | }; |
|---|
| 35 | 37 | |
|---|
| 36 | 38 | static int exynos_ohci_get_phy(struct device *dev, |
|---|
| .. | .. |
|---|
| 38 | 40 | { |
|---|
| 39 | 41 | struct device_node *child; |
|---|
| 40 | 42 | struct phy *phy; |
|---|
| 41 | | - int phy_number; |
|---|
| 43 | + int phy_number, num_phys; |
|---|
| 42 | 44 | int ret; |
|---|
| 43 | 45 | |
|---|
| 44 | 46 | /* Get PHYs for the controller */ |
|---|
| 47 | + num_phys = of_count_phandle_with_args(dev->of_node, "phys", |
|---|
| 48 | + "#phy-cells"); |
|---|
| 49 | + for (phy_number = 0; phy_number < num_phys; phy_number++) { |
|---|
| 50 | + phy = devm_of_phy_get_by_index(dev, dev->of_node, phy_number); |
|---|
| 51 | + if (IS_ERR(phy)) |
|---|
| 52 | + return PTR_ERR(phy); |
|---|
| 53 | + exynos_ohci->phy[phy_number] = phy; |
|---|
| 54 | + } |
|---|
| 55 | + if (num_phys > 0) |
|---|
| 56 | + return 0; |
|---|
| 57 | + |
|---|
| 58 | + /* Get PHYs using legacy bindings */ |
|---|
| 45 | 59 | for_each_available_child_of_node(dev->of_node, child) { |
|---|
| 46 | 60 | ret = of_property_read_u32(child, "reg", &phy_number); |
|---|
| 47 | 61 | if (ret) { |
|---|
| .. | .. |
|---|
| 72 | 86 | } |
|---|
| 73 | 87 | } |
|---|
| 74 | 88 | |
|---|
| 89 | + exynos_ohci->legacy_phy = true; |
|---|
| 75 | 90 | return 0; |
|---|
| 76 | 91 | } |
|---|
| 77 | 92 | |
|---|
| .. | .. |
|---|
| 169 | 184 | goto fail_io; |
|---|
| 170 | 185 | } |
|---|
| 171 | 186 | |
|---|
| 187 | + /* |
|---|
| 188 | + * Workaround: reset of_node pointer to avoid conflict between legacy |
|---|
| 189 | + * Exynos OHCI port subnodes and generic USB device bindings |
|---|
| 190 | + */ |
|---|
| 191 | + exynos_ohci->of_node = pdev->dev.of_node; |
|---|
| 192 | + if (exynos_ohci->legacy_phy) |
|---|
| 193 | + pdev->dev.of_node = NULL; |
|---|
| 194 | + |
|---|
| 172 | 195 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); |
|---|
| 173 | 196 | if (err) { |
|---|
| 174 | 197 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); |
|---|
| .. | .. |
|---|
| 179 | 202 | |
|---|
| 180 | 203 | fail_add_hcd: |
|---|
| 181 | 204 | exynos_ohci_phy_disable(&pdev->dev); |
|---|
| 205 | + pdev->dev.of_node = exynos_ohci->of_node; |
|---|
| 182 | 206 | fail_io: |
|---|
| 183 | 207 | clk_disable_unprepare(exynos_ohci->clk); |
|---|
| 184 | 208 | fail_clk: |
|---|
| .. | .. |
|---|
| 191 | 215 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
|---|
| 192 | 216 | struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); |
|---|
| 193 | 217 | |
|---|
| 218 | + pdev->dev.of_node = exynos_ohci->of_node; |
|---|
| 219 | + |
|---|
| 194 | 220 | usb_remove_hcd(hcd); |
|---|
| 195 | 221 | |
|---|
| 196 | 222 | exynos_ohci_phy_disable(&pdev->dev); |
|---|