aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-22 18:50:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-22 18:50:46 -0400
commita481991467d38afb43c3921d5b5b59ccb61b04ba (patch)
treea4b0b9a14da6fd5ef7b9b512bb32dbfcfcf2cd71 /drivers/usb/chipidea/core.c
parentf6a26ae7699416d86bea8cb68ce413571e9cab3c (diff)
parentcda4db53e9c28061c100400e1a4d273ea61dfba9 (diff)
Merge tag 'usb-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB 3.5-rc1 changes from Greg Kroah-Hartman: "Here is the big USB 3.5-rc1 pull request for the 3.5-rc1 merge window. It's touches a lot of different parts of the kernel, all USB drivers, due to some API cleanups (getting rid of the ancient err() macro) and some changes that are needed for USB 3.0 power management updates. There are also lots of new drivers, pimarily gadget, but others as well. We deleted a staging driver, which was nice, and finally dropped the obsolete usbfs code, which will make Al happy to never have to touch that again. There were some build errors in the tree that linux-next found a few days ago, but those were fixed by the most recent changes (all were due to us not building with CONFIG_PM disabled.) Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'usb-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (477 commits) xhci: Fix DIV_ROUND_UP compile error. xhci: Fix compile with CONFIG_USB_SUSPEND=n USB: Fix core compile with CONFIG_USB_SUSPEND=n brcm80211: Fix compile error for .disable_hub_initiated_lpm. Revert "USB: EHCI: work around bug in the Philips ISP1562 controller" MAINTAINERS: Add myself as maintainer to the USB PHY Layer USB: EHCI: fix command register configuration lost problem USB: Remove races in devio.c USB: ehci-platform: remove update_device USB: Disable hub-initiated LPM for comms devices. xhci: Add Intel U1/U2 timeout policy. xhci: Add infrastructure for host-specific LPM policies. USB: Add macros for interrupt endpoint types. xhci: Reserve one command for USB3 LPM disable. xhci: Some Evaluate Context commands must succeed. USB: Disable USB 3.0 LPM in critical sections. USB: Add support to enable/disable USB3 link states. USB: Allow drivers to disable hub-initiated LPM. USB: Calculate USB 3.0 exit latencies for LPM. USB: Refactor code to set LPM support flag. ... Conflicts: arch/arm/mach-exynos/mach-nuri.c arch/arm/mach-exynos/mach-universal_c210.c drivers/net/wireless/ath/ath6kl/usb.c
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r--drivers/usb/chipidea/core.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
new file mode 100644
index 000000000000..15e03b308f8a
--- /dev/null
+++ b/drivers/usb/chipidea/core.c
@@ -0,0 +1,474 @@
1/*
2 * core.c - ChipIdea USB IP core family device controller
3 *
4 * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
5 *
6 * Author: David Lopo
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13/*
14 * Description: ChipIdea USB IP core family device controller
15 *
16 * This driver is composed of several blocks:
17 * - HW: hardware interface
18 * - DBG: debug facilities (optional)
19 * - UTIL: utilities
20 * - ISR: interrupts handling
21 * - ENDPT: endpoint operations (Gadget API)
22 * - GADGET: gadget operations (Gadget API)
23 * - BUS: bus glue code, bus abstraction layer
24 *
25 * Compile Options
26 * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
27 * - STALL_IN: non-empty bulk-in pipes cannot be halted
28 * if defined mass storage compliance succeeds but with warnings
29 * => case 4: Hi > Dn
30 * => case 5: Hi > Di
31 * => case 8: Hi <> Do
32 * if undefined usbtest 13 fails
33 * - TRACE: enable function tracing (depends on DEBUG)
34 *
35 * Main Features
36 * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
37 * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
38 * - Normal & LPM support
39 *
40 * USBTEST Report
41 * - OK: 0-12, 13 (STALL_IN defined) & 14
42 * - Not Supported: 15 & 16 (ISO)
43 *
44 * TODO List
45 * - OTG
46 * - Isochronous & Interrupt Traffic
47 * - Handle requests which spawns into several TDs
48 * - GET_STATUS(device) - always reports 0
49 * - Gadget API (majority of optional features)
50 * - Suspend & Remote Wakeup
51 */
52#include <linux/delay.h>
53#include <linux/device.h>
54#include <linux/dmapool.h>
55#include <linux/dma-mapping.h>
56#include <linux/init.h>
57#include <linux/platform_device.h>
58#include <linux/module.h>
59#include <linux/interrupt.h>
60#include <linux/io.h>
61#include <linux/irq.h>
62#include <linux/kernel.h>
63#include <linux/slab.h>
64#include <linux/pm_runtime.h>
65#include <linux/usb/ch9.h>
66#include <linux/usb/gadget.h>
67#include <linux/usb/otg.h>
68#include <linux/usb/chipidea.h>
69
70#include "ci.h"
71#include "udc.h"
72#include "bits.h"
73#include "host.h"
74#include "debug.h"
75
76/* Controller register map */
77static uintptr_t ci_regs_nolpm[] = {
78 [CAP_CAPLENGTH] = 0x000UL,
79 [CAP_HCCPARAMS] = 0x008UL,
80 [CAP_DCCPARAMS] = 0x024UL,
81 [CAP_TESTMODE] = 0x038UL,
82 [OP_USBCMD] = 0x000UL,
83 [OP_USBSTS] = 0x004UL,
84 [OP_USBINTR] = 0x008UL,
85 [OP_DEVICEADDR] = 0x014UL,
86 [OP_ENDPTLISTADDR] = 0x018UL,
87 [OP_PORTSC] = 0x044UL,
88 [OP_DEVLC] = 0x084UL,
89 [OP_OTGSC] = 0x064UL,
90 [OP_USBMODE] = 0x068UL,
91 [OP_ENDPTSETUPSTAT] = 0x06CUL,
92 [OP_ENDPTPRIME] = 0x070UL,
93 [OP_ENDPTFLUSH] = 0x074UL,
94 [OP_ENDPTSTAT] = 0x078UL,
95 [OP_ENDPTCOMPLETE] = 0x07CUL,
96 [OP_ENDPTCTRL] = 0x080UL,
97};
98
99static uintptr_t ci_regs_lpm[] = {
100 [CAP_CAPLENGTH] = 0x000UL,
101 [CAP_HCCPARAMS] = 0x008UL,
102 [CAP_DCCPARAMS] = 0x024UL,
103 [CAP_TESTMODE] = 0x0FCUL,
104 [OP_USBCMD] = 0x000UL,
105 [OP_USBSTS] = 0x004UL,
106 [OP_USBINTR] = 0x008UL,
107 [OP_DEVICEADDR] = 0x014UL,
108 [OP_ENDPTLISTADDR] = 0x018UL,
109 [OP_PORTSC] = 0x044UL,
110 [OP_DEVLC] = 0x084UL,
111 [OP_OTGSC] = 0x0C4UL,
112 [OP_USBMODE] = 0x0C8UL,
113 [OP_ENDPTSETUPSTAT] = 0x0D8UL,
114 [OP_ENDPTPRIME] = 0x0DCUL,
115 [OP_ENDPTFLUSH] = 0x0E0UL,
116 [OP_ENDPTSTAT] = 0x0E4UL,
117 [OP_ENDPTCOMPLETE] = 0x0E8UL,
118 [OP_ENDPTCTRL] = 0x0ECUL,
119};
120
121static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
122{
123 int i;
124
125 kfree(ci->hw_bank.regmap);
126
127 ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *),
128 GFP_KERNEL);
129 if (!ci->hw_bank.regmap)
130 return -ENOMEM;
131
132 for (i = 0; i < OP_ENDPTCTRL; i++)
133 ci->hw_bank.regmap[i] =
134 (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) +
135 (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]);
136
137 for (; i <= OP_LAST; i++)
138 ci->hw_bank.regmap[i] = ci->hw_bank.op +
139 4 * (i - OP_ENDPTCTRL) +
140 (is_lpm
141 ? ci_regs_lpm[OP_ENDPTCTRL]
142 : ci_regs_nolpm[OP_ENDPTCTRL]);
143
144 return 0;
145}
146
147/**
148 * hw_port_test_set: writes port test mode (execute without interruption)
149 * @mode: new value
150 *
151 * This function returns an error code
152 */
153int hw_port_test_set(struct ci13xxx *ci, u8 mode)
154{
155 const u8 TEST_MODE_MAX = 7;
156
157 if (mode > TEST_MODE_MAX)
158 return -EINVAL;
159
160 hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
161 return 0;
162}
163
164/**
165 * hw_port_test_get: reads port test mode value
166 *
167 * This function returns port test mode value
168 */
169u8 hw_port_test_get(struct ci13xxx *ci)
170{
171 return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
172}
173
174static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
175{
176 u32 reg;
177
178 /* bank is a module variable */
179 ci->hw_bank.abs = base;
180
181 ci->hw_bank.cap = ci->hw_bank.abs;
182 ci->hw_bank.cap += ci->udc_driver->capoffset;
183 ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
184
185 hw_alloc_regmap(ci, false);
186 reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
187 ffs_nr(HCCPARAMS_LEN);
188 ci->hw_bank.lpm = reg;
189 hw_alloc_regmap(ci, !!reg);
190 ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
191 ci->hw_bank.size += OP_LAST;
192 ci->hw_bank.size /= sizeof(u32);
193
194 reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
195 ffs_nr(DCCPARAMS_DEN);
196 ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
197
198 if (ci->hw_ep_max > ENDPT_MAX)
199 return -ENODEV;
200
201 dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
202 ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
203
204 /* setup lock mode ? */
205
206 /* ENDPTSETUPSTAT is '0' by default */
207
208 /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
209
210 return 0;
211}
212
213/**
214 * hw_device_reset: resets chip (execute without interruption)
215 * @ci: the controller
216 *
217 * This function returns an error code
218 */
219int hw_device_reset(struct ci13xxx *ci, u32 mode)
220{
221 /* should flush & stop before reset */
222 hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
223 hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
224
225 hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
226 while (hw_read(ci, OP_USBCMD, USBCMD_RST))
227 udelay(10); /* not RTOS friendly */
228
229
230 if (ci->udc_driver->notify_event)
231 ci->udc_driver->notify_event(ci,
232 CI13XXX_CONTROLLER_RESET_EVENT);
233
234 if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
235 hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
236
237 /* USBMODE should be configured step by step */
238 hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
239 hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
240 /* HW >= 2.3 */
241 hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
242
243 if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
244 pr_err("cannot enter in %s mode", ci_role(ci)->name);
245 pr_err("lpm = %i", ci->hw_bank.lpm);
246 return -ENODEV;
247 }
248
249 return 0;
250}
251
252/**
253 * ci_otg_role - pick role based on ID pin state
254 * @ci: the controller
255 */
256static enum ci_role ci_otg_role(struct ci13xxx *ci)
257{
258 u32 sts = hw_read(ci, OP_OTGSC, ~0);
259 enum ci_role role = sts & OTGSC_ID
260 ? CI_ROLE_GADGET
261 : CI_ROLE_HOST;
262
263 return role;
264}
265
266/**
267 * ci_role_work - perform role changing based on ID pin
268 * @work: work struct
269 */
270static void ci_role_work(struct work_struct *work)
271{
272 struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
273 enum ci_role role = ci_otg_role(ci);
274
275 hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
276
277 if (role != ci->role) {
278 dev_dbg(ci->dev, "switching from %s to %s\n",
279 ci_role(ci)->name, ci->roles[role]->name);
280
281 ci_role_stop(ci);
282 ci_role_start(ci, role);
283 }
284}
285
286static ssize_t show_role(struct device *dev, struct device_attribute *attr,
287 char *buf)
288{
289 struct ci13xxx *ci = dev_get_drvdata(dev);
290
291 return sprintf(buf, "%s\n", ci_role(ci)->name);
292}
293
294static ssize_t store_role(struct device *dev, struct device_attribute *attr,
295 const char *buf, size_t count)
296{
297 struct ci13xxx *ci = dev_get_drvdata(dev);
298 enum ci_role role;
299 int ret;
300
301 for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
302 if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
303 break;
304
305 if (role == CI_ROLE_END || role == ci->role)
306 return -EINVAL;
307
308 ci_role_stop(ci);
309 ret = ci_role_start(ci, role);
310 if (ret)
311 return ret;
312
313 return count;
314}
315
316static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
317
318static irqreturn_t ci_irq(int irq, void *data)
319{
320 struct ci13xxx *ci = data;
321 irqreturn_t ret = IRQ_NONE;
322
323 if (ci->is_otg) {
324 u32 sts = hw_read(ci, OP_OTGSC, ~0);
325
326 if (sts & OTGSC_IDIS) {
327 queue_work(ci->wq, &ci->work);
328 ret = IRQ_HANDLED;
329 }
330 }
331
332 return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
333}
334
335static int __devinit ci_hdrc_probe(struct platform_device *pdev)
336{
337 struct device *dev = &pdev->dev;
338 struct ci13xxx *ci;
339 struct resource *res;
340 void __iomem *base;
341 int ret;
342
343 if (!dev->platform_data) {
344 dev_err(dev, "platform data missing\n");
345 return -ENODEV;
346 }
347
348 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
349 if (!res) {
350 dev_err(dev, "missing resource\n");
351 return -ENODEV;
352 }
353
354 base = devm_request_and_ioremap(dev, res);
355 if (!res) {
356 dev_err(dev, "can't request and ioremap resource\n");
357 return -ENOMEM;
358 }
359
360 ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
361 if (!ci) {
362 dev_err(dev, "can't allocate device\n");
363 return -ENOMEM;
364 }
365
366 ci->dev = dev;
367 ci->udc_driver = dev->platform_data;
368
369 ret = hw_device_init(ci, base);
370 if (ret < 0) {
371 dev_err(dev, "can't initialize hardware\n");
372 return -ENODEV;
373 }
374
375 ci->hw_bank.phys = res->start;
376
377 ci->irq = platform_get_irq(pdev, 0);
378 if (ci->irq < 0) {
379 dev_err(dev, "missing IRQ\n");
380 return -ENODEV;
381 }
382
383 INIT_WORK(&ci->work, ci_role_work);
384 ci->wq = create_singlethread_workqueue("ci_otg");
385 if (!ci->wq) {
386 dev_err(dev, "can't create workqueue\n");
387 return -ENODEV;
388 }
389
390 /* initialize role(s) before the interrupt is requested */
391 ret = ci_hdrc_host_init(ci);
392 if (ret)
393 dev_info(dev, "doesn't support host\n");
394
395 ret = ci_hdrc_gadget_init(ci);
396 if (ret)
397 dev_info(dev, "doesn't support gadget\n");
398
399 if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
400 dev_err(dev, "no supported roles\n");
401 ret = -ENODEV;
402 goto rm_wq;
403 }
404
405 if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
406 ci->is_otg = true;
407 ci->role = ci_otg_role(ci);
408 } else {
409 ci->role = ci->roles[CI_ROLE_HOST]
410 ? CI_ROLE_HOST
411 : CI_ROLE_GADGET;
412 }
413
414 ret = ci_role_start(ci, ci->role);
415 if (ret) {
416 dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
417 ret = -ENODEV;
418 goto rm_wq;
419 }
420
421 platform_set_drvdata(pdev, ci);
422 ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name,
423 ci);
424 if (ret)
425 goto stop;
426
427 ret = device_create_file(dev, &dev_attr_role);
428 if (ret)
429 goto rm_attr;
430
431 if (ci->is_otg)
432 hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
433
434 return ret;
435
436rm_attr:
437 device_remove_file(dev, &dev_attr_role);
438stop:
439 ci_role_stop(ci);
440rm_wq:
441 flush_workqueue(ci->wq);
442 destroy_workqueue(ci->wq);
443
444 return ret;
445}
446
447static int __devexit ci_hdrc_remove(struct platform_device *pdev)
448{
449 struct ci13xxx *ci = platform_get_drvdata(pdev);
450
451 flush_workqueue(ci->wq);
452 destroy_workqueue(ci->wq);
453 device_remove_file(ci->dev, &dev_attr_role);
454 free_irq(ci->irq, ci);
455 ci_role_stop(ci);
456
457 return 0;
458}
459
460static struct platform_driver ci_hdrc_driver = {
461 .probe = ci_hdrc_probe,
462 .remove = __devexit_p(ci_hdrc_remove),
463 .driver = {
464 .name = "ci_hdrc",
465 },
466};
467
468module_platform_driver(ci_hdrc_driver);
469
470MODULE_ALIAS("platform:ci_hdrc");
471MODULE_ALIAS("platform:ci13xxx");
472MODULE_LICENSE("GPL v2");
473MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
474MODULE_DESCRIPTION("ChipIdea HDRC Driver");