Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ohci-octeon.c
Go to the documentation of this file.
1 /*
2  * EHCI HCD glue for Cavium Octeon II SOCs.
3  *
4  * Loosely based on ehci-au1xxx.c
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License. See the file "COPYING" in the main directory of this archive
8  * for more details.
9  *
10  * Copyright (C) 2010 Cavium Networks
11  *
12  */
13 
14 #include <linux/platform_device.h>
15 
16 #include <asm/octeon/octeon.h>
18 
19 #define OCTEON_OHCI_HCD_NAME "octeon-ohci"
20 
21 /* Common clock init code. */
22 void octeon2_usb_clocks_start(void);
23 void octeon2_usb_clocks_stop(void);
24 
25 static void ohci_octeon_hw_start(void)
26 {
27  union cvmx_uctlx_ohci_ctl ohci_ctl;
28 
30 
31  ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
32  ohci_ctl.s.l2c_addr_msb = 0;
33  ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
34  ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
35  cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64);
36 
37 }
38 
39 static void ohci_octeon_hw_stop(void)
40 {
41  /* Undo ohci_octeon_start() */
43 }
44 
45 static int __devinit ohci_octeon_start(struct usb_hcd *hcd)
46 {
47  struct ohci_hcd *ohci = hcd_to_ohci(hcd);
48  int ret;
49 
50  ret = ohci_init(ohci);
51 
52  if (ret < 0)
53  return ret;
54 
55  ret = ohci_run(ohci);
56 
57  if (ret < 0) {
58  ohci_err(ohci, "can't start %s", hcd->self.bus_name);
59  ohci_stop(hcd);
60  return ret;
61  }
62 
63  return 0;
64 }
65 
66 static const struct hc_driver ohci_octeon_hc_driver = {
67  .description = hcd_name,
68  .product_desc = "Octeon OHCI",
69  .hcd_priv_size = sizeof(struct ohci_hcd),
70 
71  /*
72  * generic hardware linkage
73  */
74  .irq = ohci_irq,
75  .flags = HCD_USB11 | HCD_MEMORY,
76 
77  /*
78  * basic lifecycle operations
79  */
80  .start = ohci_octeon_start,
81  .stop = ohci_stop,
82  .shutdown = ohci_shutdown,
83 
84  /*
85  * managing i/o requests and associated device resources
86  */
87  .urb_enqueue = ohci_urb_enqueue,
88  .urb_dequeue = ohci_urb_dequeue,
89  .endpoint_disable = ohci_endpoint_disable,
90 
91  /*
92  * scheduling support
93  */
94  .get_frame_number = ohci_get_frame,
95 
96  /*
97  * root hub support
98  */
99  .hub_status_data = ohci_hub_status_data,
100  .hub_control = ohci_hub_control,
101 
102  .start_port_reset = ohci_start_port_reset,
103 };
104 
105 static int ohci_octeon_drv_probe(struct platform_device *pdev)
106 {
107  struct usb_hcd *hcd;
108  struct ohci_hcd *ohci;
109  void *reg_base;
110  struct resource *res_mem;
111  int irq;
112  int ret;
113 
114  if (usb_disabled())
115  return -ENODEV;
116 
117  irq = platform_get_irq(pdev, 0);
118  if (irq < 0) {
119  dev_err(&pdev->dev, "No irq assigned\n");
120  return -ENODEV;
121  }
122 
123  res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
124  if (res_mem == NULL) {
125  dev_err(&pdev->dev, "No register space assigned\n");
126  return -ENODEV;
127  }
128 
129  /* Ohci is a 32-bit device. */
130  pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
131  pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
132 
133  hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon");
134  if (!hcd)
135  return -ENOMEM;
136 
137  hcd->rsrc_start = res_mem->start;
138  hcd->rsrc_len = resource_size(res_mem);
139 
140  if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
142  dev_err(&pdev->dev, "request_mem_region failed\n");
143  ret = -EBUSY;
144  goto err1;
145  }
146 
147  reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len);
148  if (!reg_base) {
149  dev_err(&pdev->dev, "ioremap failed\n");
150  ret = -ENOMEM;
151  goto err2;
152  }
153 
154  ohci_octeon_hw_start();
155 
156  hcd->regs = reg_base;
157 
158  ohci = hcd_to_ohci(hcd);
159 
160  /* Octeon OHCI matches CPU endianness. */
161 #ifdef __BIG_ENDIAN
162  ohci->flags |= OHCI_QUIRK_BE_MMIO;
163 #endif
164 
165  ohci_hcd_init(ohci);
166 
167  ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
168  if (ret) {
169  dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
170  goto err3;
171  }
172 
173  platform_set_drvdata(pdev, hcd);
174 
175  return 0;
176 
177 err3:
178  ohci_octeon_hw_stop();
179 
180  iounmap(hcd->regs);
181 err2:
182  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
183 err1:
184  usb_put_hcd(hcd);
185  return ret;
186 }
187 
188 static int ohci_octeon_drv_remove(struct platform_device *pdev)
189 {
190  struct usb_hcd *hcd = platform_get_drvdata(pdev);
191 
192  usb_remove_hcd(hcd);
193 
194  ohci_octeon_hw_stop();
195  iounmap(hcd->regs);
196  release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
197  usb_put_hcd(hcd);
198 
199  platform_set_drvdata(pdev, NULL);
200 
201  return 0;
202 }
203 
204 static struct platform_driver ohci_octeon_driver = {
205  .probe = ohci_octeon_drv_probe,
206  .remove = ohci_octeon_drv_remove,
207  .shutdown = usb_hcd_platform_shutdown,
208  .driver = {
209  .name = OCTEON_OHCI_HCD_NAME,
210  .owner = THIS_MODULE,
211  }
212 };
213