aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-at91/at91sam9g45_devices.c
diff options
context:
space:
mode:
authorNicolas Ferre <nicolas.ferre@atmel.com>2009-06-26 15:36:58 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-06-27 11:05:22 +0100
commit789b23bc40a67d9a19bedc2655c6bcab79bcabd8 (patch)
tree01b47924223763d33034ca7d6ec85f102fd5fcc0 /arch/arm/mach-at91/at91sam9g45_devices.c
parentfddcc0ae58edefeb7ac1e460411d7dfbe8ebdacc (diff)
[ARM] 5572/1: at91: Support for at91sam9g45 series: core chip & board support
Here are the at91 specific files dedicated to the at91sam9g45 series. They mimic the traditional at91 way of managing chips & boards. The first board that embeds at91sam9g45 chip is the AT91SAM9G45-EKES. In the future, the main board for this 9g45 series will be the AT91SAM9M10G45-EK (I choose this last name for the board file). Simple drivers are enabled in _devices and board- files. Newer peripheral support will be added in future patches. Incuded peripherals support (for now): - USART - SPI - Ethernet - NAND flash - LCD - gpio/joystick/buttons - leds and pwm 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>
Diffstat (limited to 'arch/arm/mach-at91/at91sam9g45_devices.c')
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c1230
1 files changed, 1230 insertions, 0 deletions
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
new file mode 100644
index 00000000000..d746e8621bc
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -0,0 +1,1230 @@
+/*
+ * On-Chip devices setup code for the AT91SAM9G45 family
+ *
+ * Copyright (C) 2009 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+
+#include <linux/fb.h>
+#include <video/atmel_lcdc.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9g45.h>
+#include <mach/at91sam9g45_matrix.h>
+#include <mach/at91sam9_smc.h>
+
+#include "generic.h"
+
+
+/* --------------------------------------------------------------------
+ * USB Host (OHCI)
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
+static struct at91_usbh_data usbh_ohci_data;
+
+static struct resource usbh_ohci_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_OHCI_BASE,
+ .end = AT91SAM9G45_OHCI_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_UHPHS,
+ .end = AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_usbh_ohci_device = {
+ .name = "at91_ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &usbh_ohci_data,
+ },
+ .resource = usbh_ohci_resources,
+ .num_resources = ARRAY_SIZE(usbh_ohci_resources),
+};
+
+void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data)
+{
+ int i;
+
+ if (!data)
+ return;
+
+ /* Enable VBus control for UHP ports */
+ for (i = 0; i < data->ports; i++) {
+ if (data->vbus_pin[i])
+ at91_set_gpio_output(data->vbus_pin[i], 0);
+ }
+
+ usbh_ohci_data = *data;
+ platform_device_register(&at91_usbh_ohci_device);
+}
+#else
+void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * 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 = AT91SAM9G45_UDPHS_FIFO,
+ .end = AT91SAM9G45_UDPHS_FIFO + SZ_512K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_BASE_UDPHS,
+ .end = AT91SAM9G45_BASE_UDPHS + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = AT91SAM9G45_ID_UDPHS,
+ .end = AT91SAM9G45_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)
+{
+ 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
+
+
+/* --------------------------------------------------------------------
+ * Ethernet
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+static u64 eth_dmamask = DMA_BIT_MASK(32);
+static struct at91_eth_data eth_data;
+
+static struct resource eth_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_EMAC,
+ .end = AT91SAM9G45_BASE_EMAC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_EMAC,
+ .end = AT91SAM9G45_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_eth_device = {
+ .name = "macb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &eth_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &eth_data,
+ },
+ .resource = eth_resources,
+ .num_resources = ARRAY_SIZE(eth_resources),
+};
+
+void __init at91_add_device_eth(struct at91_eth_data *data)
+{
+ if (!data)
+ return;
+
+ if (data->phy_irq_pin) {
+ at91_set_gpio_input(data->phy_irq_pin, 0);
+ at91_set_deglitch(data->phy_irq_pin, 1);
+ }
+
+ /* Pins used for MII and RMII */
+ at91_set_A_periph(AT91_PIN_PA17, 0); /* ETXCK_EREFCK */
+ at91_set_A_periph(AT91_PIN_PA15, 0); /* ERXDV */
+ at91_set_A_periph(AT91_PIN_PA12, 0); /* ERX0 */
+ at91_set_A_periph(AT91_PIN_PA13, 0); /* ERX1 */
+ at91_set_A_periph(AT91_PIN_PA16, 0); /* ERXER */
+ at91_set_A_periph(AT91_PIN_PA14, 0); /* ETXEN */
+ at91_set_A_periph(AT91_PIN_PA10, 0); /* ETX0 */
+ at91_set_A_periph(AT91_PIN_PA11, 0); /* ETX1 */
+ at91_set_A_periph(AT91_PIN_PA19, 0); /* EMDIO */
+ at91_set_A_periph(AT91_PIN_PA18, 0); /* EMDC */
+
+ if (!data->is_rmii) {
+ at91_set_B_periph(AT91_PIN_PA29, 0); /* ECRS */
+ at91_set_B_periph(AT91_PIN_PA30, 0); /* ECOL */
+ at91_set_B_periph(AT91_PIN_PA8, 0); /* ERX2 */
+ at91_set_B_periph(AT91_PIN_PA9, 0); /* ERX3 */
+ at91_set_B_periph(AT91_PIN_PA28, 0); /* ERXCK */
+ at91_set_B_periph(AT91_PIN_PA6, 0); /* ETX2 */
+ at91_set_B_periph(AT91_PIN_PA7, 0); /* ETX3 */
+ at91_set_B_periph(AT91_PIN_PA27, 0); /* ETXER */
+ }
+
+ eth_data = *data;
+ platform_device_register(&at91sam9g45_eth_device);
+}
+#else
+void __init at91_add_device_eth(struct at91_eth_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
+static struct atmel_nand_data nand_data;
+
+#define NAND_BASE AT91_CHIPSELECT_3
+
+static struct resource nand_resources[] = {
+ [0] = {
+ .start = NAND_BASE,
+ .end = NAND_BASE + SZ_256M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91_BASE_SYS + AT91_ECC,
+ .end = AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device at91sam9g45_nand_device = {
+ .name = "atmel_nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &nand_data,
+ },
+ .resource = nand_resources,
+ .num_resources = ARRAY_SIZE(nand_resources),
+};
+
+void __init at91_add_device_nand(struct atmel_nand_data *data)
+{
+ unsigned long csa;
+
+ if (!data)
+ return;
+
+ csa = at91_sys_read(AT91_MATRIX_EBICSA);
+ at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
+
+ /* enable pin */
+ if (data->enable_pin)
+ at91_set_gpio_output(data->enable_pin, 1);
+
+ /* ready/busy pin */
+ if (data->rdy_pin)
+ at91_set_gpio_input(data->rdy_pin, 1);
+
+ /* card detect pin */
+ if (data->det_pin)
+ at91_set_gpio_input(data->det_pin, 1);
+
+ nand_data = *data;
+ platform_device_register(&at91sam9g45_nand_device);
+}
+#else
+void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+static struct i2c_gpio_platform_data pdata_i2c0 = {
+ .sda_pin = AT91_PIN_PA20,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PA21,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9g45_twi0_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev.platform_data = &pdata_i2c0,
+};
+
+static struct i2c_gpio_platform_data pdata_i2c1 = {
+ .sda_pin = AT91_PIN_PB10,
+ .sda_is_open_drain = 1,
+ .scl_pin = AT91_PIN_PB11,
+ .scl_is_open_drain = 1,
+ .udelay = 2, /* ~100 kHz */
+};
+
+static struct platform_device at91sam9g45_twi1_device = {
+ .name = "i2c-gpio",
+ .id = 1,
+ .dev.platform_data = &pdata_i2c1,
+};
+
+void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
+{
+ i2c_register_board_info(i2c_id, devices, nr_devices);
+
+ if (i2c_id == 0) {
+ at91_set_GPIO_periph(AT91_PIN_PA20, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PA20, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PA21, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PA21, 1);
+
+ platform_device_register(&at91sam9g45_twi0_device);
+ } else {
+ at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* TWD (SDA) */
+ at91_set_multi_drive(AT91_PIN_PB10, 1);
+
+ at91_set_GPIO_periph(AT91_PIN_PB11, 1); /* TWCK (SCL) */
+ at91_set_multi_drive(AT91_PIN_PB11, 1);
+
+ platform_device_register(&at91sam9g45_twi1_device);
+ }
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+static struct resource twi0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TWI0,
+ .end = AT91SAM9G45_BASE_TWI0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TWI0,
+ .end = AT91SAM9G45_ID_TWI0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_twi0_device = {
+ .name = "at91_i2c",
+ .id = 0,
+ .resource = twi0_resources,
+ .num_resources = ARRAY_SIZE(twi0_resources),
+};
+
+static struct resource twi1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TWI1,
+ .end = AT91SAM9G45_BASE_TWI1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TWI1,
+ .end = AT91SAM9G45_ID_TWI1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_twi1_device = {
+ .name = "at91_i2c",
+ .id = 1,
+ .resource = twi1_resources,
+ .num_resources = ARRAY_SIZE(twi1_resources),
+};
+
+void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
+{
+ i2c_register_board_info(i2c_id, devices, nr_devices);
+
+ /* pins used for TWI interface */
+ if (i2c_id == 0) {
+ at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA20, 1);
+
+ at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
+ at91_set_multi_drive(AT91_PIN_PA21, 1);
+
+ platform_device_register(&at91sam9g45_twi0_device);
+ } else {
+ at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PB10, 1);
+
+ at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
+ at91_set_multi_drive(AT91_PIN_PB11, 1);
+
+ platform_device_register(&at91sam9g45_twi1_device);
+ }
+}
+#else
+void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * SPI
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+static struct resource spi0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SPI0,
+ .end = AT91SAM9G45_BASE_SPI0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SPI0,
+ .end = AT91SAM9G45_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_spi0_device = {
+ .name = "atmel_spi",
+ .id = 0,
+ .dev = {
+ .dma_mask = &spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = spi0_resources,
+ .num_resources = ARRAY_SIZE(spi0_resources),
+};
+
+static const unsigned spi0_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PB18, AT91_PIN_PB19, AT91_PIN_PD27 };
+
+static struct resource spi1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SPI1,
+ .end = AT91SAM9G45_BASE_SPI1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SPI1,
+ .end = AT91SAM9G45_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_spi1_device = {
+ .name = "atmel_spi",
+ .id = 1,
+ .dev = {
+ .dma_mask = &spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = spi1_resources,
+ .num_resources = ARRAY_SIZE(spi1_resources),
+};
+
+static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB17, AT91_PIN_PD28, AT91_PIN_PD18, AT91_PIN_PD19 };
+
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+{
+ int i;
+ unsigned long cs_pin;
+ short enable_spi0 = 0;
+ short enable_spi1 = 0;
+
+ /* Choose SPI chip-selects */
+ for (i = 0; i < nr_devices; i++) {
+ if (devices[i].controller_data)
+ cs_pin = (unsigned long) devices[i].controller_data;
+ else if (devices[i].bus_num == 0)
+ cs_pin = spi0_standard_cs[devices[i].chip_select];
+ else
+ cs_pin = spi1_standard_cs[devices[i].chip_select];
+
+ if (devices[i].bus_num == 0)
+ enable_spi0 = 1;
+ else
+ enable_spi1 = 1;
+
+ /* enable chip-select pin */
+ at91_set_gpio_output(cs_pin, 1);
+
+ /* pass chip-select pin to driver */
+ devices[i].controller_data = (void *) cs_pin;
+ }
+
+ spi_register_board_info(devices, nr_devices);
+
+ /* Configure SPI bus(es) */
+ if (enable_spi0) {
+ at91_set_A_periph(AT91_PIN_PB0, 0); /* SPI0_MISO */
+ at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI0_MOSI */
+ at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI0_SPCK */
+
+ at91_clock_associate("spi0_clk", &at91sam9g45_spi0_device.dev, "spi_clk");
+ platform_device_register(&at91sam9g45_spi0_device);
+ }
+ if (enable_spi1) {
+ at91_set_A_periph(AT91_PIN_PB14, 0); /* SPI1_MISO */
+ at91_set_A_periph(AT91_PIN_PB15, 0); /* SPI1_MOSI */
+ at91_set_A_periph(AT91_PIN_PB16, 0); /* SPI1_SPCK */
+
+ at91_clock_associate("spi1_clk", &at91sam9g45_spi1_device.dev, "spi_clk");
+ platform_device_register(&at91sam9g45_spi1_device);
+ }
+}
+#else
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+static struct atmel_lcdfb_info lcdc_data;
+
+static struct resource lcdc_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_LCDC_BASE,
+ .end = AT91SAM9G45_LCDC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_LCDC,
+ .end = AT91SAM9G45_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_lcdc_device = {
+ .name = "atmel_lcdfb",
+ .id = 0,
+ .dev = {
+ .dma_mask = &lcdc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &lcdc_data,
+ },
+ .resource = lcdc_resources,
+ .num_resources = ARRAY_SIZE(lcdc_resources),
+};
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+ if (!data)
+ return;
+
+ at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */
+
+ at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */
+ at91_set_A_periph(AT91_PIN_PE3, 0); /* LCDVSYNC */
+ at91_set_A_periph(AT91_PIN_PE4, 0); /* LCDHSYNC */
+ at91_set_A_periph(AT91_PIN_PE5, 0); /* LCDDOTCK */
+ at91_set_A_periph(AT91_PIN_PE6, 0); /* LCDDEN */
+ at91_set_A_periph(AT91_PIN_PE7, 0); /* LCDD0 */
+ at91_set_A_periph(AT91_PIN_PE8, 0); /* LCDD1 */
+ at91_set_A_periph(AT91_PIN_PE9, 0); /* LCDD2 */
+ at91_set_A_periph(AT91_PIN_PE10, 0); /* LCDD3 */
+ at91_set_A_periph(AT91_PIN_PE11, 0); /* LCDD4 */
+ at91_set_A_periph(AT91_PIN_PE12, 0); /* LCDD5 */
+ at91_set_A_periph(AT91_PIN_PE13, 0); /* LCDD6 */
+ at91_set_A_periph(AT91_PIN_PE14, 0); /* LCDD7 */
+ at91_set_A_periph(AT91_PIN_PE15, 0); /* LCDD8 */
+ at91_set_A_periph(AT91_PIN_PE16, 0); /* LCDD9 */
+ at91_set_A_periph(AT91_PIN_PE17, 0); /* LCDD10 */
+ at91_set_A_periph(AT91_PIN_PE18, 0); /* LCDD11 */
+ at91_set_A_periph(AT91_PIN_PE19, 0); /* LCDD12 */
+ at91_set_A_periph(AT91_PIN_PE20, 0); /* LCDD13 */
+ at91_set_A_periph(AT91_PIN_PE21, 0); /* LCDD14 */
+ at91_set_A_periph(AT91_PIN_PE22, 0); /* LCDD15 */
+ at91_set_A_periph(AT91_PIN_PE23, 0); /* LCDD16 */
+ at91_set_A_periph(AT91_PIN_PE24, 0); /* LCDD17 */
+ at91_set_A_periph(AT91_PIN_PE25, 0); /* LCDD18 */
+ at91_set_A_periph(AT91_PIN_PE26, 0); /* LCDD19 */
+ at91_set_A_periph(AT91_PIN_PE27, 0); /* LCDD20 */
+ at91_set_A_periph(AT91_PIN_PE28, 0); /* LCDD21 */
+ at91_set_A_periph(AT91_PIN_PE29, 0); /* LCDD22 */
+ at91_set_A_periph(AT91_PIN_PE30, 0); /* LCDD23 */
+
+ lcdc_data = *data;
+ platform_device_register(&at91_lcdc_device);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * Timer/Counter block
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_ATMEL_TCLIB
+static struct resource tcb0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TCB0,
+ .end = AT91SAM9G45_BASE_TCB0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TCB,
+ .end = AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_tcb0_device = {
+ .name = "atmel_tcb",
+ .id = 0,
+ .resource = tcb0_resources,
+ .num_resources = ARRAY_SIZE(tcb0_resources),
+};
+
+/* TCB1 begins with TC3 */
+static struct resource tcb1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TCB1,
+ .end = AT91SAM9G45_BASE_TCB1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TCB,
+ .end = AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_tcb1_device = {
+ .name = "atmel_tcb",
+ .id = 1,
+ .resource = tcb1_resources,
+ .num_resources = ARRAY_SIZE(tcb1_resources),
+};
+
+static void __init at91_add_device_tc(void)
+{
+ /* this chip has one clock and irq for all six TC channels */
+ at91_clock_associate("tcb_clk", &at91sam9g45_tcb0_device.dev, "t0_clk");
+ platform_device_register(&at91sam9g45_tcb0_device);
+ at91_clock_associate("tcb_clk", &at91sam9g45_tcb1_device.dev, "t0_clk");
+ platform_device_register(&at91sam9g45_tcb1_device);
+}
+#else
+static void __init at91_add_device_tc(void) { }
+#endif
+
+
+/* --------------------------------------------------------------------
+ * RTC
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
+static struct platform_device at91sam9g45_rtc_device = {
+ .name = "at91_rtc",
+ .id = -1,
+ .num_resources = 0,
+};
+
+static void __init at91_add_device_rtc(void)
+{
+ platform_device_register(&at91sam9g45_rtc_device);
+}
+#else
+static void __init at91_add_device_rtc(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * RTT
+ * -------------------------------------------------------------------- */
+
+static struct resource rtt_resources[] = {
+ {
+ .start = AT91_BASE_SYS + AT91_RTT,
+ .end = AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device at91sam9g45_rtt_device = {
+ .name = "at91_rtt",
+ .id = 0,
+ .resource = rtt_resources,
+ .num_resources = ARRAY_SIZE(rtt_resources),
+};
+
+static void __init at91_add_device_rtt(void)
+{
+ platform_device_register(&at91sam9g45_rtt_device);
+}
+
+
+/* --------------------------------------------------------------------
+ * Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91sam9g45_wdt_device = {
+ .name = "at91_wdt",
+ .id = -1,
+ .num_resources = 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+ platform_device_register(&at91sam9g45_wdt_device);
+}
+#else
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * PWM
+ * --------------------------------------------------------------------*/
+
+#if defined(CONFIG_ATMEL_PWM) || defined(CONFIG_ATMEL_PWM_MODULE)
+static u32 pwm_mask;
+
+static struct resource pwm_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_PWMC,
+ .end = AT91SAM9G45_BASE_PWMC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_PWMC,
+ .end = AT91SAM9G45_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_pwm0_device = {
+ .name = "atmel_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &pwm_mask,
+ },
+ .resource = pwm_resources,
+ .num_resources = ARRAY_SIZE(pwm_resources),
+};
+
+void __init at91_add_device_pwm(u32 mask)
+{
+ if (mask & (1 << AT91_PWM0))
+ at91_set_B_periph(AT91_PIN_PD24, 1); /* enable PWM0 */
+
+ if (mask & (1 << AT91_PWM1))
+ at91_set_B_periph(AT91_PIN_PD31, 1); /* enable PWM1 */
+
+ if (mask & (1 << AT91_PWM2))
+ at91_set_B_periph(AT91_PIN_PD26, 1); /* enable PWM2 */
+
+ if (mask & (1 << AT91_PWM3))
+ at91_set_B_periph(AT91_PIN_PD0, 1); /* enable PWM3 */
+
+ pwm_mask = mask;
+
+ platform_device_register(&at91sam9g45_pwm0_device);
+}
+#else
+void __init at91_add_device_pwm(u32 mask) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SSC0,
+ .end = AT91SAM9G45_BASE_SSC0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SSC0,
+ .end = AT91SAM9G45_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_ssc0_device = {
+ .name = "ssc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ssc0_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = ssc0_resources,
+ .num_resources = ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
+{
+ if (pins & ATMEL_SSC_TF)
+ at91_set_A_periph(AT91_PIN_PD1, 1);
+ if (pins & ATMEL_SSC_TK)
+ at91_set_A_periph(AT91_PIN_PD0, 1);
+ if (pins & ATMEL_SSC_TD)
+ at91_set_A_periph(AT91_PIN_PD2, 1);
+ if (pins & ATMEL_SSC_RD)
+ at91_set_A_periph(AT91_PIN_PD3, 1);
+ if (pins & ATMEL_SSC_RK)
+ at91_set_A_periph(AT91_PIN_PD4, 1);
+ if (pins & ATMEL_SSC_RF)
+ at91_set_A_periph(AT91_PIN_PD5, 1);
+}
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_SSC1,
+ .end = AT91SAM9G45_BASE_SSC1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_SSC1,
+ .end = AT91SAM9G45_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9g45_ssc1_device = {
+ .name = "ssc",
+ .id = 1,
+ .dev = {
+ .dma_mask = &ssc1_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = ssc1_resources,
+ .num_resources = ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+ if (pins & ATMEL_SSC_TF)
+ at91_set_A_periph(AT91_PIN_PD14, 1);
+ if (pins & ATMEL_SSC_TK)
+ at91_set_A_periph(AT91_PIN_PD12, 1);
+ if (pins & ATMEL_SSC_TD)
+ at91_set_A_periph(AT91_PIN_PD10, 1);
+ if (pins & ATMEL_SSC_RD)
+ at91_set_A_periph(AT91_PIN_PD11, 1);
+ if (pins & ATMEL_SSC_RK)
+ at91_set_A_periph(AT91_PIN_PD13, 1);
+ if (pins & ATMEL_SSC_RF)
+ at91_set_A_periph(AT91_PIN_PD15, 1);
+}
+
+/*
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver. For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+ struct platform_device *pdev;
+
+ /*
+ * NOTE: caller is responsible for passing information matching
+ * "pins" to whatever will be using each particular controller.
+ */
+ switch (id) {
+ case AT91SAM9G45_ID_SSC0:
+ pdev = &at91sam9g45_ssc0_device;
+ configure_ssc0_pins(pins);
+ at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
+ break;
+ case AT91SAM9G45_ID_SSC1:
+ pdev = &at91sam9g45_ssc1_device;
+ configure_ssc1_pins(pins);
+ at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
+ break;
+ default:
+ return;
+ }
+
+ platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * UART
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SERIAL_ATMEL)
+static struct resource dbgu_resources[] = {
+ [0] = {
+ .start = AT91_VA_BASE_SYS + AT91_DBGU,
+ .end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91_ID_SYS,
+ .end = AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data dbgu_data = {
+ .use_dma_tx = 0,
+ .use_dma_rx = 0,
+ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+};
+
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_dbgu_device = {
+ .name = "atmel_usart",
+ .id = 0,
+ .dev = {
+ .dma_mask = &dbgu_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &dbgu_data,
+ },
+ .resource = dbgu_resources,
+ .num_resources = ARRAY_SIZE(dbgu_resources),
+};
+
+static inline void configure_dbgu_pins(void)
+{
+ at91_set_A_periph(AT91_PIN_PB12, 0); /* DRXD */
+ at91_set_A_periph(AT91_PIN_PB13, 1); /* DTXD */
+}
+
+static struct resource uart0_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US0,
+ .end = AT91SAM9G45_BASE_US0 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US0,
+ .end = AT91SAM9G45_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart0_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart0_device = {
+ .name = "atmel_usart",
+ .id = 1,
+ .dev = {
+ .dma_mask = &uart0_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart0_data,
+ },
+ .resource = uart0_resources,
+ .num_resources = ARRAY_SIZE(uart0_resources),
+};
+
+static inline void configure_usart0_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB19, 1); /* TXD0 */
+ at91_set_A_periph(AT91_PIN_PB18, 0); /* RXD0 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_B_periph(AT91_PIN_PB17, 0); /* RTS0 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_B_periph(AT91_PIN_PB15, 0); /* CTS0 */
+}
+
+static struct resource uart1_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US1,
+ .end = AT91SAM9G45_BASE_US1 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US1,
+ .end = AT91SAM9G45_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart1_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart1_device = {
+ .name = "atmel_usart",
+ .id = 2,
+ .dev = {
+ .dma_mask = &uart1_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart1_data,
+ },
+ .resource = uart1_resources,
+ .num_resources = ARRAY_SIZE(uart1_resources),
+};
+
+static inline void configure_usart1_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB4, 1); /* TXD1 */
+ at91_set_A_periph(AT91_PIN_PB5, 0); /* RXD1 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_A_periph(AT91_PIN_PD16, 0); /* RTS1 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_A_periph(AT91_PIN_PD17, 0); /* CTS1 */
+}
+
+static struct resource uart2_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US2,
+ .end = AT91SAM9G45_BASE_US2 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US2,
+ .end = AT91SAM9G45_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart2_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart2_device = {
+ .name = "atmel_usart",
+ .id = 3,
+ .dev = {
+ .dma_mask = &uart2_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart2_data,
+ },
+ .resource = uart2_resources,
+ .num_resources = ARRAY_SIZE(uart2_resources),
+};
+
+static inline void configure_usart2_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB6, 1); /* TXD2 */
+ at91_set_A_periph(AT91_PIN_PB7, 0); /* RXD2 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_B_periph(AT91_PIN_PC9, 0); /* RTS2 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_B_periph(AT91_PIN_PC11, 0); /* CTS2 */
+}
+
+static struct resource uart3_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_US3,
+ .end = AT91SAM9G45_BASE_US3 + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_US3,
+ .end = AT91SAM9G45_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct atmel_uart_data uart3_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+
+static u64 uart3_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91sam9g45_uart3_device = {
+ .name = "atmel_usart",
+ .id = 4,
+ .dev = {
+ .dma_mask = &uart3_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &uart3_data,
+ },
+ .resource = uart3_resources,
+ .num_resources = ARRAY_SIZE(uart3_resources),
+};
+
+static inline void configure_usart3_pins(unsigned pins)
+{
+ at91_set_A_periph(AT91_PIN_PB8, 1); /* TXD3 */
+ at91_set_A_periph(AT91_PIN_PB9, 0); /* RXD3 */
+
+ if (pins & ATMEL_UART_RTS)
+ at91_set_B_periph(AT91_PIN_PA23, 0); /* RTS3 */
+ if (pins & ATMEL_UART_CTS)
+ at91_set_B_periph(AT91_PIN_PA24, 0); /* CTS3 */
+}
+
+static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
+struct platform_device *atmel_default_console_device; /* the serial console device */
+
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0: /* DBGU */
+ pdev = &at91sam9g45_dbgu_device;
+ configure_dbgu_pins();
+ at91_clock_associate("mck", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US0:
+ pdev = &at91sam9g45_uart0_device;
+ configure_usart0_pins(pins);
+ at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US1:
+ pdev = &at91sam9g45_uart1_device;
+ configure_usart1_pins(pins);
+ at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US2:
+ pdev = &at91sam9g45_uart2_device;
+ configure_usart2_pins(pins);
+ at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+ break;
+ case AT91SAM9G45_ID_US3:
+ pdev = &at91sam9g45_uart3_device;
+ configure_usart3_pins(pins);
+ at91_clock_associate("usart3_clk", &pdev->dev, "usart");
+ break;
+ default:
+ return;
+ }
+ pdev->id = portnr; /* update to mapped ID */
+
+ if (portnr < ATMEL_MAX_UART)
+ at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+ if (portnr < ATMEL_MAX_UART)
+ atmel_default_console_device = at91_uarts[portnr];
+}
+
+void __init at91_add_device_serial(void)
+{
+ int i;
+
+ for (i = 0; i < ATMEL_MAX_UART; i++) {
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[i]);
+ }
+
+ if (!atmel_default_console_device)
+ printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+#else
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
+void __init at91_add_device_serial(void) {}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * These devices are always present and don't need any board-specific
+ * setup.
+ */
+static int __init at91_add_standard_devices(void)
+{
+ at91_add_device_rtc();
+ at91_add_device_rtt();
+ at91_add_device_watchdog();
+ at91_add_device_tc();
+ return 0;
+}
+
+arch_initcall(at91_add_standard_devices);