diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/usb/host/ehci-mxc.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/usb/host/ehci-mxc.c')
-rw-r--r-- | drivers/usb/host/ehci-mxc.c | 129 |
1 files changed, 92 insertions, 37 deletions
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index ec7f5d2c90d..555a73c864b 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c | |||
@@ -24,23 +24,47 @@ | |||
24 | #include <linux/usb/ulpi.h> | 24 | #include <linux/usb/ulpi.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | 26 | ||
27 | #include <linux/platform_data/usb-ehci-mxc.h> | 27 | #include <mach/hardware.h> |
28 | #include <mach/mxc_ehci.h> | ||
28 | 29 | ||
29 | #include <asm/mach-types.h> | 30 | #include <asm/mach-types.h> |
30 | 31 | ||
31 | #define ULPI_VIEWPORT_OFFSET 0x170 | 32 | #define ULPI_VIEWPORT_OFFSET 0x170 |
32 | 33 | ||
33 | struct ehci_mxc_priv { | 34 | struct ehci_mxc_priv { |
34 | struct clk *usbclk, *ahbclk, *phyclk; | 35 | struct clk *usbclk, *ahbclk, *phy1clk; |
35 | struct usb_hcd *hcd; | 36 | struct usb_hcd *hcd; |
36 | }; | 37 | }; |
37 | 38 | ||
38 | /* called during probe() after chip reset completes */ | 39 | /* called during probe() after chip reset completes */ |
39 | static int ehci_mxc_setup(struct usb_hcd *hcd) | 40 | static int ehci_mxc_setup(struct usb_hcd *hcd) |
40 | { | 41 | { |
42 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | ||
43 | int retval; | ||
44 | |||
45 | dbg_hcs_params(ehci, "reset"); | ||
46 | dbg_hcc_params(ehci, "reset"); | ||
47 | |||
48 | /* cache this readonly data; minimize chip reads */ | ||
49 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); | ||
50 | |||
41 | hcd->has_tt = 1; | 51 | hcd->has_tt = 1; |
42 | 52 | ||
43 | return ehci_setup(hcd); | 53 | retval = ehci_halt(ehci); |
54 | if (retval) | ||
55 | return retval; | ||
56 | |||
57 | /* data structure init */ | ||
58 | retval = ehci_init(hcd); | ||
59 | if (retval) | ||
60 | return retval; | ||
61 | |||
62 | ehci->sbrn = 0x20; | ||
63 | |||
64 | ehci_reset(ehci); | ||
65 | |||
66 | ehci_port_power(ehci, 0); | ||
67 | return 0; | ||
44 | } | 68 | } |
45 | 69 | ||
46 | static const struct hc_driver ehci_mxc_hc_driver = { | 70 | static const struct hc_driver ehci_mxc_hc_driver = { |
@@ -112,7 +136,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
112 | if (!hcd) | 136 | if (!hcd) |
113 | return -ENOMEM; | 137 | return -ENOMEM; |
114 | 138 | ||
115 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | 139 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
116 | if (!priv) { | 140 | if (!priv) { |
117 | ret = -ENOMEM; | 141 | ret = -ENOMEM; |
118 | goto err_alloc; | 142 | goto err_alloc; |
@@ -122,40 +146,51 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
122 | if (!res) { | 146 | if (!res) { |
123 | dev_err(dev, "Found HC with no register addr. Check setup!\n"); | 147 | dev_err(dev, "Found HC with no register addr. Check setup!\n"); |
124 | ret = -ENODEV; | 148 | ret = -ENODEV; |
125 | goto err_alloc; | 149 | goto err_get_resource; |
126 | } | 150 | } |
127 | 151 | ||
128 | hcd->rsrc_start = res->start; | 152 | hcd->rsrc_start = res->start; |
129 | hcd->rsrc_len = resource_size(res); | 153 | hcd->rsrc_len = resource_size(res); |
130 | 154 | ||
131 | hcd->regs = devm_request_and_ioremap(&pdev->dev, res); | 155 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { |
156 | dev_dbg(dev, "controller already in use\n"); | ||
157 | ret = -EBUSY; | ||
158 | goto err_request_mem; | ||
159 | } | ||
160 | |||
161 | hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); | ||
132 | if (!hcd->regs) { | 162 | if (!hcd->regs) { |
133 | dev_err(dev, "error mapping memory\n"); | 163 | dev_err(dev, "error mapping memory\n"); |
134 | ret = -EFAULT; | 164 | ret = -EFAULT; |
135 | goto err_alloc; | 165 | goto err_ioremap; |
136 | } | 166 | } |
137 | 167 | ||
138 | /* enable clocks */ | 168 | /* enable clocks */ |
139 | priv->usbclk = devm_clk_get(&pdev->dev, "ipg"); | 169 | priv->usbclk = clk_get(dev, "usb"); |
140 | if (IS_ERR(priv->usbclk)) { | 170 | if (IS_ERR(priv->usbclk)) { |
141 | ret = PTR_ERR(priv->usbclk); | 171 | ret = PTR_ERR(priv->usbclk); |
142 | goto err_alloc; | 172 | goto err_clk; |
143 | } | 173 | } |
144 | clk_prepare_enable(priv->usbclk); | 174 | clk_enable(priv->usbclk); |
145 | 175 | ||
146 | priv->ahbclk = devm_clk_get(&pdev->dev, "ahb"); | 176 | if (!cpu_is_mx35() && !cpu_is_mx25()) { |
147 | if (IS_ERR(priv->ahbclk)) { | 177 | priv->ahbclk = clk_get(dev, "usb_ahb"); |
148 | ret = PTR_ERR(priv->ahbclk); | 178 | if (IS_ERR(priv->ahbclk)) { |
149 | goto err_clk_ahb; | 179 | ret = PTR_ERR(priv->ahbclk); |
180 | goto err_clk_ahb; | ||
181 | } | ||
182 | clk_enable(priv->ahbclk); | ||
150 | } | 183 | } |
151 | clk_prepare_enable(priv->ahbclk); | ||
152 | 184 | ||
153 | /* "dr" device has its own clock on i.MX51 */ | 185 | /* "dr" device has its own clock on i.MX51 */ |
154 | priv->phyclk = devm_clk_get(&pdev->dev, "phy"); | 186 | if (cpu_is_mx51() && (pdev->id == 0)) { |
155 | if (IS_ERR(priv->phyclk)) | 187 | priv->phy1clk = clk_get(dev, "usb_phy1"); |
156 | priv->phyclk = NULL; | 188 | if (IS_ERR(priv->phy1clk)) { |
157 | if (priv->phyclk) | 189 | ret = PTR_ERR(priv->phy1clk); |
158 | clk_prepare_enable(priv->phyclk); | 190 | goto err_clk_phy; |
191 | } | ||
192 | clk_enable(priv->phy1clk); | ||
193 | } | ||
159 | 194 | ||
160 | 195 | ||
161 | /* call platform specific init function */ | 196 | /* call platform specific init function */ |
@@ -185,13 +220,13 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
185 | /* Initialize the transceiver */ | 220 | /* Initialize the transceiver */ |
186 | if (pdata->otg) { | 221 | if (pdata->otg) { |
187 | pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET; | 222 | pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET; |
188 | ret = usb_phy_init(pdata->otg); | 223 | ret = otg_init(pdata->otg); |
189 | if (ret) { | 224 | if (ret) { |
190 | dev_err(dev, "unable to init transceiver, probably missing\n"); | 225 | dev_err(dev, "unable to init transceiver, probably missing\n"); |
191 | ret = -ENODEV; | 226 | ret = -ENODEV; |
192 | goto err_add; | 227 | goto err_add; |
193 | } | 228 | } |
194 | ret = otg_set_vbus(pdata->otg->otg, 1); | 229 | ret = otg_set_vbus(pdata->otg, 1); |
195 | if (ret) { | 230 | if (ret) { |
196 | dev_err(dev, "unable to enable vbus on transceiver\n"); | 231 | dev_err(dev, "unable to enable vbus on transceiver\n"); |
197 | goto err_add; | 232 | goto err_add; |
@@ -201,7 +236,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
201 | priv->hcd = hcd; | 236 | priv->hcd = hcd; |
202 | platform_set_drvdata(pdev, priv); | 237 | platform_set_drvdata(pdev, priv); |
203 | 238 | ||
204 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); | 239 | ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); |
205 | if (ret) | 240 | if (ret) |
206 | goto err_add; | 241 | goto err_add; |
207 | 242 | ||
@@ -212,11 +247,9 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
212 | * It's in violation of USB specs | 247 | * It's in violation of USB specs |
213 | */ | 248 | */ |
214 | if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) { | 249 | if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) { |
215 | flags = usb_phy_io_read(pdata->otg, | 250 | flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL); |
216 | ULPI_OTG_CTRL); | ||
217 | flags |= ULPI_OTG_CTRL_CHRGVBUS; | 251 | flags |= ULPI_OTG_CTRL_CHRGVBUS; |
218 | ret = usb_phy_io_write(pdata->otg, flags, | 252 | ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL); |
219 | ULPI_OTG_CTRL); | ||
220 | if (ret) { | 253 | if (ret) { |
221 | dev_err(dev, "unable to set CHRVBUS\n"); | 254 | dev_err(dev, "unable to set CHRVBUS\n"); |
222 | goto err_add; | 255 | goto err_add; |
@@ -230,12 +263,25 @@ err_add: | |||
230 | if (pdata && pdata->exit) | 263 | if (pdata && pdata->exit) |
231 | pdata->exit(pdev); | 264 | pdata->exit(pdev); |
232 | err_init: | 265 | err_init: |
233 | if (priv->phyclk) | 266 | if (priv->phy1clk) { |
234 | clk_disable_unprepare(priv->phyclk); | 267 | clk_disable(priv->phy1clk); |
235 | 268 | clk_put(priv->phy1clk); | |
236 | clk_disable_unprepare(priv->ahbclk); | 269 | } |
270 | err_clk_phy: | ||
271 | if (priv->ahbclk) { | ||
272 | clk_disable(priv->ahbclk); | ||
273 | clk_put(priv->ahbclk); | ||
274 | } | ||
237 | err_clk_ahb: | 275 | err_clk_ahb: |
238 | clk_disable_unprepare(priv->usbclk); | 276 | clk_disable(priv->usbclk); |
277 | clk_put(priv->usbclk); | ||
278 | err_clk: | ||
279 | iounmap(hcd->regs); | ||
280 | err_ioremap: | ||
281 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
282 | err_request_mem: | ||
283 | err_get_resource: | ||
284 | kfree(priv); | ||
239 | err_alloc: | 285 | err_alloc: |
240 | usb_put_hcd(hcd); | 286 | usb_put_hcd(hcd); |
241 | return ret; | 287 | return ret; |
@@ -251,17 +297,26 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) | |||
251 | pdata->exit(pdev); | 297 | pdata->exit(pdev); |
252 | 298 | ||
253 | if (pdata->otg) | 299 | if (pdata->otg) |
254 | usb_phy_shutdown(pdata->otg); | 300 | otg_shutdown(pdata->otg); |
255 | 301 | ||
256 | usb_remove_hcd(hcd); | 302 | usb_remove_hcd(hcd); |
303 | iounmap(hcd->regs); | ||
304 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
257 | usb_put_hcd(hcd); | 305 | usb_put_hcd(hcd); |
258 | platform_set_drvdata(pdev, NULL); | 306 | platform_set_drvdata(pdev, NULL); |
259 | 307 | ||
260 | clk_disable_unprepare(priv->usbclk); | 308 | clk_disable(priv->usbclk); |
261 | clk_disable_unprepare(priv->ahbclk); | 309 | clk_put(priv->usbclk); |
310 | if (priv->ahbclk) { | ||
311 | clk_disable(priv->ahbclk); | ||
312 | clk_put(priv->ahbclk); | ||
313 | } | ||
314 | if (priv->phy1clk) { | ||
315 | clk_disable(priv->phy1clk); | ||
316 | clk_put(priv->phy1clk); | ||
317 | } | ||
262 | 318 | ||
263 | if (priv->phyclk) | 319 | kfree(priv); |
264 | clk_disable_unprepare(priv->phyclk); | ||
265 | 320 | ||
266 | return 0; | 321 | return 0; |
267 | } | 322 | } |