Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ohci-cns3xxx.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Cavium Networks
3  *
4  * This file is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License, Version 2, as
6  * published by the Free Software Foundation.
7  */
8 
10 #include <linux/atomic.h>
11 #include <mach/cns3xxx.h>
12 #include <mach/pm.h>
13 
14 static int __devinit
15 cns3xxx_ohci_start(struct usb_hcd *hcd)
16 {
17  struct ohci_hcd *ohci = hcd_to_ohci(hcd);
18  int ret;
19 
20  /*
21  * EHCI and OHCI share the same clock and power,
22  * resetting twice would cause the 1st controller been reset.
23  * Therefore only do power up at the first up device, and
24  * power down at the last down device.
25  *
26  * Set USB AHB INCR length to 16
27  */
28  if (atomic_inc_return(&usb_pwr_ref) == 1) {
34  }
35 
36  ret = ohci_init(ohci);
37  if (ret < 0)
38  return ret;
39 
40  ohci->num_ports = 1;
41 
42  ret = ohci_run(ohci);
43  if (ret < 0) {
44  dev_err(hcd->self.controller, "can't start %s\n",
45  hcd->self.bus_name);
46  ohci_stop(hcd);
47  return ret;
48  }
49  return 0;
50 }
51 
52 static const struct hc_driver cns3xxx_ohci_hc_driver = {
53  .description = hcd_name,
54  .product_desc = "CNS3XXX OHCI Host controller",
55  .hcd_priv_size = sizeof(struct ohci_hcd),
56  .irq = ohci_irq,
57  .flags = HCD_USB11 | HCD_MEMORY,
58  .start = cns3xxx_ohci_start,
59  .stop = ohci_stop,
60  .shutdown = ohci_shutdown,
61  .urb_enqueue = ohci_urb_enqueue,
62  .urb_dequeue = ohci_urb_dequeue,
63  .endpoint_disable = ohci_endpoint_disable,
64  .get_frame_number = ohci_get_frame,
65  .hub_status_data = ohci_hub_status_data,
66  .hub_control = ohci_hub_control,
67 #ifdef CONFIG_PM
68  .bus_suspend = ohci_bus_suspend,
69  .bus_resume = ohci_bus_resume,
70 #endif
71  .start_port_reset = ohci_start_port_reset,
72 };
73 
74 static int cns3xxx_ohci_probe(struct platform_device *pdev)
75 {
76  struct device *dev = &pdev->dev;
77  struct usb_hcd *hcd;
78  const struct hc_driver *driver = &cns3xxx_ohci_hc_driver;
79  struct resource *res;
80  int irq;
81  int retval;
82 
83  if (usb_disabled())
84  return -ENODEV;
85 
86  res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
87  if (!res) {
88  dev_err(dev, "Found HC with no IRQ.\n");
89  return -ENODEV;
90  }
91  irq = res->start;
92 
93  hcd = usb_create_hcd(driver, dev, dev_name(dev));
94  if (!hcd)
95  return -ENOMEM;
96 
97  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
98  if (!res) {
99  dev_err(dev, "Found HC with no register addr.\n");
100  retval = -ENODEV;
101  goto err1;
102  }
103  hcd->rsrc_start = res->start;
104  hcd->rsrc_len = resource_size(res);
105 
106  if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
107  driver->description)) {
108  dev_dbg(dev, "controller already in use\n");
109  retval = -EBUSY;
110  goto err1;
111  }
112 
113  hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
114  if (!hcd->regs) {
115  dev_dbg(dev, "error mapping memory\n");
116  retval = -EFAULT;
117  goto err2;
118  }
119 
120  ohci_hcd_init(hcd_to_ohci(hcd));
121 
122  retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
123  if (retval == 0)
124  return retval;
125 
126  iounmap(hcd->regs);
127 err2:
128  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
129 err1:
130  usb_put_hcd(hcd);
131  return retval;
132 }
133 
134 static int cns3xxx_ohci_remove(struct platform_device *pdev)
135 {
136  struct usb_hcd *hcd = platform_get_drvdata(pdev);
137 
138  usb_remove_hcd(hcd);
139  iounmap(hcd->regs);
140  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
141 
142  /*
143  * EHCI and OHCI share the same clock and power,
144  * resetting twice would cause the 1st controller been reset.
145  * Therefore only do power up at the first up device, and
146  * power down at the last down device.
147  */
148  if (atomic_dec_return(&usb_pwr_ref) == 0)
150 
151  usb_put_hcd(hcd);
152 
153  platform_set_drvdata(pdev, NULL);
154 
155  return 0;
156 }
157 
158 MODULE_ALIAS("platform:cns3xxx-ohci");
159 
160 static struct platform_driver ohci_hcd_cns3xxx_driver = {
161  .probe = cns3xxx_ohci_probe,
162  .remove = cns3xxx_ohci_remove,
163  .driver = {
164  .name = "cns3xxx-ohci",
165  },
166 };