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