diff options
author | Vivek Gautam <gautam.vivek@samsung.com> | 2013-01-22 08:00:43 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-23 06:39:22 -0500 |
commit | ed993bf19b98fdb0d364913174b5001fc3ac199b (patch) | |
tree | 61c2426b760ab6c4993204da7c4ccfaeb6042711 /drivers/usb/host | |
parent | d233c196ce1a3a33901b75ca818c85825683afba (diff) |
USB: ohci-exynos: Add phy driver support
Adding the phy-driver to ohci-exynos. Keeping the platform data
for continuing the smooth operation for boards which still uses it
Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ohci-exynos.c | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 804fb62a888c..1b3840980177 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/platform_data/usb-exynos.h> | 17 | #include <linux/platform_data/usb-exynos.h> |
18 | #include <linux/usb/phy.h> | ||
18 | #include <linux/usb/samsung_usb_phy.h> | 19 | #include <linux/usb/samsung_usb_phy.h> |
19 | #include <plat/usb-phy.h> | 20 | #include <plat/usb-phy.h> |
20 | 21 | ||
@@ -22,8 +23,31 @@ struct exynos_ohci_hcd { | |||
22 | struct device *dev; | 23 | struct device *dev; |
23 | struct usb_hcd *hcd; | 24 | struct usb_hcd *hcd; |
24 | struct clk *clk; | 25 | struct clk *clk; |
26 | struct usb_phy *phy; | ||
27 | struct usb_otg *otg; | ||
28 | struct exynos4_ohci_platdata *pdata; | ||
25 | }; | 29 | }; |
26 | 30 | ||
31 | static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) | ||
32 | { | ||
33 | struct platform_device *pdev = to_platform_device(exynos_ohci->dev); | ||
34 | |||
35 | if (exynos_ohci->phy) | ||
36 | usb_phy_init(exynos_ohci->phy); | ||
37 | else if (exynos_ohci->pdata->phy_init) | ||
38 | exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | ||
39 | } | ||
40 | |||
41 | static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) | ||
42 | { | ||
43 | struct platform_device *pdev = to_platform_device(exynos_ohci->dev); | ||
44 | |||
45 | if (exynos_ohci->phy) | ||
46 | usb_phy_shutdown(exynos_ohci->phy); | ||
47 | else if (exynos_ohci->pdata->phy_exit) | ||
48 | exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | ||
49 | } | ||
50 | |||
27 | static int ohci_exynos_reset(struct usb_hcd *hcd) | 51 | static int ohci_exynos_reset(struct usb_hcd *hcd) |
28 | { | 52 | { |
29 | return ohci_init(hcd_to_ohci(hcd)); | 53 | return ohci_init(hcd_to_ohci(hcd)); |
@@ -79,20 +103,15 @@ static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32); | |||
79 | 103 | ||
80 | static int exynos_ohci_probe(struct platform_device *pdev) | 104 | static int exynos_ohci_probe(struct platform_device *pdev) |
81 | { | 105 | { |
82 | struct exynos4_ohci_platdata *pdata; | 106 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; |
83 | struct exynos_ohci_hcd *exynos_ohci; | 107 | struct exynos_ohci_hcd *exynos_ohci; |
84 | struct usb_hcd *hcd; | 108 | struct usb_hcd *hcd; |
85 | struct ohci_hcd *ohci; | 109 | struct ohci_hcd *ohci; |
86 | struct resource *res; | 110 | struct resource *res; |
111 | struct usb_phy *phy; | ||
87 | int irq; | 112 | int irq; |
88 | int err; | 113 | int err; |
89 | 114 | ||
90 | pdata = pdev->dev.platform_data; | ||
91 | if (!pdata) { | ||
92 | dev_err(&pdev->dev, "No platform data defined\n"); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | |||
96 | /* | 115 | /* |
97 | * Right now device-tree probed devices don't get dma_mask set. | 116 | * Right now device-tree probed devices don't get dma_mask set. |
98 | * Since shared usb code relies on it, set it here for now. | 117 | * Since shared usb code relies on it, set it here for now. |
@@ -108,6 +127,20 @@ static int exynos_ohci_probe(struct platform_device *pdev) | |||
108 | if (!exynos_ohci) | 127 | if (!exynos_ohci) |
109 | return -ENOMEM; | 128 | return -ENOMEM; |
110 | 129 | ||
130 | phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); | ||
131 | if (IS_ERR_OR_NULL(phy)) { | ||
132 | /* Fallback to pdata */ | ||
133 | if (!pdata) { | ||
134 | dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); | ||
135 | return -EPROBE_DEFER; | ||
136 | } else { | ||
137 | exynos_ohci->pdata = pdata; | ||
138 | } | ||
139 | } else { | ||
140 | exynos_ohci->phy = phy; | ||
141 | exynos_ohci->otg = phy->otg; | ||
142 | } | ||
143 | |||
111 | exynos_ohci->dev = &pdev->dev; | 144 | exynos_ohci->dev = &pdev->dev; |
112 | 145 | ||
113 | hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, | 146 | hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, |
@@ -153,8 +186,11 @@ static int exynos_ohci_probe(struct platform_device *pdev) | |||
153 | goto fail_io; | 186 | goto fail_io; |
154 | } | 187 | } |
155 | 188 | ||
156 | if (pdata->phy_init) | 189 | if (exynos_ohci->otg) |
157 | pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | 190 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
191 | &exynos_ohci->hcd->self); | ||
192 | |||
193 | exynos_ohci_phy_enable(exynos_ohci); | ||
158 | 194 | ||
159 | ohci = hcd_to_ohci(hcd); | 195 | ohci = hcd_to_ohci(hcd); |
160 | ohci_hcd_init(ohci); | 196 | ohci_hcd_init(ohci); |
@@ -162,13 +198,15 @@ static int exynos_ohci_probe(struct platform_device *pdev) | |||
162 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); | 198 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); |
163 | if (err) { | 199 | if (err) { |
164 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); | 200 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); |
165 | goto fail_io; | 201 | goto fail_add_hcd; |
166 | } | 202 | } |
167 | 203 | ||
168 | platform_set_drvdata(pdev, exynos_ohci); | 204 | platform_set_drvdata(pdev, exynos_ohci); |
169 | 205 | ||
170 | return 0; | 206 | return 0; |
171 | 207 | ||
208 | fail_add_hcd: | ||
209 | exynos_ohci_phy_disable(exynos_ohci); | ||
172 | fail_io: | 210 | fail_io: |
173 | clk_disable_unprepare(exynos_ohci->clk); | 211 | clk_disable_unprepare(exynos_ohci->clk); |
174 | fail_clk: | 212 | fail_clk: |
@@ -178,14 +216,16 @@ fail_clk: | |||
178 | 216 | ||
179 | static int exynos_ohci_remove(struct platform_device *pdev) | 217 | static int exynos_ohci_remove(struct platform_device *pdev) |
180 | { | 218 | { |
181 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; | ||
182 | struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); | 219 | struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); |
183 | struct usb_hcd *hcd = exynos_ohci->hcd; | 220 | struct usb_hcd *hcd = exynos_ohci->hcd; |
184 | 221 | ||
185 | usb_remove_hcd(hcd); | 222 | usb_remove_hcd(hcd); |
186 | 223 | ||
187 | if (pdata && pdata->phy_exit) | 224 | if (exynos_ohci->otg) |
188 | pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | 225 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
226 | &exynos_ohci->hcd->self); | ||
227 | |||
228 | exynos_ohci_phy_disable(exynos_ohci); | ||
189 | 229 | ||
190 | clk_disable_unprepare(exynos_ohci->clk); | 230 | clk_disable_unprepare(exynos_ohci->clk); |
191 | 231 | ||
@@ -209,8 +249,6 @@ static int exynos_ohci_suspend(struct device *dev) | |||
209 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); | 249 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); |
210 | struct usb_hcd *hcd = exynos_ohci->hcd; | 250 | struct usb_hcd *hcd = exynos_ohci->hcd; |
211 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | 251 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
212 | struct platform_device *pdev = to_platform_device(dev); | ||
213 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; | ||
214 | unsigned long flags; | 252 | unsigned long flags; |
215 | int rc = 0; | 253 | int rc = 0; |
216 | 254 | ||
@@ -229,8 +267,11 @@ static int exynos_ohci_suspend(struct device *dev) | |||
229 | 267 | ||
230 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 268 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
231 | 269 | ||
232 | if (pdata && pdata->phy_exit) | 270 | if (exynos_ohci->otg) |
233 | pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | 271 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
272 | &exynos_ohci->hcd->self); | ||
273 | |||
274 | exynos_ohci_phy_disable(exynos_ohci); | ||
234 | 275 | ||
235 | clk_disable_unprepare(exynos_ohci->clk); | 276 | clk_disable_unprepare(exynos_ohci->clk); |
236 | 277 | ||
@@ -244,13 +285,14 @@ static int exynos_ohci_resume(struct device *dev) | |||
244 | { | 285 | { |
245 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); | 286 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); |
246 | struct usb_hcd *hcd = exynos_ohci->hcd; | 287 | struct usb_hcd *hcd = exynos_ohci->hcd; |
247 | struct platform_device *pdev = to_platform_device(dev); | ||
248 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; | ||
249 | 288 | ||
250 | clk_prepare_enable(exynos_ohci->clk); | 289 | clk_prepare_enable(exynos_ohci->clk); |
251 | 290 | ||
252 | if (pdata && pdata->phy_init) | 291 | if (exynos_ohci->otg) |
253 | pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | 292 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
293 | &exynos_ohci->hcd->self); | ||
294 | |||
295 | exynos_ohci_phy_enable(exynos_ohci); | ||
254 | 296 | ||
255 | ohci_resume(hcd, false); | 297 | ohci_resume(hcd, false); |
256 | 298 | ||