Merge tag 'fbdev-updates-for-3.6' of git://github.com/schandinat/linux-2.6
[pandora-kernel.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         int irq;
86         int err = -ENOMEM;
87
88         BUG_ON(!dev->dev.platform_data);
89
90         if (usb_disabled())
91                 return -ENODEV;
92
93         irq = platform_get_irq(dev, 0);
94         if (irq < 0) {
95                 pr_err("no irq provided");
96                 return irq;
97         }
98         res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
99         if (!res_mem) {
100                 pr_err("no memory recourse provided");
101                 return -ENXIO;
102         }
103
104         hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
105                              dev_name(&dev->dev));
106         if (!hcd)
107                 return -ENOMEM;
108
109         hcd->rsrc_start = res_mem->start;
110         hcd->rsrc_len = resource_size(res_mem);
111
112         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
113                 pr_err("controller already in use");
114                 err = -EBUSY;
115                 goto err_put_hcd;
116         }
117
118         hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
119         if (!hcd->regs)
120                 goto err_release_region;
121         err = usb_add_hcd(hcd, irq, IRQF_SHARED);
122         if (err)
123                 goto err_iounmap;
124
125         platform_set_drvdata(dev, hcd);
126
127         return err;
128
129 err_iounmap:
130         iounmap(hcd->regs);
131 err_release_region:
132         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
133 err_put_hcd:
134         usb_put_hcd(hcd);
135         return err;
136 }
137
138 static int __devexit ehci_platform_remove(struct platform_device *dev)
139 {
140         struct usb_hcd *hcd = platform_get_drvdata(dev);
141
142         usb_remove_hcd(hcd);
143         iounmap(hcd->regs);
144         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
145         usb_put_hcd(hcd);
146         platform_set_drvdata(dev, NULL);
147
148         return 0;
149 }
150
151 #ifdef CONFIG_PM
152
153 static int ehci_platform_suspend(struct device *dev)
154 {
155         struct usb_hcd *hcd = dev_get_drvdata(dev);
156         bool do_wakeup = device_may_wakeup(dev);
157
158         return ehci_suspend(hcd, do_wakeup);
159 }
160
161 static int ehci_platform_resume(struct device *dev)
162 {
163         struct usb_hcd *hcd = dev_get_drvdata(dev);
164
165         ehci_resume(hcd, false);
166         return 0;
167 }
168
169 #else /* !CONFIG_PM */
170 #define ehci_platform_suspend   NULL
171 #define ehci_platform_resume    NULL
172 #endif /* CONFIG_PM */
173
174 static const struct platform_device_id ehci_platform_table[] = {
175         { "ehci-platform", 0 },
176         { }
177 };
178 MODULE_DEVICE_TABLE(platform, ehci_platform_table);
179
180 static const struct dev_pm_ops ehci_platform_pm_ops = {
181         .suspend        = ehci_platform_suspend,
182         .resume         = ehci_platform_resume,
183 };
184
185 static struct platform_driver ehci_platform_driver = {
186         .id_table       = ehci_platform_table,
187         .probe          = ehci_platform_probe,
188         .remove         = __devexit_p(ehci_platform_remove),
189         .shutdown       = usb_hcd_platform_shutdown,
190         .driver         = {
191                 .owner  = THIS_MODULE,
192                 .name   = "ehci-platform",
193                 .pm     = &ehci_platform_pm_ops,
194         }
195 };