Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ehci-sh.c
Go to the documentation of this file.
1 /*
2  * SuperH EHCI host controller driver
3  *
4  * Copyright (C) 2010 Paul Mundt
5  *
6  * Based on ohci-sh.c and ehci-atmel.c.
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License. See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12 #include <linux/platform_device.h>
13 #include <linux/clk.h>
15 
16 struct ehci_sh_priv {
17  struct clk *iclk, *fclk;
18  struct usb_hcd *hcd;
19 };
20 
21 static int ehci_sh_reset(struct usb_hcd *hcd)
22 {
23  struct ehci_hcd *ehci = hcd_to_ehci(hcd);
24  int ret;
25 
26  ehci->caps = hcd->regs;
27 
28  ret = ehci_setup(hcd);
29  if (unlikely(ret))
30  return ret;
31 
32  ehci_port_power(ehci, 0);
33 
34  return ret;
35 }
36 
37 static const struct hc_driver ehci_sh_hc_driver = {
38  .description = hcd_name,
39  .product_desc = "SuperH EHCI",
40  .hcd_priv_size = sizeof(struct ehci_hcd),
41 
42  /*
43  * generic hardware linkage
44  */
45  .irq = ehci_irq,
46  .flags = HCD_USB2 | HCD_MEMORY,
47 
48  /*
49  * basic lifecycle operations
50  */
51  .reset = ehci_sh_reset,
52  .start = ehci_run,
53  .stop = ehci_stop,
54  .shutdown = ehci_shutdown,
55 
56  /*
57  * managing i/o requests and associated device resources
58  */
59  .urb_enqueue = ehci_urb_enqueue,
60  .urb_dequeue = ehci_urb_dequeue,
61  .endpoint_disable = ehci_endpoint_disable,
62  .endpoint_reset = ehci_endpoint_reset,
63 
64  /*
65  * scheduling support
66  */
67  .get_frame_number = ehci_get_frame,
68 
69  /*
70  * root hub support
71  */
72  .hub_status_data = ehci_hub_status_data,
73  .hub_control = ehci_hub_control,
74 
75 #ifdef CONFIG_PM
76  .bus_suspend = ehci_bus_suspend,
77  .bus_resume = ehci_bus_resume,
78 #endif
79 
80  .relinquish_port = ehci_relinquish_port,
81  .port_handed_over = ehci_port_handed_over,
82  .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
83 };
84 
85 static int ehci_hcd_sh_probe(struct platform_device *pdev)
86 {
87  const struct hc_driver *driver = &ehci_sh_hc_driver;
88  struct resource *res;
89  struct ehci_sh_priv *priv;
90  struct ehci_sh_platdata *pdata;
91  struct usb_hcd *hcd;
92  int irq, ret;
93 
94  if (usb_disabled())
95  return -ENODEV;
96 
97  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
98  if (!res) {
99  dev_err(&pdev->dev,
100  "Found HC with no register addr. Check %s setup!\n",
101  dev_name(&pdev->dev));
102  ret = -ENODEV;
103  goto fail_create_hcd;
104  }
105 
106  irq = platform_get_irq(pdev, 0);
107  if (irq <= 0) {
108  dev_err(&pdev->dev,
109  "Found HC with no IRQ. Check %s setup!\n",
110  dev_name(&pdev->dev));
111  ret = -ENODEV;
112  goto fail_create_hcd;
113  }
114 
115  pdata = pdev->dev.platform_data;
116 
117  /* initialize hcd */
118  hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
119  dev_name(&pdev->dev));
120  if (!hcd) {
121  ret = -ENOMEM;
122  goto fail_create_hcd;
123  }
124 
125  hcd->rsrc_start = res->start;
126  hcd->rsrc_len = resource_size(res);
127 
128  hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
129  if (hcd->regs == NULL) {
130  dev_dbg(&pdev->dev, "error mapping memory\n");
131  ret = -ENXIO;
132  goto fail_request_resource;
133  }
134 
135  priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv),
136  GFP_KERNEL);
137  if (!priv) {
138  dev_dbg(&pdev->dev, "error allocating priv data\n");
139  ret = -ENOMEM;
140  goto fail_request_resource;
141  }
142 
143  /* These are optional, we don't care if they fail */
144  priv->fclk = devm_clk_get(&pdev->dev, "usb_fck");
145  if (IS_ERR(priv->fclk))
146  priv->fclk = NULL;
147 
148  priv->iclk = devm_clk_get(&pdev->dev, "usb_ick");
149  if (IS_ERR(priv->iclk))
150  priv->iclk = NULL;
151 
152  clk_enable(priv->fclk);
153  clk_enable(priv->iclk);
154 
155  if (pdata && pdata->phy_init)
156  pdata->phy_init();
157 
158  ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
159  if (ret != 0) {
160  dev_err(&pdev->dev, "Failed to add hcd");
161  goto fail_add_hcd;
162  }
163 
164  priv->hcd = hcd;
165  platform_set_drvdata(pdev, priv);
166 
167  return ret;
168 
169 fail_add_hcd:
170  clk_disable(priv->iclk);
171  clk_disable(priv->fclk);
172 
173 fail_request_resource:
174  usb_put_hcd(hcd);
175 fail_create_hcd:
176  dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret);
177 
178  return ret;
179 }
180 
181 static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
182 {
183  struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
184  struct usb_hcd *hcd = priv->hcd;
185 
186  usb_remove_hcd(hcd);
187  usb_put_hcd(hcd);
188  platform_set_drvdata(pdev, NULL);
189 
190  clk_disable(priv->fclk);
191  clk_disable(priv->iclk);
192 
193  return 0;
194 }
195 
196 static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
197 {
198  struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
199  struct usb_hcd *hcd = priv->hcd;
200 
201  if (hcd->driver->shutdown)
202  hcd->driver->shutdown(hcd);
203 }
204 
205 static struct platform_driver ehci_hcd_sh_driver = {
206  .probe = ehci_hcd_sh_probe,
207  .remove = __exit_p(ehci_hcd_sh_remove),
208  .shutdown = ehci_hcd_sh_shutdown,
209  .driver = {
210  .name = "sh_ehci",
211  .owner = THIS_MODULE,
212  },
213 };
214 
215 MODULE_ALIAS("platform:sh_ehci");