diff options
author | Vivek Gautam <gautam.vivek@samsung.com> | 2013-01-22 08:00:42 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-23 06:39:18 -0500 |
commit | d233c196ce1a3a33901b75ca818c85825683afba (patch) | |
tree | 691c2f8e1edf28a9bcd8e25c37a573da1e139f35 /drivers/usb/host | |
parent | 8c1b3e16e902b010f79e2d299927ec43b495f1c7 (diff) |
USB: ehci-s5p: Add phy driver support
Adding the phy driver to ehci-s5p. 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/ehci-s5p.c | 80 |
1 files changed, 59 insertions, 21 deletions
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 46ca5efac82b..d603e6ec19a5 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/of_gpio.h> | 18 | #include <linux/of_gpio.h> |
19 | #include <linux/platform_data/usb-ehci-s5p.h> | 19 | #include <linux/platform_data/usb-ehci-s5p.h> |
20 | #include <linux/usb/phy.h> | ||
20 | #include <linux/usb/samsung_usb_phy.h> | 21 | #include <linux/usb/samsung_usb_phy.h> |
21 | #include <plat/usb-phy.h> | 22 | #include <plat/usb-phy.h> |
22 | 23 | ||
@@ -33,6 +34,9 @@ struct s5p_ehci_hcd { | |||
33 | struct device *dev; | 34 | struct device *dev; |
34 | struct usb_hcd *hcd; | 35 | struct usb_hcd *hcd; |
35 | struct clk *clk; | 36 | struct clk *clk; |
37 | struct usb_phy *phy; | ||
38 | struct usb_otg *otg; | ||
39 | struct s5p_ehci_platdata *pdata; | ||
36 | }; | 40 | }; |
37 | 41 | ||
38 | static const struct hc_driver s5p_ehci_hc_driver = { | 42 | static const struct hc_driver s5p_ehci_hc_driver = { |
@@ -66,6 +70,26 @@ static const struct hc_driver s5p_ehci_hc_driver = { | |||
66 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | 70 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
67 | }; | 71 | }; |
68 | 72 | ||
73 | static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci) | ||
74 | { | ||
75 | struct platform_device *pdev = to_platform_device(s5p_ehci->dev); | ||
76 | |||
77 | if (s5p_ehci->phy) | ||
78 | usb_phy_init(s5p_ehci->phy); | ||
79 | else if (s5p_ehci->pdata->phy_init) | ||
80 | s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | ||
81 | } | ||
82 | |||
83 | static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci) | ||
84 | { | ||
85 | struct platform_device *pdev = to_platform_device(s5p_ehci->dev); | ||
86 | |||
87 | if (s5p_ehci->phy) | ||
88 | usb_phy_shutdown(s5p_ehci->phy); | ||
89 | else if (s5p_ehci->pdata->phy_exit) | ||
90 | s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | ||
91 | } | ||
92 | |||
69 | static void s5p_setup_vbus_gpio(struct platform_device *pdev) | 93 | static void s5p_setup_vbus_gpio(struct platform_device *pdev) |
70 | { | 94 | { |
71 | int err; | 95 | int err; |
@@ -88,20 +112,15 @@ static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32); | |||
88 | 112 | ||
89 | static int s5p_ehci_probe(struct platform_device *pdev) | 113 | static int s5p_ehci_probe(struct platform_device *pdev) |
90 | { | 114 | { |
91 | struct s5p_ehci_platdata *pdata; | 115 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; |
92 | struct s5p_ehci_hcd *s5p_ehci; | 116 | struct s5p_ehci_hcd *s5p_ehci; |
93 | struct usb_hcd *hcd; | 117 | struct usb_hcd *hcd; |
94 | struct ehci_hcd *ehci; | 118 | struct ehci_hcd *ehci; |
95 | struct resource *res; | 119 | struct resource *res; |
120 | struct usb_phy *phy; | ||
96 | int irq; | 121 | int irq; |
97 | int err; | 122 | int err; |
98 | 123 | ||
99 | pdata = pdev->dev.platform_data; | ||
100 | if (!pdata) { | ||
101 | dev_err(&pdev->dev, "No platform data defined\n"); | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | |||
105 | /* | 124 | /* |
106 | * Right now device-tree probed devices don't get dma_mask set. | 125 | * Right now device-tree probed devices don't get dma_mask set. |
107 | * Since shared usb code relies on it, set it here for now. | 126 | * Since shared usb code relies on it, set it here for now. |
@@ -119,6 +138,20 @@ static int s5p_ehci_probe(struct platform_device *pdev) | |||
119 | if (!s5p_ehci) | 138 | if (!s5p_ehci) |
120 | return -ENOMEM; | 139 | return -ENOMEM; |
121 | 140 | ||
141 | phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); | ||
142 | if (IS_ERR_OR_NULL(phy)) { | ||
143 | /* Fallback to pdata */ | ||
144 | if (!pdata) { | ||
145 | dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); | ||
146 | return -EPROBE_DEFER; | ||
147 | } else { | ||
148 | s5p_ehci->pdata = pdata; | ||
149 | } | ||
150 | } else { | ||
151 | s5p_ehci->phy = phy; | ||
152 | s5p_ehci->otg = phy->otg; | ||
153 | } | ||
154 | |||
122 | s5p_ehci->dev = &pdev->dev; | 155 | s5p_ehci->dev = &pdev->dev; |
123 | 156 | ||
124 | hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, | 157 | hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, |
@@ -164,8 +197,10 @@ static int s5p_ehci_probe(struct platform_device *pdev) | |||
164 | goto fail_io; | 197 | goto fail_io; |
165 | } | 198 | } |
166 | 199 | ||
167 | if (pdata->phy_init) | 200 | if (s5p_ehci->otg) |
168 | pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | 201 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
202 | |||
203 | s5p_ehci_phy_enable(s5p_ehci); | ||
169 | 204 | ||
170 | ehci = hcd_to_ehci(hcd); | 205 | ehci = hcd_to_ehci(hcd); |
171 | ehci->caps = hcd->regs; | 206 | ehci->caps = hcd->regs; |
@@ -176,13 +211,15 @@ static int s5p_ehci_probe(struct platform_device *pdev) | |||
176 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); | 211 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); |
177 | if (err) { | 212 | if (err) { |
178 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); | 213 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); |
179 | goto fail_io; | 214 | goto fail_add_hcd; |
180 | } | 215 | } |
181 | 216 | ||
182 | platform_set_drvdata(pdev, s5p_ehci); | 217 | platform_set_drvdata(pdev, s5p_ehci); |
183 | 218 | ||
184 | return 0; | 219 | return 0; |
185 | 220 | ||
221 | fail_add_hcd: | ||
222 | s5p_ehci_phy_disable(s5p_ehci); | ||
186 | fail_io: | 223 | fail_io: |
187 | clk_disable_unprepare(s5p_ehci->clk); | 224 | clk_disable_unprepare(s5p_ehci->clk); |
188 | fail_clk: | 225 | fail_clk: |
@@ -192,14 +229,15 @@ fail_clk: | |||
192 | 229 | ||
193 | static int s5p_ehci_remove(struct platform_device *pdev) | 230 | static int s5p_ehci_remove(struct platform_device *pdev) |
194 | { | 231 | { |
195 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; | ||
196 | struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); | 232 | struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); |
197 | struct usb_hcd *hcd = s5p_ehci->hcd; | 233 | struct usb_hcd *hcd = s5p_ehci->hcd; |
198 | 234 | ||
199 | usb_remove_hcd(hcd); | 235 | usb_remove_hcd(hcd); |
200 | 236 | ||
201 | if (pdata && pdata->phy_exit) | 237 | if (s5p_ehci->otg) |
202 | pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | 238 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
239 | |||
240 | s5p_ehci_phy_disable(s5p_ehci); | ||
203 | 241 | ||
204 | clk_disable_unprepare(s5p_ehci->clk); | 242 | clk_disable_unprepare(s5p_ehci->clk); |
205 | 243 | ||
@@ -223,14 +261,14 @@ static int s5p_ehci_suspend(struct device *dev) | |||
223 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); | 261 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); |
224 | struct usb_hcd *hcd = s5p_ehci->hcd; | 262 | struct usb_hcd *hcd = s5p_ehci->hcd; |
225 | bool do_wakeup = device_may_wakeup(dev); | 263 | bool do_wakeup = device_may_wakeup(dev); |
226 | struct platform_device *pdev = to_platform_device(dev); | ||
227 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; | ||
228 | int rc; | 264 | int rc; |
229 | 265 | ||
230 | rc = ehci_suspend(hcd, do_wakeup); | 266 | rc = ehci_suspend(hcd, do_wakeup); |
231 | 267 | ||
232 | if (pdata && pdata->phy_exit) | 268 | if (s5p_ehci->otg) |
233 | pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | 269 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
270 | |||
271 | s5p_ehci_phy_disable(s5p_ehci); | ||
234 | 272 | ||
235 | clk_disable_unprepare(s5p_ehci->clk); | 273 | clk_disable_unprepare(s5p_ehci->clk); |
236 | 274 | ||
@@ -241,13 +279,13 @@ static int s5p_ehci_resume(struct device *dev) | |||
241 | { | 279 | { |
242 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); | 280 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); |
243 | struct usb_hcd *hcd = s5p_ehci->hcd; | 281 | struct usb_hcd *hcd = s5p_ehci->hcd; |
244 | struct platform_device *pdev = to_platform_device(dev); | ||
245 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; | ||
246 | 282 | ||
247 | clk_prepare_enable(s5p_ehci->clk); | 283 | clk_prepare_enable(s5p_ehci->clk); |
248 | 284 | ||
249 | if (pdata && pdata->phy_init) | 285 | if (s5p_ehci->otg) |
250 | pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | 286 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
287 | |||
288 | s5p_ehci_phy_enable(s5p_ehci); | ||
251 | 289 | ||
252 | /* DMA burst Enable */ | 290 | /* DMA burst Enable */ |
253 | writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); | 291 | writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); |