diff options
Diffstat (limited to 'arch/arm/mach-at91')
50 files changed, 1178 insertions, 313 deletions
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index e55cdcbd81fb..45db05d8d94c 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -20,9 +20,11 @@ config HAVE_AT91_USART5 config AT91_SAM9_ALT_RESET bool + default !ARCH_AT91X40 config AT91_SAM9G45_RESET bool + default !ARCH_AT91X40 menu "Atmel AT91 System-on-Chip" @@ -45,7 +47,6 @@ config ARCH_AT91SAM9260 select HAVE_AT91_USART4 select HAVE_AT91_USART5 select HAVE_NET_MACB - select AT91_SAM9_ALT_RESET config ARCH_AT91SAM9261 bool "AT91SAM9261" @@ -53,7 +54,6 @@ config ARCH_AT91SAM9261 select GENERIC_CLOCKEVENTS select HAVE_FB_ATMEL select HAVE_AT91_DBGU0 - select AT91_SAM9_ALT_RESET config ARCH_AT91SAM9G10 bool "AT91SAM9G10" @@ -61,7 +61,6 @@ config ARCH_AT91SAM9G10 select GENERIC_CLOCKEVENTS select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL - select AT91_SAM9_ALT_RESET config ARCH_AT91SAM9263 bool "AT91SAM9263" @@ -70,7 +69,6 @@ config ARCH_AT91SAM9263 select HAVE_FB_ATMEL select HAVE_NET_MACB select HAVE_AT91_DBGU1 - select AT91_SAM9_ALT_RESET config ARCH_AT91SAM9RL bool "AT91SAM9RL" @@ -79,7 +77,6 @@ config ARCH_AT91SAM9RL select HAVE_AT91_USART3 select HAVE_FB_ATMEL select HAVE_AT91_DBGU0 - select AT91_SAM9_ALT_RESET config ARCH_AT91SAM9G20 bool "AT91SAM9G20" @@ -90,7 +87,6 @@ config ARCH_AT91SAM9G20 select HAVE_AT91_USART4 select HAVE_AT91_USART5 select HAVE_NET_MACB - select AT91_SAM9_ALT_RESET config ARCH_AT91SAM9G45 bool "AT91SAM9G45" @@ -100,7 +96,6 @@ config ARCH_AT91SAM9G45 select HAVE_FB_ATMEL select HAVE_NET_MACB select HAVE_AT91_DBGU1 - select AT91_SAM9G45_RESET config ARCH_AT91SAM9X5 bool "AT91SAM9x5 family" @@ -109,7 +104,6 @@ config ARCH_AT91SAM9X5 select HAVE_FB_ATMEL select HAVE_NET_MACB select HAVE_AT91_DBGU0 - select AT91_SAM9G45_RESET config ARCH_AT91X40 bool "AT91x40" diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 1b6518518d99..8512e53bed93 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_d obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o +obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o sam9_smc.o obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o # AT91RM9200 board-specific support diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 0df1045311e4..364c19357e60 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -15,6 +15,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/system_misc.h> #include <mach/at91rm9200.h> #include <mach/at91_pmc.h> #include <mach/at91_st.h> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 640520c04c46..99ce5c955e39 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -84,7 +84,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data) {} * USB Device (Gadget) * -------------------------------------------------------------------- */ -#ifdef CONFIG_USB_AT91 +#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE) static struct at91_udc_data udc_data; static struct resource udc_resources[] = { diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 4ade265be805..46f774233298 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -16,6 +16,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/system_misc.h> #include <mach/cpu.h> #include <mach/at91_dbgu.h> #include <mach/at91sam9260.h> @@ -209,6 +210,14 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk), CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk), CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk), + /* more tc lookup table for DT entries */ + CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk), + CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk), + CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk), + CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk), + CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk), + CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk), + CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index df487ce83c5e..7e5651ee9f85 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -85,7 +85,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data) {} * USB Device (Gadget) * -------------------------------------------------------------------- */ -#ifdef CONFIG_USB_AT91 +#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE) static struct at91_udc_data udc_data; static struct resource udc_resources[] = { @@ -642,7 +642,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) static struct resource tcb0_resources[] = { [0] = { .start = AT91SAM9260_BASE_TCB0, - .end = AT91SAM9260_BASE_TCB0 + SZ_16K - 1, + .end = AT91SAM9260_BASE_TCB0 + SZ_256 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -672,7 +672,7 @@ static struct platform_device at91sam9260_tcb0_device = { static struct resource tcb1_resources[] = { [0] = { .start = AT91SAM9260_BASE_TCB1, - .end = AT91SAM9260_BASE_TCB1 + SZ_16K - 1, + .end = AT91SAM9260_BASE_TCB1 + SZ_256 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -699,8 +699,25 @@ static struct platform_device at91sam9260_tcb1_device = { .num_resources = ARRAY_SIZE(tcb1_resources), }; +#if defined(CONFIG_OF) +static struct of_device_id tcb_ids[] = { + { .compatible = "atmel,at91rm9200-tcb" }, + { /*sentinel*/ } +}; +#endif + static void __init at91_add_device_tc(void) { +#if defined(CONFIG_OF) + struct device_node *np; + + np = of_find_matching_node(NULL, tcb_ids); + if (np) { + of_node_put(np); + return; + } +#endif + platform_device_register(&at91sam9260_tcb0_device); platform_device_register(&at91sam9260_tcb1_device); } @@ -1239,8 +1256,7 @@ void __init at91_add_device_serial(void) {} * CF/IDE * -------------------------------------------------------------------- */ -#if defined(CONFIG_BLK_DEV_IDE_AT91) || defined(CONFIG_BLK_DEV_IDE_AT91_MODULE) || \ - defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) || \ +#if defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) || \ defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE) static struct at91_cf_data cf0_data; @@ -1337,10 +1353,8 @@ void __init at91_add_device_cf(struct at91_cf_data *data) if (data->flags & AT91_CF_TRUE_IDE) #if defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) pdev->name = "pata_at91"; -#elif defined(CONFIG_BLK_DEV_IDE_AT91) || defined(CONFIG_BLK_DEV_IDE_AT91_MODULE) - pdev->name = "at91_ide"; #else -#warning "board requires AT91_CF_TRUE_IDE: enable either at91_ide or pata_at91" +#warning "board requires AT91_CF_TRUE_IDE: enable pata_at91" #endif else pdev->name = "at91_cf"; diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 684c5dfd92ac..7de81e6222f1 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -16,6 +16,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/system_misc.h> #include <mach/cpu.h> #include <mach/at91sam9261.h> #include <mach/at91_pmc.h> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 3bd10ce4854e..096da87dc00d 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -88,7 +88,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data) {} * USB Device (Gadget) * -------------------------------------------------------------------- */ -#ifdef CONFIG_USB_AT91 +#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE) static struct at91_udc_data udc_data; static struct resource udc_resources[] = { diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 0b4fa5a7f685..ef301be66575 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -16,6 +16,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/system_misc.h> #include <mach/at91sam9263.h> #include <mach/at91_pmc.h> #include <mach/at91_rstc.h> diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 7792de5b83d4..53688c46f956 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -93,7 +93,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data) {} * USB Device (Gadget) * -------------------------------------------------------------------- */ -#ifdef CONFIG_USB_AT91 +#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE) static struct at91_udc_data udc_data; static struct resource udc_resources[] = { @@ -356,8 +356,8 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} * Compact Flash (PCMCIA or IDE) * -------------------------------------------------------------------- */ -#if defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE) || \ - defined(CONFIG_BLK_DEV_IDE_AT91) || defined(CONFIG_BLK_DEV_IDE_AT91_MODULE) +#if defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) || \ + defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE) static struct at91_cf_data cf0_data; @@ -451,7 +451,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data) at91_set_A_periph(AT91_PIN_PD9, 0); /* CFCE2 */ at91_set_A_periph(AT91_PIN_PD14, 0); /* CFNRW */ - pdev->name = (data->flags & AT91_CF_TRUE_IDE) ? "at91_ide" : "at91_cf"; + pdev->name = (data->flags & AT91_CF_TRUE_IDE) ? "pata_at91" : "at91_cf"; platform_device_register(pdev); } #else diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c index d89ead740a99..a94758b42737 100644 --- a/arch/arm/mach-at91/at91sam926x_time.c +++ b/arch/arm/mach-at91/at91sam926x_time.c @@ -14,6 +14,9 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/clockchips.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/mach/time.h> @@ -133,7 +136,8 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) static struct irqaction at91sam926x_pit_irq = { .name = "at91_tick", .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = at91sam926x_pit_interrupt + .handler = at91sam926x_pit_interrupt, + .irq = AT91_ID_SYS, }; static void at91sam926x_pit_reset(void) @@ -149,6 +153,51 @@ static void at91sam926x_pit_reset(void) pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); } +#ifdef CONFIG_OF +static struct of_device_id pit_timer_ids[] = { + { .compatible = "atmel,at91sam9260-pit" }, + { /* sentinel */ } +}; + +static int __init of_at91sam926x_pit_init(void) +{ + struct device_node *np; + int ret; + + np = of_find_matching_node(NULL, pit_timer_ids); + if (!np) + goto err; + + pit_base_addr = of_iomap(np, 0); + if (!pit_base_addr) + goto node_err; + + /* Get the interrupts property */ + ret = irq_of_parse_and_map(np, 0); + if (!ret) { + pr_crit("AT91: PIT: Unable to get IRQ from DT\n"); + goto ioremap_err; + } + at91sam926x_pit_irq.irq = ret; + + of_node_put(np); + + return 0; + +ioremap_err: + iounmap(pit_base_addr); +node_err: + of_node_put(np); +err: + return -EINVAL; +} +#else +static int __init of_at91sam926x_pit_init(void) +{ + return -EINVAL; +} +#endif + /* * Set up both clocksource and clockevent support. */ @@ -156,6 +205,10 @@ static void __init at91sam926x_pit_init(void) { unsigned long pit_rate; unsigned bits; + int ret; + + /* For device tree enabled device: initialize here */ + of_at91sam926x_pit_init(); /* * Use our actual MCK to figure out how many MCK/16 ticks per @@ -177,7 +230,9 @@ static void __init at91sam926x_pit_init(void) clocksource_register_hz(&pit_clk, pit_rate); /* Set up irq handler */ - setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq); + ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq); + if (ret) + pr_crit("AT91: PIT: Unable to setup IRQ\n"); /* Set up and register clockevents */ pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift); @@ -193,6 +248,15 @@ static void at91sam926x_pit_suspend(void) void __init at91sam926x_ioremap_pit(u32 addr) { +#if defined(CONFIG_OF) + struct device_node *np = + of_find_matching_node(NULL, pit_timer_ids); + + if (np) { + of_node_put(np); + return; + } +#endif pit_base_addr = ioremap(addr, 16); if (!pit_base_addr) diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index a41622ea61b8..d222f8333dab 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -16,6 +16,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/system_misc.h> #include <mach/at91sam9g45.h> #include <mach/at91_pmc.h> #include <mach/cpu.h> @@ -229,6 +230,11 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk), CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk), CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk), + /* more tc lookup table for DT entries */ + CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk), + CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk), + CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk), + CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 410829532aab..698479f1e197 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -437,7 +437,6 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) /* DMA slave channel configuration */ atslave->dma_dev = &at_hdmac_device.dev; - atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT; atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW; atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16; @@ -1052,7 +1051,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {} static struct resource tcb0_resources[] = { [0] = { .start = AT91SAM9G45_BASE_TCB0, - .end = AT91SAM9G45_BASE_TCB0 + SZ_16K - 1, + .end = AT91SAM9G45_BASE_TCB0 + SZ_256 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -1073,7 +1072,7 @@ static struct platform_device at91sam9g45_tcb0_device = { static struct resource tcb1_resources[] = { [0] = { .start = AT91SAM9G45_BASE_TCB1, - .end = AT91SAM9G45_BASE_TCB1 + SZ_16K - 1, + .end = AT91SAM9G45_BASE_TCB1 + SZ_256 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -1090,8 +1089,25 @@ static struct platform_device at91sam9g45_tcb1_device = { .num_resources = ARRAY_SIZE(tcb1_resources), }; +#if defined(CONFIG_OF) +static struct of_device_id tcb_ids[] = { + { .compatible = "atmel,at91rm9200-tcb" }, + { /*sentinel*/ } +}; +#endif + static void __init at91_add_device_tc(void) { +#if defined(CONFIG_OF) + struct device_node *np; + + np = of_find_matching_node(NULL, tcb_ids); + if (np) { + of_node_put(np); + return; + } +#endif + platform_device_register(&at91sam9g45_tcb0_device); platform_device_register(&at91sam9g45_tcb1_device); } diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 63d9372eb18e..d9f2774f385e 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -15,6 +15,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/system_misc.h> #include <mach/cpu.h> #include <mach/at91_dbgu.h> #include <mach/at91sam9rl.h> diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index d17d4262665b..b6831eeb7b76 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -131,7 +131,7 @@ static struct clk dma1_clk = { .type = CLK_TYPE_PERIPHERAL, }; static struct clk uhphs_clk = { - .name = "uhphs_clk", + .name = "uhphs", .pmc_mask = 1 << AT91SAM9X5_ID_UHPHS, .type = CLK_TYPE_PERIPHERAL, }; @@ -230,6 +230,9 @@ static struct clk_lookup periph_clocks_lookups[] = { /* additional fake clock for macb_hclk */ CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk), CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk), + CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk), + CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk), + CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk), }; /* @@ -299,16 +302,8 @@ static void __init at91sam9x5_map_io(void) at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE); } -static void __init at91sam9x5_ioremap_registers(void) -{ - if (of_at91sam926x_pit_init() < 0) - panic("Impossible to find PIT\n"); - at91_ioremap_ramc(0, AT91SAM9X5_BASE_DDRSDRC0, 512); -} - void __init at91sam9x5_initialize(void) { - arm_pm_restart = at91sam9g45_restart; at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0); /* Register GPIO subsystem (using DT) */ @@ -316,11 +311,6 @@ void __init at91sam9x5_initialize(void) } /* -------------------------------------------------------------------- - * AT91SAM9x5 devices (temporary before modification of code) - * -------------------------------------------------------------------- */ -void __init at91_add_device_nand(struct atmel_nand_data *data) {} - -/* -------------------------------------------------------------------- * Interrupt initialization * -------------------------------------------------------------------- */ /* @@ -364,7 +354,6 @@ static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = { struct at91_init_soc __initdata at91sam9x5_soc = { .map_io = at91sam9x5_map_io, .default_irq_priority = at91sam9x5_default_irq_priority, - .ioremap_registers = at91sam9x5_ioremap_registers, .register_clocks = at91sam9x5_register_clocks, .init = at91sam9x5_initialize, }; diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c index 3bb40694b02d..161efbaa1029 100644 --- a/arch/arm/mach-at91/board-afeb-9260v1.c +++ b/arch/arm/mach-at91/board-afeb-9260v1.c @@ -138,6 +138,7 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = { .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, .bus_width_16 = 0, + .ecc_mode = NAND_ECC_SOFT, .parts = afeb9260_nand_partition, .num_parts = ARRAY_SIZE(afeb9260_nand_partition), .det_pin = -EINVAL, diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c index 8510e9e54988..c6d44ee0c77e 100644 --- a/arch/arm/mach-at91/board-cam60.c +++ b/arch/arm/mach-at91/board-cam60.c @@ -140,6 +140,7 @@ static struct atmel_nand_data __initdata cam60_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PA9, .enable_pin = AT91_PIN_PA7, + .ecc_mode = NAND_ECC_SOFT, .parts = cam60_nand_partition, .num_parts = ARRAY_SIZE(cam60_nand_partition), }; diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c index 989e1c5a9ca0..5f3680e7c883 100644 --- a/arch/arm/mach-at91/board-cpu9krea.c +++ b/arch/arm/mach-at91/board-cpu9krea.c @@ -117,6 +117,7 @@ static struct atmel_nand_data __initdata cpu9krea_nand_data = { .enable_pin = AT91_PIN_PC14, .bus_width_16 = 0, .det_pin = -EINVAL, + .ecc_mode = NAND_ECC_SOFT, }; #ifdef CONFIG_MACH_CPU9260 diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c index 08c8ad8609b7..c18d4d307801 100644 --- a/arch/arm/mach-at91/board-dt.c +++ b/arch/arm/mach-at91/board-dt.c @@ -15,14 +15,11 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/gpio.h> -#include <linux/irqdomain.h> +#include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_platform.h> -#include <mach/hardware.h> #include <mach/board.h> -#include <mach/system_rev.h> -#include <mach/at91sam9_smc.h> #include <asm/setup.h> #include <asm/irq.h> @@ -30,75 +27,25 @@ #include <asm/mach/map.h> #include <asm/mach/irq.h> -#include "sam9_smc.h" #include "generic.h" -static void __init ek_init_early(void) -{ - /* Initialize processor: 12.000 MHz crystal */ - at91_initialize(12000000); -} - -/* det_pin is not connected */ -static struct atmel_nand_data __initdata ek_nand_data = { - .ale = 21, - .cle = 22, - .det_pin = -EINVAL, - .rdy_pin = AT91_PIN_PC8, - .enable_pin = AT91_PIN_PC14, -}; +static const struct of_device_id irq_of_match[] __initconst = { -static struct sam9_smc_config __initdata ek_nand_smc_config = { - .ncs_read_setup = 0, - .nrd_setup = 2, - .ncs_write_setup = 0, - .nwe_setup = 2, - - .ncs_read_pulse = 4, - .nrd_pulse = 4, - .ncs_write_pulse = 4, - .nwe_pulse = 4, - - .read_cycle = 7, - .write_cycle = 7, - - .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, - .tdf_cycles = 3, -}; - -static void __init ek_add_device_nand(void) -{ - ek_nand_data.bus_width_16 = board_have_nand_16bit(); - /* setup bus-width (8 or 16) */ - if (ek_nand_data.bus_width_16) - ek_nand_smc_config.mode |= AT91_SMC_DBW_16; - else - ek_nand_smc_config.mode |= AT91_SMC_DBW_8; - - /* configure chip-select 3 (NAND) */ - sam9_smc_configure(0, 3, &ek_nand_smc_config); - - at91_add_device_nand(&ek_nand_data); -} - -static const struct of_device_id aic_of_match[] __initconst = { - { .compatible = "atmel,at91rm9200-aic", }, - {}, + { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init }, + { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup }, + { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup }, + { /*sentinel*/ } }; static void __init at91_dt_init_irq(void) { - irq_domain_generate_simple(aic_of_match, 0xfffff000, 0); - at91_init_irq_default(); + of_irq_init(irq_of_match); } static void __init at91_dt_device_init(void) { of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - - /* NAND */ - ek_add_device_nand(); } static const char *at91_dt_board_compat[] __initdata = { @@ -112,7 +59,7 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)") /* Maintainer: Atmel */ .timer = &at91sam926x_timer, .map_io = at91_map_io, - .init_early = ek_init_early, + .init_early = at91_dt_initialize, .init_irq = at91_dt_init_irq, .init_machine = at91_dt_device_init, .dt_compat = at91_dt_board_compat, diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index bb9914582013..59b92aab9bcf 100644 --- a/arch/arm/mach-at91/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -108,6 +108,7 @@ static struct atmel_nand_data __initdata kb9202_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PC29, .enable_pin = AT91_PIN_PC28, + .ecc_mode = NAND_ECC_SOFT, .parts = kb9202_nand_partition, .num_parts = ARRAY_SIZE(kb9202_nand_partition), }; diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c index 3f8617c0e04e..57d5f6a4726a 100644 --- a/arch/arm/mach-at91/board-neocore926.c +++ b/arch/arm/mach-at91/board-neocore926.c @@ -190,6 +190,7 @@ static struct atmel_nand_data __initdata neocore926_nand_data = { .rdy_pin = AT91_PIN_PB19, .rdy_pin_active_low = 1, .enable_pin = AT91_PIN_PD15, + .ecc_mode = NAND_ECC_SOFT, .parts = neocore926_nand_partition, .num_parts = ARRAY_SIZE(neocore926_nand_partition), .det_pin = -EINVAL, diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c index e029d220cb84..b6ed5ed7081a 100644 --- a/arch/arm/mach-at91/board-qil-a9260.c +++ b/arch/arm/mach-at91/board-qil-a9260.c @@ -138,6 +138,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c index 9083df04e7ed..01332aa538b2 100644 --- a/arch/arm/mach-at91/board-rm9200dk.c +++ b/arch/arm/mach-at91/board-rm9200dk.c @@ -150,6 +150,8 @@ static struct atmel_nand_data __initdata dk_nand_data = { .det_pin = AT91_PIN_PB1, .rdy_pin = AT91_PIN_PC2, .enable_pin = -EINVAL, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = dk_nand_partition, .num_parts = ARRAY_SIZE(dk_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c index 84bce587735f..e8b116b6cba6 100644 --- a/arch/arm/mach-at91/board-sam9-l9260.c +++ b/arch/arm/mach-at91/board-sam9-l9260.c @@ -139,6 +139,7 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, + .ecc_mode = NAND_ECC_SOFT, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index be8233bcabdc..d5aec55b0eb4 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -181,6 +181,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 40895072a1a7..c3f994462864 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -187,6 +187,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PC15, .enable_pin = AT91_PIN_PC14, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index 29f66052fe63..66f0ddf4b2ae 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -187,6 +187,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PA22, .enable_pin = AT91_PIN_PD15, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 843d6286c6f4..8923ec9f5831 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -166,6 +166,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, .det_pin = -EINVAL, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index 57497e2b8878..e1bea73e6b30 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c @@ -148,6 +148,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .rdy_pin = AT91_PIN_PC8, .enable_pin = AT91_PIN_PC14, .det_pin = -EINVAL, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index c1366d0032bf..b109ce2ba864 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -94,6 +94,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PD17, .enable_pin = AT91_PIN_PB6, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c index 4770db08e5a6..ebc9d01ce742 100644 --- a/arch/arm/mach-at91/board-snapper9260.c +++ b/arch/arm/mach-at91/board-snapper9260.c @@ -110,6 +110,7 @@ static struct atmel_nand_data __initdata snapper9260_nand_data = { .bus_width_16 = 0, .enable_pin = -EINVAL, .det_pin = -EINVAL, + .ecc_mode = NAND_ECC_SOFT, }; static struct sam9_smc_config __initdata snapper9260_nand_smc_config = { @@ -145,11 +146,11 @@ static struct i2c_board_info __initdata snapper9260_i2c_devices[] = { /* Audio codec */ I2C_BOARD_INFO("tlv320aic23", 0x1a), }, - { +}; + +static struct i2c_board_info __initdata snapper9260_i2c_isl1208 = { /* RTC */ I2C_BOARD_INFO("isl1208", 0x6f), - .irq = gpio_to_irq(AT91_PIN_PA31), - }, }; static void __init snapper9260_add_device_nand(void) @@ -163,6 +164,10 @@ static void __init snapper9260_board_init(void) { at91_add_device_i2c(snapper9260_i2c_devices, ARRAY_SIZE(snapper9260_i2c_devices)); + + snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31); + i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1); + at91_add_device_serial(); at91_add_device_usbh(&snapper9260_usbh_data); at91_add_device_udc(&snapper9260_udc_data); diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c index 72eb3b4d9ab6..7640049410a0 100644 --- a/arch/arm/mach-at91/board-stamp9g20.c +++ b/arch/arm/mach-at91/board-stamp9g20.c @@ -86,6 +86,7 @@ static struct atmel_nand_data __initdata nand_data = { .enable_pin = AT91_PIN_PC14, .bus_width_16 = 0, .det_pin = -EINVAL, + .ecc_mode = NAND_ECC_SOFT, }; static struct sam9_smc_config __initdata nand_smc_config = { diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c index 26c36fc2d1e5..b7483a3d0980 100644 --- a/arch/arm/mach-at91/board-usb-a926x.c +++ b/arch/arm/mach-at91/board-usb-a926x.c @@ -198,6 +198,8 @@ static struct atmel_nand_data __initdata ek_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PA22, .enable_pin = AT91_PIN_PD15, + .ecc_mode = NAND_ECC_SOFT, + .on_flash_bbt = 1, .parts = ek_nand_partition, .num_parts = ARRAY_SIZE(ek_nand_partition), }; diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c index 52f460768f71..38dd279d30b2 100644 --- a/arch/arm/mach-at91/board-yl-9200.c +++ b/arch/arm/mach-at91/board-yl-9200.c @@ -182,6 +182,7 @@ static struct atmel_nand_data __initdata yl9200_nand_data = { .det_pin = -EINVAL, .rdy_pin = AT91_PIN_PC14, /* R/!B (Sheet10) */ .enable_pin = AT91_PIN_PC15, /* !CE (Sheet10) */ + .ecc_mode = NAND_ECC_SOFT, .parts = yl9200_nand_partition, .num_parts = ARRAY_SIZE(yl9200_nand_partition), }; diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index be51ca7f694d..a0f4d7424cdc 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/of_address.h> #include <mach/hardware.h> #include <mach/at91_pmc.h> @@ -671,16 +672,12 @@ static void __init at91_upll_usbfs_clock_init(unsigned long main_clock) uhpck.rate_hz /= 1 + ((at91_pmc_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); } -int __init at91_clock_init(unsigned long main_clock) +static int __init at91_pmc_init(unsigned long main_clock) { unsigned tmp, freq, mckr; int i; int pll_overclock = false; - at91_pmc_base = ioremap(AT91_PMC, 256); - if (!at91_pmc_base) - panic("Impossible to ioremap AT91_PMC 0x%x\n", AT91_PMC); - /* * When the bootloader initialized the main oscillator correctly, * there's no problem using the cycle counter. But if it didn't, @@ -802,6 +799,55 @@ int __init at91_clock_init(unsigned long main_clock) return 0; } +#if defined(CONFIG_OF) +static struct of_device_id pmc_ids[] = { + { .compatible = "atmel,at91rm9200-pmc" }, + { /*sentinel*/ } +}; + +static struct of_device_id osc_ids[] = { + { .compatible = "atmel,osc" }, + { /*sentinel*/ } +}; + +int __init at91_dt_clock_init(void) +{ + struct device_node *np; + u32 main_clock = 0; + + np = of_find_matching_node(NULL, pmc_ids); + if (!np) + panic("unable to find compatible pmc node in dtb\n"); + + at91_pmc_base = of_iomap(np, 0); + if (!at91_pmc_base) + panic("unable to map pmc cpu registers\n"); + + of_node_put(np); + + /* retrieve the freqency of fixed clocks from device tree */ + np = of_find_matching_node(NULL, osc_ids); + if (np) { + u32 rate; + if (!of_property_read_u32(np, "clock-frequency", &rate)) + main_clock = rate; + } + + of_node_put(np); + + return at91_pmc_init(main_clock); +} +#endif + +int __init at91_clock_init(unsigned long main_clock) +{ + at91_pmc_base = ioremap(AT91_PMC, 256); + if (!at91_pmc_base) + panic("Impossible to ioremap AT91_PMC 0x%x\n", AT91_PMC); + + return at91_pmc_init(main_clock); +} + /* * Several unused clocks may be active. Turn them off. */ diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 4cad85e57470..dd9b346c451d 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -9,6 +9,7 @@ */ #include <linux/clkdev.h> +#include <linux/of.h> /* Map io */ extern void __init at91_map_io(void); @@ -19,12 +20,16 @@ extern void __init at91_init_sram(int bank, unsigned long base, extern void __init at91rm9200_set_type(int type); extern void __init at91_initialize(unsigned long main_clock); extern void __init at91x40_initialize(unsigned long main_clock); +extern void __init at91_dt_initialize(void); /* Interrupts */ extern void __init at91_init_irq_default(void); extern void __init at91_init_interrupts(unsigned int priority[]); extern void __init at91x40_init_interrupts(unsigned int priority[]); extern void __init at91_aic_init(unsigned int priority[]); +extern int __init at91_aic_of_init(struct device_node *node, + struct device_node *parent); + /* Timer */ struct sys_timer; @@ -48,6 +53,7 @@ extern void __init at91sam9rl_set_console_clock(int id); extern void __init at91sam9g45_set_console_clock(int id); #ifdef CONFIG_AT91_PMC_UNIT extern int __init at91_clock_init(unsigned long main_clock); +extern int __init at91_dt_clock_init(void); #else static int inline at91_clock_init(unsigned long main_clock) { return 0; } #endif @@ -84,5 +90,7 @@ struct at91_gpio_bank { }; extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks); extern void __init at91_gpio_irq_setup(void); +extern int __init at91_gpio_of_irq_setup(struct device_node *node, + struct device_node *parent); extern int at91_extern_irq; diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 74d6783eeabb..325837a264c9 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -11,6 +11,7 @@ #include <linux/clk.h> #include <linux/errno.h> +#include <linux/device.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -20,6 +21,10 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/irqdomain.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> #include <mach/hardware.h> #include <mach/at91_pio.h> @@ -29,9 +34,12 @@ struct at91_gpio_chip { struct gpio_chip chip; struct at91_gpio_chip *next; /* Bank sharing same clock */ - int id; /* ID of register bank */ - void __iomem *regbase; /* Base of register bank */ + int pioc_hwirq; /* PIO bank interrupt identifier on AIC */ + int pioc_virq; /* PIO bank Linux virtual interrupt */ + int pioc_idx; /* PIO bank index */ + void __iomem *regbase; /* PIO bank virtual address */ struct clk *clock; /* associated clock */ + struct irq_domain *domain; /* associated irq domain */ }; #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip) @@ -43,8 +51,9 @@ static int at91_gpiolib_direction_output(struct gpio_chip *chip, unsigned offset, int val); static int at91_gpiolib_direction_input(struct gpio_chip *chip, unsigned offset); +static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset); -#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio) \ +#define AT91_GPIO_CHIP(name, nr_gpio) \ { \ .chip = { \ .label = name, \ @@ -53,20 +62,28 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip, .get = at91_gpiolib_get, \ .set = at91_gpiolib_set, \ .dbg_show = at91_gpiolib_dbg_show, \ - .base = base_gpio, \ + .to_irq = at91_gpiolib_to_irq, \ .ngpio = nr_gpio, \ }, \ } static struct at91_gpio_chip gpio_chip[] = { - AT91_GPIO_CHIP("pioA", 0x00, 32), - AT91_GPIO_CHIP("pioB", 0x20, 32), - AT91_GPIO_CHIP("pioC", 0x40, 32), - AT91_GPIO_CHIP("pioD", 0x60, 32), - AT91_GPIO_CHIP("pioE", 0x80, 32), + AT91_GPIO_CHIP("pioA", 32), + AT91_GPIO_CHIP("pioB", 32), + AT91_GPIO_CHIP("pioC", 32), + AT91_GPIO_CHIP("pioD", 32), + AT91_GPIO_CHIP("pioE", 32), }; static int gpio_banks; +static unsigned long at91_gpio_caps; + +/* All PIO controllers support PIO3 features */ +#define AT91_GPIO_CAP_PIO3 (1 << 0) + +#define has_pio3() (at91_gpio_caps & AT91_GPIO_CAP_PIO3) + +/*--------------------------------------------------------------------------*/ static inline void __iomem *pin_to_controller(unsigned pin) { @@ -83,6 +100,25 @@ static inline unsigned pin_to_mask(unsigned pin) } +static char peripheral_function(void __iomem *pio, unsigned mask) +{ + char ret = 'X'; + u8 select; + + if (pio) { + if (has_pio3()) { + select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask); + select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1); + ret = 'A' + select; + } else { + ret = __raw_readl(pio + PIO_ABSR) & mask ? + 'B' : 'A'; + } + } + + return ret; +} + /*--------------------------------------------------------------------------*/ /* Not all hardware capabilities are exposed through these calls; they @@ -130,7 +166,14 @@ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup) __raw_writel(mask, pio + PIO_IDR); __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); - __raw_writel(mask, pio + PIO_ASR); + if (has_pio3()) { + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, + pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); + } else { + __raw_writel(mask, pio + PIO_ASR); + } __raw_writel(mask, pio + PIO_PDR); return 0; } @@ -150,7 +193,14 @@ int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup) __raw_writel(mask, pio + PIO_IDR); __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); - __raw_writel(mask, pio + PIO_BSR); + if (has_pio3()) { + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, + pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); + } else { + __raw_writel(mask, pio + PIO_BSR); + } __raw_writel(mask, pio + PIO_PDR); return 0; } @@ -158,8 +208,50 @@ EXPORT_SYMBOL(at91_set_B_periph); /* - * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and - * configure it for an input. + * mux the pin to the "C" internal peripheral role. + */ +int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !has_pio3()) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); + __raw_writel(mask, pio + PIO_PDR); + return 0; +} +EXPORT_SYMBOL(at91_set_C_periph); + + +/* + * mux the pin to the "D" internal peripheral role. + */ +int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !has_pio3()) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); + __raw_writel(mask, pio + PIO_PDR); + return 0; +} +EXPORT_SYMBOL(at91_set_D_periph); + + +/* + * mux the pin to the gpio controller (instead of "A", "B", "C" + * or "D" peripheral), and configure it for an input. */ int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup) { @@ -179,8 +271,8 @@ EXPORT_SYMBOL(at91_set_gpio_input); /* - * mux the pin to the gpio controller (instead of "A" or "B" peripheral), - * and configure it for an output. + * mux the pin to the gpio controller (instead of "A", "B", "C" + * or "D" peripheral), and configure it for an output. */ int __init_or_module at91_set_gpio_output(unsigned pin, int value) { @@ -210,12 +302,37 @@ int __init_or_module at91_set_deglitch(unsigned pin, int is_on) if (!pio) return -EINVAL; + + if (has_pio3() && is_on) + __raw_writel(mask, pio + PIO_IFSCDR); __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); return 0; } EXPORT_SYMBOL(at91_set_deglitch); /* + * enable/disable the debounce filter; + */ +int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !has_pio3()) + return -EINVAL; + + if (is_on) { + __raw_writel(mask, pio + PIO_IFSCER); + __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); + __raw_writel(mask, pio + PIO_IFER); + } else { + __raw_writel(mask, pio + PIO_IFDR); + } + return 0; +} +EXPORT_SYMBOL(at91_set_debounce); + +/* * enable/disable the multi-driver; This is only valid for output and * allows the output pin to run as an open collector output. */ @@ -233,6 +350,41 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on) EXPORT_SYMBOL(at91_set_multi_drive); /* + * enable/disable the pull-down. + * If pull-up already enabled while calling the function, we disable it. + */ +int __init_or_module at91_set_pulldown(unsigned pin, int is_on) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !has_pio3()) + return -EINVAL; + + /* Disable pull-up anyway */ + __raw_writel(mask, pio + PIO_PUDR); + __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); + return 0; +} +EXPORT_SYMBOL(at91_set_pulldown); + +/* + * disable Schmitt trigger + */ +int __init_or_module at91_disable_schmitt_trig(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !has_pio3()) + return -EINVAL; + + __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); + return 0; +} +EXPORT_SYMBOL(at91_disable_schmitt_trig); + +/* * assuming the pin is muxed as a gpio output, set its value. */ int at91_set_gpio_value(unsigned pin, int value) @@ -273,9 +425,9 @@ static u32 backups[MAX_GPIO_BANKS]; static int gpio_irq_set_wake(struct irq_data *d, unsigned state) { - unsigned pin = irq_to_gpio(d->irq); - unsigned mask = pin_to_mask(pin); - unsigned bank = pin / 32; + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + unsigned mask = 1 << d->hwirq; + unsigned bank = at91_gpio->pioc_idx; if (unlikely(bank >= MAX_GPIO_BANKS)) return -EINVAL; @@ -285,7 +437,7 @@ static int gpio_irq_set_wake(struct irq_data *d, unsigned state) else wakeups[bank] &= ~mask; - irq_set_irq_wake(gpio_chip[bank].id, state); + irq_set_irq_wake(at91_gpio->pioc_virq, state); return 0; } @@ -301,9 +453,10 @@ void at91_gpio_suspend(void) __raw_writel(backups[i], pio + PIO_IDR); __raw_writel(wakeups[i], pio + PIO_IER); - if (!wakeups[i]) + if (!wakeups[i]) { + clk_unprepare(gpio_chip[i].clock); clk_disable(gpio_chip[i].clock); - else { + } else { #ifdef CONFIG_PM_DEBUG printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]); #endif @@ -318,8 +471,10 @@ void at91_gpio_resume(void) for (i = 0; i < gpio_banks; i++) { void __iomem *pio = gpio_chip[i].regbase; - if (!wakeups[i]) - clk_enable(gpio_chip[i].clock); + if (!wakeups[i]) { + if (clk_prepare(gpio_chip[i].clock) == 0) + clk_enable(gpio_chip[i].clock); + } __raw_writel(wakeups[i], pio + PIO_IDR); __raw_writel(backups[i], pio + PIO_IER); @@ -335,7 +490,10 @@ void at91_gpio_resume(void) * To use any AT91_PIN_* as an externally triggered IRQ, first call * at91_set_gpio_input() then maybe enable its glitch filter. * Then just request_irq() with the pin ID; it works like any ARM IRQ - * handler, though it always triggers on rising and falling edges. + * handler. + * First implementation always triggers on rising and falling edges + * whereas the newer PIO3 can be additionally configured to trigger on + * level, edge with any polarity. * * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after * configuring them with at91_set_a_periph() or at91_set_b_periph(). @@ -344,9 +502,9 @@ void at91_gpio_resume(void) static void gpio_irq_mask(struct irq_data *d) { - unsigned pin = irq_to_gpio(d->irq); - void __iomem *pio = pin_to_controller(pin); - unsigned mask = pin_to_mask(pin); + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; if (pio) __raw_writel(mask, pio + PIO_IDR); @@ -354,9 +512,9 @@ static void gpio_irq_mask(struct irq_data *d) static void gpio_irq_unmask(struct irq_data *d) { - unsigned pin = irq_to_gpio(d->irq); - void __iomem *pio = pin_to_controller(pin); - unsigned mask = pin_to_mask(pin); + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; if (pio) __raw_writel(mask, pio + PIO_IER); @@ -373,23 +531,66 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) } } +/* Alternate irq type for PIO3 support */ +static int alt_gpio_irq_type(struct irq_data *d, unsigned type) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + __raw_writel(mask, pio + PIO_ESR); + __raw_writel(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_FALLING: + __raw_writel(mask, pio + PIO_ESR); + __raw_writel(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_LOW: + __raw_writel(mask, pio + PIO_LSR); + __raw_writel(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_HIGH: + __raw_writel(mask, pio + PIO_LSR); + __raw_writel(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_BOTH: + /* + * disable additional interrupt modes: + * fall back to default behavior + */ + __raw_writel(mask, pio + PIO_AIMDR); + return 0; + case IRQ_TYPE_NONE: + default: + pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq)); + return -EINVAL; + } + + /* enable additional interrupt modes */ + __raw_writel(mask, pio + PIO_AIMER); + + return 0; +} + static struct irq_chip gpio_irqchip = { .name = "GPIO", .irq_disable = gpio_irq_mask, .irq_mask = gpio_irq_mask, .irq_unmask = gpio_irq_unmask, - .irq_set_type = gpio_irq_type, + /* .irq_set_type is set dynamically */ .irq_set_wake = gpio_irq_set_wake, }; static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - unsigned irq_pin; struct irq_data *idata = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(idata); struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata); void __iomem *pio = at91_gpio->regbase; - u32 isr; + unsigned long isr; + int n; /* temporarily mask (level sensitive) parent IRQ */ chip->irq_ack(idata); @@ -407,13 +608,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) continue; } - irq_pin = gpio_to_irq(at91_gpio->chip.base); - - while (isr) { - if (isr & 1) - generic_handle_irq(irq_pin); - irq_pin++; - isr >>= 1; + n = find_first_bit(&isr, BITS_PER_LONG); + while (n < BITS_PER_LONG) { + generic_handle_irq(irq_find_mapping(at91_gpio->domain, n)); + n = find_next_bit(&isr, BITS_PER_LONG, n + 1); } } chip->irq_unmask(idata); @@ -424,6 +622,33 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) #ifdef CONFIG_DEBUG_FS +static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask) +{ + char *trigger = NULL; + char *polarity = NULL; + + if (__raw_readl(pio + PIO_IMR) & mask) { + if (!has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) { + trigger = "edge"; + polarity = "both"; + } else { + if (__raw_readl(pio + PIO_ELSR) & mask) { + trigger = "level"; + polarity = __raw_readl(pio + PIO_FRLHSR) & mask ? + "high" : "low"; + } else { + trigger = "edge"; + polarity = __raw_readl(pio + PIO_FRLHSR) & mask ? + "rising" : "falling"; + } + } + seq_printf(s, "IRQ:%s-%s\t", trigger, polarity); + } else { + seq_printf(s, "GPIO:%s\t\t", + __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0"); + } +} + static int at91_gpio_show(struct seq_file *s, void *unused) { int bank, j; @@ -431,7 +656,7 @@ static int at91_gpio_show(struct seq_file *s, void *unused) /* print heading */ seq_printf(s, "Pin\t"); for (bank = 0; bank < gpio_banks; bank++) { - seq_printf(s, "PIO%c\t", 'A' + bank); + seq_printf(s, "PIO%c\t\t", 'A' + bank); }; seq_printf(s, "\n\n"); @@ -445,11 +670,10 @@ static int at91_gpio_show(struct seq_file *s, void *unused) unsigned mask = pin_to_mask(pin); if (__raw_readl(pio + PIO_PSR) & mask) - seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0"); + gpio_printf(s, pio, mask); else - seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A"); - - seq_printf(s, "\t"); + seq_printf(s, "%c\t\t", + peripheral_function(pio, mask)); } seq_printf(s, "\n"); @@ -488,46 +712,152 @@ postcore_initcall(at91_gpio_debugfs_init); */ static struct lock_class_key gpio_lock_class; +#if defined(CONFIG_OF) +static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct at91_gpio_chip *at91_gpio = h->host_data; + + irq_set_lockdep_class(virq, &gpio_lock_class); + + /* + * Can use the "simple" and not "edge" handler since it's + * shorter, and the AIC handles interrupts sanely. + */ + irq_set_chip_and_handler(virq, &gpio_irqchip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + irq_set_chip_data(virq, at91_gpio); + + return 0; +} + +static struct irq_domain_ops at91_gpio_ops = { + .map = at91_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +int __init at91_gpio_of_irq_setup(struct device_node *node, + struct device_node *parent) +{ + struct at91_gpio_chip *prev = NULL; + int alias_idx = of_alias_get_id(node, "gpio"); + struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx]; + + /* Setup proper .irq_set_type function */ + if (has_pio3()) + gpio_irqchip.irq_set_type = alt_gpio_irq_type; + else + gpio_irqchip.irq_set_type = gpio_irq_type; + + /* Disable irqs of this PIO controller */ + __raw_writel(~0, at91_gpio->regbase + PIO_IDR); + + /* Setup irq domain */ + at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio, + &at91_gpio_ops, at91_gpio); + if (!at91_gpio->domain) + panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", + at91_gpio->pioc_idx); + + /* Setup chained handler */ + if (at91_gpio->pioc_idx) + prev = &gpio_chip[at91_gpio->pioc_idx - 1]; + + /* The toplevel handler handles one bank of GPIOs, except + * on some SoC it can handles up to three... + * We only set up the handler for the first of the list. + */ + if (prev && prev->next == at91_gpio) + return 0; + + at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent), + at91_gpio->pioc_hwirq); + irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio); + irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler); + + return 0; +} +#else +int __init at91_gpio_of_irq_setup(struct device_node *node, + struct device_node *parent) +{ + return -EINVAL; +} +#endif + +/* + * irqdomain initialization: pile up irqdomains on top of AIC range + */ +static void __init at91_gpio_irqdomain(struct at91_gpio_chip *at91_gpio) +{ + int irq_base; + + irq_base = irq_alloc_descs(-1, 0, at91_gpio->chip.ngpio, 0); + if (irq_base < 0) + panic("at91_gpio.%d: error %d: couldn't allocate IRQ numbers.\n", + at91_gpio->pioc_idx, irq_base); + at91_gpio->domain = irq_domain_add_legacy(NULL, at91_gpio->chip.ngpio, + irq_base, 0, + &irq_domain_simple_ops, NULL); + if (!at91_gpio->domain) + panic("at91_gpio.%d: couldn't allocate irq domain.\n", + at91_gpio->pioc_idx); +} + /* * Called from the processor-specific init to enable GPIO interrupt support. */ void __init at91_gpio_irq_setup(void) { - unsigned pioc, irq = gpio_to_irq(0); + unsigned pioc; + int gpio_irqnbr = 0; struct at91_gpio_chip *this, *prev; + /* Setup proper .irq_set_type function */ + if (has_pio3()) + gpio_irqchip.irq_set_type = alt_gpio_irq_type; + else + gpio_irqchip.irq_set_type = gpio_irq_type; + for (pioc = 0, this = gpio_chip, prev = NULL; pioc++ < gpio_banks; prev = this, this++) { - unsigned id = this->id; - unsigned i; + int offset; __raw_writel(~0, this->regbase + PIO_IDR); - for (i = 0, irq = gpio_to_irq(this->chip.base); i < 32; - i++, irq++) { - irq_set_lockdep_class(irq, &gpio_lock_class); + /* setup irq domain for this GPIO controller */ + at91_gpio_irqdomain(this); + + for (offset = 0; offset < this->chip.ngpio; offset++) { + unsigned int virq = irq_find_mapping(this->domain, offset); + irq_set_lockdep_class(virq, &gpio_lock_class); /* * Can use the "simple" and not "edge" handler since it's * shorter, and the AIC handles interrupts sanely. */ - irq_set_chip_and_handler(irq, &gpio_irqchip, + irq_set_chip_and_handler(virq, &gpio_irqchip, handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(virq, IRQF_VALID); + irq_set_chip_data(virq, this); + + gpio_irqnbr++; } /* The toplevel handler handles one bank of GPIOs, except - * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in - * the list, so we only set up that handler. + * on some SoC it can handles up to three... + * We only set up the handler for the first of the list. */ if (prev && prev->next == this) continue; - irq_set_chip_data(id, this); - irq_set_chained_handler(id, gpio_irq_handler); + this->pioc_virq = irq_create_mapping(NULL, this->pioc_hwirq); + irq_set_chip_data(this->pioc_virq, this); + irq_set_chained_handler(this->pioc_virq, gpio_irq_handler); } - pr_info("AT91: %d gpio irqs in %d banks\n", irq - gpio_to_irq(0), gpio_banks); + pr_info("AT91: %d gpio irqs in %d banks\n", gpio_irqnbr, gpio_banks); } /* gpiolib support */ @@ -593,48 +923,175 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) at91_get_gpio_value(pin) ? "set" : "clear"); else - seq_printf(s, "[periph %s]\n", - __raw_readl(pio + PIO_ABSR) & - mask ? "B" : "A"); + seq_printf(s, "[periph %c]\n", + peripheral_function(pio, mask)); } } } +static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + int virq; + + if (offset < chip->ngpio) + virq = irq_create_mapping(at91_gpio->domain, offset); + else + virq = -ENXIO; + + dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", + chip->label, offset + chip->base, virq); + return virq; +} + +static int __init at91_gpio_setup_clk(int idx) +{ + struct at91_gpio_chip *at91_gpio = &gpio_chip[idx]; + + /* retreive PIO controller's clock */ + at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label); + if (IS_ERR(at91_gpio->clock)) { + pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", idx); + goto err; + } + + if (clk_prepare(at91_gpio->clock)) + goto clk_prep_err; + + /* enable PIO controller's clock */ + if (clk_enable(at91_gpio->clock)) { + pr_err("at91_gpio.%d, failed to enable clock, ignoring.\n", idx); + goto clk_err; + } + + return 0; + +clk_err: + clk_unprepare(at91_gpio->clock); +clk_prep_err: + clk_put(at91_gpio->clock); +err: + return -EINVAL; +} + +#ifdef CONFIG_OF_GPIO +static void __init of_at91_gpio_init_one(struct device_node *np) +{ + int alias_idx; + struct at91_gpio_chip *at91_gpio; + + if (!np) + return; + + alias_idx = of_alias_get_id(np, "gpio"); + if (alias_idx >= MAX_GPIO_BANKS) { + pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n", + alias_idx, MAX_GPIO_BANKS); + return; + } + + at91_gpio = &gpio_chip[alias_idx]; + at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio; + + at91_gpio->regbase = of_iomap(np, 0); + if (!at91_gpio->regbase) { + pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", + alias_idx); + return; + } + + /* Get the interrupts property */ + if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) { + pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n", + alias_idx); + goto ioremap_err; + } + + /* Get capabilities from compatibility property */ + if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio")) + at91_gpio_caps |= AT91_GPIO_CAP_PIO3; + + /* Setup clock */ + if (at91_gpio_setup_clk(alias_idx)) + goto ioremap_err; + + at91_gpio->chip.of_node = np; + gpio_banks = max(gpio_banks, alias_idx + 1); + at91_gpio->pioc_idx = alias_idx; + return; + +ioremap_err: + iounmap(at91_gpio->regbase); +} + +static int __init of_at91_gpio_init(void) +{ + struct device_node *np = NULL; + + /* + * This isn't ideal, but it gets things hooked up until this + * driver is converted into a platform_device + */ + for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio") + of_at91_gpio_init_one(np); + + return gpio_banks > 0 ? 0 : -EINVAL; +} +#else +static int __init of_at91_gpio_init(void) +{ + return -EINVAL; +} +#endif + +static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq) +{ + struct at91_gpio_chip *at91_gpio = &gpio_chip[idx]; + + at91_gpio->chip.base = idx * at91_gpio->chip.ngpio; + at91_gpio->pioc_hwirq = pioc_hwirq; + at91_gpio->pioc_idx = idx; + + at91_gpio->regbase = ioremap(regbase, 512); + if (!at91_gpio->regbase) { + pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", idx); + return; + } + + if (at91_gpio_setup_clk(idx)) + goto ioremap_err; + + gpio_banks = max(gpio_banks, idx + 1); + return; + +ioremap_err: + iounmap(at91_gpio->regbase); +} + /* * Called from the processor-specific init to enable GPIO pin support. */ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) { - unsigned i; + unsigned i; struct at91_gpio_chip *at91_gpio, *last = NULL; BUG_ON(nr_banks > MAX_GPIO_BANKS); - gpio_banks = nr_banks; + if (of_at91_gpio_init() < 0) { + /* No GPIO controller found in device tree */ + for (i = 0; i < nr_banks; i++) + at91_gpio_init_one(i, data[i].regbase, data[i].id); + } - for (i = 0; i < nr_banks; i++) { + for (i = 0; i < gpio_banks; i++) { at91_gpio = &gpio_chip[i]; - at91_gpio->id = data[i].id; - at91_gpio->chip.base = i * 32; - - at91_gpio->regbase = ioremap(data[i].regbase, 512); - if (!at91_gpio->regbase) { - pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i); - continue; - } - - at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label); - if (!at91_gpio->clock) { - pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i); - continue; - } - - /* enable PIO controller's clock */ - clk_enable(at91_gpio->clock); - - /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ - if (last && last->id == at91_gpio->id) + /* + * GPIO controller are grouped on some SoC: + * PIOC, PIOD and PIOE can share the same IRQ line + */ + if (last && last->pioc_hwirq == at91_gpio->pioc_hwirq) last->next = at91_gpio; last = at91_gpio; diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h index c6a31bf8a5c6..732b11c37f1a 100644 --- a/arch/arm/mach-at91/include/mach/at91_pio.h +++ b/arch/arm/mach-at91/include/mach/at91_pio.h @@ -40,10 +40,35 @@ #define PIO_PUER 0x64 /* Pull-up Enable Register */ #define PIO_PUSR 0x68 /* Pull-up Status Register */ #define PIO_ASR 0x70 /* Peripheral A Select Register */ +#define PIO_ABCDSR1 0x70 /* Peripheral ABCD Select Register 1 [some sam9 only] */ #define PIO_BSR 0x74 /* Peripheral B Select Register */ +#define PIO_ABCDSR2 0x74 /* Peripheral ABCD Select Register 2 [some sam9 only] */ #define PIO_ABSR 0x78 /* AB Status Register */ +#define PIO_IFSCDR 0x80 /* Input Filter Slow Clock Disable Register */ +#define PIO_IFSCER 0x84 /* Input Filter Slow Clock Enable Register */ +#define PIO_IFSCSR 0x88 /* Input Filter Slow Clock Status Register */ +#define PIO_SCDR 0x8c /* Slow Clock Divider Debouncing Register */ +#define PIO_SCDR_DIV (0x3fff << 0) /* Slow Clock Divider Mask */ +#define PIO_PPDDR 0x90 /* Pad Pull-down Disable Register */ +#define PIO_PPDER 0x94 /* Pad Pull-down Enable Register */ +#define PIO_PPDSR 0x98 /* Pad Pull-down Status Register */ #define PIO_OWER 0xa0 /* Output Write Enable Register */ #define PIO_OWDR 0xa4 /* Output Write Disable Register */ #define PIO_OWSR 0xa8 /* Output Write Status Register */ +#define PIO_AIMER 0xb0 /* Additional Interrupt Modes Enable Register */ +#define PIO_AIMDR 0xb4 /* Additional Interrupt Modes Disable Register */ +#define PIO_AIMMR 0xb8 /* Additional Interrupt Modes Mask Register */ +#define PIO_ESR 0xc0 /* Edge Select Register */ +#define PIO_LSR 0xc4 /* Level Select Register */ +#define PIO_ELSR 0xc8 /* Edge/Level Status Register */ +#define PIO_FELLSR 0xd0 /* Falling Edge/Low Level Select Register */ +#define PIO_REHLSR 0xd4 /* Rising Edge/ High Level Select Register */ +#define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */ +#define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */ + +#define ABCDSR_PERIPH_A 0x0 +#define ABCDSR_PERIPH_B 0x1 +#define ABCDSR_PERIPH_C 0x2 +#define ABCDSR_PERIPH_D 0x3 #endif diff --git a/arch/arm/mach-at91/include/mach/at91_shdwc.h b/arch/arm/mach-at91/include/mach/at91_shdwc.h index 1d4fe822c77a..60478ea8bd46 100644 --- a/arch/arm/mach-at91/include/mach/at91_shdwc.h +++ b/arch/arm/mach-at91/include/mach/at91_shdwc.h @@ -36,9 +36,11 @@ extern void __iomem *at91_shdwc_base; #define AT91_SHDW_WKMODE0_HIGH 1 #define AT91_SHDW_WKMODE0_LOW 2 #define AT91_SHDW_WKMODE0_ANYLEVEL 3 -#define AT91_SHDW_CPTWK0 (0xf << 4) /* Counter On Wake Up 0 */ +#define AT91_SHDW_CPTWK0_MAX 0xf /* Maximum Counter On Wake Up 0 */ +#define AT91_SHDW_CPTWK0 (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */ #define AT91_SHDW_CPTWK0_(x) ((x) << 4) #define AT91_SHDW_RTTWKEN (1 << 16) /* Real Time Timer Wake-up Enable */ +#define AT91_SHDW_RTCWKEN (1 << 17) /* Real Time Clock Wake-up Enable */ #define AT91_SHDW_SR 0x08 /* Shut Down Status Register */ #define AT91_SHDW_WAKEUP0 (1 << 0) /* Wake-up 0 Status */ diff --git a/arch/arm/mach-at91/include/mach/at91sam9_smc.h b/arch/arm/mach-at91/include/mach/at91sam9_smc.h index eb18a70fa647..175e1fdd9fe8 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9_smc.h +++ b/arch/arm/mach-at91/include/mach/at91sam9_smc.h @@ -18,6 +18,35 @@ #include <mach/cpu.h> +#ifndef __ASSEMBLY__ +struct sam9_smc_config { + /* Setup register */ + u8 ncs_read_setup; + u8 nrd_setup; + u8 ncs_write_setup; + u8 nwe_setup; + + /* Pulse register */ + u8 ncs_read_pulse; + u8 nrd_pulse; + u8 ncs_write_pulse; + u8 nwe_pulse; + + /* Cycle register */ + u16 read_cycle; + u16 write_cycle; + + /* Mode register */ + u32 mode; + u8 tdf_cycles:4; +}; + +extern void sam9_smc_configure(int id, int cs, struct sam9_smc_config *config); +extern void sam9_smc_read(int id, int cs, struct sam9_smc_config *config); +extern void sam9_smc_read_mode(int id, int cs, struct sam9_smc_config *config); +extern void sam9_smc_write_mode(int id, int cs, struct sam9_smc_config *config); +#endif + #define AT91_SMC_SETUP 0x00 /* Setup Register for CS n */ #define AT91_SMC_NWESETUP (0x3f << 0) /* NWE Setup Length */ #define AT91_SMC_NWESETUP_(x) ((x) << 0) diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h index a297a77d88e2..88e43d534cdf 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9x5.h +++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h @@ -55,11 +55,6 @@ #define AT91SAM9X5_BASE_USART2 0xf8024000 /* - * System Peripherals - */ -#define AT91SAM9X5_BASE_DDRSDRC0 0xffffe800 - -/* * Base addresses for early serial code (uncompress.h) */ #define AT91_DBGU AT91_BASE_DBGU0 diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h index 187cb58345c0..fff48d1a0f4e 100644 --- a/arch/arm/mach-at91/include/mach/at_hdmac.h +++ b/arch/arm/mach-at91/include/mach/at_hdmac.h @@ -24,18 +24,6 @@ struct at_dma_platform_data { }; /** - * enum at_dma_slave_width - DMA slave register access width. - * @AT_DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses - * @AT_DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses - * @AT_DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses - */ -enum at_dma_slave_width { - AT_DMA_SLAVE_WIDTH_8BIT = 0, - AT_DMA_SLAVE_WIDTH_16BIT, - AT_DMA_SLAVE_WIDTH_32BIT, -}; - -/** * struct at_dma_slave - Controller-specific information about a slave * @dma_dev: required DMA master device * @tx_reg: physical address of data register used for @@ -48,9 +36,6 @@ enum at_dma_slave_width { */ struct at_dma_slave { struct device *dma_dev; - dma_addr_t tx_reg; - dma_addr_t rx_reg; - enum at_dma_slave_width reg_width; u32 cfg; u32 ctrla; }; diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index dc8d6d4f17cf..544a5d5ce416 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -41,6 +41,7 @@ #include <sound/atmel-ac97c.h> #include <linux/serial.h> #include <linux/platform_data/macb.h> +#include <linux/platform_data/atmel.h> /* USB Device */ struct at91_udc_data { @@ -98,20 +99,6 @@ extern void __init at91_add_device_usbh(struct at91_usbh_data *data); extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data); extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data); - /* NAND / SmartMedia */ -struct atmel_nand_data { - int enable_pin; /* chip enable */ - int det_pin; /* card detect */ - int rdy_pin; /* ready/busy */ - u8 rdy_pin_active_low; /* rdy_pin value is inverted */ - u8 ale; /* address line number connected to ALE */ - u8 cle; /* address line number connected to CLE */ - u8 bus_width_16; /* buswidth is 16 bit */ - u8 correction_cap; /* PMECC correction capability */ - u16 sector_size; /* Sector size for PMECC */ - struct mtd_partition *parts; - unsigned int num_parts; -}; extern void __init at91_add_device_nand(struct atmel_nand_data *data); /* I2C*/ diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h index e3fd225121c7..eed465ab0dd7 100644 --- a/arch/arm/mach-at91/include/mach/gpio.h +++ b/arch/arm/mach-at91/include/mach/gpio.h @@ -191,10 +191,15 @@ extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup); extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup); extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup); +extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup); +extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup); extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup); extern int __init_or_module at91_set_gpio_output(unsigned pin, int value); extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on); +extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div); extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on); +extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on); +extern int __init_or_module at91_disable_schmitt_trig(unsigned pin); /* callable at any time */ extern int at91_set_gpio_value(unsigned pin, int value); @@ -204,18 +209,6 @@ extern int at91_get_gpio_value(unsigned pin); extern void at91_gpio_suspend(void); extern void at91_gpio_resume(void); -/*-------------------------------------------------------------------------*/ - -/* wrappers for "new style" GPIO calls. the old AT91-specific ones should - * eventually be removed (along with this errno.h inclusion), and the - * gpio request/free calls should probably be implemented. - */ - -#include <asm/errno.h> - -#define gpio_to_irq(gpio) (gpio + NR_AIC_IRQS) -#define irq_to_gpio(irq) (irq - NR_AIC_IRQS) - #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h index ec164a4124c9..ef79a9aafc08 100644 --- a/arch/arm/mach-at91/include/mach/system_rev.h +++ b/arch/arm/mach-at91/include/mach/system_rev.h @@ -7,6 +7,8 @@ #ifndef __ARCH_SYSTEM_REV_H__ #define __ARCH_SYSTEM_REV_H__ +#include <asm/system_info.h> + /* * board revision encoding * mach specific diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c index be6b639ecd7b..cfcfcbe36269 100644 --- a/arch/arm/mach-at91/irq.c +++ b/arch/arm/mach-at91/irq.c @@ -24,6 +24,12 @@ #include <linux/module.h> #include <linux/mm.h> #include <linux/types.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/irqdomain.h> +#include <linux/err.h> #include <mach/hardware.h> #include <asm/irq.h> @@ -34,22 +40,24 @@ #include <asm/mach/map.h> void __iomem *at91_aic_base; +static struct irq_domain *at91_aic_domain; +static struct device_node *at91_aic_np; static void at91_aic_mask_irq(struct irq_data *d) { /* Disable interrupt on AIC */ - at91_aic_write(AT91_AIC_IDCR, 1 << d->irq); + at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq); } static void at91_aic_unmask_irq(struct irq_data *d) { /* Enable interrupt on AIC */ - at91_aic_write(AT91_AIC_IECR, 1 << d->irq); + at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq); } unsigned int at91_extern_irq; -#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq) +#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq) static int at91_aic_set_type(struct irq_data *d, unsigned type) { @@ -63,13 +71,13 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type) srctype = AT91_AIC_SRCTYPE_RISING; break; case IRQ_TYPE_LEVEL_LOW: - if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */ + if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ srctype = AT91_AIC_SRCTYPE_LOW; else return -EINVAL; break; case IRQ_TYPE_EDGE_FALLING: - if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */ + if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ srctype = AT91_AIC_SRCTYPE_FALLING; else return -EINVAL; @@ -78,8 +86,8 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type) return -EINVAL; } - smr = at91_aic_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE; - at91_aic_write(AT91_AIC_SMR(d->irq), smr | srctype); + smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE; + at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); return 0; } @@ -90,13 +98,13 @@ static u32 backups; static int at91_aic_set_wake(struct irq_data *d, unsigned value) { - if (unlikely(d->irq >= 32)) + if (unlikely(d->hwirq >= NR_AIC_IRQS)) return -EINVAL; if (value) - wakeups |= (1 << d->irq); + wakeups |= (1 << d->hwirq); else - wakeups &= ~(1 << d->irq); + wakeups &= ~(1 << d->hwirq); return 0; } @@ -127,46 +135,112 @@ static struct irq_chip at91_aic_chip = { .irq_set_wake = at91_aic_set_wake, }; +static void __init at91_aic_hw_init(unsigned int spu_vector) +{ + int i; + + /* + * Perform 8 End Of Interrupt Command to make sure AIC + * will not Lock out nIRQ + */ + for (i = 0; i < 8; i++) + at91_aic_write(AT91_AIC_EOICR, 0); + + /* + * Spurious Interrupt ID in Spurious Vector Register. + * When there is no current interrupt, the IRQ Vector Register + * reads the value stored in AIC_SPU + */ + at91_aic_write(AT91_AIC_SPU, spu_vector); + + /* No debugging in AIC: Debug (Protect) Control Register */ + at91_aic_write(AT91_AIC_DCR, 0); + + /* Disable and clear all interrupts initially */ + at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF); + at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); +} + +#if defined(CONFIG_OF) +static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + /* Put virq number in Source Vector Register */ + at91_aic_write(AT91_AIC_SVR(hw), virq); + + /* Active Low interrupt, without priority */ + at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW); + + irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops at91_aic_irq_ops = { + .map = at91_aic_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +int __init at91_aic_of_init(struct device_node *node, + struct device_node *parent) +{ + at91_aic_base = of_iomap(node, 0); + at91_aic_np = node; + + at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS, + &at91_aic_irq_ops, NULL); + if (!at91_aic_domain) + panic("Unable to add AIC irq domain (DT)\n"); + + irq_set_default_host(at91_aic_domain); + + at91_aic_hw_init(NR_AIC_IRQS); + + return 0; +} +#endif + /* * Initialize the AIC interrupt controller. */ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) { unsigned int i; + int irq_base; at91_aic_base = ioremap(AT91_AIC, 512); - if (!at91_aic_base) - panic("Impossible to ioremap AT91_AIC\n"); + panic("Unable to ioremap AIC registers\n"); + + /* Add irq domain for AIC */ + irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0); + if (irq_base < 0) { + WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n"); + irq_base = 0; + } + at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS, + irq_base, 0, + &irq_domain_simple_ops, NULL); + + if (!at91_aic_domain) + panic("Unable to add AIC irq domain\n"); + + irq_set_default_host(at91_aic_domain); /* * The IVR is used by macro get_irqnr_and_base to read and verify. * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. */ for (i = 0; i < NR_AIC_IRQS; i++) { - /* Put irq number in Source Vector Register: */ + /* Put hardware irq number in Source Vector Register: */ at91_aic_write(AT91_AIC_SVR(i), i); /* Active Low interrupt, with the specified priority */ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - - /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */ - if (i < 8) - at91_aic_write(AT91_AIC_EOICR, 0); } - /* - * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS - * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU - */ - at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS); - - /* No debugging in AIC: Debug (Protect) Control Register */ - at91_aic_write(AT91_AIC_DCR, 0); - - /* Disable and clear all interrupts initially */ - at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF); - at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); + at91_aic_hw_init(NR_AIC_IRQS); } diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 6c9d5e69ac28..f630250c6b87 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -197,19 +197,6 @@ extern void at91_slow_clock(void __iomem *pmc, void __iomem *ramc0, extern u32 at91_slow_clock_sz; #endif -void __iomem *at91_ramc_base[2]; - -void __init at91_ioremap_ramc(int id, u32 addr, u32 size) -{ - if (id < 0 || id > 1) { - pr_emerg("Wrong RAM controller id (%d), cannot continue\n", id); - BUG(); - } - at91_ramc_base[id] = ioremap(addr, size); - if (!at91_ramc_base[id]) - panic("Impossible to ioremap ramc.%d 0x%x\n", id, addr); -} - static int at91_pm_enter(suspend_state_t state) { at91_gpio_suspend(); diff --git a/arch/arm/mach-at91/sam9_smc.c b/arch/arm/mach-at91/sam9_smc.c index 8294783b679d..99a0a1d2b7dc 100644 --- a/arch/arm/mach-at91/sam9_smc.c +++ b/arch/arm/mach-at91/sam9_smc.c @@ -2,6 +2,7 @@ * linux/arch/arm/mach-at91/sam9_smc.c * * Copyright (C) 2008 Andrew Victor + * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,7 +23,22 @@ static void __iomem *smc_base_addr[2]; -static void __init sam9_smc_cs_configure(void __iomem *base, struct sam9_smc_config* config) +static void sam9_smc_cs_write_mode(void __iomem *base, + struct sam9_smc_config *config) +{ + __raw_writel(config->mode + | AT91_SMC_TDF_(config->tdf_cycles), + base + AT91_SMC_MODE); +} + +void sam9_smc_write_mode(int id, int cs, + struct sam9_smc_config *config) +{ + sam9_smc_cs_write_mode(AT91_SMC_CS(id, cs), config); +} + +static void sam9_smc_cs_configure(void __iomem *base, + struct sam9_smc_config *config) { /* Setup register */ @@ -45,16 +61,66 @@ static void __init sam9_smc_cs_configure(void __iomem *base, struct sam9_smc_con base + AT91_SMC_CYCLE); /* Mode register */ - __raw_writel(config->mode - | AT91_SMC_TDF_(config->tdf_cycles), - base + AT91_SMC_MODE); + sam9_smc_cs_write_mode(base, config); } -void __init sam9_smc_configure(int id, int cs, struct sam9_smc_config* config) +void sam9_smc_configure(int id, int cs, + struct sam9_smc_config *config) { sam9_smc_cs_configure(AT91_SMC_CS(id, cs), config); } +static void sam9_smc_cs_read_mode(void __iomem *base, + struct sam9_smc_config *config) +{ + u32 val = __raw_readl(base + AT91_SMC_MODE); + + config->mode = (val & ~AT91_SMC_NWECYCLE); + config->tdf_cycles = (val & AT91_SMC_NWECYCLE) >> 16 ; +} + +void sam9_smc_read_mode(int id, int cs, + struct sam9_smc_config *config) +{ + sam9_smc_cs_read_mode(AT91_SMC_CS(id, cs), config); +} + +static void sam9_smc_cs_read(void __iomem *base, + struct sam9_smc_config *config) +{ + u32 val; + + /* Setup register */ + val = __raw_readl(base + AT91_SMC_SETUP); + + config->nwe_setup = val & AT91_SMC_NWESETUP; + config->ncs_write_setup = (val & AT91_SMC_NCS_WRSETUP) >> 8; + config->nrd_setup = (val & AT91_SMC_NRDSETUP) >> 16; + config->ncs_read_setup = (val & AT91_SMC_NCS_RDSETUP) >> 24; + + /* Pulse register */ + val = __raw_readl(base + AT91_SMC_PULSE); + + config->nwe_setup = val & AT91_SMC_NWEPULSE; + config->ncs_write_pulse = (val & AT91_SMC_NCS_WRPULSE) >> 8; + config->nrd_pulse = (val & AT91_SMC_NRDPULSE) >> 16; + config->ncs_read_pulse = (val & AT91_SMC_NCS_RDPULSE) >> 24; + + /* Cycle register */ + val = __raw_readl(base + AT91_SMC_CYCLE); + + config->write_cycle = val & AT91_SMC_NWECYCLE; + config->read_cycle = (val & AT91_SMC_NRDCYCLE) >> 16; + + /* Mode register */ + sam9_smc_cs_read_mode(base, config); +} + +void sam9_smc_read(int id, int cs, struct sam9_smc_config *config) +{ + sam9_smc_cs_read(AT91_SMC_CS(id, cs), config); +} + void __init at91sam9_ioremap_smc(int id, u32 addr) { if (id > 1) { diff --git a/arch/arm/mach-at91/sam9_smc.h b/arch/arm/mach-at91/sam9_smc.h index 039c5ce17aec..3e52dcd4a59f 100644 --- a/arch/arm/mach-at91/sam9_smc.h +++ b/arch/arm/mach-at91/sam9_smc.h @@ -8,27 +8,4 @@ * published by the Free Software Foundation. */ -struct sam9_smc_config { - /* Setup register */ - u8 ncs_read_setup; - u8 nrd_setup; - u8 ncs_write_setup; - u8 nwe_setup; - - /* Pulse register */ - u8 ncs_read_pulse; - u8 nrd_pulse; - u8 ncs_write_pulse; - u8 nwe_pulse; - - /* Cycle register */ - u16 read_cycle; - u16 write_cycle; - - /* Mode register */ - u32 mode; - u8 tdf_cycles:4; -}; - -extern void __init sam9_smc_configure(int id, int cs, struct sam9_smc_config* config); extern void __init at91sam9_ioremap_smc(int id, u32 addr); diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 372396c2ecb6..1083739e3065 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -9,6 +9,7 @@ #include <linux/io.h> #include <linux/mm.h> #include <linux/pm.h> +#include <linux/of_address.h> #include <asm/mach/map.h> @@ -51,6 +52,19 @@ void __init at91_init_interrupts(unsigned int *priority) at91_gpio_irq_setup(); } +void __iomem *at91_ramc_base[2]; + +void __init at91_ioremap_ramc(int id, u32 addr, u32 size) +{ + if (id < 0 || id > 1) { + pr_emerg("Wrong RAM controller id (%d), cannot continue\n", id); + BUG(); + } + at91_ramc_base[id] = ioremap(addr, size); + if (!at91_ramc_base[id]) + panic("Impossible to ioremap ramc.%d 0x%x\n", id, addr); +} + static struct map_desc sram_desc[2] __initdata; void __init at91_init_sram(int bank, unsigned long base, unsigned int length) @@ -285,6 +299,150 @@ void __init at91_ioremap_matrix(u32 base_addr) panic("Impossible to ioremap at91_matrix_base\n"); } +#if defined(CONFIG_OF) +static struct of_device_id rstc_ids[] = { + { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart }, + { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, + { /*sentinel*/ } +}; + +static void at91_dt_rstc(void) +{ + struct device_node *np; + const struct of_device_id *of_id; + + np = of_find_matching_node(NULL, rstc_ids); + if (!np) + panic("unable to find compatible rstc node in dtb\n"); + + at91_rstc_base = of_iomap(np, 0); + if (!at91_rstc_base) + panic("unable to map rstc cpu registers\n"); + + of_id = of_match_node(rstc_ids, np); + if (!of_id) + panic("AT91: rtsc no restart function availlable\n"); + + arm_pm_restart = of_id->data; + + of_node_put(np); +} + +static struct of_device_id ramc_ids[] = { + { .compatible = "atmel,at91sam9260-sdramc" }, + { .compatible = "atmel,at91sam9g45-ddramc" }, + { /*sentinel*/ } +}; + +static void at91_dt_ramc(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, ramc_ids); + if (!np) + panic("unable to find compatible ram conroller node in dtb\n"); + + at91_ramc_base[0] = of_iomap(np, 0); + if (!at91_ramc_base[0]) + panic("unable to map ramc[0] cpu registers\n"); + /* the controller may have 2 banks */ + at91_ramc_base[1] = of_iomap(np, 1); + + of_node_put(np); +} + +static struct of_device_id shdwc_ids[] = { + { .compatible = "atmel,at91sam9260-shdwc", }, + { .compatible = "atmel,at91sam9rl-shdwc", }, + { .compatible = "atmel,at91sam9x5-shdwc", }, + { /*sentinel*/ } +}; + +static const char *shdwc_wakeup_modes[] = { + [AT91_SHDW_WKMODE0_NONE] = "none", + [AT91_SHDW_WKMODE0_HIGH] = "high", + [AT91_SHDW_WKMODE0_LOW] = "low", + [AT91_SHDW_WKMODE0_ANYLEVEL] = "any", +}; + +const int at91_dtget_shdwc_wakeup_mode(struct device_node *np) +{ + const char *pm; + int err, i; + + err = of_property_read_string(np, "atmel,wakeup-mode", &pm); + if (err < 0) + return AT91_SHDW_WKMODE0_ANYLEVEL; + + for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++) + if (!strcasecmp(pm, shdwc_wakeup_modes[i])) + return i; + + return -ENODEV; +} + +static void at91_dt_shdwc(void) +{ + struct device_node *np; + int wakeup_mode; + u32 reg; + u32 mode = 0; + + np = of_find_matching_node(NULL, shdwc_ids); + if (!np) { + pr_debug("AT91: unable to find compatible shutdown (shdwc) conroller node in dtb\n"); + return; + } + + at91_shdwc_base = of_iomap(np, 0); + if (!at91_shdwc_base) + panic("AT91: unable to map shdwc cpu registers\n"); + + wakeup_mode = at91_dtget_shdwc_wakeup_mode(np); + if (wakeup_mode < 0) { + pr_warn("AT91: shdwc unknown wakeup mode\n"); + goto end; + } + + if (!of_property_read_u32(np, "atmel,wakeup-counter", ®)) { + if (reg > AT91_SHDW_CPTWK0_MAX) { + pr_warn("AT91: shdwc wakeup conter 0x%x > 0x%x reduce it to 0x%x\n", + reg, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX); + reg = AT91_SHDW_CPTWK0_MAX; + } + mode |= AT91_SHDW_CPTWK0_(reg); + } + + if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) + mode |= AT91_SHDW_RTCWKEN; + + if (of_property_read_bool(np, "atmel,wakeup-rtt-timer")) + mode |= AT91_SHDW_RTTWKEN; + + at91_shdwc_write(AT91_SHDW_MR, wakeup_mode | mode); + +end: + pm_power_off = at91sam9_poweroff; + + of_node_put(np); +} + +void __init at91_dt_initialize(void) +{ + at91_dt_rstc(); + at91_dt_ramc(); + at91_dt_shdwc(); + + /* Init clock subsystem */ + at91_dt_clock_init(); + + /* Register the processor-specific clocks */ + at91_boot_soc.register_clocks(); + + at91_boot_soc.init(); +} +#endif + void __init at91_initialize(unsigned long main_clock) { at91_boot_soc.ioremap_registers(); |