Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ohci-exynos.c
Go to the documentation of this file.
1 /*
2  * SAMSUNG EXYNOS USB HOST OHCI Controller
3  *
4  * Copyright (C) 2011 Samsung Electronics Co.Ltd
5  * Author: Jingoo Han <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2 of the License, or (at your
10  * option) any later version.
11  *
12  */
13 
14 #include <linux/clk.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
18 #include <plat/usb-phy.h>
19 
21  struct device *dev;
22  struct usb_hcd *hcd;
23  struct clk *clk;
24 };
25 
26 static int ohci_exynos_start(struct usb_hcd *hcd)
27 {
28  struct ohci_hcd *ohci = hcd_to_ohci(hcd);
29  int ret;
30 
31  ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci);
32 
33  ret = ohci_init(ohci);
34  if (ret < 0)
35  return ret;
36 
37  ret = ohci_run(ohci);
38  if (ret < 0) {
39  dev_err(hcd->self.controller, "can't start %s\n",
40  hcd->self.bus_name);
41  ohci_stop(hcd);
42  return ret;
43  }
44 
45  return 0;
46 }
47 
48 static const struct hc_driver exynos_ohci_hc_driver = {
49  .description = hcd_name,
50  .product_desc = "EXYNOS OHCI Host Controller",
51  .hcd_priv_size = sizeof(struct ohci_hcd),
52 
53  .irq = ohci_irq,
54  .flags = HCD_MEMORY|HCD_USB11,
55 
56  .start = ohci_exynos_start,
57  .stop = ohci_stop,
58  .shutdown = ohci_shutdown,
59 
60  .get_frame_number = ohci_get_frame,
61 
62  .urb_enqueue = ohci_urb_enqueue,
63  .urb_dequeue = ohci_urb_dequeue,
64  .endpoint_disable = ohci_endpoint_disable,
65 
66  .hub_status_data = ohci_hub_status_data,
67  .hub_control = ohci_hub_control,
68 #ifdef CONFIG_PM
69  .bus_suspend = ohci_bus_suspend,
70  .bus_resume = ohci_bus_resume,
71 #endif
72  .start_port_reset = ohci_start_port_reset,
73 };
74 
75 static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32);
76 
77 static int __devinit exynos_ohci_probe(struct platform_device *pdev)
78 {
80  struct exynos_ohci_hcd *exynos_ohci;
81  struct usb_hcd *hcd;
82  struct ohci_hcd *ohci;
83  struct resource *res;
84  int irq;
85  int err;
86 
87  pdata = pdev->dev.platform_data;
88  if (!pdata) {
89  dev_err(&pdev->dev, "No platform data defined\n");
90  return -EINVAL;
91  }
92 
93  /*
94  * Right now device-tree probed devices don't get dma_mask set.
95  * Since shared usb code relies on it, set it here for now.
96  * Once we move to full device tree support this will vanish off.
97  */
98  if (!pdev->dev.dma_mask)
99  pdev->dev.dma_mask = &ohci_exynos_dma_mask;
100  if (!pdev->dev.coherent_dma_mask)
101  pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
102 
103  exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd),
104  GFP_KERNEL);
105  if (!exynos_ohci)
106  return -ENOMEM;
107 
108  exynos_ohci->dev = &pdev->dev;
109 
110  hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
111  dev_name(&pdev->dev));
112  if (!hcd) {
113  dev_err(&pdev->dev, "Unable to create HCD\n");
114  return -ENOMEM;
115  }
116 
117  exynos_ohci->hcd = hcd;
118  exynos_ohci->clk = clk_get(&pdev->dev, "usbhost");
119 
120  if (IS_ERR(exynos_ohci->clk)) {
121  dev_err(&pdev->dev, "Failed to get usbhost clock\n");
122  err = PTR_ERR(exynos_ohci->clk);
123  goto fail_clk;
124  }
125 
126  err = clk_enable(exynos_ohci->clk);
127  if (err)
128  goto fail_clken;
129 
130  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
131  if (!res) {
132  dev_err(&pdev->dev, "Failed to get I/O memory\n");
133  err = -ENXIO;
134  goto fail_io;
135  }
136 
137  hcd->rsrc_start = res->start;
138  hcd->rsrc_len = resource_size(res);
139  hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
140  if (!hcd->regs) {
141  dev_err(&pdev->dev, "Failed to remap I/O memory\n");
142  err = -ENOMEM;
143  goto fail_io;
144  }
145 
146  irq = platform_get_irq(pdev, 0);
147  if (!irq) {
148  dev_err(&pdev->dev, "Failed to get IRQ\n");
149  err = -ENODEV;
150  goto fail_io;
151  }
152 
153  if (pdata->phy_init)
154  pdata->phy_init(pdev, S5P_USB_PHY_HOST);
155 
156  ohci = hcd_to_ohci(hcd);
157  ohci_hcd_init(ohci);
158 
159  err = usb_add_hcd(hcd, irq, IRQF_SHARED);
160  if (err) {
161  dev_err(&pdev->dev, "Failed to add USB HCD\n");
162  goto fail_io;
163  }
164 
165  platform_set_drvdata(pdev, exynos_ohci);
166 
167  return 0;
168 
169 fail_io:
170  clk_disable(exynos_ohci->clk);
171 fail_clken:
172  clk_put(exynos_ohci->clk);
173 fail_clk:
174  usb_put_hcd(hcd);
175  return err;
176 }
177 
178 static int __devexit exynos_ohci_remove(struct platform_device *pdev)
179 {
180  struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
181  struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
182  struct usb_hcd *hcd = exynos_ohci->hcd;
183 
184  usb_remove_hcd(hcd);
185 
186  if (pdata && pdata->phy_exit)
187  pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
188 
189  clk_disable(exynos_ohci->clk);
190  clk_put(exynos_ohci->clk);
191 
192  usb_put_hcd(hcd);
193 
194  return 0;
195 }
196 
197 static void exynos_ohci_shutdown(struct platform_device *pdev)
198 {
199  struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
200  struct usb_hcd *hcd = exynos_ohci->hcd;
201 
202  if (hcd->driver->shutdown)
203  hcd->driver->shutdown(hcd);
204 }
205 
206 #ifdef CONFIG_PM
207 static int exynos_ohci_suspend(struct device *dev)
208 {
209  struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
210  struct usb_hcd *hcd = exynos_ohci->hcd;
211  struct ohci_hcd *ohci = hcd_to_ohci(hcd);
212  struct platform_device *pdev = to_platform_device(dev);
213  struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
214  unsigned long flags;
215  int rc = 0;
216 
217  /*
218  * Root hub was already suspended. Disable irq emission and
219  * mark HW unaccessible, bail out if RH has been resumed. Use
220  * the spinlock to properly synchronize with possible pending
221  * RH suspend or resume activity.
222  */
223  spin_lock_irqsave(&ohci->lock, flags);
224  if (ohci->rh_state != OHCI_RH_SUSPENDED &&
225  ohci->rh_state != OHCI_RH_HALTED) {
226  rc = -EINVAL;
227  goto fail;
228  }
229 
230  clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
231 
232  if (pdata && pdata->phy_exit)
233  pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
234 
235  clk_disable(exynos_ohci->clk);
236 
237 fail:
238  spin_unlock_irqrestore(&ohci->lock, flags);
239 
240  return rc;
241 }
242 
243 static int exynos_ohci_resume(struct device *dev)
244 {
245  struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev);
246  struct usb_hcd *hcd = exynos_ohci->hcd;
247  struct platform_device *pdev = to_platform_device(dev);
248  struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
249 
250  clk_enable(exynos_ohci->clk);
251 
252  if (pdata && pdata->phy_init)
253  pdata->phy_init(pdev, S5P_USB_PHY_HOST);
254 
255  /* Mark hardware accessible again as we are out of D3 state by now */
256  set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
257 
258  ohci_finish_controller_resume(hcd);
259 
260  return 0;
261 }
262 #else
263 #define exynos_ohci_suspend NULL
264 #define exynos_ohci_resume NULL
265 #endif
266 
267 static const struct dev_pm_ops exynos_ohci_pm_ops = {
268  .suspend = exynos_ohci_suspend,
269  .resume = exynos_ohci_resume,
270 };
271 
272 #ifdef CONFIG_OF
273 static const struct of_device_id exynos_ohci_match[] = {
274  { .compatible = "samsung,exynos-ohci" },
275  {},
276 };
277 MODULE_DEVICE_TABLE(of, exynos_ohci_match);
278 #endif
279 
280 static struct platform_driver exynos_ohci_driver = {
281  .probe = exynos_ohci_probe,
282  .remove = __devexit_p(exynos_ohci_remove),
283  .shutdown = exynos_ohci_shutdown,
284  .driver = {
285  .name = "exynos-ohci",
286  .owner = THIS_MODULE,
287  .pm = &exynos_ohci_pm_ops,
288  .of_match_table = of_match_ptr(exynos_ohci_match),
289  }
290 };
291 
292 MODULE_ALIAS("platform:exynos-ohci");
293 MODULE_AUTHOR("Jingoo Han <[email protected]>");