]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/usb/host/ehci-s5p.c
Merge tag 'mvebu' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[karo-tx-linux.git] / drivers / usb / host / ehci-s5p.c
1 /*
2  * SAMSUNG S5P USB HOST EHCI Controller
3  *
4  * Copyright (C) 2011 Samsung Electronics Co.Ltd
5  * Author: Jingoo Han <jg1.han@samsung.com>
6  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  *
13  */
14
15 #include <linux/clk.h>
16 #include <linux/of.h>
17 #include <linux/platform_device.h>
18 #include <linux/of_gpio.h>
19 #include <linux/platform_data/usb-ehci-s5p.h>
20 #include <plat/usb-phy.h>
21
22 #define EHCI_INSNREG00(base)                    (base + 0x90)
23 #define EHCI_INSNREG00_ENA_INCR16               (0x1 << 25)
24 #define EHCI_INSNREG00_ENA_INCR8                (0x1 << 24)
25 #define EHCI_INSNREG00_ENA_INCR4                (0x1 << 23)
26 #define EHCI_INSNREG00_ENA_INCRX_ALIGN          (0x1 << 22)
27 #define EHCI_INSNREG00_ENABLE_DMA_BURST \
28         (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
29          EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
30
31 struct s5p_ehci_hcd {
32         struct device *dev;
33         struct usb_hcd *hcd;
34         struct clk *clk;
35 };
36
37 static const struct hc_driver s5p_ehci_hc_driver = {
38         .description            = hcd_name,
39         .product_desc           = "S5P EHCI Host Controller",
40         .hcd_priv_size          = sizeof(struct ehci_hcd),
41
42         .irq                    = ehci_irq,
43         .flags                  = HCD_MEMORY | HCD_USB2,
44
45         .reset                  = ehci_setup,
46         .start                  = ehci_run,
47         .stop                   = ehci_stop,
48         .shutdown               = ehci_shutdown,
49
50         .get_frame_number       = ehci_get_frame,
51
52         .urb_enqueue            = ehci_urb_enqueue,
53         .urb_dequeue            = ehci_urb_dequeue,
54         .endpoint_disable       = ehci_endpoint_disable,
55         .endpoint_reset         = ehci_endpoint_reset,
56
57         .hub_status_data        = ehci_hub_status_data,
58         .hub_control            = ehci_hub_control,
59         .bus_suspend            = ehci_bus_suspend,
60         .bus_resume             = ehci_bus_resume,
61
62         .relinquish_port        = ehci_relinquish_port,
63         .port_handed_over       = ehci_port_handed_over,
64
65         .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
66 };
67
68 static void s5p_setup_vbus_gpio(struct platform_device *pdev)
69 {
70         int err;
71         int gpio;
72
73         if (!pdev->dev.of_node)
74                 return;
75
76         gpio = of_get_named_gpio(pdev->dev.of_node,
77                         "samsung,vbus-gpio", 0);
78         if (!gpio_is_valid(gpio))
79                 return;
80
81         err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio");
82         if (err)
83                 dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
84 }
85
86 static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
87
88 static int s5p_ehci_probe(struct platform_device *pdev)
89 {
90         struct s5p_ehci_platdata *pdata;
91         struct s5p_ehci_hcd *s5p_ehci;
92         struct usb_hcd *hcd;
93         struct ehci_hcd *ehci;
94         struct resource *res;
95         int irq;
96         int err;
97
98         pdata = pdev->dev.platform_data;
99         if (!pdata) {
100                 dev_err(&pdev->dev, "No platform data defined\n");
101                 return -EINVAL;
102         }
103
104         /*
105          * Right now device-tree probed devices don't get dma_mask set.
106          * Since shared usb code relies on it, set it here for now.
107          * Once we move to full device tree support this will vanish off.
108          */
109         if (!pdev->dev.dma_mask)
110                 pdev->dev.dma_mask = &ehci_s5p_dma_mask;
111         if (!pdev->dev.coherent_dma_mask)
112                 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
113
114         s5p_setup_vbus_gpio(pdev);
115
116         s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd),
117                                 GFP_KERNEL);
118         if (!s5p_ehci)
119                 return -ENOMEM;
120
121         s5p_ehci->dev = &pdev->dev;
122
123         hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
124                                         dev_name(&pdev->dev));
125         if (!hcd) {
126                 dev_err(&pdev->dev, "Unable to create HCD\n");
127                 return -ENOMEM;
128         }
129
130         s5p_ehci->hcd = hcd;
131         s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
132
133         if (IS_ERR(s5p_ehci->clk)) {
134                 dev_err(&pdev->dev, "Failed to get usbhost clock\n");
135                 err = PTR_ERR(s5p_ehci->clk);
136                 goto fail_clk;
137         }
138
139         err = clk_prepare_enable(s5p_ehci->clk);
140         if (err)
141                 goto fail_clk;
142
143         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144         if (!res) {
145                 dev_err(&pdev->dev, "Failed to get I/O memory\n");
146                 err = -ENXIO;
147                 goto fail_io;
148         }
149
150         hcd->rsrc_start = res->start;
151         hcd->rsrc_len = resource_size(res);
152         hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
153         if (!hcd->regs) {
154                 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
155                 err = -ENOMEM;
156                 goto fail_io;
157         }
158
159         irq = platform_get_irq(pdev, 0);
160         if (!irq) {
161                 dev_err(&pdev->dev, "Failed to get IRQ\n");
162                 err = -ENODEV;
163                 goto fail_io;
164         }
165
166         if (pdata->phy_init)
167                 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
168
169         ehci = hcd_to_ehci(hcd);
170         ehci->caps = hcd->regs;
171
172         /* DMA burst Enable */
173         writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
174
175         err = usb_add_hcd(hcd, irq, IRQF_SHARED);
176         if (err) {
177                 dev_err(&pdev->dev, "Failed to add USB HCD\n");
178                 goto fail_io;
179         }
180
181         platform_set_drvdata(pdev, s5p_ehci);
182
183         return 0;
184
185 fail_io:
186         clk_disable_unprepare(s5p_ehci->clk);
187 fail_clk:
188         usb_put_hcd(hcd);
189         return err;
190 }
191
192 static int s5p_ehci_remove(struct platform_device *pdev)
193 {
194         struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
195         struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
196         struct usb_hcd *hcd = s5p_ehci->hcd;
197
198         usb_remove_hcd(hcd);
199
200         if (pdata && pdata->phy_exit)
201                 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
202
203         clk_disable_unprepare(s5p_ehci->clk);
204
205         usb_put_hcd(hcd);
206
207         return 0;
208 }
209
210 static void s5p_ehci_shutdown(struct platform_device *pdev)
211 {
212         struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
213         struct usb_hcd *hcd = s5p_ehci->hcd;
214
215         if (hcd->driver->shutdown)
216                 hcd->driver->shutdown(hcd);
217 }
218
219 #ifdef CONFIG_PM
220 static int s5p_ehci_suspend(struct device *dev)
221 {
222         struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
223         struct usb_hcd *hcd = s5p_ehci->hcd;
224         bool do_wakeup = device_may_wakeup(dev);
225         struct platform_device *pdev = to_platform_device(dev);
226         struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
227         int rc;
228
229         rc = ehci_suspend(hcd, do_wakeup);
230
231         if (pdata && pdata->phy_exit)
232                 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
233
234         clk_disable_unprepare(s5p_ehci->clk);
235
236         return rc;
237 }
238
239 static int s5p_ehci_resume(struct device *dev)
240 {
241         struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
242         struct usb_hcd *hcd = s5p_ehci->hcd;
243         struct platform_device *pdev = to_platform_device(dev);
244         struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
245
246         clk_prepare_enable(s5p_ehci->clk);
247
248         if (pdata && pdata->phy_init)
249                 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
250
251         /* DMA burst Enable */
252         writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
253
254         ehci_resume(hcd, false);
255         return 0;
256 }
257 #else
258 #define s5p_ehci_suspend        NULL
259 #define s5p_ehci_resume         NULL
260 #endif
261
262 static const struct dev_pm_ops s5p_ehci_pm_ops = {
263         .suspend        = s5p_ehci_suspend,
264         .resume         = s5p_ehci_resume,
265 };
266
267 #ifdef CONFIG_OF
268 static const struct of_device_id exynos_ehci_match[] = {
269         { .compatible = "samsung,exynos-ehci" },
270         {},
271 };
272 MODULE_DEVICE_TABLE(of, exynos_ehci_match);
273 #endif
274
275 static struct platform_driver s5p_ehci_driver = {
276         .probe          = s5p_ehci_probe,
277         .remove         = s5p_ehci_remove,
278         .shutdown       = s5p_ehci_shutdown,
279         .driver = {
280                 .name   = "s5p-ehci",
281                 .owner  = THIS_MODULE,
282                 .pm     = &s5p_ehci_pm_ops,
283                 .of_match_table = of_match_ptr(exynos_ehci_match),
284         }
285 };
286
287 MODULE_ALIAS("platform:s5p-ehci");