blob: 30c48789389e98a8e78c3be0e7d2d09cbeae6c23 [file] [log] [blame]
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +04001/*
2 * OHCI HCD (Host Controller Driver) for USB.
3 *
4 * TI DA8xx (OMAP-L1x) Bus Glue
5 *
6 * Derived from: ohci-omap.c and ohci-s3c2410.c
7 * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
8 *
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
12 */
13
Manjunath Goudar6c21caa2016-10-27 15:52:29 +020014#include <linux/clk.h>
15#include <linux/io.h>
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040016#include <linux/interrupt.h>
17#include <linux/jiffies.h>
Manjunath Goudar6c21caa2016-10-27 15:52:29 +020018#include <linux/kernel.h>
19#include <linux/module.h>
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040020#include <linux/platform_device.h>
David Lechner6110c422016-10-12 20:44:46 -050021#include <linux/phy/phy.h>
Arnd Bergmannec2a0832012-08-24 15:11:34 +020022#include <linux/platform_data/usb-davinci.h>
Manjunath Goudar6c21caa2016-10-27 15:52:29 +020023#include <linux/usb.h>
24#include <linux/usb/hcd.h>
25#include <asm/unaligned.h>
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040026
Manjunath Goudar6c21caa2016-10-27 15:52:29 +020027#include "ohci.h"
28
29#define DRIVER_DESC "DA8XX"
30#define DRV_NAME "ohci"
31
32static struct hc_driver __read_mostly ohci_da8xx_hc_driver;
33
34static int (*orig_ohci_hub_control)(struct usb_hcd *hcd, u16 typeReq,
35 u16 wValue, u16 wIndex, char *buf, u16 wLength);
36static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040037
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040038static struct clk *usb11_clk;
David Lechner6110c422016-10-12 20:44:46 -050039static struct phy *usb11_phy;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040040
41/* Over-current indicator change bitmask */
42static volatile u16 ocic_mask;
43
David Lechner6110c422016-10-12 20:44:46 -050044static int ohci_da8xx_enable(void)
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040045{
David Lechner6110c422016-10-12 20:44:46 -050046 int ret;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040047
David Lechner6110c422016-10-12 20:44:46 -050048 ret = clk_prepare_enable(usb11_clk);
49 if (ret)
50 return ret;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040051
David Lechner6110c422016-10-12 20:44:46 -050052 ret = phy_init(usb11_phy);
53 if (ret)
54 goto err_phy_init;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040055
David Lechner6110c422016-10-12 20:44:46 -050056 ret = phy_power_on(usb11_phy);
57 if (ret)
58 goto err_phy_power_on;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040059
David Lechner6110c422016-10-12 20:44:46 -050060 return 0;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040061
David Lechner6110c422016-10-12 20:44:46 -050062err_phy_power_on:
63 phy_exit(usb11_phy);
64err_phy_init:
65 clk_disable_unprepare(usb11_clk);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040066
David Lechner6110c422016-10-12 20:44:46 -050067 return ret;
68}
69
70static void ohci_da8xx_disable(void)
71{
72 phy_power_off(usb11_phy);
73 phy_exit(usb11_phy);
74 clk_disable_unprepare(usb11_clk);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040075}
76
77/*
78 * Handle the port over-current indicator change.
79 */
80static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
81 unsigned port)
82{
83 ocic_mask |= 1 << port;
84
85 /* Once over-current is detected, the port needs to be powered down */
86 if (hub->get_oci(port) > 0)
87 hub->set_power(port, 0);
88}
89
Manjunath Goudar6c21caa2016-10-27 15:52:29 +020090static int ohci_da8xx_reset(struct usb_hcd *hcd)
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040091{
92 struct device *dev = hcd->self.controller;
Jingoo Hand4f09e22013-07-30 19:59:40 +090093 struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +040094 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
95 int result;
96 u32 rh_a;
97
98 dev_dbg(dev, "starting USB controller\n");
99
David Lechner6110c422016-10-12 20:44:46 -0500100 result = ohci_da8xx_enable();
101 if (result < 0)
102 return result;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400103
104 /*
105 * DA8xx only have 1 port connected to the pins but the HC root hub
106 * register A reports 2 ports, thus we'll have to override it...
107 */
108 ohci->num_ports = 1;
109
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200110 result = ohci_setup(hcd);
David Lechner6110c422016-10-12 20:44:46 -0500111 if (result < 0) {
112 ohci_da8xx_disable();
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400113 return result;
David Lechner6110c422016-10-12 20:44:46 -0500114 }
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400115
116 /*
117 * Since we're providing a board-specific root hub port power control
118 * and over-current reporting, we have to override the HC root hub A
119 * register's default value, so that ohci_hub_control() could return
120 * the correct hub descriptor...
121 */
122 rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
123 if (hub->set_power) {
124 rh_a &= ~RH_A_NPS;
125 rh_a |= RH_A_PSM;
126 }
127 if (hub->get_oci) {
128 rh_a &= ~RH_A_NOCP;
129 rh_a |= RH_A_OCPM;
130 }
131 rh_a &= ~RH_A_POTPGT;
132 rh_a |= hub->potpgt << 24;
133 ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
134
135 return result;
136}
137
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400138/*
139 * Update the status data from the hub with the over-current indicator change.
140 */
141static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
142{
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200143 int length = orig_ohci_hub_status_data(hcd, buf);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400144
145 /* See if we have OCIC bit set on port 1 */
146 if (ocic_mask & (1 << 1)) {
147 dev_dbg(hcd->self.controller, "over-current indicator change "
148 "on port 1\n");
149
150 if (!length)
151 length = 1;
152
153 buf[0] |= 1 << 1;
154 }
155 return length;
156}
157
158/*
159 * Look at the control requests to the root hub and see if we need to override.
160 */
161static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
162 u16 wIndex, char *buf, u16 wLength)
163{
164 struct device *dev = hcd->self.controller;
Jingoo Hand4f09e22013-07-30 19:59:40 +0900165 struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400166 int temp;
167
168 switch (typeReq) {
169 case GetPortStatus:
170 /* Check the port number */
171 if (wIndex != 1)
172 break;
173
174 dev_dbg(dev, "GetPortStatus(%u)\n", wIndex);
175
176 temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
177
178 /* The port power status (PPS) bit defaults to 1 */
179 if (hub->get_power && hub->get_power(wIndex) == 0)
180 temp &= ~RH_PS_PPS;
181
182 /* The port over-current indicator (POCI) bit is always 0 */
183 if (hub->get_oci && hub->get_oci(wIndex) > 0)
184 temp |= RH_PS_POCI;
185
186 /* The over-current indicator change (OCIC) bit is 0 too */
187 if (ocic_mask & (1 << wIndex))
188 temp |= RH_PS_OCIC;
189
190 put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
191 return 0;
192 case SetPortFeature:
193 temp = 1;
194 goto check_port;
195 case ClearPortFeature:
196 temp = 0;
197
198check_port:
199 /* Check the port number */
200 if (wIndex != 1)
201 break;
202
203 switch (wValue) {
204 case USB_PORT_FEAT_POWER:
205 dev_dbg(dev, "%sPortFeature(%u): %s\n",
206 temp ? "Set" : "Clear", wIndex, "POWER");
207
208 if (!hub->set_power)
209 return -EPIPE;
210
211 return hub->set_power(wIndex, temp) ? -EPIPE : 0;
212 case USB_PORT_FEAT_C_OVER_CURRENT:
213 dev_dbg(dev, "%sPortFeature(%u): %s\n",
214 temp ? "Set" : "Clear", wIndex,
215 "C_OVER_CURRENT");
216
217 if (temp)
218 ocic_mask |= 1 << wIndex;
219 else
220 ocic_mask &= ~(1 << wIndex);
221 return 0;
222 }
223 }
224
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200225 return orig_ohci_hub_control(hcd, typeReq, wValue,
226 wIndex, buf, wLength);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400227}
228
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400229/*-------------------------------------------------------------------------*/
230
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200231static int ohci_da8xx_probe(struct platform_device *pdev)
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400232{
Jingoo Hand4f09e22013-07-30 19:59:40 +0900233 struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400234 struct usb_hcd *hcd;
235 struct resource *mem;
236 int error, irq;
237
238 if (hub == NULL)
239 return -ENODEV;
240
Jingoo Han644db162013-12-11 16:23:39 +0900241 usb11_clk = devm_clk_get(&pdev->dev, "usb11");
David Lechner6110c422016-10-12 20:44:46 -0500242 if (IS_ERR(usb11_clk)) {
243 if (PTR_ERR(usb11_clk) != -EPROBE_DEFER)
244 dev_err(&pdev->dev, "Failed to get clock.\n");
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400245 return PTR_ERR(usb11_clk);
David Lechner6110c422016-10-12 20:44:46 -0500246 }
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400247
David Lechner6110c422016-10-12 20:44:46 -0500248 usb11_phy = devm_phy_get(&pdev->dev, "usb-phy");
249 if (IS_ERR(usb11_phy)) {
250 if (PTR_ERR(usb11_phy) != -EPROBE_DEFER)
251 dev_err(&pdev->dev, "Failed to get phy.\n");
252 return PTR_ERR(usb11_phy);
253 }
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400254
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200255 hcd = usb_create_hcd(&ohci_da8xx_hc_driver, &pdev->dev,
256 dev_name(&pdev->dev));
Jingoo Han644db162013-12-11 16:23:39 +0900257 if (!hcd)
258 return -ENOMEM;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400259
260 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Jingoo Han644db162013-12-11 16:23:39 +0900261 hcd->regs = devm_ioremap_resource(&pdev->dev, mem);
262 if (IS_ERR(hcd->regs)) {
263 error = PTR_ERR(hcd->regs);
David Lechner6110c422016-10-12 20:44:46 -0500264 dev_err(&pdev->dev, "failed to map ohci.\n");
Jingoo Han644db162013-12-11 16:23:39 +0900265 goto err;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400266 }
Varka Bhadram54891d72014-11-04 07:51:09 +0530267 hcd->rsrc_start = mem->start;
268 hcd->rsrc_len = resource_size(mem);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400269
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400270 irq = platform_get_irq(pdev, 0);
271 if (irq < 0) {
272 error = -ENODEV;
Jingoo Han644db162013-12-11 16:23:39 +0900273 goto err;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400274 }
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200275
Yong Zhangb5dd18d2011-09-07 16:10:52 +0800276 error = usb_add_hcd(hcd, irq, 0);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400277 if (error)
Jingoo Han644db162013-12-11 16:23:39 +0900278 goto err;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400279
Peter Chen3c9740a2013-11-05 10:46:02 +0800280 device_wakeup_enable(hcd->self.controller);
281
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400282 if (hub->ocic_notify) {
283 error = hub->ocic_notify(ohci_da8xx_ocic_handler);
284 if (!error)
285 return 0;
286 }
287
288 usb_remove_hcd(hcd);
Jingoo Han644db162013-12-11 16:23:39 +0900289err:
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400290 usb_put_hcd(hcd);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400291 return error;
292}
293
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200294static int ohci_da8xx_remove(struct platform_device *pdev)
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400295{
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200296 struct usb_hcd *hcd = platform_get_drvdata(pdev);
Jingoo Hand4f09e22013-07-30 19:59:40 +0900297 struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400298
299 hub->ocic_notify(NULL);
300 usb_remove_hcd(hcd);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400301 usb_put_hcd(hcd);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400302
303 return 0;
304}
305
306#ifdef CONFIG_PM
Majunath Goudar933bb1f2013-11-13 17:40:19 +0530307static int ohci_da8xx_suspend(struct platform_device *pdev,
308 pm_message_t message)
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400309{
Majunath Goudar933bb1f2013-11-13 17:40:19 +0530310 struct usb_hcd *hcd = platform_get_drvdata(pdev);
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400311 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
Majunath Goudar933bb1f2013-11-13 17:40:19 +0530312 bool do_wakeup = device_may_wakeup(&pdev->dev);
313 int ret;
314
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400315
316 if (time_before(jiffies, ohci->next_statechange))
317 msleep(5);
318 ohci->next_statechange = jiffies;
319
Majunath Goudar933bb1f2013-11-13 17:40:19 +0530320 ret = ohci_suspend(hcd, do_wakeup);
321 if (ret)
322 return ret;
323
David Lechner6110c422016-10-12 20:44:46 -0500324 ohci_da8xx_disable();
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400325 hcd->state = HC_STATE_SUSPENDED;
Majunath Goudar933bb1f2013-11-13 17:40:19 +0530326
327 return ret;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400328}
329
330static int ohci_da8xx_resume(struct platform_device *dev)
331{
332 struct usb_hcd *hcd = platform_get_drvdata(dev);
333 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
David Lechner6110c422016-10-12 20:44:46 -0500334 int ret;
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400335
336 if (time_before(jiffies, ohci->next_statechange))
337 msleep(5);
338 ohci->next_statechange = jiffies;
339
David Lechner6110c422016-10-12 20:44:46 -0500340 ret = ohci_da8xx_enable();
341 if (ret)
342 return ret;
343
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400344 dev->dev.power.power_state = PMSG_ON;
345 usb_hcd_resume_root_hub(hcd);
David Lechner6110c422016-10-12 20:44:46 -0500346
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400347 return 0;
348}
349#endif
350
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200351static const struct ohci_driver_overrides da8xx_overrides __initconst = {
352 .reset = ohci_da8xx_reset,
353};
354
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400355/*
356 * Driver definition to register with platform structure.
357 */
358static struct platform_driver ohci_hcd_da8xx_driver = {
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200359 .probe = ohci_da8xx_probe,
360 .remove = ohci_da8xx_remove,
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400361 .shutdown = usb_hcd_platform_shutdown,
362#ifdef CONFIG_PM
363 .suspend = ohci_da8xx_suspend,
364 .resume = ohci_da8xx_resume,
365#endif
366 .driver = {
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200367 .name = DRV_NAME,
Sergei Shtylyovefe7daf2010-02-12 23:52:34 +0400368 },
369};
Jan Luebbeab59ac012012-05-07 10:25:16 +0200370
Manjunath Goudar6c21caa2016-10-27 15:52:29 +0200371static int __init ohci_da8xx_init(void)
372{
373
374 if (usb_disabled())
375 return -ENODEV;
376
377 pr_info("%s: " DRIVER_DESC "\n", DRV_NAME);
378 ohci_init_driver(&ohci_da8xx_hc_driver, &da8xx_overrides);
379
380 /*
381 * The Davinci da8xx HW has some unusual quirks, which require
382 * da8xx-specific workarounds. We override certain hc_driver
383 * functions here to achieve that. We explicitly do not enhance
384 * ohci_driver_overrides to allow this more easily, since this
385 * is an unusual case, and we don't want to encourage others to
386 * override these functions by making it too easy.
387 */
388
389 orig_ohci_hub_control = ohci_da8xx_hc_driver.hub_control;
390 orig_ohci_hub_status_data = ohci_da8xx_hc_driver.hub_status_data;
391
392 ohci_da8xx_hc_driver.hub_status_data = ohci_da8xx_hub_status_data;
393 ohci_da8xx_hc_driver.hub_control = ohci_da8xx_hub_control;
394
395 return platform_driver_register(&ohci_hcd_da8xx_driver);
396}
397module_init(ohci_da8xx_init);
398
399static void __exit ohci_da8xx_exit(void)
400{
401 platform_driver_unregister(&ohci_hcd_da8xx_driver);
402}
403module_exit(ohci_da8xx_exit);
404MODULE_DESCRIPTION(DRIVER_DESC);
405MODULE_LICENSE("GPL");
406MODULE_ALIAS("platform:" DRV_NAME);