aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Prisk <linux@prisktech.co.nz>2012-07-21 06:58:53 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 17:00:37 -0400
commit100d45970327f78584ff4846deeca14bba511e28 (patch)
tree3698827ac9c75aa66d461fd9862b7fcef4768e94
parent8ad551d150e3bb0902696496a9d2aa094335705a (diff)
ARM: vt8500: Add support for UHCI companion controller
Add support for a generic non-pci UHCI companion controller. Existing board files for arch-vt8500 updated to include UHCI support. Signed-off-by: Tony Prisk <linux@prisktech.co.nz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/devicetree/bindings/usb/platform-uhci.txt12
-rw-r--r--arch/arm/mach-vt8500/bv07.c1
-rw-r--r--arch/arm/mach-vt8500/devices-vt8500.c5
-rw-r--r--arch/arm/mach-vt8500/devices-wm8505.c4
-rw-r--r--arch/arm/mach-vt8500/devices.c11
-rw-r--r--arch/arm/mach-vt8500/devices.h1
-rw-r--r--arch/arm/mach-vt8500/wm8505_7in.c1
-rw-r--r--drivers/usb/host/Kconfig12
-rw-r--r--drivers/usb/host/uhci-hcd.c5
-rw-r--r--drivers/usb/host/uhci-platform.c157
10 files changed, 207 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt
new file mode 100644
index 000000000000..91477d6830ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/platform-uhci.txt
@@ -0,0 +1,12 @@
1Generic Platform UHCI controllers.
2
3Required properties:
4 - compatible: Should be "platform-uhci".
5 - reg: Address range of the uhci registers
6 - interrupts: Should contain the uhci interrupt.
7
8usb: uhci@D8007301 {
9 compatible = "platform-uhci", "usb-uhci";
10 reg = <0xD8007301 0x200>;
11 interrupts = <0>;
12};
diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c
index f9fbeb2d10e9..6fd9d609ebaa 100644
--- a/arch/arm/mach-vt8500/bv07.c
+++ b/arch/arm/mach-vt8500/bv07.c
@@ -33,6 +33,7 @@ static struct platform_device *devices[] __initdata = {
33 &vt8500_device_uart0, 33 &vt8500_device_uart0,
34 &vt8500_device_lcdc, 34 &vt8500_device_lcdc,
35 &vt8500_device_ehci, 35 &vt8500_device_ehci,
36 &vt8500_device_uhci,
36 &vt8500_device_ge_rops, 37 &vt8500_device_ge_rops,
37 &vt8500_device_pwm, 38 &vt8500_device_pwm,
38 &vt8500_device_pwmbl, 39 &vt8500_device_pwmbl,
diff --git a/arch/arm/mach-vt8500/devices-vt8500.c b/arch/arm/mach-vt8500/devices-vt8500.c
index 19519aeecf37..def7fe393a2c 100644
--- a/arch/arm/mach-vt8500/devices-vt8500.c
+++ b/arch/arm/mach-vt8500/devices-vt8500.c
@@ -48,6 +48,11 @@ void __init vt8500_set_resources(void)
48 tmp[1] = wmt_irq_res(IRQ_EHCI); 48 tmp[1] = wmt_irq_res(IRQ_EHCI);
49 wmt_res_add(&vt8500_device_ehci, tmp, 2); 49 wmt_res_add(&vt8500_device_ehci, tmp, 2);
50 50
51 /* vt8500 uses a single IRQ for both EHCI and UHCI controllers */
52 tmp[0] = wmt_mmio_res(VT8500_UHCI_BASE, SZ_512);
53 tmp[1] = wmt_irq_res(IRQ_EHCI);
54 wmt_res_add(&vt8500_device_uhci, tmp, 2);
55
51 tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256); 56 tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256);
52 wmt_res_add(&vt8500_device_ge_rops, tmp, 1); 57 wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
53 58
diff --git a/arch/arm/mach-vt8500/devices-wm8505.c b/arch/arm/mach-vt8500/devices-wm8505.c
index db4594e029f4..c810454178dc 100644
--- a/arch/arm/mach-vt8500/devices-wm8505.c
+++ b/arch/arm/mach-vt8500/devices-wm8505.c
@@ -55,6 +55,10 @@ void __init wm8505_set_resources(void)
55 tmp[1] = wmt_irq_res(IRQ_EHCI); 55 tmp[1] = wmt_irq_res(IRQ_EHCI);
56 wmt_res_add(&vt8500_device_ehci, tmp, 2); 56 wmt_res_add(&vt8500_device_ehci, tmp, 2);
57 57
58 tmp[0] = wmt_mmio_res(WM8505_UHCI_BASE, SZ_512);
59 tmp[1] = wmt_irq_res(IRQ_UHCI);
60 wmt_res_add(&vt8500_device_uhci, tmp, 2);
61
58 tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256); 62 tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256);
59 wmt_res_add(&vt8500_device_ge_rops, tmp, 1); 63 wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
60 64
diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c
index 1fcdc36b358d..46ff82dad544 100644
--- a/arch/arm/mach-vt8500/devices.c
+++ b/arch/arm/mach-vt8500/devices.c
@@ -204,6 +204,17 @@ struct platform_device vt8500_device_ehci = {
204 }, 204 },
205}; 205};
206 206
207static u64 uhci_dma_mask = DMA_BIT_MASK(32);
208
209struct platform_device vt8500_device_uhci = {
210 .name = "platform-uhci",
211 .id = 0,
212 .dev = {
213 .dma_mask = &uhci_dma_mask,
214 .coherent_dma_mask = DMA_BIT_MASK(32),
215 },
216};
217
207struct platform_device vt8500_device_ge_rops = { 218struct platform_device vt8500_device_ge_rops = {
208 .name = "wmt_ge_rops", 219 .name = "wmt_ge_rops",
209 .id = -1, 220 .id = -1,
diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h
index 188d4e17f35c..0e6d9f904c77 100644
--- a/arch/arm/mach-vt8500/devices.h
+++ b/arch/arm/mach-vt8500/devices.h
@@ -81,6 +81,7 @@ extern struct platform_device vt8500_device_uart5;
81extern struct platform_device vt8500_device_lcdc; 81extern struct platform_device vt8500_device_lcdc;
82extern struct platform_device vt8500_device_wm8505_fb; 82extern struct platform_device vt8500_device_wm8505_fb;
83extern struct platform_device vt8500_device_ehci; 83extern struct platform_device vt8500_device_ehci;
84extern struct platform_device vt8500_device_uhci;
84extern struct platform_device vt8500_device_ge_rops; 85extern struct platform_device vt8500_device_ge_rops;
85extern struct platform_device vt8500_device_pwm; 86extern struct platform_device vt8500_device_pwm;
86extern struct platform_device vt8500_device_pwmbl; 87extern struct platform_device vt8500_device_pwmbl;
diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c
index db19886caf7c..4804e2a45574 100644
--- a/arch/arm/mach-vt8500/wm8505_7in.c
+++ b/arch/arm/mach-vt8500/wm8505_7in.c
@@ -32,6 +32,7 @@ static void __iomem *pmc_hiber;
32static struct platform_device *devices[] __initdata = { 32static struct platform_device *devices[] __initdata = {
33 &vt8500_device_uart0, 33 &vt8500_device_uart0,
34 &vt8500_device_ehci, 34 &vt8500_device_ehci,
35 &vt8500_device_uhci,
35 &vt8500_device_wm8505_fb, 36 &vt8500_device_wm8505_fb,
36 &vt8500_device_ge_rops, 37 &vt8500_device_ge_rops,
37 &vt8500_device_pwm, 38 &vt8500_device_pwm,
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 075d2eca8108..c3f619b1f598 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -450,7 +450,7 @@ config USB_OHCI_LITTLE_ENDIAN
450 450
451config USB_UHCI_HCD 451config USB_UHCI_HCD
452 tristate "UHCI HCD (most Intel and VIA) support" 452 tristate "UHCI HCD (most Intel and VIA) support"
453 depends on USB && (PCI || SPARC_LEON) 453 depends on USB && (PCI || SPARC_LEON || ARCH_VT8500)
454 ---help--- 454 ---help---
455 The Universal Host Controller Interface is a standard by Intel for 455 The Universal Host Controller Interface is a standard by Intel for
456 accessing the USB hardware in the PC (which is also called the USB 456 accessing the USB hardware in the PC (which is also called the USB
@@ -468,7 +468,15 @@ config USB_UHCI_HCD
468config USB_UHCI_SUPPORT_NON_PCI_HC 468config USB_UHCI_SUPPORT_NON_PCI_HC
469 bool 469 bool
470 depends on USB_UHCI_HCD 470 depends on USB_UHCI_HCD
471 default y if SPARC_LEON 471 default y if (SPARC_LEON || ARCH_VT8500)
472
473config USB_UHCI_PLATFORM
474 bool "Generic UHCI Platform Driver support"
475 depends on USB_UHCI_SUPPORT_NON_PCI_HC
476 default y if ARCH_VT8500
477 ---help---
478 Enable support for generic UHCI platform devices that require no
479 additional configuration.
472 480
473config USB_UHCI_BIG_ENDIAN_MMIO 481config USB_UHCI_BIG_ENDIAN_MMIO
474 bool 482 bool
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e4db350602b8..4b9e9aba2665 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -846,6 +846,11 @@ static const char hcd_name[] = "uhci_hcd";
846#define PLATFORM_DRIVER uhci_grlib_driver 846#define PLATFORM_DRIVER uhci_grlib_driver
847#endif 847#endif
848 848
849#ifdef CONFIG_USB_UHCI_PLATFORM
850#include "uhci-platform.c"
851#define PLATFORM_DRIVER uhci_platform_driver
852#endif
853
849#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) 854#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
850#error "missing bus glue for uhci-hcd" 855#error "missing bus glue for uhci-hcd"
851#endif 856#endif
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
new file mode 100644
index 000000000000..e4780491df4a
--- /dev/null
+++ b/drivers/usb/host/uhci-platform.c
@@ -0,0 +1,157 @@
1/*
2 * Generic UHCI HCD (Host Controller Driver) for Platform Devices
3 *
4 * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
5 *
6 * This file is based on uhci-grlib.c
7 * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
8 */
9
10#include <linux/of.h>
11#include <linux/platform_device.h>
12
13static int uhci_platform_init(struct usb_hcd *hcd)
14{
15 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
16
17 uhci->rh_numports = uhci_count_ports(hcd);
18
19 /* Set up pointers to to generic functions */
20 uhci->reset_hc = uhci_generic_reset_hc;
21 uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
22
23 /* No special actions need to be taken for the functions below */
24 uhci->configure_hc = NULL;
25 uhci->resume_detect_interrupts_are_broken = NULL;
26 uhci->global_suspend_mode_is_broken = NULL;
27
28 /* Reset if the controller isn't already safely quiescent. */
29 check_and_reset_hc(uhci);
30 return 0;
31}
32
33static const struct hc_driver uhci_platform_hc_driver = {
34 .description = hcd_name,
35 .product_desc = "Generic UHCI Host Controller",
36 .hcd_priv_size = sizeof(struct uhci_hcd),
37
38 /* Generic hardware linkage */
39 .irq = uhci_irq,
40 .flags = HCD_MEMORY | HCD_USB11,
41
42 /* Basic lifecycle operations */
43 .reset = uhci_platform_init,
44 .start = uhci_start,
45#ifdef CONFIG_PM
46 .pci_suspend = NULL,
47 .pci_resume = NULL,
48 .bus_suspend = uhci_rh_suspend,
49 .bus_resume = uhci_rh_resume,
50#endif
51 .stop = uhci_stop,
52
53 .urb_enqueue = uhci_urb_enqueue,
54 .urb_dequeue = uhci_urb_dequeue,
55
56 .endpoint_disable = uhci_hcd_endpoint_disable,
57 .get_frame_number = uhci_hcd_get_frame_number,
58
59 .hub_status_data = uhci_hub_status_data,
60 .hub_control = uhci_hub_control,
61};
62
63
64static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev)
65{
66 struct usb_hcd *hcd;
67 struct uhci_hcd *uhci;
68 struct resource *res;
69 int ret;
70
71 if (usb_disabled())
72 return -ENODEV;
73
74 hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
75 pdev->name);
76 if (!hcd)
77 return -ENOMEM;
78
79 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
80 hcd->rsrc_start = res->start;
81 hcd->rsrc_len = resource_size(res);
82
83 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
84 pr_err("%s: request_mem_region failed\n", __func__);
85 ret = -EBUSY;
86 goto err_rmr;
87 }
88
89 hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
90 if (!hcd->regs) {
91 pr_err("%s: ioremap failed\n", __func__);
92 ret = -ENOMEM;
93 goto err_irq;
94 }
95 uhci = hcd_to_uhci(hcd);
96
97 uhci->regs = hcd->regs;
98
99 ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED |
100 IRQF_SHARED);
101 if (ret)
102 goto err_uhci;
103
104 return 0;
105
106err_uhci:
107 iounmap(hcd->regs);
108err_irq:
109 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
110err_rmr:
111 usb_put_hcd(hcd);
112
113 return ret;
114}
115
116static int uhci_hcd_platform_remove(struct platform_device *pdev)
117{
118 struct usb_hcd *hcd = platform_get_drvdata(pdev);
119
120 usb_remove_hcd(hcd);
121 iounmap(hcd->regs);
122 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
123 usb_put_hcd(hcd);
124 platform_set_drvdata(pdev, NULL);
125
126 return 0;
127}
128
129/* Make sure the controller is quiescent and that we're not using it
130 * any more. This is mainly for the benefit of programs which, like kexec,
131 * expect the hardware to be idle: not doing DMA or generating IRQs.
132 *
133 * This routine may be called in a damaged or failing kernel. Hence we
134 * do not acquire the spinlock before shutting down the controller.
135 */
136static void uhci_hcd_platform_shutdown(struct platform_device *op)
137{
138 struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
139
140 uhci_hc_died(hcd_to_uhci(hcd));
141}
142
143static const struct of_device_id platform_uhci_ids[] = {
144 { .compatible = "platform-uhci", },
145 {}
146};
147
148static struct platform_driver uhci_platform_driver = {
149 .probe = uhci_hcd_platform_probe,
150 .remove = uhci_hcd_platform_remove,
151 .shutdown = uhci_hcd_platform_shutdown,
152 .driver = {
153 .name = "platform-uhci",
154 .owner = THIS_MODULE,
155 .of_match_table = of_match_ptr(platform_uhci_ids),
156 },
157};