Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ohci-sm501.c
Go to the documentation of this file.
1 /*
2  * OHCI HCD (Host Controller Driver) for USB.
3  *
4  * (C) Copyright 1999 Roman Weissgaerber <[email protected]>
5  * (C) Copyright 2000-2005 David Brownell
6  * (C) Copyright 2002 Hewlett-Packard Company
7  * (C) Copyright 2008 Magnus Damm
8  *
9  * SM501 Bus Glue - based on ohci-omap.c
10  *
11  * This file is licenced under the GPL.
12  */
13 
14 #include <linux/interrupt.h>
15 #include <linux/jiffies.h>
16 #include <linux/platform_device.h>
17 #include <linux/dma-mapping.h>
18 #include <linux/sm501.h>
19 #include <linux/sm501-regs.h>
20 
21 static int ohci_sm501_init(struct usb_hcd *hcd)
22 {
23  return ohci_init(hcd_to_ohci(hcd));
24 }
25 
26 static int ohci_sm501_start(struct usb_hcd *hcd)
27 {
28  struct device *dev = hcd->self.controller;
29  int ret;
30 
31  ret = ohci_run(hcd_to_ohci(hcd));
32  if (ret < 0) {
33  dev_err(dev, "can't start %s", hcd->self.bus_name);
34  ohci_stop(hcd);
35  }
36 
37  return ret;
38 }
39 
40 /*-------------------------------------------------------------------------*/
41 
42 static const struct hc_driver ohci_sm501_hc_driver = {
43  .description = hcd_name,
44  .product_desc = "SM501 OHCI",
45  .hcd_priv_size = sizeof(struct ohci_hcd),
46 
47  /*
48  * generic hardware linkage
49  */
50  .irq = ohci_irq,
51  .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
52 
53  /*
54  * basic lifecycle operations
55  */
56  .reset = ohci_sm501_init,
57  .start = ohci_sm501_start,
58  .stop = ohci_stop,
59  .shutdown = ohci_shutdown,
60 
61  /*
62  * managing i/o requests and associated device resources
63  */
64  .urb_enqueue = ohci_urb_enqueue,
65  .urb_dequeue = ohci_urb_dequeue,
66  .endpoint_disable = ohci_endpoint_disable,
67 
68  /*
69  * scheduling support
70  */
71  .get_frame_number = ohci_get_frame,
72 
73  /*
74  * root hub support
75  */
76  .hub_status_data = ohci_hub_status_data,
77  .hub_control = ohci_hub_control,
78 #ifdef CONFIG_PM
79  .bus_suspend = ohci_bus_suspend,
80  .bus_resume = ohci_bus_resume,
81 #endif
82  .start_port_reset = ohci_start_port_reset,
83 };
84 
85 /*-------------------------------------------------------------------------*/
86 
87 static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
88 {
89  const struct hc_driver *driver = &ohci_sm501_hc_driver;
90  struct device *dev = &pdev->dev;
91  struct resource *res, *mem;
92  int retval, irq;
93  struct usb_hcd *hcd = NULL;
94 
95  irq = retval = platform_get_irq(pdev, 0);
96  if (retval < 0)
97  goto err0;
98 
99  mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
100  if (mem == NULL) {
101  dev_err(dev, "no resource definition for memory\n");
102  retval = -ENOENT;
103  goto err0;
104  }
105 
106  if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
107  dev_err(dev, "request_mem_region failed\n");
108  retval = -EBUSY;
109  goto err0;
110  }
111 
112  /* The sm501 chip is equipped with local memory that may be used
113  * by on-chip devices such as the video controller and the usb host.
114  * This driver uses dma_declare_coherent_memory() to make sure
115  * usb allocations with dma_alloc_coherent() allocate from
116  * this local memory. The dma_handle returned by dma_alloc_coherent()
117  * will be an offset starting from 0 for the first local memory byte.
118  *
119  * So as long as data is allocated using dma_alloc_coherent() all is
120  * fine. This is however not always the case - buffers may be allocated
121  * using kmalloc() - so the usb core needs to be told that it must copy
122  * data into our local memory if the buffers happen to be placed in
123  * regular memory. The HCD_LOCAL_MEM flag does just that.
124  */
125 
126  if (!dma_declare_coherent_memory(dev, mem->start,
127  mem->start - mem->parent->start,
128  resource_size(mem),
131  dev_err(dev, "cannot declare coherent memory\n");
132  retval = -ENXIO;
133  goto err1;
134  }
135 
136  /* allocate, reserve and remap resources for registers */
137  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
138  if (res == NULL) {
139  dev_err(dev, "no resource definition for registers\n");
140  retval = -ENOENT;
141  goto err2;
142  }
143 
144  hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
145  if (!hcd) {
146  retval = -ENOMEM;
147  goto err2;
148  }
149 
150  hcd->rsrc_start = res->start;
151  hcd->rsrc_len = resource_size(res);
152 
153  if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) {
154  dev_err(dev, "request_mem_region failed\n");
155  retval = -EBUSY;
156  goto err3;
157  }
158 
159  hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
160  if (hcd->regs == NULL) {
161  dev_err(dev, "cannot remap registers\n");
162  retval = -ENXIO;
163  goto err4;
164  }
165 
166  ohci_hcd_init(hcd_to_ohci(hcd));
167 
168  retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
169  if (retval)
170  goto err5;
171 
172  /* enable power and unmask interrupts */
173 
175  sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
176 
177  return 0;
178 err5:
179  iounmap(hcd->regs);
180 err4:
181  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
182 err3:
183  usb_put_hcd(hcd);
184 err2:
186 err1:
187  release_mem_region(mem->start, resource_size(mem));
188 err0:
189  return retval;
190 }
191 
192 static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
193 {
194  struct usb_hcd *hcd = platform_get_drvdata(pdev);
195  struct resource *mem;
196 
197  usb_remove_hcd(hcd);
198  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
199  usb_put_hcd(hcd);
201  mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
202  if (mem)
203  release_mem_region(mem->start, resource_size(mem));
204 
205  /* mask interrupts and disable power */
206 
207  sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
208  sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
209 
210  platform_set_drvdata(pdev, NULL);
211  return 0;
212 }
213 
214 /*-------------------------------------------------------------------------*/
215 
216 #ifdef CONFIG_PM
217 static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
218 {
219  struct device *dev = &pdev->dev;
220  struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
221 
222  if (time_before(jiffies, ohci->next_statechange))
223  msleep(5);
224  ohci->next_statechange = jiffies;
225 
227  return 0;
228 }
229 
230 static int ohci_sm501_resume(struct platform_device *pdev)
231 {
232  struct device *dev = &pdev->dev;
233  struct usb_hcd *hcd = platform_get_drvdata(pdev);
234  struct ohci_hcd *ohci = hcd_to_ohci(hcd);
235 
236  if (time_before(jiffies, ohci->next_statechange))
237  msleep(5);
238  ohci->next_statechange = jiffies;
239 
241  ohci_finish_controller_resume(hcd);
242  return 0;
243 }
244 #else
245 #define ohci_sm501_suspend NULL
246 #define ohci_sm501_resume NULL
247 #endif
248 
249 /*-------------------------------------------------------------------------*/
250 
251 /*
252  * Driver definition to register with the SM501 bus
253  */
254 static struct platform_driver ohci_hcd_sm501_driver = {
255  .probe = ohci_hcd_sm501_drv_probe,
256  .remove = ohci_hcd_sm501_drv_remove,
257  .shutdown = usb_hcd_platform_shutdown,
258  .suspend = ohci_sm501_suspend,
259  .resume = ohci_sm501_resume,
260  .driver = {
261  .owner = THIS_MODULE,
262  .name = "sm501-usb",
263  },
264 };
265 MODULE_ALIAS("platform:sm501-usb");