aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/board-armadillo800eva.c
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2012-04-24 05:09:08 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-12 16:33:05 -0400
commit1c96293e9f8b8ec9620201bcf7f776f0e0f89edb (patch)
tree4c08046761891b95acd0930d30de2640720207a4 /arch/arm/mach-shmobile/board-armadillo800eva.c
parent46cf668748070e54879d528fa58107abc835dff3 (diff)
ARM: mach-shmobile: armadillo800eva: add USB function support
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Tested-by: Simon Horman <horms@verge.net.au> Acked-by: Magnus Damm <damm@opensource.se> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'arch/arm/mach-shmobile/board-armadillo800eva.c')
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c247
1 files changed, 237 insertions, 10 deletions
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 4d066f9230dd..1d25d5fee605 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -20,14 +20,17 @@
20 */ 20 */
21 21
22#include <linux/clk.h> 22#include <linux/clk.h>
23#include <linux/delay.h>
23#include <linux/err.h> 24#include <linux/err.h>
24#include <linux/kernel.h> 25#include <linux/kernel.h>
25#include <linux/input.h> 26#include <linux/input.h>
27#include <linux/irq.h>
26#include <linux/platform_device.h> 28#include <linux/platform_device.h>
27#include <linux/gpio.h> 29#include <linux/gpio.h>
28#include <linux/gpio_keys.h> 30#include <linux/gpio_keys.h>
29#include <linux/sh_eth.h> 31#include <linux/sh_eth.h>
30#include <linux/videodev2.h> 32#include <linux/videodev2.h>
33#include <linux/usb/renesas_usbhs.h>
31#include <mach/common.h> 34#include <mach/common.h>
32#include <mach/irqs.h> 35#include <mach/irqs.h>
33#include <asm/page.h> 36#include <asm/page.h>
@@ -90,6 +93,9 @@
90 * 0 | SDHI1 | COM8 enable, COM14 disable 93 * 0 | SDHI1 | COM8 enable, COM14 disable
91 * 1 | SDHI1 | COM8 enable, COM14 disable 94 * 1 | SDHI1 | COM8 enable, COM14 disable
92 * -12345678-+---------------+---------------------------- 95 * -12345678-+---------------+----------------------------
96 * 0 | USB0 | COM20 enable, COM24 disable
97 * 1 | USB0 | COM20 disable, COM24 enable
98 * -12345678-+---------------+----------------------------
93 * 00 | JTAG | SH-X2 99 * 00 | JTAG | SH-X2
94 * 10 | JTAG | ARM 100 * 10 | JTAG | ARM
95 * 01 | JTAG | - 101 * 01 | JTAG | -
@@ -97,6 +103,195 @@
97 *-----------+---------------+---------------------------- 103 *-----------+---------------+----------------------------
98 */ 104 */
99 105
106/*
107 * USB function
108 *
109 * When you use USB Function,
110 * set SW1.6 ON, and connect cable to CN24.
111 *
112 * USBF needs workaround on R8A7740 chip.
113 * These are a little bit complex.
114 * see
115 * usbhsf_power_ctrl()
116 *
117 * CAUTION
118 *
119 * It uses autonomy mode for USB hotplug at this point
120 * (= usbhs_private.platform_callback.get_vbus is NULL),
121 * since we don't know what's happen on PM control
122 * on this workaround.
123 */
124#define USBCR1 0xe605810a
125#define USBH 0xC6700000
126#define USBH_USBCTR 0x10834
127
128struct usbhsf_private {
129 struct clk *phy;
130 struct clk *usb24;
131 struct clk *pci;
132 struct clk *func;
133 struct clk *host;
134 void __iomem *usbh_base;
135 struct renesas_usbhs_platform_info info;
136};
137
138#define usbhsf_get_priv(pdev) \
139 container_of(renesas_usbhs_get_info(pdev), \
140 struct usbhsf_private, info)
141
142static int usbhsf_get_id(struct platform_device *pdev)
143{
144 return USBHS_GADGET;
145}
146
147static void usbhsf_power_ctrl(struct platform_device *pdev,
148 void __iomem *base, int enable)
149{
150 struct usbhsf_private *priv = usbhsf_get_priv(pdev);
151
152 /*
153 * Work around for USB Function.
154 * It needs USB host clock, and settings
155 */
156 if (enable) {
157 /*
158 * enable all the related usb clocks
159 * for usb workaround
160 */
161 clk_enable(priv->usb24);
162 clk_enable(priv->pci);
163 clk_enable(priv->host);
164 clk_enable(priv->func);
165 clk_enable(priv->phy);
166
167 /*
168 * set USBCR1
169 *
170 * Port1 is driven by USB function,
171 * Port2 is driven by USB HOST
172 * One HOST (Port1 or Port2 is HOST)
173 * USB PLL input clock = 24MHz
174 */
175 __raw_writew(0xd750, USBCR1);
176 mdelay(1);
177
178 /*
179 * start USB Host
180 */
181 __raw_writel(0x0000000c, priv->usbh_base + USBH_USBCTR);
182 __raw_writel(0x00000008, priv->usbh_base + USBH_USBCTR);
183 mdelay(10);
184
185 /*
186 * USB PHY Power ON
187 */
188 __raw_writew(0xd770, USBCR1);
189 __raw_writew(0x4000, base + 0x102); /* USBF :: SUSPMODE */
190
191 } else {
192 __raw_writel(0x0000010f, priv->usbh_base + USBH_USBCTR);
193 __raw_writew(0xd7c0, USBCR1); /* GPIO */
194
195 clk_disable(priv->phy);
196 clk_disable(priv->func); /* usb work around */
197 clk_disable(priv->host); /* usb work around */
198 clk_disable(priv->pci); /* usb work around */
199 clk_disable(priv->usb24); /* usb work around */
200 }
201}
202
203static void usbhsf_hardware_exit(struct platform_device *pdev)
204{
205 struct usbhsf_private *priv = usbhsf_get_priv(pdev);
206
207 if (!IS_ERR(priv->phy))
208 clk_put(priv->phy);
209 if (!IS_ERR(priv->usb24))
210 clk_put(priv->usb24);
211 if (!IS_ERR(priv->pci))
212 clk_put(priv->pci);
213 if (!IS_ERR(priv->host))
214 clk_put(priv->host);
215 if (!IS_ERR(priv->func))
216 clk_put(priv->func);
217 if (priv->usbh_base)
218 iounmap(priv->usbh_base);
219
220 priv->phy = NULL;
221 priv->usb24 = NULL;
222 priv->pci = NULL;
223 priv->host = NULL;
224 priv->func = NULL;
225 priv->usbh_base = NULL;
226}
227
228static int usbhsf_hardware_init(struct platform_device *pdev)
229{
230 struct usbhsf_private *priv = usbhsf_get_priv(pdev);
231
232 priv->phy = clk_get(&pdev->dev, "phy");
233 priv->usb24 = clk_get(&pdev->dev, "usb24");
234 priv->pci = clk_get(&pdev->dev, "pci");
235 priv->func = clk_get(&pdev->dev, "func");
236 priv->host = clk_get(&pdev->dev, "host");
237 priv->usbh_base = ioremap_nocache(USBH, 0x20000);
238
239 if (IS_ERR(priv->phy) ||
240 IS_ERR(priv->usb24) ||
241 IS_ERR(priv->pci) ||
242 IS_ERR(priv->host) ||
243 IS_ERR(priv->func) ||
244 !priv->usbh_base) {
245 dev_err(&pdev->dev, "USB clock setting failed\n");
246 usbhsf_hardware_exit(pdev);
247 return -EIO;
248 }
249
250 /* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */
251 clk_set_rate(priv->usb24,
252 clk_get_rate(clk_get_parent(priv->usb24)));
253
254 return 0;
255}
256
257static struct usbhsf_private usbhsf_private = {
258 .info = {
259 .platform_callback = {
260 .get_id = usbhsf_get_id,
261 .hardware_init = usbhsf_hardware_init,
262 .hardware_exit = usbhsf_hardware_exit,
263 .power_ctrl = usbhsf_power_ctrl,
264 },
265 .driver_param = {
266 .buswait_bwait = 5,
267 .detection_delay = 5,
268 },
269 }
270};
271
272static struct resource usbhsf_resources[] = {
273 {
274 .name = "USBHS",
275 .start = 0xe6890000,
276 .end = 0xe6890104 - 1,
277 .flags = IORESOURCE_MEM,
278 },
279 {
280 .start = evt2irq(0x0A20),
281 .flags = IORESOURCE_IRQ,
282 },
283};
284
285static struct platform_device usbhsf_device = {
286 .name = "renesas_usbhs",
287 .dev = {
288 .platform_data = &usbhsf_private.info,
289 },
290 .id = -1,
291 .num_resources = ARRAY_SIZE(usbhsf_resources),
292 .resource = usbhsf_resources,
293};
294
100/* Ether */ 295/* Ether */
101static struct sh_eth_plat_data sh_eth_platdata = { 296static struct sh_eth_plat_data sh_eth_platdata = {
102 .phy = 0x00, /* LAN8710A */ 297 .phy = 0x00, /* LAN8710A */
@@ -224,11 +419,41 @@ static struct platform_device *eva_devices[] __initdata = {
224 &sh_eth_device, 419 &sh_eth_device,
225}; 420};
226 421
422static void __init eva_clock_init(void)
423{
424 struct clk *system = clk_get(NULL, "system_clk");
425 struct clk *xtal1 = clk_get(NULL, "extal1");
426 struct clk *usb24s = clk_get(NULL, "usb24s");
427
428 if (IS_ERR(system) ||
429 IS_ERR(xtal1) ||
430 IS_ERR(usb24s)) {
431 pr_err("armadillo800eva board clock init failed\n");
432 goto clock_error;
433 }
434
435 /* armadillo 800 eva extal1 is 24MHz */
436 clk_set_rate(xtal1, 24000000);
437
438 /* usb24s use extal1 (= system) clock (= 24MHz) */
439 clk_set_parent(usb24s, system);
440
441clock_error:
442 if (!IS_ERR(system))
443 clk_put(system);
444 if (!IS_ERR(xtal1))
445 clk_put(xtal1);
446 if (!IS_ERR(usb24s))
447 clk_put(usb24s);
448}
449
227/* 450/*
228 * board init 451 * board init
229 */ 452 */
230static void __init eva_init(void) 453static void __init eva_init(void)
231{ 454{
455 eva_clock_init();
456
232 r8a7740_pinmux_init(); 457 r8a7740_pinmux_init();
233 458
234 /* SCIFA1 */ 459 /* SCIFA1 */
@@ -302,6 +527,18 @@ static void __init eva_init(void)
302 gpio_request(GPIO_PORT18, NULL); /* PHY_RST */ 527 gpio_request(GPIO_PORT18, NULL); /* PHY_RST */
303 gpio_direction_output(GPIO_PORT18, 1); 528 gpio_direction_output(GPIO_PORT18, 1);
304 529
530 /* USB */
531 gpio_request(GPIO_PORT159, NULL); /* USB_DEVICE_MODE */
532 gpio_direction_input(GPIO_PORT159);
533
534 if (gpio_get_value(GPIO_PORT159)) {
535 /* USB Host */
536 } else {
537 /* USB Func */
538 gpio_request(GPIO_FN_VBUS, NULL);
539 platform_device_register(&usbhsf_device);
540 }
541
305 /* 542 /*
306 * CAUTION 543 * CAUTION
307 * 544 *
@@ -326,17 +563,7 @@ static void __init eva_init(void)
326 563
327static void __init eva_earlytimer_init(void) 564static void __init eva_earlytimer_init(void)
328{ 565{
329 struct clk *xtal1;
330
331 r8a7740_clock_init(MD_CK0 | MD_CK2); 566 r8a7740_clock_init(MD_CK0 | MD_CK2);
332
333 xtal1 = clk_get(NULL, "extal1");
334 if (!IS_ERR(xtal1)) {
335 /* armadillo 800 eva extal1 is 24MHz */
336 clk_set_rate(xtal1, 24000000);
337 clk_put(xtal1);
338 }
339
340 shmobile_earlytimer_init(); 567 shmobile_earlytimer_init();
341} 568}
342 569