]> Pileus Git - ~andy/linux/blob - drivers/usb/host/ohci-exynos.c
Merge tag 'kirkwood_fixes_for_v3.7' of git://git.infradead.org/users/jcooper/linux...
[~andy/linux] / drivers / usb / host / ohci-exynos.c
1 /*
2  * SAMSUNG EXYNOS USB HOST OHCI Controller
3  *
4  * Copyright (C) 2011 Samsung Electronics Co.Ltd
5  * Author: Jingoo Han <jg1.han@samsung.com>
6  *
7  * This program is free software; you can redistribute  it and/or modify it
8  * under  the terms of  the GNU General  Public License as published by the
9  * Free Software Foundation;  either version 2 of the  License, or (at your
10  * option) any later version.
11  *
12  */
13
14 #include <linux/clk.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/platform_data/usb-exynos.h>
18 #include <plat/usb-phy.h>
19
20 struct exynos_ohci_hcd {
21         struct device *dev;
22         struct usb_hcd *hcd;
23         struct clk *clk;
24 };
25
26 static int ohci_exynos_start(struct usb_hcd *hcd)
27 {
28         struct ohci_hcd *ohci = hcd_to_ohci(hcd);
29         int ret;
30
31         ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci);
32
33         ret = ohci_init(ohci);
34         if (ret < 0)
35                 return ret;
36
37         ret = ohci_run(ohci);
38         if (ret < 0) {
39                 dev_err(hcd->self.controller, "can't start %s\n",
40                         hcd->self.bus_name);
41                 ohci_stop(hcd);
42                 return ret;
43         }
44
45         return 0;
46 }
47
48 static const struct hc_driver exynos_ohci_hc_driver = {
49         .description            = hcd_name,
50         .product_desc           = "EXYNOS OHCI Host Controller",
51         .hcd_priv_size          = sizeof(struct ohci_hcd),
52
53         .irq                    = ohci_irq,
54         .flags                  = HCD_MEMORY|HCD_USB11,
55
56         .start                  = ohci_exynos_start,
57         .stop                   = ohci_stop,
58         .shutdown               = ohci_shutdown,
59
60         .get_frame_number       = ohci_get_frame,
61
62         .urb_enqueue            = ohci_urb_enqueue,
63         .urb_dequeue            = ohci_urb_dequeue,
64         .endpoint_disable       = ohci_endpoint_disable,
65
66         .hub_status_data        = ohci_hub_status_data,
67         .hub_control            = ohci_hub_control,
68 #ifdef  CONFIG_PM
69         .bus_suspend            = ohci_bus_suspend,
70         .bus_resume             = ohci_bus_resume,
71 #endif
72         .start_port_reset       = ohci_start_port_reset,
73 };
74
75 static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32);
76
77 static int __devinit exynos_ohci_probe(struct platform_device *pdev)
78 {
79         struct exynos4_ohci_platdata *pdata;
80         struct exynos_ohci_hcd *exynos_ohci;
81         struct usb_hcd *hcd;
82         struct ohci_hcd *ohci;
83         struct resource *res;
84         int irq;
85         int err;
86
87         pdata = pdev->dev.platform_data;
88         if (!pdata) {
89                 dev_err(&pdev->dev, "No platform data defined\n");
90                 return -EINVAL;
91         }
92
93         /*
94          * Right now device-tree probed devices don't get dma_mask set.
95          * Since shared usb code relies on it, set it here for now.
96          * Once we move to full device tree support this will vanish off.
97          */
98         if (!pdev->dev.dma_mask)
99                 pdev->dev.dma_mask = &ohci_exynos_dma_mask;
100         if (!pdev->dev.coherent_dma_mask)
101                 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
102
103         exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd),
104                                         GFP_KERNEL);
105         if (!exynos_ohci)
106                 return -ENOMEM;
107
108         exynos_ohci->dev = &pdev->dev;
109
110         hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
111                                         dev_name(&pdev->dev));
112         if (!hcd) {
113                 dev_err(&pdev->dev, "Unable to create HCD\n");
114                 return -ENOMEM;
115         }
116
117         exynos_ohci->hcd = hcd;
118         exynos_ohci->clk = clk_get(&pdev->dev, "usbhost");
119
120         if (IS_ERR(exynos_ohci->clk)) {
121                 dev_err(&pdev->dev, "Failed to get usbhost clock\n");
122                 err = PTR_ERR(exynos_ohci->clk);
123                 goto fail_clk;
124         }
125
126         err = clk_enable(exynos_ohci->clk);
127         if (err)
128                 goto fail_clken;
129
130         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
131         if (!res) {
132                 dev_err(&pdev->dev, "Failed to get I/O memory\n");
133                 err = -ENXIO;
134                 goto fail_io;
135         }
136
137         hcd->rsrc_start = res->start;
138         hcd->rsrc_len = resource_size(res);
139         hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
140         if (!hcd->regs) {
141                 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
142                 err = -ENOMEM;
143                 goto fail_io;
144         }
145
146         irq = platform_get_irq(pdev, 0);
147         if (!irq) {
148                 dev_err(&pdev->dev, "Failed to get IRQ\n");
149                 err = -ENODEV;
150                 goto fail_io;
151         }
152
153         if (pdata->phy_init)
154                 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
155
156         ohci = hcd_to_ohci(hcd);
157         ohci_hcd_init(ohci);
158
159         err = usb_add_hcd(hcd, irq, IRQF_SHARED);
160         if (err) {
161                 dev_err(&pdev->dev, "Failed to add USB HCD\n");
162                 goto fail_io;
163         }
164
165         platform_set_drvdata(pdev, exynos_ohci);
166
167         return 0;
168
169 fail_io:
170         clk_disable(exynos_ohci->clk);
171 fail_clken:
172         clk_put(exynos_ohci->clk);
173 fail_clk:
174         usb_put_hcd(hcd);
175         return err;
176 }
177
178 static int __devexit exynos_ohci_remove(struct platform_device *pdev)
179 {
180         struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
181         struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
182         struct usb_hcd *hcd = exynos_ohci->hcd;
183
184         usb_remove_hcd(hcd);
185
186         if (pdata && pdata->phy_exit)
187                 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
188
189         clk_disable(exynos_ohci->clk);
190         clk_put(exynos_ohci->clk);
191
192         usb_put_hcd(hcd);
193
194         return 0;
195 }
196
197 static void exynos_ohci_shutdown(struct platform_device *pdev)
198 {
199         struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
200         struct usb_hcd *hcd = exynos_ohci->hcd;
201
202         if (hcd->driver->shutdown)
203                 hcd->driver->shutdown(hcd);
204 }
205
206 #ifdef CONFIG_PM
207 static int exynos_ohci_suspend(struct device *dev)
208 {
209         struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
210         struct usb_hcd *hcd = exynos_ohci->hcd;
211         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;
215         int rc = 0;
216
217         /*
218          * Root hub was already suspended. Disable irq emission and
219          * mark HW unaccessible, bail out if RH has been resumed. Use
220          * the spinlock to properly synchronize with possible pending
221          * RH suspend or resume activity.
222          */
223         spin_lock_irqsave(&ohci->lock, flags);
224         if (ohci->rh_state != OHCI_RH_SUSPENDED &&
225                         ohci->rh_state != OHCI_RH_HALTED) {
226                 rc = -EINVAL;
227                 goto fail;
228         }
229
230         clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
231
232         if (pdata && pdata->phy_exit)
233                 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
234
235         clk_disable(exynos_ohci->clk);
236
237 fail:
238         spin_unlock_irqrestore(&ohci->lock, flags);
239
240         return rc;
241 }
242
243 static int exynos_ohci_resume(struct device *dev)
244 {
245         struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
246         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
250         clk_enable(exynos_ohci->clk);
251
252         if (pdata && pdata->phy_init)
253                 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
254
255         /* Mark hardware accessible again as we are out of D3 state by now */
256         set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
257
258         ohci_finish_controller_resume(hcd);
259
260         return 0;
261 }
262 #else
263 #define exynos_ohci_suspend     NULL
264 #define exynos_ohci_resume      NULL
265 #endif
266
267 static const struct dev_pm_ops exynos_ohci_pm_ops = {
268         .suspend        = exynos_ohci_suspend,
269         .resume         = exynos_ohci_resume,
270 };
271
272 #ifdef CONFIG_OF
273 static const struct of_device_id exynos_ohci_match[] = {
274         { .compatible = "samsung,exynos-ohci" },
275         {},
276 };
277 MODULE_DEVICE_TABLE(of, exynos_ohci_match);
278 #endif
279
280 static struct platform_driver exynos_ohci_driver = {
281         .probe          = exynos_ohci_probe,
282         .remove         = __devexit_p(exynos_ohci_remove),
283         .shutdown       = exynos_ohci_shutdown,
284         .driver = {
285                 .name   = "exynos-ohci",
286                 .owner  = THIS_MODULE,
287                 .pm     = &exynos_ohci_pm_ops,
288                 .of_match_table = of_match_ptr(exynos_ohci_match),
289         }
290 };
291
292 MODULE_ALIAS("platform:exynos-ohci");
293 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");