[ARM] 4940/1: AT91: UDPHS driver: SAM9RL board and cpu integration.
authorNicolas Ferre <nicolas.ferre@atmel.com>
Tue, 8 Apr 2008 12:59:18 +0000 (13:59 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 2 Jun 2008 14:08:13 +0000 (15:08 +0100)
Adds support for the USB High Speed Device Port on the AT91SAM9RL
system on chip. The AT91SAM9RL uses the same UDPHS IP as the AVR32 and
the AT91CAP9 (atmel_usba_udc driver).

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Andrew Victor <linux@maxim.org.za>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/clock.c
drivers/usb/gadget/Kconfig
include/asm-arm/arch-at91/at91sam9rl.h

index 450db30..8507dd0 100644 (file)
 
 
 /* --------------------------------------------------------------------
+ *  USB HS Device (Gadget)
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
+
+static struct resource usba_udc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9RL_UDPHS_FIFO,
+               .end    = AT91SAM9RL_UDPHS_FIFO + SZ_512K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9RL_BASE_UDPHS,
+               .end    = AT91SAM9RL_BASE_UDPHS + SZ_1K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = AT91SAM9RL_ID_UDPHS,
+               .end    = AT91SAM9RL_ID_UDPHS,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                 \
+       [idx] = {                                               \
+               .name           = nam,                          \
+               .index          = idx,                          \
+               .fifo_size      = maxpkt,                       \
+               .nr_banks       = maxbk,                        \
+               .can_dma        = dma,                          \
+               .can_isoc       = isoc,                         \
+       }
+
+static struct usba_ep_data usba_udc_ep[] __initdata = {
+       EP("ep0", 0, 64, 1, 0, 0),
+       EP("ep1", 1, 1024, 2, 1, 1),
+       EP("ep2", 2, 1024, 2, 1, 1),
+       EP("ep3", 3, 1024, 3, 1, 0),
+       EP("ep4", 4, 1024, 3, 1, 0),
+       EP("ep5", 5, 1024, 3, 1, 1),
+       EP("ep6", 6, 1024, 3, 1, 1),
+};
+
+#undef EP
+
+/*
+ * pdata doesn't have room for any endpoints, so we need to
+ * append room for the ones we need right after it.
+ */
+static struct {
+       struct usba_platform_data pdata;
+       struct usba_ep_data ep[7];
+} usba_udc_data;
+
+static struct platform_device at91_usba_udc_device = {
+       .name           = "atmel_usba_udc",
+       .id             = -1,
+       .dev            = {
+                               .platform_data  = &usba_udc_data.pdata,
+       },
+       .resource       = usba_udc_resources,
+       .num_resources  = ARRAY_SIZE(usba_udc_resources),
+};
+
+void __init at91_add_device_usba(struct usba_platform_data *data)
+{
+       /*
+        * Invalid pins are 0 on AT91, but the usba driver is shared
+        * with AVR32, which use negative values instead. Once/if
+        * gpio_is_valid() is ported to AT91, revisit this code.
+        */
+       usba_udc_data.pdata.vbus_pin = -EINVAL;
+       usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
+       memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));;
+
+       if (data && data->vbus_pin > 0) {
+               at91_set_gpio_input(data->vbus_pin, 0);
+               at91_set_deglitch(data->vbus_pin, 1);
+               usba_udc_data.pdata.vbus_pin = data->vbus_pin;
+       }
+
+       /* Pullup pin is handled internally by USB device peripheral */
+
+       /* Clocks */
+       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
+       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
+
+       platform_device_register(&at91_usba_udc_device);
+}
+#else
+void __init at91_add_device_usba(struct usba_platform_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
index ffc0597..b6a70fc 100644 (file)
@@ -56,6 +56,14 @@ static void __init ek_init_irq(void)
 
 
 /*
+ * USB HS Device port
+ */
+static struct usba_platform_data __initdata ek_usba_udc_data = {
+       .vbus_pin       = AT91_PIN_PA8,
+};
+
+
+/*
  * MCI (SD/MMC)
  */
 static struct at91_mmc_data __initdata ek_mmc_data = {
@@ -175,6 +183,8 @@ static void __init ek_board_init(void)
 {
        /* Serial */
        at91_add_device_serial();
+       /* USB HS */
+       at91_add_device_usba(&ek_usba_udc_data);
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* NAND */
index b87772c..e8ce8f0 100644 (file)
@@ -391,8 +391,9 @@ static int at91_clk_show(struct seq_file *s, void *unused)
        seq_printf(s, "MOR  = %8x\n", at91_sys_read(AT91_CKGR_MOR));
        seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR));
        seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR));
-       seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
-       if (cpu_is_at91cap9())
+       if (!cpu_is_at91sam9rl())
+               seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
+       if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
                seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR));
        seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));
        seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));
@@ -610,7 +611,7 @@ int __init at91_clock_init(unsigned long main_clock)
        /*
         * USB HS clock init
         */
-       if (cpu_is_at91cap9()) {
+       if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) {
                /*
                 * multiplier is hard-wired to 40
                 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
@@ -635,7 +636,7 @@ int __init at91_clock_init(unsigned long main_clock)
        for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
                list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
 
-       if (cpu_is_at91cap9())
+       if (cpu_is_at91cap9() || cpu_is_at91sam9rl())
                list_add_tail(&utmi_clk.node, &clocks);
 
        /* MCK and CPU clock are "always on" */
index 6e784d2..3565d43 100644 (file)
@@ -118,10 +118,10 @@ config USB_AMD5536UDC
 config USB_GADGET_ATMEL_USBA
        boolean "Atmel USBA"
        select USB_GADGET_DUALSPEED
-       depends on AVR32 || ARCH_AT91CAP9
+       depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL
        help
          USBA is the integrated high-speed USB Device controller on
-         the AT32AP700x and AT91CAP9 processors from Atmel.
+         the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
 
 config USB_ATMEL_USBA
        tristate
index 16d2832..622e56f 100644 (file)
 #define AT91SAM9RL_ROM_SIZE    (2 * SZ_16K)    /* Internal ROM size (32Kb) */
 
 #define AT91SAM9RL_LCDC_BASE   0x00500000      /* LCD Controller */
-#define AT91SAM9RL_UDPHS_BASE  0x00600000      /* USB Device HS controller */
+#define AT91SAM9RL_UDPHS_FIFO  0x00600000      /* USB Device HS controller */
 
 #endif