usb: host: ehci-platform: add platform specific power callback
[firefly-linux-kernel-4.4.55.git] / drivers / usb / host / ehci-platform.c
1 /*
2  * Generic platform ehci driver
3  *
4  * Copyright 2007 Steven Brown <sbrown@cortland.com>
5  * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
6  *
7  * Derived from the ohci-ssb driver
8  * Copyright 2007 Michael Buesch <m@bues.ch>
9  *
10  * Derived from the EHCI-PCI driver
11  * Copyright (c) 2000-2004 by David Brownell
12  *
13  * Derived from the ohci-pci driver
14  * Copyright 1999 Roman Weissgaerber
15  * Copyright 2000-2002 David Brownell
16  * Copyright 1999 Linus Torvalds
17  * Copyright 1999 Gregory P. Smith
18  *
19  * Licensed under the GNU/GPL. See COPYING for details.
20  */
21 #include <linux/platform_device.h>
22 #include <linux/usb/ehci_pdriver.h>
23
24 static int ehci_platform_reset(struct usb_hcd *hcd)
25 {
26         struct platform_device *pdev = to_platform_device(hcd->self.controller);
27         struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
28         struct ehci_hcd *ehci = hcd_to_ehci(hcd);
29         int retval;
30
31         hcd->has_tt = pdata->has_tt;
32         ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
33         ehci->big_endian_desc = pdata->big_endian_desc;
34         ehci->big_endian_mmio = pdata->big_endian_mmio;
35
36         ehci->caps = hcd->regs + pdata->caps_offset;
37         retval = ehci_setup(hcd);
38         if (retval)
39                 return retval;
40
41         if (pdata->port_power_on)
42                 ehci_port_power(ehci, 1);
43         if (pdata->port_power_off)
44                 ehci_port_power(ehci, 0);
45
46         return 0;
47 }
48
49 static const struct hc_driver ehci_platform_hc_driver = {
50         .description            = hcd_name,
51         .product_desc           = "Generic Platform EHCI Controller",
52         .hcd_priv_size          = sizeof(struct ehci_hcd),
53
54         .irq                    = ehci_irq,
55         .flags                  = HCD_MEMORY | HCD_USB2,
56
57         .reset                  = ehci_platform_reset,
58         .start                  = ehci_run,
59         .stop                   = ehci_stop,
60         .shutdown               = ehci_shutdown,
61
62         .urb_enqueue            = ehci_urb_enqueue,
63         .urb_dequeue            = ehci_urb_dequeue,
64         .endpoint_disable       = ehci_endpoint_disable,
65         .endpoint_reset         = ehci_endpoint_reset,
66
67         .get_frame_number       = ehci_get_frame,
68
69         .hub_status_data        = ehci_hub_status_data,
70         .hub_control            = ehci_hub_control,
71 #if defined(CONFIG_PM)
72         .bus_suspend            = ehci_bus_suspend,
73         .bus_resume             = ehci_bus_resume,
74 #endif
75         .relinquish_port        = ehci_relinquish_port,
76         .port_handed_over       = ehci_port_handed_over,
77
78         .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
79 };
80
81 static int __devinit ehci_platform_probe(struct platform_device *dev)
82 {
83         struct usb_hcd *hcd;
84         struct resource *res_mem;
85         struct usb_ehci_pdata *pdata = dev->dev.platform_data;
86         int irq;
87         int err = -ENOMEM;
88
89         if (!pdata) {
90                 WARN_ON(1);
91                 return -ENODEV;
92         }
93
94         if (usb_disabled())
95                 return -ENODEV;
96
97         irq = platform_get_irq(dev, 0);
98         if (irq < 0) {
99                 pr_err("no irq provided");
100                 return irq;
101         }
102         res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
103         if (!res_mem) {
104                 pr_err("no memory recourse provided");
105                 return -ENXIO;
106         }
107
108         if (pdata->power_on) {
109                 err = pdata->power_on(dev);
110                 if (err < 0)
111                         return err;
112         }
113
114         hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
115                              dev_name(&dev->dev));
116         if (!hcd) {
117                 err = -ENOMEM;
118                 goto err_power;
119         }
120
121         hcd->rsrc_start = res_mem->start;
122         hcd->rsrc_len = resource_size(res_mem);
123
124         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
125                 pr_err("controller already in use");
126                 err = -EBUSY;
127                 goto err_put_hcd;
128         }
129
130         hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
131         if (!hcd->regs)
132                 goto err_release_region;
133         err = usb_add_hcd(hcd, irq, IRQF_SHARED);
134         if (err)
135                 goto err_iounmap;
136
137         platform_set_drvdata(dev, hcd);
138
139         return err;
140
141 err_iounmap:
142         iounmap(hcd->regs);
143 err_release_region:
144         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
145 err_put_hcd:
146         usb_put_hcd(hcd);
147 err_power:
148         if (pdata->power_off)
149                 pdata->power_off(dev);
150
151         return err;
152 }
153
154 static int __devexit ehci_platform_remove(struct platform_device *dev)
155 {
156         struct usb_hcd *hcd = platform_get_drvdata(dev);
157         struct usb_ehci_pdata *pdata = dev->dev.platform_data;
158
159         usb_remove_hcd(hcd);
160         iounmap(hcd->regs);
161         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
162         usb_put_hcd(hcd);
163         platform_set_drvdata(dev, NULL);
164
165         if (pdata->power_off)
166                 pdata->power_off(dev);
167
168         return 0;
169 }
170
171 #ifdef CONFIG_PM
172
173 static int ehci_platform_suspend(struct device *dev)
174 {
175         struct usb_hcd *hcd = dev_get_drvdata(dev);
176         struct usb_ehci_pdata *pdata = dev->platform_data;
177         struct platform_device *pdev =
178                 container_of(dev, struct platform_device, dev);
179         bool do_wakeup = device_may_wakeup(dev);
180         int ret;
181
182         ret = ehci_suspend(hcd, do_wakeup);
183
184         if (pdata->power_suspend)
185                 pdata->power_suspend(pdev);
186
187         return ret;
188 }
189
190 static int ehci_platform_resume(struct device *dev)
191 {
192         struct usb_hcd *hcd = dev_get_drvdata(dev);
193         struct usb_ehci_pdata *pdata = dev->platform_data;
194         struct platform_device *pdev =
195                 container_of(dev, struct platform_device, dev);
196
197         if (pdata->power_on) {
198                 int err = pdata->power_on(pdev);
199                 if (err < 0)
200                         return err;
201         }
202
203         ehci_resume(hcd, false);
204         return 0;
205 }
206
207 #else /* !CONFIG_PM */
208 #define ehci_platform_suspend   NULL
209 #define ehci_platform_resume    NULL
210 #endif /* CONFIG_PM */
211
212 static const struct platform_device_id ehci_platform_table[] = {
213         { "ehci-platform", 0 },
214         { }
215 };
216 MODULE_DEVICE_TABLE(platform, ehci_platform_table);
217
218 static const struct dev_pm_ops ehci_platform_pm_ops = {
219         .suspend        = ehci_platform_suspend,
220         .resume         = ehci_platform_resume,
221 };
222
223 static struct platform_driver ehci_platform_driver = {
224         .id_table       = ehci_platform_table,
225         .probe          = ehci_platform_probe,
226         .remove         = __devexit_p(ehci_platform_remove),
227         .shutdown       = usb_hcd_platform_shutdown,
228         .driver         = {
229                 .owner  = THIS_MODULE,
230                 .name   = "ehci-platform",
231                 .pm     = &ehci_platform_pm_ops,
232         }
233 };