ARM: samsung: move platform_data definitions
[sfrench/cifs-2.6.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 __devinit 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 = 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_enable(s5p_ehci->clk);
140         if (err)
141                 goto fail_clken;
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(s5p_ehci->clk);
187 fail_clken:
188         clk_put(s5p_ehci->clk);
189 fail_clk:
190         usb_put_hcd(hcd);
191         return err;
192 }
193
194 static int __devexit s5p_ehci_remove(struct platform_device *pdev)
195 {
196         struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
197         struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
198         struct usb_hcd *hcd = s5p_ehci->hcd;
199
200         usb_remove_hcd(hcd);
201
202         if (pdata && pdata->phy_exit)
203                 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
204
205         clk_disable(s5p_ehci->clk);
206         clk_put(s5p_ehci->clk);
207
208         usb_put_hcd(hcd);
209
210         return 0;
211 }
212
213 static void s5p_ehci_shutdown(struct platform_device *pdev)
214 {
215         struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
216         struct usb_hcd *hcd = s5p_ehci->hcd;
217
218         if (hcd->driver->shutdown)
219                 hcd->driver->shutdown(hcd);
220 }
221
222 #ifdef CONFIG_PM
223 static int s5p_ehci_suspend(struct device *dev)
224 {
225         struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
226         struct usb_hcd *hcd = s5p_ehci->hcd;
227         bool do_wakeup = device_may_wakeup(dev);
228         struct platform_device *pdev = to_platform_device(dev);
229         struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
230         int rc;
231
232         rc = ehci_suspend(hcd, do_wakeup);
233
234         if (pdata && pdata->phy_exit)
235                 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
236
237         clk_disable(s5p_ehci->clk);
238
239         return rc;
240 }
241
242 static int s5p_ehci_resume(struct device *dev)
243 {
244         struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
245         struct usb_hcd *hcd = s5p_ehci->hcd;
246         struct platform_device *pdev = to_platform_device(dev);
247         struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
248
249         clk_enable(s5p_ehci->clk);
250
251         if (pdata && pdata->phy_init)
252                 pdata->phy_init(pdev, S5P_USB_PHY_HOST);
253
254         /* DMA burst Enable */
255         writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
256
257         ehci_resume(hcd, false);
258         return 0;
259 }
260 #else
261 #define s5p_ehci_suspend        NULL
262 #define s5p_ehci_resume         NULL
263 #endif
264
265 static const struct dev_pm_ops s5p_ehci_pm_ops = {
266         .suspend        = s5p_ehci_suspend,
267         .resume         = s5p_ehci_resume,
268 };
269
270 #ifdef CONFIG_OF
271 static const struct of_device_id exynos_ehci_match[] = {
272         { .compatible = "samsung,exynos-ehci" },
273         {},
274 };
275 MODULE_DEVICE_TABLE(of, exynos_ehci_match);
276 #endif
277
278 static struct platform_driver s5p_ehci_driver = {
279         .probe          = s5p_ehci_probe,
280         .remove         = __devexit_p(s5p_ehci_remove),
281         .shutdown       = s5p_ehci_shutdown,
282         .driver = {
283                 .name   = "s5p-ehci",
284                 .owner  = THIS_MODULE,
285                 .pm     = &s5p_ehci_pm_ops,
286                 .of_match_table = of_match_ptr(exynos_ehci_match),
287         }
288 };
289
290 MODULE_ALIAS("platform:s5p-ehci");