Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
uhci-grlib.c
Go to the documentation of this file.
1 /*
2  * UHCI HCD (Host Controller Driver) for GRLIB GRUSBHC
3  *
4  * Copyright (c) 2011 Jan Andersson <[email protected]>
5  *
6  * This file is based on UHCI PCI HCD:
7  * (C) Copyright 1999 Linus Torvalds
8  * (C) Copyright 1999-2002 Johannes Erdfelt, [email protected]
9  * (C) Copyright 1999 Randy Dunlap
10  * (C) Copyright 1999 Georg Acher, [email protected]
11  * (C) Copyright 1999 Deti Fliegl, [email protected]
12  * (C) Copyright 1999 Thomas Sailer, [email protected]
13  * (C) Copyright 1999 Roman Weissgaerber, [email protected]
14  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
15  * support from usb-ohci.c by Adam Richter, [email protected]).
16  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
17  * (C) Copyright 2004-2007 Alan Stern, [email protected]
18  */
19 
20 #include <linux/of_irq.h>
21 #include <linux/of_address.h>
22 #include <linux/of_platform.h>
23 
24 static int uhci_grlib_init(struct usb_hcd *hcd)
25 {
26  struct uhci_hcd *uhci = hcd_to_uhci(hcd);
27 
28  /*
29  * Probe to determine the endianness of the controller.
30  * We know that bit 7 of the PORTSC1 register is always set
31  * and bit 15 is always clear. If uhci_readw() yields a value
32  * with bit 7 (0x80) turned on then the current little-endian
33  * setting is correct. Otherwise we assume the value was
34  * byte-swapped; hence the register interface and presumably
35  * also the descriptors are big-endian.
36  */
37  if (!(uhci_readw(uhci, USBPORTSC1) & 0x80)) {
38  uhci->big_endian_mmio = 1;
39  uhci->big_endian_desc = 1;
40  }
41 
42  uhci->rh_numports = uhci_count_ports(hcd);
43 
44  /* Set up pointers to to generic functions */
45  uhci->reset_hc = uhci_generic_reset_hc;
46  uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
47  /* No special actions need to be taken for the functions below */
48  uhci->configure_hc = NULL;
51 
52  /* Reset if the controller isn't already safely quiescent. */
53  check_and_reset_hc(uhci);
54  return 0;
55 }
56 
57 static const struct hc_driver uhci_grlib_hc_driver = {
58  .description = hcd_name,
59  .product_desc = "GRLIB GRUSBHC UHCI Host Controller",
60  .hcd_priv_size = sizeof(struct uhci_hcd),
61 
62  /* Generic hardware linkage */
63  .irq = uhci_irq,
64  .flags = HCD_MEMORY | HCD_USB11,
65 
66  /* Basic lifecycle operations */
67  .reset = uhci_grlib_init,
68  .start = uhci_start,
69 #ifdef CONFIG_PM
70  .pci_suspend = NULL,
71  .pci_resume = NULL,
72  .bus_suspend = uhci_rh_suspend,
73  .bus_resume = uhci_rh_resume,
74 #endif
75  .stop = uhci_stop,
76 
77  .urb_enqueue = uhci_urb_enqueue,
78  .urb_dequeue = uhci_urb_dequeue,
79 
80  .endpoint_disable = uhci_hcd_endpoint_disable,
81  .get_frame_number = uhci_hcd_get_frame_number,
82 
83  .hub_status_data = uhci_hub_status_data,
84  .hub_control = uhci_hub_control,
85 };
86 
87 
88 static int __devinit uhci_hcd_grlib_probe(struct platform_device *op)
89 {
90  struct device_node *dn = op->dev.of_node;
91  struct usb_hcd *hcd;
92  struct uhci_hcd *uhci = NULL;
93  struct resource res;
94  int irq;
95  int rv;
96 
97  if (usb_disabled())
98  return -ENODEV;
99 
100  dev_dbg(&op->dev, "initializing GRUSBHC UHCI USB Controller\n");
101 
102  rv = of_address_to_resource(dn, 0, &res);
103  if (rv)
104  return rv;
105 
106  /* usb_create_hcd requires dma_mask != NULL */
107  op->dev.dma_mask = &op->dev.coherent_dma_mask;
108  hcd = usb_create_hcd(&uhci_grlib_hc_driver, &op->dev,
109  "GRUSBHC UHCI USB");
110  if (!hcd)
111  return -ENOMEM;
112 
113  hcd->rsrc_start = res.start;
114  hcd->rsrc_len = resource_size(&res);
115 
116  if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
117  printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
118  rv = -EBUSY;
119  goto err_rmr;
120  }
121 
122  irq = irq_of_parse_and_map(dn, 0);
123  if (irq == NO_IRQ) {
124  printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
125  rv = -EBUSY;
126  goto err_irq;
127  }
128 
129  hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
130  if (!hcd->regs) {
131  printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
132  rv = -ENOMEM;
133  goto err_ioremap;
134  }
135 
136  uhci = hcd_to_uhci(hcd);
137 
138  uhci->regs = hcd->regs;
139 
140  rv = usb_add_hcd(hcd, irq, 0);
141  if (rv)
142  goto err_uhci;
143 
144  return 0;
145 
146 err_uhci:
147  iounmap(hcd->regs);
148 err_ioremap:
149  irq_dispose_mapping(irq);
150 err_irq:
151  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
152 err_rmr:
153  usb_put_hcd(hcd);
154 
155  return rv;
156 }
157 
158 static int uhci_hcd_grlib_remove(struct platform_device *op)
159 {
160  struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
161 
162  dev_set_drvdata(&op->dev, NULL);
163 
164  dev_dbg(&op->dev, "stopping GRLIB GRUSBHC UHCI USB Controller\n");
165 
166  usb_remove_hcd(hcd);
167 
168  iounmap(hcd->regs);
169  irq_dispose_mapping(hcd->irq);
170  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
171 
172  usb_put_hcd(hcd);
173 
174  return 0;
175 }
176 
177 /* Make sure the controller is quiescent and that we're not using it
178  * any more. This is mainly for the benefit of programs which, like kexec,
179  * expect the hardware to be idle: not doing DMA or generating IRQs.
180  *
181  * This routine may be called in a damaged or failing kernel. Hence we
182  * do not acquire the spinlock before shutting down the controller.
183  */
184 static void uhci_hcd_grlib_shutdown(struct platform_device *op)
185 {
186  struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
187 
188  uhci_hc_died(hcd_to_uhci(hcd));
189 }
190 
191 static const struct of_device_id uhci_hcd_grlib_of_match[] = {
192  { .name = "GAISLER_UHCI", },
193  { .name = "01_027", },
194  {},
195 };
196 MODULE_DEVICE_TABLE(of, uhci_hcd_grlib_of_match);
197 
198 
199 static struct platform_driver uhci_grlib_driver = {
200  .probe = uhci_hcd_grlib_probe,
201  .remove = uhci_hcd_grlib_remove,
202  .shutdown = uhci_hcd_grlib_shutdown,
203  .driver = {
204  .name = "grlib-uhci",
205  .owner = THIS_MODULE,
206  .of_match_table = uhci_hcd_grlib_of_match,
207  },
208 };