aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-08-19 10:39:15 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-08-19 21:32:17 -0400
commit5a1c4cb5bc228662bfb116f1e07ad658915a5742 (patch)
tree37a92460734f2c2f2409ada265f4578d524ced35
parent0bb886d2a9c2d4e069ca364e36c52c7ae6d1ca8c (diff)
sh: add r8a66597 usb0 gadget to the kfr2r09 board
Add USB gadget support for port YC301 on the KFR2R09 board. The r8a66597-udc driver is hooked up as a platform device, clocks are enabled via I2C and some registers are configured to enable the USB in gadget mode. The hardware driving the USB port is the on-chip USB0 block in the sh7724 processor configured as USB gadget controller. This board is using external hardware to detect USB hotplug events and allows the processor to dynamically start and stop clocks. This well thought out hardware feature is unused at this point and plug and play is unfortunately unsupported. To properly support all hardware features the USB gadget stack may need some adjustment. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index bdb10c29ef1..1cbd6a3655c 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -16,6 +16,8 @@
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/gpio.h> 17#include <linux/gpio.h>
18#include <linux/input.h> 18#include <linux/input.h>
19#include <linux/i2c.h>
20#include <linux/usb/r8a66597.h>
19#include <video/sh_mobile_lcdc.h> 21#include <video/sh_mobile_lcdc.h>
20#include <asm/clock.h> 22#include <asm/clock.h>
21#include <asm/machvec.h> 23#include <asm/machvec.h>
@@ -175,6 +177,35 @@ static struct platform_device kfr2r09_sh_lcdc_device = {
175 }, 177 },
176}; 178};
177 179
180static struct r8a66597_platdata kfr2r09_usb0_gadget_data = {
181 .on_chip = 1,
182};
183
184static struct resource kfr2r09_usb0_gadget_resources[] = {
185 [0] = {
186 .start = 0x04d80000,
187 .end = 0x04d80123,
188 .flags = IORESOURCE_MEM,
189 },
190 [1] = {
191 .start = 65,
192 .end = 65,
193 .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
194 },
195};
196
197static struct platform_device kfr2r09_usb0_gadget_device = {
198 .name = "r8a66597_udc",
199 .id = 0,
200 .dev = {
201 .dma_mask = NULL, /* not use dma */
202 .coherent_dma_mask = 0xffffffff,
203 .platform_data = &kfr2r09_usb0_gadget_data,
204 },
205 .num_resources = ARRAY_SIZE(kfr2r09_usb0_gadget_resources),
206 .resource = kfr2r09_usb0_gadget_resources,
207};
208
178static struct platform_device *kfr2r09_devices[] __initdata = { 209static struct platform_device *kfr2r09_devices[] __initdata = {
179 &kfr2r09_nor_flash_device, 210 &kfr2r09_nor_flash_device,
180 &kfr2r09_nand_flash_device, 211 &kfr2r09_nand_flash_device,
@@ -186,6 +217,74 @@ static struct platform_device *kfr2r09_devices[] __initdata = {
186#define BSC_CS0WCR 0xfec10024 217#define BSC_CS0WCR 0xfec10024
187#define BSC_CS4BCR 0xfec10010 218#define BSC_CS4BCR 0xfec10010
188#define BSC_CS4WCR 0xfec10030 219#define BSC_CS4WCR 0xfec10030
220#define PORT_MSELCRB 0xa4050182
221
222static int kfr2r09_usb0_gadget_i2c_setup(void)
223{
224 struct i2c_adapter *a;
225 struct i2c_msg msg;
226 unsigned char buf[2];
227 int ret;
228
229 a = i2c_get_adapter(0);
230 if (!a)
231 return -ENODEV;
232
233 /* set bit 1 (the second bit) of chip at 0x09, register 0x13 */
234 buf[0] = 0x13;
235 msg.addr = 0x09;
236 msg.buf = buf;
237 msg.len = 1;
238 msg.flags = 0;
239 ret = i2c_transfer(a, &msg, 1);
240 if (ret != 1)
241 return -ENODEV;
242
243 buf[0] = 0;
244 msg.addr = 0x09;
245 msg.buf = buf;
246 msg.len = 1;
247 msg.flags = I2C_M_RD;
248 ret = i2c_transfer(a, &msg, 1);
249 if (ret != 1)
250 return -ENODEV;
251
252 buf[1] = buf[0] | (1 << 1);
253 buf[0] = 0x13;
254 msg.addr = 0x09;
255 msg.buf = buf;
256 msg.len = 2;
257 msg.flags = 0;
258 ret = i2c_transfer(a, &msg, 1);
259 if (ret != 1)
260 return -ENODEV;
261
262 return 0;
263}
264
265static int kfr2r09_usb0_gadget_setup(void)
266{
267 int plugged_in;
268
269 gpio_request(GPIO_PTN4, NULL); /* USB_DET */
270 gpio_direction_input(GPIO_PTN4);
271 plugged_in = gpio_get_value(GPIO_PTN4);
272 if (!plugged_in)
273 return -ENODEV; /* no cable plugged in */
274
275 if (kfr2r09_usb0_gadget_i2c_setup() != 0)
276 return -ENODEV; /* unable to configure using i2c */
277
278 ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB);
279 gpio_request(GPIO_FN_PDSTATUS, NULL); /* R-standby disables USB clock */
280 gpio_request(GPIO_PTV6, NULL); /* USBCLK_ON */
281 gpio_direction_output(GPIO_PTV6, 1); /* USBCLK_ON = H */
282 msleep(20); /* wait 20ms to let the clock settle */
283 clk_enable(clk_get(NULL, "usb0"));
284 ctrl_outw(0x0600, 0xa40501d4);
285
286 return 0;
287}
189 288
190static int __init kfr2r09_devices_setup(void) 289static int __init kfr2r09_devices_setup(void)
191{ 290{
@@ -245,6 +344,10 @@ static int __init kfr2r09_devices_setup(void)
245 gpio_request(GPIO_PTU0, NULL); /* LEDSTDBY/ */ 344 gpio_request(GPIO_PTU0, NULL); /* LEDSTDBY/ */
246 gpio_direction_output(GPIO_PTU0, 1); 345 gpio_direction_output(GPIO_PTU0, 1);
247 346
347 /* setup USB function */
348 if (kfr2r09_usb0_gadget_setup() == 0)
349 platform_device_register(&kfr2r09_usb0_gadget_device);
350
248 return platform_add_devices(kfr2r09_devices, 351 return platform_add_devices(kfr2r09_devices,
249 ARRAY_SIZE(kfr2r09_devices)); 352 ARRAY_SIZE(kfr2r09_devices));
250} 353}