ar71xx: add support for ar7241 and ar7242
[openwrt/svn-archive/archive.git] / target / linux / ar71xx / files / arch / mips / ar71xx / dev-usb.c
1 /*
2 * Atheros AR71xx USB host device support
3 *
4 * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6 *
7 * Parts of this file are based on Atheros' 2.6.15 BSP
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
12 */
13
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/dma-mapping.h>
18 #include <linux/platform_device.h>
19
20 #include <asm/mach-ar71xx/ar71xx.h>
21 #include <asm/mach-ar71xx/platform.h>
22
23 #include "dev-usb.h"
24
25 /*
26 * OHCI (USB full speed host controller)
27 */
28 static struct resource ar71xx_ohci_resources[] = {
29 [0] = {
30 .start = AR71XX_OHCI_BASE,
31 .end = AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1,
32 .flags = IORESOURCE_MEM,
33 },
34 [1] = {
35 .start = AR71XX_MISC_IRQ_OHCI,
36 .end = AR71XX_MISC_IRQ_OHCI,
37 .flags = IORESOURCE_IRQ,
38 },
39 };
40
41 static struct resource ar7240_ohci_resources[] = {
42 [0] = {
43 .start = AR7240_OHCI_BASE,
44 .end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1,
45 .flags = IORESOURCE_MEM,
46 },
47 [1] = {
48 .start = AR71XX_CPU_IRQ_USB,
49 .end = AR71XX_CPU_IRQ_USB,
50 .flags = IORESOURCE_IRQ,
51 },
52 };
53
54 static u64 ar71xx_ohci_dmamask = DMA_BIT_MASK(32);
55 static struct platform_device ar71xx_ohci_device = {
56 .name = "ar71xx-ohci",
57 .id = -1,
58 .resource = ar71xx_ohci_resources,
59 .num_resources = ARRAY_SIZE(ar71xx_ohci_resources),
60 .dev = {
61 .dma_mask = &ar71xx_ohci_dmamask,
62 .coherent_dma_mask = DMA_BIT_MASK(32),
63 },
64 };
65
66 /*
67 * EHCI (USB full speed host controller)
68 */
69 static struct resource ar71xx_ehci_resources[] = {
70 [0] = {
71 .start = AR71XX_EHCI_BASE,
72 .end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1,
73 .flags = IORESOURCE_MEM,
74 },
75 [1] = {
76 .start = AR71XX_CPU_IRQ_USB,
77 .end = AR71XX_CPU_IRQ_USB,
78 .flags = IORESOURCE_IRQ,
79 },
80 };
81
82 static u64 ar71xx_ehci_dmamask = DMA_BIT_MASK(32);
83 static struct ar71xx_ehci_platform_data ar71xx_ehci_data;
84
85 static struct platform_device ar71xx_ehci_device = {
86 .name = "ar71xx-ehci",
87 .id = -1,
88 .resource = ar71xx_ehci_resources,
89 .num_resources = ARRAY_SIZE(ar71xx_ehci_resources),
90 .dev = {
91 .dma_mask = &ar71xx_ehci_dmamask,
92 .coherent_dma_mask = DMA_BIT_MASK(32),
93 .platform_data = &ar71xx_ehci_data,
94 },
95 };
96
97 #define AR71XX_USB_RESET_MASK \
98 (RESET_MODULE_USB_HOST | RESET_MODULE_USB_PHY \
99 | RESET_MODULE_USB_OHCI_DLL)
100
101 #define AR7240_USB_RESET_MASK \
102 (RESET_MODULE_USB_HOST | RESET_MODULE_USB_OHCI_DLL_7240)
103
104 static void __init ar71xx_usb_setup(void)
105 {
106 ar71xx_device_stop(AR71XX_USB_RESET_MASK);
107 mdelay(1000);
108 ar71xx_device_start(AR71XX_USB_RESET_MASK);
109
110 /* Turning on the Buff and Desc swap bits */
111 ar71xx_usb_ctrl_wr(USB_CTRL_REG_CONFIG, 0xf0000);
112
113 /* WAR for HW bug. Here it adjusts the duration between two SOFS */
114 ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x20c00);
115
116 mdelay(900);
117
118 platform_device_register(&ar71xx_ohci_device);
119 platform_device_register(&ar71xx_ehci_device);
120 }
121
122 static void __init ar7240_usb_setup(void)
123 {
124 ar71xx_device_stop(AR7240_USB_RESET_MASK);
125 mdelay(1000);
126 ar71xx_device_start(AR7240_USB_RESET_MASK);
127
128 /* WAR for HW bug. Here it adjusts the duration between two SOFS */
129 ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x3);
130
131 if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) {
132 ar71xx_ehci_data.is_ar91xx = 1;
133 ar71xx_ehci_device.resource = ar7240_ohci_resources;
134 ar71xx_ehci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources);
135 platform_device_register(&ar71xx_ehci_device);
136 } else {
137 ar71xx_ohci_device.resource = ar7240_ohci_resources;
138 ar71xx_ohci_device.num_resources = ARRAY_SIZE(ar7240_ohci_resources);
139 platform_device_register(&ar71xx_ohci_device);
140 }
141 }
142
143 static void __init ar91xx_usb_setup(void)
144 {
145 ar71xx_device_stop(RESET_MODULE_USBSUS_OVERRIDE);
146 mdelay(10);
147
148 ar71xx_device_start(RESET_MODULE_USB_HOST);
149 mdelay(10);
150
151 ar71xx_device_start(RESET_MODULE_USB_PHY);
152 mdelay(10);
153
154 ar71xx_ehci_data.is_ar91xx = 1;
155 platform_device_register(&ar71xx_ehci_device);
156 }
157
158 void __init ar71xx_add_device_usb(void)
159 {
160 switch (ar71xx_soc) {
161 case AR71XX_SOC_AR7240:
162 case AR71XX_SOC_AR7241:
163 case AR71XX_SOC_AR7242:
164 ar7240_usb_setup();
165 break;
166
167 case AR71XX_SOC_AR7130:
168 case AR71XX_SOC_AR7141:
169 case AR71XX_SOC_AR7161:
170 ar71xx_usb_setup();
171 break;
172
173 case AR71XX_SOC_AR9130:
174 case AR71XX_SOC_AR9132:
175 ar91xx_usb_setup();
176 break;
177
178 default:
179 BUG();
180 }
181 }