Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ehci-ls1x.c
Go to the documentation of this file.
1 /*
2  * Bus Glue for Loongson LS1X built-in EHCI controller.
3  *
4  * Copyright (c) 2012 Zhang, Keguang <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published
8  * by the Free Software Foundation.
9  */
10 
11 
12 #include <linux/platform_device.h>
13 
14 static int ehci_ls1x_reset(struct usb_hcd *hcd)
15 {
16  struct ehci_hcd *ehci = hcd_to_ehci(hcd);
17  int ret;
18 
19  ehci->caps = hcd->regs;
20 
21  ret = ehci_setup(hcd);
22  if (ret)
23  return ret;
24 
25  ehci_port_power(ehci, 0);
26 
27  return 0;
28 }
29 
30 static const struct hc_driver ehci_ls1x_hc_driver = {
31  .description = hcd_name,
32  .product_desc = "LOONGSON1 EHCI",
33  .hcd_priv_size = sizeof(struct ehci_hcd),
34 
35  /*
36  * generic hardware linkage
37  */
38  .irq = ehci_irq,
39  .flags = HCD_MEMORY | HCD_USB2,
40 
41  /*
42  * basic lifecycle operations
43  */
44  .reset = ehci_ls1x_reset,
45  .start = ehci_run,
46  .stop = ehci_stop,
47  .shutdown = ehci_shutdown,
48 
49  /*
50  * managing i/o requests and associated device resources
51  */
52  .urb_enqueue = ehci_urb_enqueue,
53  .urb_dequeue = ehci_urb_dequeue,
54  .endpoint_disable = ehci_endpoint_disable,
55  .endpoint_reset = ehci_endpoint_reset,
56 
57  /*
58  * scheduling support
59  */
60  .get_frame_number = ehci_get_frame,
61 
62  /*
63  * root hub support
64  */
65  .hub_status_data = ehci_hub_status_data,
66  .hub_control = ehci_hub_control,
67  .relinquish_port = ehci_relinquish_port,
68  .port_handed_over = ehci_port_handed_over,
69 
70  .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
71 };
72 
73 static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
74 {
75  struct usb_hcd *hcd;
76  struct resource *res;
77  int irq;
78  int ret;
79 
80  pr_debug("initializing loongson1 ehci USB Controller\n");
81 
82  if (usb_disabled())
83  return -ENODEV;
84 
85  res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
86  if (!res) {
87  dev_err(&pdev->dev,
88  "Found HC with no IRQ. Check %s setup!\n",
89  dev_name(&pdev->dev));
90  return -ENODEV;
91  }
92  irq = res->start;
93 
94  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
95  if (!res) {
96  dev_err(&pdev->dev,
97  "Found HC with no register addr. Check %s setup!\n",
98  dev_name(&pdev->dev));
99  return -ENODEV;
100  }
101 
102  hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
103  dev_name(&pdev->dev));
104  if (!hcd)
105  return -ENOMEM;
106  hcd->rsrc_start = res->start;
107  hcd->rsrc_len = resource_size(res);
108 
109  hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
110  if (hcd->regs == NULL) {
111  dev_dbg(&pdev->dev, "error mapping memory\n");
112  ret = -EFAULT;
113  goto err_put_hcd;
114  }
115 
116  ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
117  if (ret)
118  goto err_put_hcd;
119 
120  return ret;
121 
122 err_put_hcd:
123  usb_put_hcd(hcd);
124  return ret;
125 }
126 
127 static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
128 {
129  struct usb_hcd *hcd = platform_get_drvdata(pdev);
130 
131  usb_remove_hcd(hcd);
132  usb_put_hcd(hcd);
133 
134  return 0;
135 }
136 
137 static struct platform_driver ehci_ls1x_driver = {
138  .probe = ehci_hcd_ls1x_probe,
139  .remove = ehci_hcd_ls1x_remove,
140  .shutdown = usb_hcd_platform_shutdown,
141  .driver = {
142  .name = "ls1x-ehci",
143  .owner = THIS_MODULE,
144  },
145 };
146