diff options
author | Hamish Guthrie <hcg@openwrt.org> | 2008-07-04 16:05:00 +0000 |
---|---|---|
committer | Hamish Guthrie <hcg@openwrt.org> | 2008-07-04 16:05:00 +0000 |
commit | 34d362d1a7c6c28b7a2d7c364972ef14091b29b9 (patch) | |
tree | bb791c41e8f5e2529c42eb05f202af8faf2024e5 /target/linux/at91/patches-2.6.25 | |
parent | 385bcf948bbecb0db8f0b59f20453629b9e1deb1 (diff) | |
download | mtk-20170518-34d362d1a7c6c28b7a2d7c364972ef14091b29b9.zip mtk-20170518-34d362d1a7c6c28b7a2d7c364972ef14091b29b9.tar.gz mtk-20170518-34d362d1a7c6c28b7a2d7c364972ef14091b29b9.tar.bz2 |
First stage of update for at91 devices to 2.6.25.10 kernel
SVN-Revision: 11631
Diffstat (limited to 'target/linux/at91/patches-2.6.25')
7 files changed, 13652 insertions, 0 deletions
diff --git a/target/linux/at91/patches-2.6.25/000-at91patches.patch b/target/linux/at91/patches-2.6.25/000-at91patches.patch new file mode 100644 index 0000000..b522a30 --- /dev/null +++ b/target/linux/at91/patches-2.6.25/000-at91patches.patch @@ -0,0 +1,13136 @@ +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/Kconfig linux-2.6/arch/arm/mach-at91/Kconfig +--- linux-2.6.25/arch/arm/mach-at91/Kconfig 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/Kconfig 2008-04-25 21:15:43.000000000 +0200 +@@ -12,18 +12,28 @@ + + config ARCH_AT91SAM9260 + bool "AT91SAM9260 or AT91SAM9XE" ++ select GENERIC_TIME ++ select GENERIC_CLOCKEVENTS + + config ARCH_AT91SAM9261 + bool "AT91SAM9261" ++ select GENERIC_TIME ++ select GENERIC_CLOCKEVENTS + + config ARCH_AT91SAM9263 + bool "AT91SAM9263" ++ select GENERIC_TIME ++ select GENERIC_CLOCKEVENTS + + config ARCH_AT91SAM9RL + bool "AT91SAM9RL" ++ select GENERIC_TIME ++ select GENERIC_CLOCKEVENTS + + config ARCH_AT91CAP9 + bool "AT91CAP9" ++ select GENERIC_TIME ++ select GENERIC_CLOCKEVENTS + + config ARCH_AT91X40 + bool "AT91x40" +@@ -45,7 +55,7 @@ + depends on ARCH_AT91RM9200 + help + Select this if you are using Ajeco's 1ARM Single Board Computer. +- <http://www.ajeco.fi/products.htm> ++ <http://www.ajeco.fi/eng/products_e.htm> + + config ARCH_AT91RM9200DK + bool "Atmel AT91RM9200-DK Development board" +@@ -94,7 +104,7 @@ + depends on ARCH_AT91RM9200 + help + Select this if you are using KwikByte's KB920x board. +- <http://kwikbyte.com/KB9202_description_new.htm> ++ <http://www.kwikbyte.com/KB9202.html> + + config MACH_PICOTUX2XX + bool "picotux 200" +@@ -109,6 +119,38 @@ + help + Select this if you are using Sperry-Sun's KAFA board. + ++config MACH_CHUB ++ bool "Promwad Chub board" ++ depends on ARCH_AT91RM9200 ++ help ++ Select this if you are using Promwad's Chub board. ++ ++config MACH_HOMEMATIC ++ bool "eQ-3 HomeMatic" ++ depends on ARCH_AT91RM9200 ++ help ++ Select this if you are using eQ-3's HomeMatic device. ++ <http://www.eq-3.com> ++ ++config MACH_ECBAT91 ++ bool "emQbit ECB_AT91 SBC" ++ depends on ARCH_AT91RM9200 ++ help ++ Select this if you are using emQbit's ECB_AT91 board. ++ <http://wiki.emqbit.com/free-ecb-at91> ++ ++config MACH_SWEDATMS ++ bool "Sweda TMS Board" ++ depends on ARCH_AT91RM9200 ++ help ++ Select this if you are using Sweda TMS-100 board. ++ ++config MACH_TT9200 ++ bool "Toptech TT9200" ++ depends on ARCH_AT91RM9200 ++ help ++ Select this if you are using Toptech's TT9200 board. ++ + endif + + # ---------------------------------------------------------- +@@ -133,6 +175,34 @@ + Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit + <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933> + ++config MACH_CAM60 ++ bool "KwikByte KB9260 (CAM60) board" ++ depends on ARCH_AT91SAM9260 ++ help ++ Select this if you are using KwikByte's KB9260 (CAM60) board based on the Atmel AT91SAM9260. ++ <http://www.kwikbyte.com/KB9260.html> ++ ++config MACH_SAM9_L9260 ++ bool "Olimex SAM9-L9260 board" ++ depends on ARCH_AT91SAM9260 ++ help ++ Select this if you are using Olimex's SAM9-L9260 board based on the Atmel AT91SAM9260. ++ <http://www.olimex.com/dev/sam9-L9260.html> ++ ++config MACH_USB_A9260 ++ bool "CALAO USB-A9260" ++ depends on ARCH_AT91SAM9260 ++ help ++ Select this if you are using a Calao Systems USB-A9260. ++ <http://www.calao-systems.com> ++ ++config MACH_QIL_A9260 ++ bool "CALAO QIL-A9260 board" ++ depends on ARCH_AT91SAM9260 ++ help ++ Select this if you are using a Calao Systems QIL-A9260 Board. ++ <http://www.calao-systems.com> ++ + endif + + # ---------------------------------------------------------- +@@ -163,6 +233,13 @@ + Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit. + <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057> + ++config MACH_USB_A9263 ++ bool "CALAO USB-A9263" ++ depends on ARCH_AT91SAM9263 ++ help ++ Select this if you are using a Calao Systems USB-A9263. ++ <http://www.calao-systems.com> ++ + endif + + # ---------------------------------------------------------- +@@ -216,7 +293,7 @@ + + config MTD_AT91_DATAFLASH_CARD + bool "Enable DataFlash Card support" +- depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91CAP9ADK) ++ depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_ECBAT91 || MACH_SAM9_L9260 || MACH_AT91CAP9ADK) + help + Enable support for the DataFlash card. + +@@ -237,6 +314,19 @@ + Select this if you need to program one or more of the PCK0..PCK3 + programmable clock outputs. + ++config AT91_SLOW_CLOCK ++ bool "Suspend-to-RAM disables main oscillator" ++ depends on SUSPEND ++ help ++ Select this if you want Suspend-to-RAM to save the most power ++ possible (without powering off the CPU) by disabling the PLLs ++ and main oscillator so that only the 32 KiHz clock is available. ++ ++ When only that slow-clock is available, some peripherals lose ++ functionality. Many can't issue wakeup events unless faster ++ clocks are available. Some lose their operating state and ++ need to be completely re-initialized. ++ + config AT91_TIMER_HZ + int "Kernel HZ (jiffies per second)" + range 32 1024 +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/Makefile linux-2.6/arch/arm/mach-at91/Makefile +--- linux-2.6.25/arch/arm/mach-at91/Makefile 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/Makefile 2008-04-25 21:15:43.000000000 +0200 +@@ -28,16 +28,26 @@ + obj-$(CONFIG_MACH_KB9200) += board-kb9202.o + obj-$(CONFIG_MACH_ATEB9200) += board-eb9200.o + obj-$(CONFIG_MACH_KAFA) += board-kafa.o ++obj-$(CONFIG_MACH_CHUB) += board-chub.o + obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o ++obj-$(CONFIG_MACH_HOMEMATIC) += board-homematic.o ++obj-$(CONFIG_MACH_ECBAT91) += board-ecbat91.o ++obj-$(CONFIG_MACH_SWEDATMS) += board-tms.o ++obj-$(CONFIG_MACH_TT9200) += board-tt9200.o + + # AT91SAM9260 board-specific support + obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o ++obj-$(CONFIG_MACH_CAM60) += board-cam60.o ++obj-$(CONFIG_MACH_SAM9_L9260) += board-sam9-l9260.o ++obj-$(CONFIG_MACH_USB_A9260) += board-usb-a9260.o ++obj-$(CONFIG_MACH_QIL_A9260) += board-qil-a9260.o + + # AT91SAM9261 board-specific support + obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o + + # AT91SAM9263 board-specific support + obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o ++obj-$(CONFIG_MACH_USB_A9263) += board-usb-a9263.o + + # AT91SAM9RL board-specific support + obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o +@@ -50,9 +60,11 @@ + + # Drivers + obj-y += leds.o ++obj-$(CONFIG_FB_S1D13XXX) += ics1523.o + + # Power Management + obj-$(CONFIG_PM) += pm.o ++obj-$(CONFIG_AT91_SLOW_CLOCK) += pm_slowclock.o + + ifeq ($(CONFIG_PM_DEBUG),y) + CFLAGS_pm.o += -DDEBUG +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91cap9.c linux-2.6/arch/arm/mach-at91/at91cap9.c +--- linux-2.6.25/arch/arm/mach-at91/at91cap9.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91cap9.c 2008-05-05 22:01:39.000000000 +0200 +@@ -13,12 +13,15 @@ + */ + + #include <linux/module.h> ++#include <linux/pm.h> + + #include <asm/mach/arch.h> + #include <asm/mach/map.h> ++#include <asm/arch/cpu.h> + #include <asm/arch/at91cap9.h> + #include <asm/arch/at91_pmc.h> + #include <asm/arch/at91_rstc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + #include "clock.h" +@@ -288,6 +291,12 @@ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + } + ++static void at91cap9_poweroff(void) ++{ ++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); ++} ++ ++ + /* -------------------------------------------------------------------- + * AT91CAP9 processor initialization + * -------------------------------------------------------------------- */ +@@ -298,6 +307,7 @@ + iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc)); + + at91_arch_reset = at91cap9_reset; ++ pm_power_off = at91cap9_poweroff; + at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1); + + /* Init clock subsystem */ +@@ -308,6 +318,12 @@ + + /* Register GPIO subsystem */ + at91_gpio_init(at91cap9_gpio, 4); ++ ++ /* Remember the silicon revision */ ++ if (cpu_is_at91cap9_revB()) ++ system_rev = 0xB; ++ else if (cpu_is_at91cap9_revC()) ++ system_rev = 0xC; + } + + /* -------------------------------------------------------------------- +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91cap9_devices.c linux-2.6/arch/arm/mach-at91/at91cap9_devices.c +--- linux-2.6.25/arch/arm/mach-at91/at91cap9_devices.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91cap9_devices.c 2008-05-05 22:01:39.000000000 +0200 +@@ -13,18 +13,20 @@ + */ + #include <asm/mach/arch.h> + #include <asm/mach/map.h> ++#include <asm/mach/irq.h> + + #include <linux/dma-mapping.h> + #include <linux/platform_device.h> +-#include <linux/mtd/physmap.h> ++#include <linux/i2c-gpio.h> + + #include <video/atmel_lcdc.h> + + #include <asm/arch/board.h> ++#include <asm/arch/cpu.h> + #include <asm/arch/gpio.h> + #include <asm/arch/at91cap9.h> +-#include <asm/arch/at91sam926x_mc.h> + #include <asm/arch/at91cap9_matrix.h> ++#include <asm/arch/at91sam9_smc.h> + + #include "generic.h" + +@@ -69,6 +71,9 @@ + if (!data) + return; + ++ if (cpu_is_at91cap9_revB()) ++ set_irq_type(AT91CAP9_ID_UHP, IRQT_HIGH); ++ + /* Enable VBus control for UHP ports */ + for (i = 0; i < data->ports; i++) { + if (data->vbus_pin[i]) +@@ -84,6 +89,110 @@ + + + /* -------------------------------------------------------------------- ++ * 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 = AT91CAP9_UDPHS_FIFO, ++ .end = AT91CAP9_UDPHS_FIFO + SZ_512K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91CAP9_BASE_UDPHS, ++ .end = AT91CAP9_BASE_UDPHS + SZ_1K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = AT91CAP9_ID_UDPHS, ++ .end = AT91CAP9_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[] = { ++ EP("ep0", 0, 64, 1, 0, 0), ++ EP("ep1", 1, 1024, 3, 1, 1), ++ EP("ep2", 2, 1024, 3, 1, 1), ++ EP("ep3", 3, 1024, 2, 1, 1), ++ EP("ep4", 4, 1024, 2, 1, 1), ++ EP("ep5", 5, 1024, 2, 1, 0), ++ EP("ep6", 6, 1024, 2, 1, 0), ++ EP("ep7", 7, 1024, 2, 0, 0), ++}; ++ ++#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[8]; ++} 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) ++{ ++ if (cpu_is_at91cap9_revB()) { ++ set_irq_type(AT91CAP9_ID_UDPHS, IRQT_HIGH); ++ at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS | ++ AT91_MATRIX_UDPHS_BYPASS_LOCK); ++ } ++ else ++ at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS); ++ ++ /* ++ * Invalid pins are 0 on AT91, but the usba driver is shared ++ * with AVR32, which use negative values instead. Once/if ++ * gpio_is_valid() is ported to AT91, revisit this code. ++ */ ++ usba_udc_data.pdata.vbus_pin = -EINVAL; ++ usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep); ++ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));; ++ ++ if (data && data->vbus_pin > 0) { ++ at91_set_gpio_input(data->vbus_pin, 0); ++ at91_set_deglitch(data->vbus_pin, 1); ++ usba_udc_data.pdata.vbus_pin = data->vbus_pin; ++ } ++ ++ /* Pullup pin is handled internally by USB device peripheral */ ++ ++ /* Clocks */ ++ at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk"); ++ at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk"); ++ ++ platform_device_register(&at91_usba_udc_device); ++} ++#else ++void __init at91_add_device_usba(struct usba_platform_data *data) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * Ethernet + * -------------------------------------------------------------------- */ + +@@ -246,7 +355,7 @@ + } + + mmc0_data = *data; +- at91_clock_associate("mci0_clk", &at91cap9_mmc1_device.dev, "mci_clk"); ++ at91_clock_associate("mci0_clk", &at91cap9_mmc0_device.dev, "mci_clk"); + platform_device_register(&at91cap9_mmc0_device); + } else { /* MCI1 */ + /* CLK */ +@@ -283,10 +392,15 @@ + #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, + } + }; + +@@ -344,6 +458,7 @@ + void __init at91_add_device_nand(struct at91_nand_data *data) {} + #endif + ++ + /* -------------------------------------------------------------------- + * TWI (i2c) + * -------------------------------------------------------------------- */ +@@ -532,17 +647,64 @@ + + + /* -------------------------------------------------------------------- ++ * Timer/Counter block ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++ ++static struct resource tcb_resources[] = { ++ [0] = { ++ .start = AT91CAP9_BASE_TCB0, ++ .end = AT91CAP9_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91CAP9_ID_TCB, ++ .end = AT91CAP9_ID_TCB, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91cap9_tcb_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb_resources, ++ .num_resources = ARRAY_SIZE(tcb_resources), ++}; ++ ++static void __init at91_add_device_tc(void) ++{ ++ /* this chip has one clock and irq for all three TC channels */ ++ at91_clock_associate("tcb_clk", &at91cap9_tcb_device.dev, "t0_clk"); ++ platform_device_register(&at91cap9_tcb_device); ++} ++#else ++static void __init at91_add_device_tc(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 at91cap9_rtt_device = { + .name = "at91_rtt", +- .id = -1, +- .num_resources = 0, ++ .id = 0, ++ .resource = rtt_resources, ++ .num_resources = ARRAY_SIZE(rtt_resources), + }; + + static void __init at91_add_device_rtt(void) + { ++ device_init_wakeup(&at91cap9_rtt_device.dev, 1); + platform_device_register(&at91cap9_rtt_device); + } + +@@ -660,6 +822,9 @@ + if (!data) + return; + ++ if (cpu_is_at91cap9_revB()) ++ set_irq_type(AT91CAP9_ID_LCDC, IRQT_HIGH); ++ + at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDHSYNC */ + at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDDOTCK */ + at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDDEN */ +@@ -990,7 +1155,7 @@ + at91_set_B_periph(AT91_PIN_PD6, 0); /* CTS2 */ + } + +-static struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ ++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) +@@ -1031,8 +1196,6 @@ + { + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + + void __init at91_add_device_serial(void) +@@ -1043,6 +1206,9 @@ + 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) {} +@@ -1060,6 +1226,7 @@ + { + at91_add_device_rtt(); + at91_add_device_watchdog(); ++ at91_add_device_tc(); + return 0; + } + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91rm9200_devices.c linux-2.6/arch/arm/mach-at91/at91rm9200_devices.c +--- linux-2.6.25/arch/arm/mach-at91/at91rm9200_devices.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91rm9200_devices.c 2008-04-25 21:15:43.000000000 +0200 +@@ -513,7 +513,18 @@ + * SPI + * -------------------------------------------------------------------- */ + +-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) ++#if defined(CONFIG_AT91_SPI) || defined(CONFIG_AT91_SPI_MODULE) /* legacy SPI driver */ ++#define SPI_DEVNAME "at91_spi" ++ ++#elif defined(CONFIG_SPI_AT91) || defined(CONFIG_SPI_AT91_MODULE) /* SPI bitbanging driver */ ++#define SPI_DEVNAME "at91_spi" ++ ++#elif defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) /* new SPI driver */ ++#define SPI_DEVNAME "atmel_spi" ++ ++#endif ++ ++#ifdef SPI_DEVNAME + static u64 spi_dmamask = DMA_BIT_MASK(32); + + static struct resource spi_resources[] = { +@@ -530,7 +541,7 @@ + }; + + static struct platform_device at91rm9200_spi_device = { +- .name = "atmel_spi", ++ .name = SPI_DEVNAME, + .id = 0, + .dev = { + .dma_mask = &spi_dmamask, +@@ -563,6 +574,12 @@ + else + at91_set_gpio_output(cs_pin, 1); + ++#if defined(CONFIG_AT91_SPI) || defined(CONFIG_AT91_SPI_MODULE) ++ /* ++ * Force peripheral mode when using the legacy SPI driver. ++ */ ++ at91_set_A_periph(cs_pin, 0); ++#endif + + /* pass chip-select pin to driver */ + devices[i].controller_data = (void *) cs_pin; +@@ -577,6 +594,90 @@ + + + /* -------------------------------------------------------------------- ++ * Timer/Counter blocks ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++ ++static struct resource tcb0_resources[] = { ++ [0] = { ++ .start = AT91RM9200_BASE_TCB0, ++ .end = AT91RM9200_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91RM9200_ID_TC0, ++ .end = AT91RM9200_ID_TC0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [2] = { ++ .start = AT91RM9200_ID_TC1, ++ .end = AT91RM9200_ID_TC1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = AT91RM9200_ID_TC2, ++ .end = AT91RM9200_ID_TC2, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91rm9200_tcb0_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb0_resources, ++ .num_resources = ARRAY_SIZE(tcb0_resources), ++}; ++ ++static struct resource tcb1_resources[] = { ++ [0] = { ++ .start = AT91RM9200_BASE_TCB1, ++ .end = AT91RM9200_BASE_TCB1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91RM9200_ID_TC3, ++ .end = AT91RM9200_ID_TC3, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [2] = { ++ .start = AT91RM9200_ID_TC4, ++ .end = AT91RM9200_ID_TC4, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = AT91RM9200_ID_TC5, ++ .end = AT91RM9200_ID_TC5, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91rm9200_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 a separate clock and irq for each TC channel */ ++ at91_clock_associate("tc0_clk", &at91rm9200_tcb0_device.dev, "t0_clk"); ++ at91_clock_associate("tc1_clk", &at91rm9200_tcb0_device.dev, "t1_clk"); ++ at91_clock_associate("tc2_clk", &at91rm9200_tcb0_device.dev, "t2_clk"); ++ platform_device_register(&at91rm9200_tcb0_device); ++ ++ at91_clock_associate("tc3_clk", &at91rm9200_tcb1_device.dev, "t0_clk"); ++ at91_clock_associate("tc4_clk", &at91rm9200_tcb1_device.dev, "t1_clk"); ++ at91_clock_associate("tc5_clk", &at91rm9200_tcb1_device.dev, "t2_clk"); ++ platform_device_register(&at91rm9200_tcb1_device); ++} ++#else ++static void __init at91_add_device_tc(void) { } ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * RTC + * -------------------------------------------------------------------- */ + +@@ -589,6 +690,7 @@ + + static void __init at91_add_device_rtc(void) + { ++ device_init_wakeup(&at91rm9200_rtc_device.dev, 1); + platform_device_register(&at91rm9200_rtc_device); + } + #else +@@ -1019,7 +1121,7 @@ + at91_set_B_periph(AT91_PIN_PB0, 0); /* RTS3 */ + } + +-static struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ ++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 __deprecated at91_init_serial(struct at91_uart_config *config) +@@ -1110,8 +1212,6 @@ + { + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + + void __init at91_add_device_serial(void) +@@ -1122,6 +1222,9 @@ + 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 __deprecated at91_init_serial(struct at91_uart_config *config) {} +@@ -1141,6 +1244,7 @@ + { + at91_add_device_rtc(); + at91_add_device_watchdog(); ++ at91_add_device_tc(); + return 0; + } + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91rm9200_time.c linux-2.6/arch/arm/mach-at91/at91rm9200_time.c +--- linux-2.6.25/arch/arm/mach-at91/at91rm9200_time.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91rm9200_time.c 2008-04-25 21:15:43.000000000 +0200 +@@ -136,8 +136,6 @@ + u32 alm; + int status = 0; + +- BUG_ON(delta < 2); +- + /* Use "raw" primitives so we behave correctly on RT kernels. */ + raw_local_irq_save(flags); + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9260.c linux-2.6/arch/arm/mach-at91/at91sam9260.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9260.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9260.c 2008-04-25 21:15:43.000000000 +0200 +@@ -11,6 +11,7 @@ + */ + + #include <linux/module.h> ++#include <linux/pm.h> + + #include <asm/mach/arch.h> + #include <asm/mach/map.h> +@@ -18,6 +19,7 @@ + #include <asm/arch/at91sam9260.h> + #include <asm/arch/at91_pmc.h> + #include <asm/arch/at91_rstc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + #include "clock.h" +@@ -267,6 +269,11 @@ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + } + ++static void at91sam9260_poweroff(void) ++{ ++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); ++} ++ + + /* -------------------------------------------------------------------- + * AT91SAM9260 processor initialization +@@ -304,6 +311,7 @@ + iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc)); + + at91_arch_reset = at91sam9260_reset; ++ pm_power_off = at91sam9260_poweroff; + at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1) + | (1 << AT91SAM9260_ID_IRQ2); + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9260_devices.c linux-2.6/arch/arm/mach-at91/at91sam9260_devices.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9260_devices.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9260_devices.c 2008-04-25 21:15:43.000000000 +0200 +@@ -19,8 +19,8 @@ + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> + #include <asm/arch/at91sam9260.h> +-#include <asm/arch/at91sam926x_mc.h> + #include <asm/arch/at91sam9260_matrix.h> ++#include <asm/arch/at91sam9_smc.h> + + #include "generic.h" + +@@ -288,10 +288,15 @@ + #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, + } + }; + +@@ -540,6 +545,90 @@ + + + /* -------------------------------------------------------------------- ++ * Timer/Counter blocks ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++ ++static struct resource tcb0_resources[] = { ++ [0] = { ++ .start = AT91SAM9260_BASE_TCB0, ++ .end = AT91SAM9260_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9260_ID_TC0, ++ .end = AT91SAM9260_ID_TC0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [2] = { ++ .start = AT91SAM9260_ID_TC1, ++ .end = AT91SAM9260_ID_TC1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = AT91SAM9260_ID_TC2, ++ .end = AT91SAM9260_ID_TC2, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9260_tcb0_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb0_resources, ++ .num_resources = ARRAY_SIZE(tcb0_resources), ++}; ++ ++static struct resource tcb1_resources[] = { ++ [0] = { ++ .start = AT91SAM9260_BASE_TCB1, ++ .end = AT91SAM9260_BASE_TCB1 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9260_ID_TC3, ++ .end = AT91SAM9260_ID_TC3, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [2] = { ++ .start = AT91SAM9260_ID_TC4, ++ .end = AT91SAM9260_ID_TC4, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = AT91SAM9260_ID_TC5, ++ .end = AT91SAM9260_ID_TC5, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9260_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 a separate clock and irq for each TC channel */ ++ at91_clock_associate("tc0_clk", &at91sam9260_tcb0_device.dev, "t0_clk"); ++ at91_clock_associate("tc1_clk", &at91sam9260_tcb0_device.dev, "t1_clk"); ++ at91_clock_associate("tc2_clk", &at91sam9260_tcb0_device.dev, "t2_clk"); ++ platform_device_register(&at91sam9260_tcb0_device); ++ ++ at91_clock_associate("tc3_clk", &at91sam9260_tcb1_device.dev, "t0_clk"); ++ at91_clock_associate("tc4_clk", &at91sam9260_tcb1_device.dev, "t1_clk"); ++ at91_clock_associate("tc5_clk", &at91sam9260_tcb1_device.dev, "t2_clk"); ++ platform_device_register(&at91sam9260_tcb1_device); ++} ++#else ++static void __init at91_add_device_tc(void) { } ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * RTT + * -------------------------------------------------------------------- */ + +@@ -553,13 +642,14 @@ + + static struct platform_device at91sam9260_rtt_device = { + .name = "at91_rtt", +- .id = -1, ++ .id = 0, + .resource = rtt_resources, + .num_resources = ARRAY_SIZE(rtt_resources), + }; + + static void __init at91_add_device_rtt(void) + { ++ device_init_wakeup(&at91sam9260_rtt_device.dev, 1); + platform_device_register(&at91sam9260_rtt_device); + } + +@@ -962,7 +1052,7 @@ + at91_set_A_periph(AT91_PIN_PB13, 0); /* RXD5 */ + } + +-static struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ ++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 __deprecated at91_init_serial(struct at91_uart_config *config) +@@ -1073,8 +1163,6 @@ + { + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + + void __init at91_add_device_serial(void) +@@ -1085,6 +1173,9 @@ + 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 __deprecated at91_init_serial(struct at91_uart_config *config) {} +@@ -1103,6 +1194,7 @@ + { + at91_add_device_rtt(); + at91_add_device_watchdog(); ++ at91_add_device_tc(); + return 0; + } + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9261.c linux-2.6/arch/arm/mach-at91/at91sam9261.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9261.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9261.c 2008-04-25 21:15:43.000000000 +0200 +@@ -11,12 +11,14 @@ + */ + + #include <linux/module.h> ++#include <linux/pm.h> + + #include <asm/mach/arch.h> + #include <asm/mach/map.h> + #include <asm/arch/at91sam9261.h> + #include <asm/arch/at91_pmc.h> + #include <asm/arch/at91_rstc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + #include "clock.h" +@@ -245,6 +247,11 @@ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + } + ++static void at91sam9261_poweroff(void) ++{ ++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); ++} ++ + + /* -------------------------------------------------------------------- + * AT91SAM9261 processor initialization +@@ -256,6 +263,7 @@ + iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc)); + + at91_arch_reset = at91sam9261_reset; ++ pm_power_off = at91sam9261_poweroff; + at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1) + | (1 << AT91SAM9261_ID_IRQ2); + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9261_devices.c linux-2.6/arch/arm/mach-at91/at91sam9261_devices.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9261_devices.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9261_devices.c 2008-04-25 21:15:43.000000000 +0200 +@@ -24,7 +24,7 @@ + #include <asm/arch/gpio.h> + #include <asm/arch/at91sam9261.h> + #include <asm/arch/at91sam9261_matrix.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91sam9_smc.h> + + #include "generic.h" + +@@ -548,6 +548,55 @@ + + + /* -------------------------------------------------------------------- ++ * Timer/Counter block ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++ ++static struct resource tcb_resources[] = { ++ [0] = { ++ .start = AT91SAM9261_BASE_TCB0, ++ .end = AT91SAM9261_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9261_ID_TC0, ++ .end = AT91SAM9261_ID_TC0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [2] = { ++ .start = AT91SAM9261_ID_TC1, ++ .end = AT91SAM9261_ID_TC1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = AT91SAM9261_ID_TC2, ++ .end = AT91SAM9261_ID_TC2, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9261_tcb_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb_resources, ++ .num_resources = ARRAY_SIZE(tcb_resources), ++}; ++ ++static void __init at91_add_device_tc(void) ++{ ++ /* this chip has a separate clock and irq for each TC channel */ ++ at91_clock_associate("tc0_clk", &at91sam9261_tcb_device.dev, "t0_clk"); ++ at91_clock_associate("tc1_clk", &at91sam9261_tcb_device.dev, "t1_clk"); ++ at91_clock_associate("tc2_clk", &at91sam9261_tcb_device.dev, "t2_clk"); ++ platform_device_register(&at91sam9261_tcb_device); ++} ++#else ++static void __init at91_add_device_tc(void) { } ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * RTT + * -------------------------------------------------------------------- */ + +@@ -561,13 +610,14 @@ + + static struct platform_device at91sam9261_rtt_device = { + .name = "at91_rtt", +- .id = -1, ++ .id = 0, + .resource = rtt_resources, + .num_resources = ARRAY_SIZE(rtt_resources), + }; + + static void __init at91_add_device_rtt(void) + { ++ device_init_wakeup(&at91sam9261_rtt_device.dev, 1); + platform_device_register(&at91sam9261_rtt_device); + } + +@@ -938,7 +988,7 @@ + at91_set_B_periph(AT91_PIN_PA16, 0); /* CTS2 */ + } + +-static struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ ++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 __deprecated at91_init_serial(struct at91_uart_config *config) +@@ -1019,8 +1069,6 @@ + { + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + + void __init at91_add_device_serial(void) +@@ -1031,6 +1079,9 @@ + 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 __deprecated at91_init_serial(struct at91_uart_config *config) {} +@@ -1050,6 +1101,7 @@ + { + at91_add_device_rtt(); + at91_add_device_watchdog(); ++ at91_add_device_tc(); + return 0; + } + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9263.c linux-2.6/arch/arm/mach-at91/at91sam9263.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9263.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9263.c 2008-04-25 21:15:43.000000000 +0200 +@@ -11,12 +11,14 @@ + */ + + #include <linux/module.h> ++#include <linux/pm.h> + + #include <asm/mach/arch.h> + #include <asm/mach/map.h> + #include <asm/arch/at91sam9263.h> + #include <asm/arch/at91_pmc.h> + #include <asm/arch/at91_rstc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + #include "clock.h" +@@ -271,6 +273,11 @@ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + } + ++static void at91sam9263_poweroff(void) ++{ ++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); ++} ++ + + /* -------------------------------------------------------------------- + * AT91SAM9263 processor initialization +@@ -282,6 +289,7 @@ + iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc)); + + at91_arch_reset = at91sam9263_reset; ++ pm_power_off = at91sam9263_poweroff; + at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1); + + /* Init clock subsystem */ +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9263_devices.c linux-2.6/arch/arm/mach-at91/at91sam9263_devices.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9263_devices.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9263_devices.c 2008-04-25 21:16:23.000000000 +0200 +@@ -22,8 +22,8 @@ + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> + #include <asm/arch/at91sam9263.h> +-#include <asm/arch/at91sam926x_mc.h> + #include <asm/arch/at91sam9263_matrix.h> ++#include <asm/arch/at91sam9_smc.h> + + #include "generic.h" + +@@ -308,7 +308,7 @@ + } + + mmc0_data = *data; +- at91_clock_associate("mci0_clk", &at91sam9263_mmc1_device.dev, "mci_clk"); ++ at91_clock_associate("mci0_clk", &at91sam9263_mmc0_device.dev, "mci_clk"); + platform_device_register(&at91sam9263_mmc0_device); + } else { /* MCI1 */ + /* CLK */ +@@ -358,10 +358,15 @@ + #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_ECC0, ++ .end = AT91_BASE_SYS + AT91_ECC0 + SZ_512 - 1, ++ .flags = IORESOURCE_MEM, + } + }; + +@@ -783,6 +788,43 @@ + + + /* -------------------------------------------------------------------- ++ * Timer/Counter block ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++ ++static struct resource tcb_resources[] = { ++ [0] = { ++ .start = AT91SAM9263_BASE_TCB0, ++ .end = AT91SAM9263_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9263_ID_TCB, ++ .end = AT91SAM9263_ID_TCB, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9263_tcb_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb_resources, ++ .num_resources = ARRAY_SIZE(tcb_resources), ++}; ++ ++static void __init at91_add_device_tc(void) ++{ ++ /* this chip has one clock and irq for all three TC channels */ ++ at91_clock_associate("tcb_clk", &at91sam9263_tcb_device.dev, "t0_clk"); ++ platform_device_register(&at91sam9263_tcb_device); ++} ++#else ++static void __init at91_add_device_tc(void) { } ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * RTT + * -------------------------------------------------------------------- */ + +@@ -818,7 +860,9 @@ + + static void __init at91_add_device_rtt(void) + { ++ device_init_wakeup(&at91sam9263_rtt0_device.dev, 1); + platform_device_register(&at91sam9263_rtt0_device); ++ device_init_wakeup(&at91sam9263_rtt1_device.dev, 1); + platform_device_register(&at91sam9263_rtt1_device); + } + +@@ -933,9 +977,6 @@ + } + + /* +- * Return the device node so that board init code can use it as the +- * parent for the device node reflecting how it's used on this board. +- * + * 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 +@@ -1146,7 +1187,7 @@ + at91_set_B_periph(AT91_PIN_PD6, 0); /* CTS2 */ + } + +-static struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ ++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 __deprecated at91_init_serial(struct at91_uart_config *config) +@@ -1227,8 +1268,6 @@ + { + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + + void __init at91_add_device_serial(void) +@@ -1239,9 +1278,12 @@ + 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_init_serial(struct at91_uart_config *config) {} ++void __init __deprecated at91_init_serial(struct at91_uart_config *config) {} + 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) {} +@@ -1257,6 +1299,7 @@ + { + at91_add_device_rtt(); + at91_add_device_watchdog(); ++ at91_add_device_tc(); + return 0; + } + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam926x_time.c linux-2.6/arch/arm/mach-at91/at91sam926x_time.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam926x_time.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam926x_time.c 2008-04-25 21:15:43.000000000 +0200 +@@ -1,23 +1,20 @@ + /* +- * linux/arch/arm/mach-at91/at91sam926x_time.c ++ * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x + * + * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France + * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France ++ * Converted to ClockSource/ClockEvents by David Brownell. + * + * 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 + * published by the Free Software Foundation. + */ +- +-#include <linux/init.h> + #include <linux/interrupt.h> + #include <linux/irq.h> + #include <linux/kernel.h> +-#include <linux/sched.h> +-#include <linux/time.h> ++#include <linux/clk.h> ++#include <linux/clockchips.h> + +-#include <asm/hardware.h> +-#include <asm/io.h> + #include <asm/mach/time.h> + + #include <asm/arch/at91_pit.h> +@@ -26,85 +23,167 @@ + #define PIT_CPIV(x) ((x) & AT91_PIT_CPIV) + #define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20) + ++static u32 pit_cycle; /* write-once */ ++static u32 pit_cnt; /* access only w/system irq blocked */ ++ ++ + /* +- * Returns number of microseconds since last timer interrupt. Note that interrupts +- * will have been disabled by do_gettimeofday() +- * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. ++ * Clocksource: just a monotonic counter of MCK/16 cycles. ++ * We don't care whether or not PIT irqs are enabled. + */ +-static unsigned long at91sam926x_gettimeoffset(void) ++static cycle_t read_pit_clk(void) + { +- unsigned long elapsed; +- unsigned long t = at91_sys_read(AT91_PIT_PIIR); ++ unsigned long flags; ++ u32 elapsed; ++ u32 t; ++ ++ raw_local_irq_save(flags); ++ elapsed = pit_cnt; ++ t = at91_sys_read(AT91_PIT_PIIR); ++ raw_local_irq_restore(flags); ++ ++ elapsed += PIT_PICNT(t) * pit_cycle; ++ elapsed += PIT_CPIV(t); ++ return elapsed; ++} ++ ++static struct clocksource pit_clk = { ++ .name = "pit", ++ .rating = 175, ++ .read = read_pit_clk, ++ .shift = 20, ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++}; ++ + +- elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t); /* hardware clock cycles */ ++/* ++ * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) ++ */ ++static void ++pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) ++{ ++ unsigned long flags; + +- return (unsigned long)(elapsed * jiffies_to_usecs(1)) / LATCH; ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ /* update clocksource counter, then enable the IRQ */ ++ raw_local_irq_save(flags); ++ pit_cnt += pit_cycle * PIT_PICNT(at91_sys_read(AT91_PIT_PIVR)); ++ at91_sys_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN ++ | AT91_PIT_PITIEN); ++ raw_local_irq_restore(flags); ++ break; ++ case CLOCK_EVT_MODE_ONESHOT: ++ BUG(); ++ /* FALLTHROUGH */ ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ case CLOCK_EVT_MODE_UNUSED: ++ /* disable irq, leaving the clocksource active */ ++ at91_sys_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ break; ++ } + } + ++static struct clock_event_device pit_clkevt = { ++ .name = "pit", ++ .features = CLOCK_EVT_FEAT_PERIODIC, ++ .shift = 32, ++ .rating = 100, ++ .cpumask = CPU_MASK_CPU0, ++ .set_mode = pit_clkevt_mode, ++}; ++ ++ + /* + * IRQ handler for the timer. + */ +-static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id) ++static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) + { +- volatile long nr_ticks; + +- if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */ +- /* Get number to ticks performed before interrupt and clear PIT interrupt */ ++ /* The PIT interrupt may be disabled, and is shared */ ++ if ((pit_clkevt.mode == CLOCK_EVT_MODE_PERIODIC) ++ && (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS)) { ++ unsigned nr_ticks; ++ ++ /* Get number of ticks performed before irq, and ack it */ + nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR)); + do { +- timer_tick(); ++ pit_cnt += pit_cycle; ++ pit_clkevt.event_handler(&pit_clkevt); + nr_ticks--; + } while (nr_ticks); + + return IRQ_HANDLED; +- } else +- return IRQ_NONE; /* not handled */ ++ } ++ ++ return IRQ_NONE; + } + +-static struct irqaction at91sam926x_timer_irq = { ++static struct irqaction at91sam926x_pit_irq = { + .name = "at91_tick", + .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, +- .handler = at91sam926x_timer_interrupt ++ .handler = at91sam926x_pit_interrupt + }; + +-void at91sam926x_timer_reset(void) ++static void at91sam926x_pit_reset(void) + { +- /* Disable timer */ ++ /* Disable timer and irqs */ + at91_sys_write(AT91_PIT_MR, 0); + +- /* Clear any pending interrupts */ +- (void) at91_sys_read(AT91_PIT_PIVR); ++ /* Clear any pending interrupts, wait for PIT to stop counting */ ++ while (PIT_CPIV(at91_sys_read(AT91_PIT_PIVR)) != 0) ++ cpu_relax(); + +- /* Set Period Interval timer and enable its interrupt */ +- at91_sys_write(AT91_PIT_MR, (LATCH & AT91_PIT_PIV) | AT91_PIT_PITIEN | AT91_PIT_PITEN); ++ /* Start PIT but don't enable IRQ */ ++ at91_sys_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); + } + + /* +- * Set up timer interrupt. ++ * Set up both clocksource and clockevent support. + */ +-void __init at91sam926x_timer_init(void) ++static void __init at91sam926x_pit_init(void) + { ++ unsigned long pit_rate; ++ unsigned bits; ++ ++ /* ++ * Use our actual MCK to figure out how many MCK/16 ticks per ++ * 1/HZ period (instead of a compile-time constant LATCH). ++ */ ++ pit_rate = clk_get_rate(clk_get(NULL, "mck")) / 16; ++ pit_cycle = (pit_rate + HZ/2) / HZ; ++ WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0); ++ + /* Initialize and enable the timer */ +- at91sam926x_timer_reset(); ++ at91sam926x_pit_reset(); + +- /* Make IRQs happen for the system timer. */ +- setup_irq(AT91_ID_SYS, &at91sam926x_timer_irq); ++ /* ++ * Register clocksource. The high order bits of PIV are unused, ++ * so this isn't a 32-bit counter unless we get clockevent irqs. ++ */ ++ pit_clk.mult = clocksource_hz2mult(pit_rate, pit_clk.shift); ++ bits = 12 /* PICNT */ + ilog2(pit_cycle) /* PIV */; ++ pit_clk.mask = CLOCKSOURCE_MASK(bits); ++ clocksource_register(&pit_clk); ++ ++ /* Set up irq handler */ ++ setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq); ++ ++ /* Set up and register clockevents */ ++ pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift); ++ clockevents_register_device(&pit_clkevt); + } + +-#ifdef CONFIG_PM +-static void at91sam926x_timer_suspend(void) ++static void at91sam926x_pit_suspend(void) + { + /* Disable timer */ + at91_sys_write(AT91_PIT_MR, 0); + } +-#else +-#define at91sam926x_timer_suspend NULL +-#endif + + struct sys_timer at91sam926x_timer = { +- .init = at91sam926x_timer_init, +- .offset = at91sam926x_gettimeoffset, +- .suspend = at91sam926x_timer_suspend, +- .resume = at91sam926x_timer_reset, ++ .init = at91sam926x_pit_init, ++ .suspend = at91sam926x_pit_suspend, ++ .resume = at91sam926x_pit_reset, + }; +- +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9rl.c linux-2.6/arch/arm/mach-at91/at91sam9rl.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9rl.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9rl.c 2008-04-25 21:15:43.000000000 +0200 +@@ -10,6 +10,7 @@ + */ + + #include <linux/module.h> ++#include <linux/pm.h> + + #include <asm/mach/arch.h> + #include <asm/mach/map.h> +@@ -17,6 +18,7 @@ + #include <asm/arch/at91sam9rl.h> + #include <asm/arch/at91_pmc.h> + #include <asm/arch/at91_rstc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + #include "clock.h" +@@ -244,6 +246,11 @@ + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST); + } + ++static void at91sam9rl_poweroff(void) ++{ ++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); ++} ++ + + /* -------------------------------------------------------------------- + * AT91SAM9RL processor initialization +@@ -274,6 +281,7 @@ + iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc)); + + at91_arch_reset = at91sam9rl_reset; ++ pm_power_off = at91sam9rl_poweroff; + at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0); + + /* Init clock subsystem */ +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/at91sam9rl_devices.c linux-2.6/arch/arm/mach-at91/at91sam9rl_devices.c +--- linux-2.6.25/arch/arm/mach-at91/at91sam9rl_devices.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/at91sam9rl_devices.c 2008-05-02 00:52:36.000000000 +0200 +@@ -20,12 +20,107 @@ + #include <asm/arch/gpio.h> + #include <asm/arch/at91sam9rl.h> + #include <asm/arch/at91sam9rl_matrix.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91sam9_smc.h> + + #include "generic.h" + + + /* -------------------------------------------------------------------- ++ * USB HS Device (Gadget) ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE) ++ ++static struct resource usba_udc_resources[] = { ++ [0] = { ++ .start = AT91SAM9RL_UDPHS_FIFO, ++ .end = AT91SAM9RL_UDPHS_FIFO + SZ_512K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9RL_BASE_UDPHS, ++ .end = AT91SAM9RL_BASE_UDPHS + SZ_1K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [2] = { ++ .start = AT91SAM9RL_ID_UDPHS, ++ .end = AT91SAM9RL_ID_UDPHS, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ ++ [idx] = { \ ++ .name = nam, \ ++ .index = idx, \ ++ .fifo_size = maxpkt, \ ++ .nr_banks = maxbk, \ ++ .can_dma = dma, \ ++ .can_isoc = isoc, \ ++ } ++ ++static struct usba_ep_data usba_udc_ep[] __initdata = { ++ EP("ep0", 0, 64, 1, 0, 0), ++ EP("ep1", 1, 1024, 2, 1, 1), ++ EP("ep2", 2, 1024, 2, 1, 1), ++ EP("ep3", 3, 1024, 3, 1, 0), ++ EP("ep4", 4, 1024, 3, 1, 0), ++ EP("ep5", 5, 1024, 3, 1, 1), ++ EP("ep6", 6, 1024, 3, 1, 1), ++}; ++ ++#undef EP ++ ++/* ++ * pdata doesn't have room for any endpoints, so we need to ++ * append room for the ones we need right after it. ++ */ ++static struct { ++ struct usba_platform_data pdata; ++ struct usba_ep_data ep[7]; ++} usba_udc_data; ++ ++static struct platform_device at91_usba_udc_device = { ++ .name = "atmel_usba_udc", ++ .id = -1, ++ .dev = { ++ .platform_data = &usba_udc_data.pdata, ++ }, ++ .resource = usba_udc_resources, ++ .num_resources = ARRAY_SIZE(usba_udc_resources), ++}; ++ ++void __init at91_add_device_usba(struct usba_platform_data *data) ++{ ++ /* ++ * Invalid pins are 0 on AT91, but the usba driver is shared ++ * with AVR32, which use negative values instead. Once/if ++ * gpio_is_valid() is ported to AT91, revisit this code. ++ */ ++ usba_udc_data.pdata.vbus_pin = -EINVAL; ++ usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep); ++ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));; ++ ++ if (data && data->vbus_pin > 0) { ++ at91_set_gpio_input(data->vbus_pin, 0); ++ at91_set_deglitch(data->vbus_pin, 1); ++ usba_udc_data.pdata.vbus_pin = data->vbus_pin; ++ } ++ ++ /* Pullup pin is handled internally by USB device peripheral */ ++ ++ /* Clocks */ ++ at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk"); ++ at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk"); ++ ++ platform_device_register(&at91_usba_udc_device); ++} ++#else ++void __init at91_add_device_usba(struct usba_platform_data *data) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * MMC / SD + * -------------------------------------------------------------------- */ + +@@ -105,10 +200,15 @@ + #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, + } + }; + +@@ -385,6 +485,100 @@ + + + /* -------------------------------------------------------------------- ++ * Timer/Counter block ++ * -------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ATMEL_TCLIB ++ ++static struct resource tcb_resources[] = { ++ [0] = { ++ .start = AT91SAM9RL_BASE_TCB0, ++ .end = AT91SAM9RL_BASE_TCB0 + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9RL_ID_TC0, ++ .end = AT91SAM9RL_ID_TC0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [2] = { ++ .start = AT91SAM9RL_ID_TC1, ++ .end = AT91SAM9RL_ID_TC1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [3] = { ++ .start = AT91SAM9RL_ID_TC2, ++ .end = AT91SAM9RL_ID_TC2, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device at91sam9rl_tcb_device = { ++ .name = "atmel_tcb", ++ .id = 0, ++ .resource = tcb_resources, ++ .num_resources = ARRAY_SIZE(tcb_resources), ++}; ++ ++static void __init at91_add_device_tc(void) ++{ ++ /* this chip has a separate clock and irq for each TC channel */ ++ at91_clock_associate("tc0_clk", &at91sam9rl_tcb_device.dev, "t0_clk"); ++ at91_clock_associate("tc1_clk", &at91sam9rl_tcb_device.dev, "t1_clk"); ++ at91_clock_associate("tc2_clk", &at91sam9rl_tcb_device.dev, "t2_clk"); ++ platform_device_register(&at91sam9rl_tcb_device); ++} ++#else ++static void __init at91_add_device_tc(void) { } ++#endif ++ ++ ++/* -------------------------------------------------------------------- ++ * Touchscreen ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE) ++static u64 tsadcc_dmamask = DMA_BIT_MASK(32); ++ ++static struct resource tsadcc_resources[] = { ++ [0] = { ++ .start = AT91SAM9RL_BASE_TSC, ++ .end = AT91SAM9RL_BASE_TSC + SZ_16K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = AT91SAM9RL_ID_TSC, ++ .end = AT91SAM9RL_ID_TSC, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device at91_tsadcc_device = { ++ .name = "atmel_tsadcc", ++ .id = -1, ++ .dev = { ++ .dma_mask = &tsadcc_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ }, ++ .resource = tsadcc_resources, ++ .num_resources = ARRAY_SIZE(tsadcc_resources), ++}; ++ ++void __init at91_add_device_tsadcc(void) ++{ ++ at91_set_A_periph(AT91_PIN_PA17, 0); /* AD0_XR */ ++ at91_set_A_periph(AT91_PIN_PA18, 0); /* AD1_XL */ ++ at91_set_A_periph(AT91_PIN_PA19, 0); /* AD2_YT */ ++ at91_set_A_periph(AT91_PIN_PA20, 0); /* AD3_TB */ ++ ++ platform_device_register(&at91_tsadcc_device); ++} ++#else ++void __init at91_add_device_tsadcc(void) {} ++#endif ++ ++ ++/* -------------------------------------------------------------------- + * RTC + * -------------------------------------------------------------------- */ + +@@ -397,6 +591,7 @@ + + static void __init at91_add_device_rtc(void) + { ++ device_init_wakeup(&at91sam9rl_rtc_device.dev, 1); + platform_device_register(&at91sam9rl_rtc_device); + } + #else +@@ -418,13 +613,14 @@ + + static struct platform_device at91sam9rl_rtt_device = { + .name = "at91_rtt", +- .id = -1, ++ .id = 0, + .resource = rtt_resources, + .num_resources = ARRAY_SIZE(rtt_resources), + }; + + static void __init at91_add_device_rtt(void) + { ++ device_init_wakeup(&at91sam9rl_rtt_device.dev, 1); + platform_device_register(&at91sam9rl_rtt_device); + } + +@@ -539,9 +735,6 @@ + } + + /* +- * Return the device node so that board init code can use it as the +- * parent for the device node reflecting how it's used on this board. +- * + * 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 +@@ -802,7 +995,7 @@ + at91_set_B_periph(AT91_PIN_PD3, 0); /* CTS3 */ + } + +-static struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ ++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 __deprecated at91_init_serial(struct at91_uart_config *config) +@@ -893,8 +1086,6 @@ + { + if (portnr < ATMEL_MAX_UART) + atmel_default_console_device = at91_uarts[portnr]; +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + + void __init at91_add_device_serial(void) +@@ -905,6 +1096,9 @@ + 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 __deprecated at91_init_serial(struct at91_uart_config *config) {} +@@ -925,6 +1119,7 @@ + at91_add_device_rtc(); + at91_add_device_rtt(); + at91_add_device_watchdog(); ++ at91_add_device_tc(); + return 0; + } + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-cam60.c linux-2.6/arch/arm/mach-at91/board-cam60.c +--- linux-2.6.25/arch/arm/mach-at91/board-cam60.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-cam60.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,180 @@ ++/* ++ * KwikByte CAM60 (KB9260) ++ * ++ * based on board-sam9260ek.c ++ * Copyright (C) 2005 SAN People ++ * Copyright (C) 2006 Atmel ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++ ++#include "generic.h" ++ ++ ++static void __init cam60_map_io(void) ++{ ++ /* Initialize processor: 10 MHz crystal */ ++ at91sam9260_initialize(10000000); ++ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init cam60_init_irq(void) ++{ ++ at91sam9260_init_interrupts(NULL); ++} ++ ++ ++/* ++ * USB Host ++ */ ++static struct at91_usbh_data __initdata cam60_usbh_data = { ++ .ports = 1, ++}; ++ ++ ++/* ++ * SPI devices. ++ */ ++#if defined(CONFIG_MTD_DATAFLASH) ++static struct mtd_partition __initdata cam60_spi_partitions[] = { ++ { ++ .name = "BOOT1", ++ .offset = 0, ++ .size = 4 * 1056, ++ }, ++ { ++ .name = "BOOT2", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 256 * 1056, ++ }, ++ { ++ .name = "kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 2222 * 1056, ++ }, ++ { ++ .name = "file system", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct flash_platform_data __initdata cam60_spi_flash_platform_data = { ++ .name = "spi_flash", ++ .parts = cam60_spi_partitions, ++ .nr_parts = ARRAY_SIZE(cam60_spi_partitions) ++}; ++#endif ++ ++static struct spi_board_info cam60_spi_devices[] = { ++#if defined(CONFIG_MTD_DATAFLASH) ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ .bus_num = 0, ++ .platform_data = &cam60_spi_flash_platform_data ++ }, ++#endif ++}; ++ ++ ++/* ++ * MACB Ethernet device ++ */ ++static struct __initdata at91_eth_data cam60_macb_data = { ++ .phy_irq_pin = AT91_PIN_PB5, ++ .is_rmii = 0, ++}; ++ ++ ++/* ++ * NAND Flash ++ */ ++static struct mtd_partition __initdata cam60_nand_partition[] = { ++ { ++ .name = "nand_fs", ++ .offset = 0, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(cam60_nand_partition); ++ return cam60_nand_partition; ++} ++ ++static struct at91_nand_data __initdata cam60_nand_data = { ++ .ale = 21, ++ .cle = 22, ++ // .det_pin = ... not there ++ .rdy_pin = AT91_PIN_PA9, ++ .enable_pin = AT91_PIN_PA7, ++ .partition_info = nand_partitions, ++}; ++ ++ ++static void __init cam60_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* SPI */ ++ at91_add_device_spi(cam60_spi_devices, ARRAY_SIZE(cam60_spi_devices)); ++ /* Ethernet */ ++ at91_add_device_eth(&cam60_macb_data); ++ /* USB Host */ ++ /* enable USB power supply circuit */ ++ at91_set_gpio_output(AT91_PIN_PB18, 1); ++ at91_add_device_usbh(&cam60_usbh_data); ++ /* NAND */ ++ at91_add_device_nand(&cam60_nand_data); ++} ++ ++MACHINE_START(CAM60, "KwikByte CAM60") ++ /* Maintainer: KwikByte */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91sam926x_timer, ++ .map_io = cam60_map_io, ++ .init_irq = cam60_init_irq, ++ .init_machine = cam60_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-cap9adk.c linux-2.6/arch/arm/mach-at91/board-cap9adk.c +--- linux-2.6.25/arch/arm/mach-at91/board-cap9adk.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-cap9adk.c 2008-05-05 22:01:39.000000000 +0200 +@@ -36,16 +36,14 @@ + #include <asm/hardware.h> + #include <asm/setup.h> + #include <asm/mach-types.h> +-#include <asm/irq.h> + + #include <asm/mach/arch.h> + #include <asm/mach/map.h> +-#include <asm/mach/irq.h> + + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> + #include <asm/arch/at91cap9_matrix.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91sam9_smc.h> + + #include "generic.h" + +@@ -78,6 +76,12 @@ + .ports = 2, + }; + ++/* ++ * USB HS Device port ++ */ ++static struct usba_platform_data __initdata cap9adk_usba_udc_data = { ++ .vbus_pin = AT91_PIN_PB31, ++}; + + /* + * ADS7846 Touchscreen +@@ -130,7 +134,7 @@ + { + .modalias = "ads7846", + .chip_select = 3, /* can be 2 or 3, depending on J2 jumper */ +- .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ ++ .max_speed_hz = 125000 * 16, /* max sample rate * clocks per sample */ + .bus_num = 0, + .platform_data = &ads_info, + .irq = AT91_PIN_PC4, +@@ -324,8 +328,9 @@ + /* Serial */ + at91_add_device_serial(); + /* USB Host */ +- set_irq_type(AT91CAP9_ID_UHP, IRQT_HIGH); + at91_add_device_usbh(&cap9adk_usbh_data); ++ /* USB HS */ ++ at91_add_device_usba(&cap9adk_usba_udc_data); + /* SPI */ + at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices)); + /* Touchscreen */ +@@ -341,7 +346,6 @@ + /* I2C */ + at91_add_device_i2c(NULL, 0); + /* LCD Controller */ +- set_irq_type(AT91CAP9_ID_LCDC, IRQT_HIGH); + at91_add_device_lcdc(&cap9adk_lcdc_data); + /* AC97 */ + at91_add_device_ac97(&cap9adk_ac97_data); +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-carmeva.c linux-2.6/arch/arm/mach-at91/board-carmeva.c +--- linux-2.6.25/arch/arm/mach-at91/board-carmeva.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-carmeva.c 2008-04-25 21:15:43.000000000 +0200 +@@ -40,24 +40,21 @@ + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata carmeva_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; +- + static void __init carmeva_map_io(void) + { + /* Initialize processor: 20.000 MHz crystal */ + at91rm9200_initialize(20000000, AT91RM9200_BGA); + +- /* Setup the serial ports and console */ +- at91_init_serial(&carmeva_uart_config); ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init carmeva_init_irq(void) +@@ -117,6 +114,30 @@ + }, + }; + ++static struct gpio_led carmeva_leds[] = { ++ { /* "user led 1", LED9 */ ++ .name = "led9", ++ .gpio = AT91_PIN_PA21, ++ .active_low = 1, ++ .default_trigger = "heartbeat", ++ }, ++ { /* "user led 2", LED10 */ ++ .name = "led10", ++ .gpio = AT91_PIN_PA25, ++ .active_low = 1, ++ }, ++ { /* "user led 3", LED11 */ ++ .name = "led11", ++ .gpio = AT91_PIN_PA26, ++ .active_low = 1, ++ }, ++ { /* "user led 4", LED12 */ ++ .name = "led12", ++ .gpio = AT91_PIN_PA18, ++ .active_low = 1, ++ } ++}; ++ + static void __init carmeva_board_init(void) + { + /* Serial */ +@@ -135,6 +156,8 @@ + // at91_add_device_cf(&carmeva_cf_data); + /* MMC */ + at91_add_device_mmc(0, &carmeva_mmc_data); ++ /* LEDs */ ++ at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds)); + } + + MACHINE_START(CARMEVA, "Carmeva") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-chub.c linux-2.6/arch/arm/mach-at91/board-chub.c +--- linux-2.6.25/arch/arm/mach-at91/board-chub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-chub.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,132 @@ ++/* ++ * linux/arch/arm/mach-at91/board-chub.c ++ * ++ * Copyright (C) 2005 SAN People, adapted for Promwad Chub board ++ * by Kuten Ivan ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++ ++#include "generic.h" ++ ++/* ++ * Serial port configuration. ++ * 0 .. 3 = USART0 .. USART3 ++ * 4 = DBGU ++ */ ++static struct at91_uart_config __initdata chub_uart_config = { ++ .console_tty = 0, /* ttyS0 */ ++ .nr_tty = 5, ++ .tty_map = { 4, 0, 1, 2, 3 } /* ttyS0, ..., ttyS4 */ ++}; ++ ++static void __init chub_init_irq(void) ++{ ++ at91rm9200_init_interrupts(NULL); ++} ++ ++static void __init chub_map_io(void) ++{ ++ /* Initialize clocks: 18.432 MHz crystal */ ++ at91rm9200_initialize(18432000, AT91RM9200_PQFP); ++ ++ /* Setup the serial ports and console */ ++ at91_init_serial(&chub_uart_config); ++} ++ ++static struct at91_eth_data __initdata chub_eth_data = { ++ .phy_irq_pin = AT91_PIN_PB29, ++ .is_rmii = 0, ++}; ++ ++static struct mtd_partition __initdata chub_nand_partition[] = { ++ { ++ .name = "NAND Partition 1", ++ .offset = 0, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(chub_nand_partition); ++ return chub_nand_partition; ++} ++ ++static struct at91_nand_data __initdata chub_nand_data = { ++ .ale = 22, ++ .cle = 21, ++ .enable_pin = AT91_PIN_PA27, ++ .partition_info = nand_partitions, ++}; ++ ++static struct spi_board_info chub_spi_devices[] = { ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ }, ++}; ++ ++static void __init chub_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++ /* Ethernet */ ++ at91_add_device_eth(&chub_eth_data); ++ /* SPI */ ++ at91_add_device_spi(chub_spi_devices, ARRAY_SIZE(chub_spi_devices)); ++ /* NAND Flash */ ++ at91_add_device_nand(&chub_nand_data); ++ /* Disable write protect for NAND */ ++ at91_set_gpio_output(AT91_PIN_PB7, 1); ++ /* Power enable for 3x RS-232 and 1x RS-485 */ ++ at91_set_gpio_output(AT91_PIN_PB9, 1); ++ /* Disable write protect for FRAM */ ++ at91_set_gpio_output(AT91_PIN_PA21, 1); ++ /* Disable write protect for Dataflash */ ++ at91_set_gpio_output(AT91_PIN_PA19, 1); ++} ++ ++MACHINE_START(CHUB, "Promwad Chub") ++ /* Maintainer: Ivan Kuten AT Promwad DOT com */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91rm9200_timer, ++ .map_io = chub_map_io, ++ .init_irq = chub_init_irq, ++ .init_machine = chub_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-csb337.c linux-2.6/arch/arm/mach-at91/board-csb337.c +--- linux-2.6.25/arch/arm/mach-at91/board-csb337.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-csb337.c 2008-05-02 00:05:42.000000000 +0200 +@@ -61,6 +61,7 @@ + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); ++ at91_set_gpio_output(AT91_PIN_PB2, 1); /* third (unused) LED */ + + /* Setup the serial ports and console */ + at91_init_serial(&csb337_uart_config); +@@ -202,11 +203,11 @@ + + static void __init csb300_add_device_buttons(void) + { +- at91_set_gpio_input(AT91_PIN_PB29, 0); /* sw0 */ ++ at91_set_gpio_input(AT91_PIN_PB29, 1); /* sw0 */ + at91_set_deglitch(AT91_PIN_PB29, 1); +- at91_set_gpio_input(AT91_PIN_PB28, 0); /* sw1 */ ++ at91_set_gpio_input(AT91_PIN_PB28, 1); /* sw1 */ + at91_set_deglitch(AT91_PIN_PB28, 1); +- at91_set_gpio_input(AT91_PIN_PA21, 0); /* sw2 */ ++ at91_set_gpio_input(AT91_PIN_PA21, 1); /* sw2 */ + at91_set_deglitch(AT91_PIN_PA21, 1); + + platform_device_register(&csb300_button_device); +@@ -233,7 +234,7 @@ + .gpio = AT91_PIN_PB0, + .active_low = 1, + .default_trigger = "ide-disk", +- }, ++ } + }; + + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-csb637.c linux-2.6/arch/arm/mach-at91/board-csb637.c +--- linux-2.6.25/arch/arm/mach-at91/board-csb637.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-csb637.c 2008-04-25 21:15:43.000000000 +0200 +@@ -40,27 +40,16 @@ + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata csb637_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; +- + static void __init csb637_map_io(void) + { + /* Initialize processor: 3.6864 MHz crystal */ + at91rm9200_initialize(3686400, AT91RM9200_BGA); + +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + +- /* Setup the serial ports and console */ +- at91_init_serial(&csb637_uart_config); ++ /* make console=ttyS0 (ie, DBGU) the default */ ++ at91_set_serial_console(0); + } + + static void __init csb637_init_irq(void) +@@ -118,8 +107,19 @@ + .num_resources = ARRAY_SIZE(csb_flash_resources), + }; + ++static struct gpio_led csb_leds[] = { ++ { /* "d1", red */ ++ .name = "d1", ++ .gpio = AT91_PIN_PB2, ++ .active_low = 1, ++ .default_trigger = "heartbeat", ++ } ++}; ++ + static void __init csb637_board_init(void) + { ++ /* LED(s) */ ++ at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds)); + /* Serial */ + at91_add_device_serial(); + /* Ethernet */ +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-dk.c linux-2.6/arch/arm/mach-at91/board-dk.c +--- linux-2.6.25/arch/arm/mach-at91/board-dk.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-dk.c 2008-05-03 00:44:06.000000000 +0200 +@@ -25,6 +25,7 @@ + #include <linux/init.h> + #include <linux/mm.h> + #include <linux/module.h> ++#include <linux/dma-mapping.h> + #include <linux/platform_device.h> + #include <linux/spi/spi.h> + #include <linux/mtd/physmap.h> +@@ -45,17 +46,6 @@ + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata dk_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; +- + static void __init dk_map_io(void) + { + /* Initialize processor: 18.432 MHz crystal */ +@@ -64,8 +54,16 @@ + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + +- /* Setup the serial ports and console */ +- at91_init_serial(&dk_uart_config); ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init dk_init_irq(void) +@@ -73,6 +71,185 @@ + at91rm9200_init_interrupts(NULL); + } + ++#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE) ++#include <video/s1d13xxxfb.h> ++#include <asm/arch/ics1523.h> ++ ++/* EPSON S1D13806 FB */ ++#define AT91_FB_REG_BASE 0x30000000L ++#define AT91_FB_REG_SIZE 0x200 ++#define AT91_FB_VMEM_BASE 0x30200000L ++#define AT91_FB_VMEM_SIZE 0x140000L ++ ++static void dk_init_video(void) ++{ ++ /* NWAIT Signal */ ++ at91_set_A_periph(AT91_PIN_PC6, 0); ++ ++ /* Initialization of the Static Memory Controller for Chip Select 2 */ ++ at91_sys_write(AT91_SMC_CSR(2), AT91_SMC_DBW_16 /* 16 bit */ ++ | AT91_SMC_WSEN | AT91_SMC_NWS_(4) /* wait states */ ++ | AT91_SMC_TDF_(1) /* float time */ ++ ); ++ ++ at91_ics1523_init(); ++} ++ ++/* CRT: (active) 640x480 60Hz (PCLK=CLKI=25.175MHz) ++ Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=60.000MHz) */ ++static const struct s1d13xxxfb_regval dk_s1dfb_initregs[] = { ++ {S1DREG_MISC, 0x00}, /* Enable Memory/Register select bit */ ++ {S1DREG_COM_DISP_MODE, 0x00}, /* disable display output */ ++ {S1DREG_GPIO_CNF0, 0x00}, ++ {S1DREG_GPIO_CNF1, 0x00}, ++ {S1DREG_GPIO_CTL0, 0x08}, ++ {S1DREG_GPIO_CTL1, 0x00}, ++ {S1DREG_CLK_CNF, 0x01}, /* no divide, MCLK source is CLKI3 0x02*/ ++ {S1DREG_LCD_CLK_CNF, 0x00}, ++ {S1DREG_CRT_CLK_CNF, 0x00}, ++ {S1DREG_MPLUG_CLK_CNF, 0x00}, ++ {S1DREG_CPU2MEM_WST_SEL, 0x01}, /* 2*period(MCLK) - 4ns > period(BCLK) */ ++ {S1DREG_SDRAM_REF_RATE, 0x03}, /* 32768 <= MCLK <= 50000 (MHz) */ ++ {S1DREG_SDRAM_TC0, 0x00}, /* MCLK source freq (MHz): */ ++ {S1DREG_SDRAM_TC1, 0x01}, /* 42 <= MCLK <= 50 */ ++ {S1DREG_MEM_CNF, 0x80}, /* SDRAM Initialization - needed before mem access */ ++ {S1DREG_PANEL_TYPE, 0x25}, /* std TFT 16bit, 8bit SCP format 2, single passive LCD */ ++ {S1DREG_MOD_RATE, 0x00}, /* toggle every FPFRAME */ ++ {S1DREG_LCD_DISP_HWIDTH, 0x4F}, /* 680 pix */ ++ {S1DREG_LCD_NDISP_HPER, 0x12}, /* 152 pix */ ++ {S1DREG_TFT_FPLINE_START, 0x01}, /* 13 pix */ ++ {S1DREG_TFT_FPLINE_PWIDTH, 0x0B}, /* 96 pix */ ++ {S1DREG_LCD_DISP_VHEIGHT0, 0xDF}, ++ {S1DREG_LCD_DISP_VHEIGHT1, 0x01}, /* 480 lines */ ++ {S1DREG_LCD_NDISP_VPER, 0x2C}, /* 44 lines */ ++ {S1DREG_TFT_FPFRAME_START, 0x0A}, /* 10 lines */ ++ {S1DREG_TFT_FPFRAME_PWIDTH, 0x01}, /* 2 lines */ ++ {S1DREG_LCD_DISP_MODE, 0x05}, /* 16 bpp */ ++ {S1DREG_LCD_MISC, 0x00}, /* dithering enabled, dual panel buffer enabled */ ++ {S1DREG_LCD_DISP_START0, 0x00}, ++ {S1DREG_LCD_DISP_START1, 0xC8}, ++ {S1DREG_LCD_DISP_START2, 0x00}, ++ {S1DREG_LCD_MEM_OFF0, 0x80}, ++ {S1DREG_LCD_MEM_OFF1, 0x02}, ++ {S1DREG_LCD_PIX_PAN, 0x00}, ++ {S1DREG_LCD_DISP_FIFO_HTC, 0x3B}, ++ {S1DREG_LCD_DISP_FIFO_LTC, 0x3C}, ++ {S1DREG_CRT_DISP_HWIDTH, 0x4F}, /* 680 pix */ ++ {S1DREG_CRT_NDISP_HPER, 0x13}, /* 160 pix */ ++ {S1DREG_CRT_HRTC_START, 0x01}, /* 13 pix */ ++ {S1DREG_CRT_HRTC_PWIDTH, 0x0B}, /* 96 pix */ ++ {S1DREG_CRT_DISP_VHEIGHT0, 0xDF}, ++ {S1DREG_CRT_DISP_VHEIGHT1, 0x01}, /* 480 lines */ ++ {S1DREG_CRT_NDISP_VPER, 0x2B}, /* 44 lines */ ++ {S1DREG_CRT_VRTC_START, 0x09}, /* 10 lines */ ++ {S1DREG_CRT_VRTC_PWIDTH, 0x01}, /* 2 lines */ ++ {S1DREG_TV_OUT_CTL, 0x10}, ++ {S1DREG_CRT_DISP_MODE, 0x05}, /* 16 bpp */ ++ {S1DREG_CRT_DISP_START0, 0x00}, ++ {S1DREG_CRT_DISP_START1, 0x00}, ++ {S1DREG_CRT_DISP_START2, 0x00}, ++ {S1DREG_CRT_MEM_OFF0, 0x80}, ++ {S1DREG_CRT_MEM_OFF1, 0x02}, ++ {S1DREG_CRT_PIX_PAN, 0x00}, ++ {S1DREG_CRT_DISP_FIFO_HTC, 0x3B}, ++ {S1DREG_CRT_DISP_FIFO_LTC, 0x3C}, ++ {S1DREG_LCD_CUR_CTL, 0x00}, /* inactive */ ++ {S1DREG_LCD_CUR_START, 0x01}, ++ {S1DREG_LCD_CUR_XPOS0, 0x00}, ++ {S1DREG_LCD_CUR_XPOS1, 0x00}, ++ {S1DREG_LCD_CUR_YPOS0, 0x00}, ++ {S1DREG_LCD_CUR_YPOS1, 0x00}, ++ {S1DREG_LCD_CUR_BCTL0, 0x00}, ++ {S1DREG_LCD_CUR_GCTL0, 0x00}, ++ {S1DREG_LCD_CUR_RCTL0, 0x00}, ++ {S1DREG_LCD_CUR_BCTL1, 0x1F}, ++ {S1DREG_LCD_CUR_GCTL1, 0x3F}, ++ {S1DREG_LCD_CUR_RCTL1, 0x1F}, ++ {S1DREG_LCD_CUR_FIFO_HTC, 0x00}, ++ {S1DREG_CRT_CUR_CTL, 0x00}, /* inactive */ ++ {S1DREG_CRT_CUR_START, 0x01}, ++ {S1DREG_CRT_CUR_XPOS0, 0x00}, ++ {S1DREG_CRT_CUR_XPOS1, 0x00}, ++ {S1DREG_CRT_CUR_YPOS0, 0x00}, ++ {S1DREG_CRT_CUR_YPOS1, 0x00}, ++ {S1DREG_CRT_CUR_BCTL0, 0x00}, ++ {S1DREG_CRT_CUR_GCTL0, 0x00}, ++ {S1DREG_CRT_CUR_RCTL0, 0x00}, ++ {S1DREG_CRT_CUR_BCTL1, 0x1F}, ++ {S1DREG_CRT_CUR_GCTL1, 0x3F}, ++ {S1DREG_CRT_CUR_RCTL1, 0x1F}, ++ {S1DREG_CRT_CUR_FIFO_HTC, 0x00}, ++ {S1DREG_BBLT_CTL0, 0x00}, ++ {S1DREG_BBLT_CTL0, 0x00}, ++ {S1DREG_BBLT_CC_EXP, 0x00}, ++ {S1DREG_BBLT_OP, 0x00}, ++ {S1DREG_BBLT_SRC_START0, 0x00}, ++ {S1DREG_BBLT_SRC_START1, 0x00}, ++ {S1DREG_BBLT_SRC_START2, 0x00}, ++ {S1DREG_BBLT_DST_START0, 0x00}, ++ {S1DREG_BBLT_DST_START1, 0x00}, ++ {S1DREG_BBLT_DST_START2, 0x00}, ++ {S1DREG_BBLT_MEM_OFF0, 0x00}, ++ {S1DREG_BBLT_MEM_OFF1, 0x00}, ++ {S1DREG_BBLT_WIDTH0, 0x00}, ++ {S1DREG_BBLT_WIDTH1, 0x00}, ++ {S1DREG_BBLT_HEIGHT0, 0x00}, ++ {S1DREG_BBLT_HEIGHT1, 0x00}, ++ {S1DREG_BBLT_BGC0, 0x00}, ++ {S1DREG_BBLT_BGC1, 0x00}, ++ {S1DREG_BBLT_FGC0, 0x00}, ++ {S1DREG_BBLT_FGC1, 0x00}, ++ {S1DREG_LKUP_MODE, 0x00}, /* LCD LUT r | LCD and CRT/TV LUT w */ ++ {S1DREG_LKUP_ADDR, 0x00}, ++ {S1DREG_PS_CNF, 0x00}, /* Power Save disable */ ++ {S1DREG_PS_STATUS, 0x02}, /* LCD Panel down, mem up */ ++ {S1DREG_CPU2MEM_WDOGT, 0x00}, ++ {S1DREG_COM_DISP_MODE, 0x02}, /* enable CRT display output */ ++}; ++ ++static struct s1d13xxxfb_pdata dk_s1dfb_pdata = { ++ .initregs = dk_s1dfb_initregs, ++ .initregssize = ARRAY_SIZE(dk_s1dfb_initregs), ++ .platform_init_video = dk_init_video, ++}; ++ ++static u64 s1dfb_dmamask = DMA_BIT_MASK(32); ++ ++static struct resource dk_s1dfb_resource[] = { ++ [0] = { /* video mem */ ++ .name = "s1d13806 memory", ++ .start = AT91_FB_VMEM_BASE, ++ .end = AT91_FB_VMEM_BASE + AT91_FB_VMEM_SIZE -1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { /* video registers */ ++ .name = "s1d13806 registers", ++ .start = AT91_FB_REG_BASE, ++ .end = AT91_FB_REG_BASE + AT91_FB_REG_SIZE -1, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct platform_device dk_s1dfb_device = { ++ .name = "s1d13806fb", ++ .id = -1, ++ .dev = { ++ .dma_mask = &s1dfb_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &dk_s1dfb_pdata, ++ }, ++ .resource = dk_s1dfb_resource, ++ .num_resources = ARRAY_SIZE(dk_s1dfb_resource), ++}; ++ ++static void __init dk_add_device_video(void) ++{ ++ platform_device_register(&dk_s1dfb_device); ++} ++#else ++static void __init dk_add_device_video(void) {} ++#endif ++ + static struct at91_eth_data __initdata dk_eth_data = { + .phy_irq_pin = AT91_PIN_PC4, + .is_rmii = 1, +@@ -164,7 +341,7 @@ + #define DK_FLASH_SIZE 0x200000 + + static struct physmap_flash_data dk_flash_data = { +- .width = 2, ++ .width = 2, + }; + + static struct resource dk_flash_resource = { +@@ -223,8 +400,12 @@ + platform_device_register(&dk_flash); + /* LEDs */ + at91_gpio_leds(dk_leds, ARRAY_SIZE(dk_leds)); ++ /* SSC (to LM4549 audio codec) */ ++ at91_add_device_ssc(AT91RM9200_ID_SSC1, ATMEL_SSC_TD | ATMEL_SSC_RX); ++ /* SSC (to SI3021 line interface) */ ++ at91_add_device_ssc(AT91RM9200_ID_SSC2, ATMEL_SSC_TD | ATMEL_SSC_TK | ATMEL_SSC_RD | ATMEL_SSC_RF); + /* VGA */ +-// dk_add_device_video(); ++ dk_add_device_video(); + } + + MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-eb9200.c linux-2.6/arch/arm/mach-at91/board-eb9200.c +--- linux-2.6.25/arch/arm/mach-at91/board-eb9200.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-eb9200.c 2008-04-25 21:15:43.000000000 +0200 +@@ -40,24 +40,24 @@ + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata eb9200_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; +- + static void __init eb9200_map_io(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91rm9200_initialize(18432000, AT91RM9200_BGA); + +- /* Setup the serial ports and console */ +- at91_init_serial(&eb9200_uart_config); ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART2 on ttyS2. (Rx, Tx) - IRDA */ ++ at91_register_uart(AT91RM9200_ID_US2, 2, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init eb9200_init_irq(void) +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-ecbat91.c linux-2.6/arch/arm/mach-at91/board-ecbat91.c +--- linux-2.6.25/arch/arm/mach-at91/board-ecbat91.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-ecbat91.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,178 @@ ++/* ++ * linux/arch/arm/mach-at91rm9200/board-ecbat91.c ++ * Copyright (C) 2007 emQbit.com. ++ * ++ * We started from board-dk.c, which is Copyright (C) 2005 SAN People. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++ ++#include "generic.h" ++ ++ ++static void __init ecb_at91map_io(void) ++{ ++ /* Initialize processor: 18.432 MHz crystal */ ++ at91rm9200_initialize(18432000, AT91RM9200_PQFP); ++ ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7); ++ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init ecb_at91init_irq(void) ++{ ++ at91rm9200_init_interrupts(NULL); ++} ++ ++static struct at91_eth_data __initdata ecb_at91eth_data = { ++ .phy_irq_pin = AT91_PIN_PC4, ++ .is_rmii = 0, ++}; ++ ++static struct at91_usbh_data __initdata ecb_at91usbh_data = { ++ .ports = 1, ++}; ++ ++static struct at91_mmc_data __initdata ecb_at91mmc_data = { ++ .slot_b = 0, ++ .wire4 = 1, ++}; ++ ++ ++#if defined(CONFIG_MTD_DATAFLASH) ++static struct mtd_partition __initdata my_flash0_partitions[] = ++{ ++ { /* 0x8400 */ ++ .name = "Darrell-loader", ++ .offset = 0, ++ .size = 12* 1056, ++ }, ++ { ++ .name = "U-boot", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 110 * 1056, ++ }, ++ { /* 1336 (167 blocks) pages * 1056 bytes = 0x158700 bytes */ ++ .name = "Uoot-env", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 8 * 1056, ++ }, ++ { /* 1336 (167 blocks) pages * 1056 bytes = 0x158700 bytes */ ++ .name = "Kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 1534 * 1056, ++ }, ++ { /* 190200 - jffs2 root filesystem */ ++ .name = "Filesystem", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, /* 26 sectors */ ++ } ++}; ++ ++static struct flash_platform_data __initdata my_flash0_platform = { ++ .name = "Removable flash card", ++ .parts = my_flash0_partitions, ++ .nr_parts = ARRAY_SIZE(my_flash0_partitions) ++}; ++ ++#endif ++ ++static struct spi_board_info __initdata ecb_at91spi_devices[] = { ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 10 * 1000 * 1000, ++ .bus_num = 0, ++#if defined(CONFIG_MTD_DATAFLASH) ++ .platform_data = &my_flash0_platform, ++#endif ++ }, ++ { /* User accessable spi - cs1 (250KHz) */ ++ .modalias = "spi-cs1", ++ .chip_select = 1, ++ .max_speed_hz = 250 * 1000, ++ }, ++ { /* User accessable spi - cs2 (1MHz) */ ++ .modalias = "spi-cs2", ++ .chip_select = 2, ++ .max_speed_hz = 1 * 1000 * 1000, ++ }, ++ { /* User accessable spi - cs3 (10MHz) */ ++ .modalias = "spi-cs3", ++ .chip_select = 3, ++ .max_speed_hz = 10 * 1000 * 1000, ++ }, ++}; ++ ++static void __init ecb_at91board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ ++ /* Ethernet */ ++ at91_add_device_eth(&ecb_at91eth_data); ++ ++ /* USB Host */ ++ at91_add_device_usbh(&ecb_at91usbh_data); ++ ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++ ++ /* MMC */ ++ at91_add_device_mmc(0, &ecb_at91mmc_data); ++ ++ /* SPI */ ++ at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices)); ++} ++ ++MACHINE_START(ECBAT91, "emQbit's ECB_AT91") ++ /* Maintainer: emQbit.com */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91rm9200_timer, ++ .map_io = ecb_at91map_io, ++ .init_irq = ecb_at91init_irq, ++ .init_machine = ecb_at91board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-ek.c linux-2.6/arch/arm/mach-at91/board-ek.c +--- linux-2.6.25/arch/arm/mach-at91/board-ek.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-ek.c 2008-05-03 00:44:38.000000000 +0200 +@@ -25,6 +25,7 @@ + #include <linux/init.h> + #include <linux/mm.h> + #include <linux/module.h> ++#include <linux/dma-mapping.h> + #include <linux/platform_device.h> + #include <linux/spi/spi.h> + #include <linux/mtd/physmap.h> +@@ -45,17 +46,6 @@ + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata ek_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; +- + static void __init ek_map_io(void) + { + /* Initialize processor: 18.432 MHz crystal */ +@@ -64,8 +54,16 @@ + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); + +- /* Setup the serial ports and console */ +- at91_init_serial(&ek_uart_config); ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init ek_init_irq(void) +@@ -73,6 +71,187 @@ + at91rm9200_init_interrupts(NULL); + } + ++#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE) ++#include <video/s1d13xxxfb.h> ++#include <asm/arch/ics1523.h> ++ ++/* EPSON S1D13806 FB */ ++#define AT91_FB_REG_BASE 0x40000000L ++#define AT91_FB_REG_SIZE 0x200 ++#define AT91_FB_VMEM_BASE 0x40200000L ++#define AT91_FB_VMEM_SIZE 0x140000L ++ ++static void ek_init_video(void) ++{ ++ /* NWAIT Signal */ ++ at91_set_A_periph(AT91_PIN_PC6, 0); ++ ++ /* Initialization of the Static Memory Controller for Chip Select 3 */ ++ at91_sys_write(AT91_SMC_CSR(3), AT91_SMC_DBW_16 /* 16 bit */ ++ | AT91_SMC_WSEN | AT91_SMC_NWS_(5) /* wait states */ ++ | AT91_SMC_TDF_(1) /* float time */ ++ ); ++ ++ at91_ics1523_init(); ++} ++ ++/* CRT: (active) 640x480 60Hz (PCLK=CLKI=25.175MHz) ++ Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=60.000MHz) */ ++static const struct s1d13xxxfb_regval ek_s1dfb_initregs[] = { ++ {S1DREG_MISC, 0x00}, /* Enable Memory/Register select bit */ ++ {S1DREG_COM_DISP_MODE, 0x00}, /* disable display output */ ++ {S1DREG_GPIO_CNF0, 0xFF}, // 0x00 ++ {S1DREG_GPIO_CNF1, 0x1F}, // 0x08 ++ {S1DREG_GPIO_CTL0, 0x00}, ++ {S1DREG_GPIO_CTL1, 0x00}, ++ {S1DREG_CLK_CNF, 0x01}, /* no divide, MCLK source is CLKI3 0x02*/ ++ {S1DREG_LCD_CLK_CNF, 0x00}, ++ {S1DREG_CRT_CLK_CNF, 0x00}, ++ {S1DREG_MPLUG_CLK_CNF, 0x00}, ++ {S1DREG_CPU2MEM_WST_SEL, 0x01}, /* 2*period(MCLK) - 4ns > period(BCLK) */ ++ {S1DREG_SDRAM_REF_RATE, 0x03}, /* 32768 <= MCLK <= 50000 (MHz) */ ++ {S1DREG_SDRAM_TC0, 0x00}, /* MCLK source freq (MHz): */ ++ {S1DREG_SDRAM_TC1, 0x01}, /* 42 <= MCLK <= 50 */ ++ {S1DREG_MEM_CNF, 0x80}, /* SDRAM Initialization - needed before mem access */ ++ {S1DREG_PANEL_TYPE, 0x25}, /* std TFT 16bit, 8bit SCP format 2, single passive LCD */ ++ {S1DREG_MOD_RATE, 0x00}, /* toggle every FPFRAME */ ++ {S1DREG_LCD_DISP_HWIDTH, 0x4F}, /* 680 pix */ ++ {S1DREG_LCD_NDISP_HPER, 0x12}, /* 152 pix */ ++ {S1DREG_TFT_FPLINE_START, 0x01}, /* 13 pix */ ++ {S1DREG_TFT_FPLINE_PWIDTH, 0x0B}, /* 96 pix */ ++ {S1DREG_LCD_DISP_VHEIGHT0, 0xDF}, ++ {S1DREG_LCD_DISP_VHEIGHT1, 0x01}, /* 480 lines */ ++ {S1DREG_LCD_NDISP_VPER, 0x2C}, /* 44 lines */ ++ {S1DREG_TFT_FPFRAME_START, 0x0A}, /* 10 lines */ ++ {S1DREG_TFT_FPFRAME_PWIDTH, 0x01}, /* 2 lines */ ++ {S1DREG_LCD_DISP_MODE, 0x05}, /* 16 bpp */ ++ {S1DREG_LCD_MISC, 0x00}, /* dithering enabled, dual panel buffer enabled */ ++ {S1DREG_LCD_DISP_START0, 0x00}, ++ {S1DREG_LCD_DISP_START1, 0xC8}, ++ {S1DREG_LCD_DISP_START2, 0x00}, ++ {S1DREG_LCD_MEM_OFF0, 0x80}, ++ {S1DREG_LCD_MEM_OFF1, 0x02}, ++ {S1DREG_LCD_PIX_PAN, 0x00}, ++ {S1DREG_LCD_DISP_FIFO_HTC, 0x3B}, ++ {S1DREG_LCD_DISP_FIFO_LTC, 0x3C}, ++ {S1DREG_CRT_DISP_HWIDTH, 0x4F}, /* 680 pix */ ++ {S1DREG_CRT_NDISP_HPER, 0x13}, /* 160 pix */ ++ {S1DREG_CRT_HRTC_START, 0x01}, /* 13 pix */ ++ {S1DREG_CRT_HRTC_PWIDTH, 0x0B}, /* 96 pix */ ++ {S1DREG_CRT_DISP_VHEIGHT0, 0xDF}, ++ {S1DREG_CRT_DISP_VHEIGHT1, 0x01}, /* 480 lines */ ++ {S1DREG_CRT_NDISP_VPER, 0x2B}, /* 44 lines */ ++ {S1DREG_CRT_VRTC_START, 0x09}, /* 10 lines */ ++ {S1DREG_CRT_VRTC_PWIDTH, 0x01}, /* 2 lines */ ++ {S1DREG_TV_OUT_CTL, 0x10}, ++ {0x005E, 0x9F}, ++ {0x005F, 0x00}, ++ {S1DREG_CRT_DISP_MODE, 0x05}, /* 16 bpp */ ++ {S1DREG_CRT_DISP_START0, 0x00}, ++ {S1DREG_CRT_DISP_START1, 0x00}, ++ {S1DREG_CRT_DISP_START2, 0x00}, ++ {S1DREG_CRT_MEM_OFF0, 0x80}, ++ {S1DREG_CRT_MEM_OFF1, 0x02}, ++ {S1DREG_CRT_PIX_PAN, 0x00}, ++ {S1DREG_CRT_DISP_FIFO_HTC, 0x3B}, ++ {S1DREG_CRT_DISP_FIFO_LTC, 0x3C}, ++ {S1DREG_LCD_CUR_CTL, 0x00}, /* inactive */ ++ {S1DREG_LCD_CUR_START, 0x01}, ++ {S1DREG_LCD_CUR_XPOS0, 0x00}, ++ {S1DREG_LCD_CUR_XPOS1, 0x00}, ++ {S1DREG_LCD_CUR_YPOS0, 0x00}, ++ {S1DREG_LCD_CUR_YPOS1, 0x00}, ++ {S1DREG_LCD_CUR_BCTL0, 0x00}, ++ {S1DREG_LCD_CUR_GCTL0, 0x00}, ++ {S1DREG_LCD_CUR_RCTL0, 0x00}, ++ {S1DREG_LCD_CUR_BCTL1, 0x1F}, ++ {S1DREG_LCD_CUR_GCTL1, 0x3F}, ++ {S1DREG_LCD_CUR_RCTL1, 0x1F}, ++ {S1DREG_LCD_CUR_FIFO_HTC, 0x00}, ++ {S1DREG_CRT_CUR_CTL, 0x00}, /* inactive */ ++ {S1DREG_CRT_CUR_START, 0x01}, ++ {S1DREG_CRT_CUR_XPOS0, 0x00}, ++ {S1DREG_CRT_CUR_XPOS1, 0x00}, ++ {S1DREG_CRT_CUR_YPOS0, 0x00}, ++ {S1DREG_CRT_CUR_YPOS1, 0x00}, ++ {S1DREG_CRT_CUR_BCTL0, 0x00}, ++ {S1DREG_CRT_CUR_GCTL0, 0x00}, ++ {S1DREG_CRT_CUR_RCTL0, 0x00}, ++ {S1DREG_CRT_CUR_BCTL1, 0x1F}, ++ {S1DREG_CRT_CUR_GCTL1, 0x3F}, ++ {S1DREG_CRT_CUR_RCTL1, 0x1F}, ++ {S1DREG_CRT_CUR_FIFO_HTC, 0x00}, ++ {S1DREG_BBLT_CTL0, 0x00}, ++ {S1DREG_BBLT_CTL0, 0x00}, ++ {S1DREG_BBLT_CC_EXP, 0x00}, ++ {S1DREG_BBLT_OP, 0x00}, ++ {S1DREG_BBLT_SRC_START0, 0x00}, ++ {S1DREG_BBLT_SRC_START1, 0x00}, ++ {S1DREG_BBLT_SRC_START2, 0x00}, ++ {S1DREG_BBLT_DST_START0, 0x00}, ++ {S1DREG_BBLT_DST_START1, 0x00}, ++ {S1DREG_BBLT_DST_START2, 0x00}, ++ {S1DREG_BBLT_MEM_OFF0, 0x00}, ++ {S1DREG_BBLT_MEM_OFF1, 0x00}, ++ {S1DREG_BBLT_WIDTH0, 0x00}, ++ {S1DREG_BBLT_WIDTH1, 0x00}, ++ {S1DREG_BBLT_HEIGHT0, 0x00}, ++ {S1DREG_BBLT_HEIGHT1, 0x00}, ++ {S1DREG_BBLT_BGC0, 0x00}, ++ {S1DREG_BBLT_BGC1, 0x00}, ++ {S1DREG_BBLT_FGC0, 0x00}, ++ {S1DREG_BBLT_FGC1, 0x00}, ++ {S1DREG_LKUP_MODE, 0x00}, /* LCD LUT r | LCD and CRT/TV LUT w */ ++ {S1DREG_LKUP_ADDR, 0x00}, ++ {S1DREG_PS_CNF, 0x10}, /* Power Save disable */ ++ {S1DREG_PS_STATUS, 0x02}, /* LCD Panel down, mem up */ ++ {S1DREG_CPU2MEM_WDOGT, 0x00}, ++ {S1DREG_COM_DISP_MODE, 0x02}, /* enable CRT display output */ ++}; ++ ++static struct s1d13xxxfb_pdata ek_s1dfb_pdata = { ++ .initregs = ek_s1dfb_initregs, ++ .initregssize = ARRAY_SIZE(ek_s1dfb_initregs), ++ .platform_init_video = ek_init_video, ++}; ++ ++static u64 s1dfb_dmamask = DMA_BIT_MASK(32); ++ ++static struct resource ek_s1dfb_resource[] = { ++ [0] = { /* video mem */ ++ .name = "s1d13806 memory", ++ .start = AT91_FB_VMEM_BASE, ++ .end = AT91_FB_VMEM_BASE + AT91_FB_VMEM_SIZE -1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { /* video registers */ ++ .name = "s1d13806 registers", ++ .start = AT91_FB_REG_BASE, ++ .end = AT91_FB_REG_BASE + AT91_FB_REG_SIZE -1, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct platform_device ek_s1dfb_device = { ++ .name = "s1d13806fb", ++ .id = -1, ++ .dev = { ++ .dma_mask = &s1dfb_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &ek_s1dfb_pdata, ++ }, ++ .resource = ek_s1dfb_resource, ++ .num_resources = ARRAY_SIZE(ek_s1dfb_resource), ++}; ++ ++static void __init ek_add_device_video(void) ++{ ++ platform_device_register(&ek_s1dfb_device); ++} ++#else ++static void __init ek_add_device_video(void) {} ++#endif ++ + static struct at91_eth_data __initdata ek_eth_data = { + .phy_irq_pin = AT91_PIN_PC4, + .is_rmii = 1, +@@ -122,7 +301,7 @@ + #define EK_FLASH_SIZE 0x200000 + + static struct physmap_flash_data ek_flash_data = { +- .width = 2, ++ .width = 2, + }; + + static struct resource ek_flash_resource = { +@@ -189,7 +368,7 @@ + /* LEDs */ + at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); + /* VGA */ +-// ek_add_device_video(); ++ ek_add_device_video(); + } + + MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-homematic.c linux-2.6/arch/arm/mach-at91/board-homematic.c +--- linux-2.6.25/arch/arm/mach-at91/board-homematic.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-homematic.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,163 @@ ++/* ++ * linux/arch/arm/mach-at91/board-homematic.c ++ * ++ * Copyright (C) 2007 eQ-3 Entwicklung GmbH ++ * ++ * based on work ++ * Copyright (C) 2005 SAN People ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/mtd/physmap.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++#include <asm/arch/at91rm9200_mc.h> ++ ++#include "generic.h" ++ ++ ++/* ++ * Serial port configuration. ++ * 0 .. 3 = USART0 .. USART3 ++ * 4 = DBGU ++ */ ++static struct at91_uart_config __initdata homematic_uart_config = { ++ .console_tty = 0, /* ttyS0 */ ++ .nr_tty = 2, ++ .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ ++}; ++ ++static void __init homematic_map_io(void) ++{ ++ /* Initialize processor: 18.432 MHz crystal */ ++ at91rm9200_initialize(18432000, AT91RM9200_BGA); ++ ++ /* Setup the serial ports and console */ ++ at91_init_serial(&homematic_uart_config); ++} ++ ++static void __init homematic_init_irq(void) ++{ ++ at91rm9200_init_interrupts(NULL); ++} ++ ++static struct at91_eth_data __initdata homematic_eth_data = { ++ .phy_irq_pin = AT91_PIN_PC4, ++ .is_rmii = 0, ++}; ++ ++static struct at91_usbh_data __initdata homematic_usbh_data = { ++ .ports = 2, ++}; ++ ++static struct at91_udc_data __initdata homematic_udc_data = { ++ .vbus_pin = AT91_PIN_PD4, ++ .pullup_pin = AT91_PIN_PD5, ++}; ++ ++static struct at91_mmc_data __initdata homematic_mmc_data = { ++ .slot_b = 0, ++ .wire4 = 1, ++}; ++ ++static struct spi_board_info homematic_spi_devices[] = { ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ }, ++}; ++ ++static struct mtd_partition __initdata homematic_nand_partition[] = { ++ { ++ .name = "root", ++ .offset = 0, ++ .size = 0x02000000, ++ }, { ++ .name = "storage", ++ .offset = 0x02000000, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(homematic_nand_partition); ++ return homematic_nand_partition; ++} ++ ++static struct at91_nand_data __initdata homematic_nand_data = { ++ .ale = 22, ++ .cle = 21, ++// .det_pin = AT91_PIN_PB1, ++ .rdy_pin = AT91_PIN_PC2, ++ .enable_pin = AT91_PIN_PC0, ++ .partition_info = nand_partitions, ++}; ++ ++static void __init homematic_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* Ethernet */ ++ at91_add_device_eth(&homematic_eth_data); ++ /* USB Host */ ++ at91_add_device_usbh(&homematic_usbh_data); ++ /* USB Device */ ++ at91_add_device_udc(&homematic_udc_data); ++ at91_set_multi_drive(homematic_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */ ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++ /* SPI */ ++ at91_add_device_spi(homematic_spi_devices, ARRAY_SIZE(homematic_spi_devices)); ++#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD ++ /* DataFlash card */ ++ at91_set_gpio_output(AT91_PIN_PB7, 0); ++#else ++ /* MMC */ ++ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ ++ at91_add_device_mmc(0, &homematic_mmc_data); ++#endif ++ /* NAND */ ++ at91_add_device_nand(&homematic_nand_data); ++} ++ ++MACHINE_START(HOMEMATIC, "HomeMatic") ++ /* Maintainer: eQ-3 */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91rm9200_timer, ++ .map_io = homematic_map_io, ++ .init_irq = homematic_init_irq, ++ .init_machine = homematic_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-kb9202.c linux-2.6/arch/arm/mach-at91/board-kb9202.c +--- linux-2.6.25/arch/arm/mach-at91/board-kb9202.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-kb9202.c 2008-04-25 21:15:43.000000000 +0200 +@@ -37,19 +37,10 @@ + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> + +-#include "generic.h" ++#include <asm/arch/at91rm9200_mc.h> + ++#include "generic.h" + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata kb9202_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 3, +- .tty_map = { 4, 0, 1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; + + static void __init kb9202_map_io(void) + { +@@ -59,8 +50,20 @@ + /* Set up the LEDs */ + at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18); + +- /* Setup the serial ports and console */ +- at91_init_serial(&kb9202_uart_config); ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1 (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, 0); ++ ++ /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */ ++ at91_register_uart(AT91RM9200_ID_US1, 2, 0); ++ ++ /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */ ++ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init kb9202_init_irq(void) +@@ -111,6 +114,48 @@ + .partition_info = nand_partitions, + }; + ++ ++#if defined(CONFIG_FB_S1D15605) ++#warning "The Reset pin must be passed via platform_data, not this way" ++static struct resource kb9202_lcd_resources[] = { ++ [0] = { ++ .start = AT91_CHIPSELECT_2, ++ .end = AT91_CHIPSELECT_2 + 0x200FF, ++ .flags = IORESOURCE_MEM ++ }, ++ [1] = { /* reset pin */ ++ .start = AT91_PIN_PC22, ++ .end = AT91_PIN_PC22, ++ .flags = IORESOURCE_MEM ++ }, ++}; ++ ++static struct platform_device kb9202_lcd_device = { ++ .name = "s1d15605fb", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(kb9202_lcd_resources), ++ .resource = kb9202_lcd_resources, ++}; ++ ++static void __init kb9202_add_device_lcd(void) ++{ ++ /* In case the boot loader did not set the chip select mode and timing */ ++ at91_sys_write(AT91_SMC_CSR(2), ++ AT91_SMC_WSEN | AT91_SMC_NWS_(18) | AT91_SMC_TDF_(1) | AT91_SMC_DBW_8 | ++ AT91_SMC_RWSETUP_(1) | AT91_SMC_RWHOLD_(1)); ++ ++ /* Backlight pin = output, off */ ++ at91_set_gpio_output(AT91_PIN_PC23, 0); ++ ++ /* Reset pin = output, in reset */ ++ at91_set_gpio_output(AT91_PIN_PC22, 0); ++ ++ platform_device_register(&kb9202_lcd_device); ++} ++#else ++static void __init kb9202_add_device_lcd(void) {} ++#endif ++ + static void __init kb9202_board_init(void) + { + /* Serial */ +@@ -129,6 +174,8 @@ + at91_add_device_spi(NULL, 0); + /* NAND */ + at91_add_device_nand(&kb9202_nand_data); ++ /* LCD */ ++ kb9202_add_device_lcd(); + } + + MACHINE_START(KB9200, "KB920x") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-qil-a9260.c linux-2.6/arch/arm/mach-at91/board-qil-a9260.c +--- linux-2.6.25/arch/arm/mach-at91/board-qil-a9260.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-qil-a9260.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,255 @@ ++/* ++ * linux/arch/arm/mach-at91/board-qil-a9260.c ++ * ++ * Copyright (C) 2005 SAN People ++ * Copyright (C) 2006 Atmel ++ * Copyright (C) 2007 Calao-systems ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++#include <linux/clk.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++#include <asm/arch/at91_shdwc.h> ++ ++#include "generic.h" ++ ++ ++static void __init ek_map_io(void) ++{ ++ /* Initialize processor: 12.000 MHz crystal */ ++ at91sam9260_initialize(12000000); ++ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* set serial console to ttyS1 (ie, USART0) */ ++ at91_set_serial_console(1); ++ ++} ++ ++static void __init ek_init_irq(void) ++{ ++ at91sam9260_init_interrupts(NULL); ++} ++ ++ ++/* ++ * USB Host port ++ */ ++static struct at91_usbh_data __initdata ek_usbh_data = { ++ .ports = 2, ++}; ++ ++/* ++ * USB Device port ++ */ ++static struct at91_udc_data __initdata ek_udc_data = { ++ .vbus_pin = AT91_PIN_PC5, ++ .pullup_pin = 0, /* pull-up driven by UDC */ ++}; ++ ++/* ++ * SPI devices. ++ */ ++static struct spi_board_info ek_spi_devices[] = { ++#if defined(CONFIG_RTC_DRV_M41T94) ++ { /* M41T94 RTC */ ++ .modalias = "m41t94", ++ .chip_select = 0, ++ .max_speed_hz = 1 * 1000 * 1000, ++ .bus_num = 0, ++ } ++#endif ++}; ++ ++/* ++ * MACB Ethernet device ++ */ ++static struct at91_eth_data __initdata ek_macb_data = { ++ .phy_irq_pin = AT91_PIN_PA31, ++ .is_rmii = 1, ++}; ++ ++/* ++ * NAND flash ++ */ ++static struct mtd_partition __initdata ek_nand_partition[] = { ++ { ++ .name = "Uboot & Kernel", ++ .offset = 0x00000000, ++ .size = 16 * 1024 * 1024, ++ }, ++ { ++ .name = "Root FS", ++ .offset = 0x01000000, ++ .size = 120 * 1024 * 1024, ++ }, ++ { ++ .name = "FS", ++ .offset = 0x08800000, ++ .size = 120 * 1024 * 1024, ++ }, ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(ek_nand_partition); ++ return ek_nand_partition; ++} ++ ++static struct at91_nand_data __initdata ek_nand_data = { ++ .ale = 21, ++ .cle = 22, ++// .det_pin = ... not connected ++ .rdy_pin = AT91_PIN_PC13, ++ .enable_pin = AT91_PIN_PC14, ++ .partition_info = nand_partitions, ++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) ++ .bus_width_16 = 1, ++#else ++ .bus_width_16 = 0, ++#endif ++}; ++ ++/* ++ * MCI (SD/MMC) ++ */ ++static struct at91_mmc_data __initdata ek_mmc_data = { ++ .slot_b = 0, ++ .wire4 = 1, ++// .det_pin = ... not connected ++// .wp_pin = ... not connected ++// .vcc_pin = ... not connected ++}; ++ ++/* ++ * GPIO Buttons ++ */ ++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) ++static struct gpio_keys_button ek_buttons[] = { ++ { /* USER PUSH BUTTON */ ++ .code = KEY_ENTER, ++ .gpio = AT91_PIN_PB10, ++ .active_low = 1, ++ .desc = "user_pb", ++ .wakeup = 1, ++ } ++}; ++ ++static struct gpio_keys_platform_data ek_button_data = { ++ .buttons = ek_buttons, ++ .nbuttons = ARRAY_SIZE(ek_buttons), ++}; ++ ++static struct platform_device ek_button_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &ek_button_data, ++ } ++}; ++ ++static void __init ek_add_device_buttons(void) ++{ ++ at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* user push button, pull up enabled */ ++ at91_set_deglitch(AT91_PIN_PB10, 1); ++ ++ platform_device_register(&ek_button_device); ++} ++#else ++static void __init ek_add_device_buttons(void) {} ++#endif ++ ++/* ++ * LEDs ++ */ ++static struct gpio_led ek_leds[] = { ++ { /* user_led (green) */ ++ .name = "user_led", ++ .gpio = AT91_PIN_PB21, ++ .active_low = 0, ++ .default_trigger = "heartbeat", ++ } ++}; ++ ++static void __init ek_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* USB Host */ ++ at91_add_device_usbh(&ek_usbh_data); ++ /* USB Device */ ++ at91_add_device_udc(&ek_udc_data); ++ /* SPI */ ++ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); ++ /* NAND */ ++ at91_add_device_nand(&ek_nand_data); ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++ /* Ethernet */ ++ at91_add_device_eth(&ek_macb_data); ++ /* MMC */ ++ at91_add_device_mmc(0, &ek_mmc_data); ++ /* Push Buttons */ ++ ek_add_device_buttons(); ++ /* LEDs */ ++ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); ++} ++ ++MACHINE_START(QIL_A9260, "CALAO QIL_A9260") ++ /* Maintainer: calao-systems */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91sam926x_timer, ++ .map_io = ek_map_io, ++ .init_irq = ek_init_irq, ++ .init_machine = ek_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-sam9-l9260.c linux-2.6/arch/arm/mach-at91/board-sam9-l9260.c +--- linux-2.6.25/arch/arm/mach-at91/board-sam9-l9260.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-sam9-l9260.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,199 @@ ++/* ++ * linux/arch/arm/mach-at91/board-sam9-l9260.c ++ * ++ * Copyright (C) 2005 SAN People ++ * Copyright (C) 2006 Atmel ++ * Copyright (C) 2007 Olimex Ltd ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++ ++#include "generic.h" ++ ++ ++static void __init ek_map_io(void) ++{ ++ /* Initialize processor: 18.432 MHz crystal */ ++ at91sam9260_initialize(18432000); ++ ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6); ++ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init ek_init_irq(void) ++{ ++ at91sam9260_init_interrupts(NULL); ++} ++ ++ ++/* ++ * USB Host port ++ */ ++static struct at91_usbh_data __initdata ek_usbh_data = { ++ .ports = 2, ++}; ++ ++/* ++ * USB Device port ++ */ ++static struct at91_udc_data __initdata ek_udc_data = { ++ .vbus_pin = AT91_PIN_PC5, ++ .pullup_pin = 0, /* pull-up driven by UDC */ ++}; ++ ++ ++/* ++ * SPI devices. ++ */ ++static struct spi_board_info ek_spi_devices[] = { ++#if !defined(CONFIG_MMC_AT91) ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 1, ++ .max_speed_hz = 15 * 1000 * 1000, ++ .bus_num = 0, ++ }, ++#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD) ++ { /* DataFlash card */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ .bus_num = 0, ++ }, ++#endif ++#endif ++}; ++ ++ ++/* ++ * MACB Ethernet device ++ */ ++static struct at91_eth_data __initdata ek_macb_data = { ++ .phy_irq_pin = AT91_PIN_PA7, ++ .is_rmii = 0, ++}; ++ ++ ++/* ++ * NAND flash ++ */ ++static struct mtd_partition __initdata ek_nand_partition[] = { ++ { ++ .name = "Bootloader Area", ++ .offset = 0, ++ .size = 10 * 1024 * 1024, ++ }, ++ { ++ .name = "User Area", ++ .offset = 10 * 1024 * 1024, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(ek_nand_partition); ++ return ek_nand_partition; ++} ++ ++static struct at91_nand_data __initdata ek_nand_data = { ++ .ale = 21, ++ .cle = 22, ++// .det_pin = ... not connected ++ .rdy_pin = AT91_PIN_PC13, ++ .enable_pin = AT91_PIN_PC14, ++ .partition_info = nand_partitions, ++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) ++ .bus_width_16 = 1, ++#else ++ .bus_width_16 = 0, ++#endif ++}; ++ ++ ++/* ++ * MCI (SD/MMC) ++ */ ++static struct at91_mmc_data __initdata ek_mmc_data = { ++ .slot_b = 1, ++ .wire4 = 1, ++ .det_pin = AT91_PIN_PC8, ++ .wp_pin = AT91_PIN_PC4, ++// .vcc_pin = ... not connected ++}; ++ ++static void __init ek_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* USB Host */ ++ at91_add_device_usbh(&ek_usbh_data); ++ /* USB Device */ ++ at91_add_device_udc(&ek_udc_data); ++ /* SPI */ ++ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); ++ /* NAND */ ++ at91_add_device_nand(&ek_nand_data); ++ /* Ethernet */ ++ at91_add_device_eth(&ek_macb_data); ++ /* MMC */ ++ at91_add_device_mmc(0, &ek_mmc_data); ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++} ++ ++MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260") ++ /* Maintainer: Olimex */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91sam926x_timer, ++ .map_io = ek_map_io, ++ .init_irq = ek_init_irq, ++ .init_machine = ek_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-sam9260ek.c linux-2.6/arch/arm/mach-at91/board-sam9260ek.c +--- linux-2.6.25/arch/arm/mach-at91/board-sam9260ek.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-sam9260ek.c 2008-05-01 23:56:24.000000000 +0200 +@@ -25,6 +25,10 @@ + #include <linux/module.h> + #include <linux/platform_device.h> + #include <linux/spi/spi.h> ++#include <linux/spi/at73c213.h> ++#include <linux/clk.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> + + #include <asm/hardware.h> + #include <asm/setup.h> +@@ -37,29 +41,29 @@ + + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 5 = USART0 .. USART5 +- * 6 = DBGU +- */ +-static struct at91_uart_config __initdata ek_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 3, +- .tty_map = { 6, 0, 1, -1, -1, -1, -1 } /* ttyS0, ..., ttyS6 */ +-}; +- + static void __init ek_map_io(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91sam9260_initialize(18432000); + +- /* Setup the serial ports and console */ +- at91_init_serial(&ek_uart_config); ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init ek_init_irq(void) +@@ -85,6 +89,35 @@ + + + /* ++ * Audio ++ */ ++static struct at73c213_board_info at73c213_data = { ++ .ssc_id = 0, ++ .shortname = "AT91SAM9260-EK external DAC", ++}; ++ ++#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE) ++static void __init at73c213_set_clk(struct at73c213_board_info *info) ++{ ++ struct clk *pck0; ++ struct clk *plla; ++ ++ pck0 = clk_get(NULL, "pck0"); ++ plla = clk_get(NULL, "plla"); ++ ++ /* AT73C213 MCK Clock */ ++ at91_set_B_periph(AT91_PIN_PC1, 0); /* PCK0 */ ++ ++ clk_set_parent(pck0, plla); ++ clk_put(plla); ++ ++ info->dac_clk = pck0; ++} ++#else ++static void __init at73c213_set_clk(struct at73c213_board_info *info) {} ++#endif ++ ++/* + * SPI devices. + */ + static struct spi_board_info ek_spi_devices[] = { +@@ -110,6 +143,8 @@ + .chip_select = 0, + .max_speed_hz = 10 * 1000 * 1000, + .bus_num = 1, ++ .mode = SPI_MODE_1, ++ .platform_data = &at73c213_data, + }, + #endif + }; +@@ -172,6 +207,74 @@ + // .vcc_pin = ... not connected + }; + ++ ++/* ++ * LEDs ++ */ ++static struct gpio_led ek_leds[] = { ++ { /* "bottom" led, green, userled1 to be defined */ ++ .name = "ds5", ++ .gpio = AT91_PIN_PA6, ++ .active_low = 1, ++ .default_trigger = "none", ++ }, ++ { /* "power" led, yellow */ ++ .name = "ds1", ++ .gpio = AT91_PIN_PA9, ++ .default_trigger = "heartbeat", ++ } ++}; ++ ++ ++/* ++ * GPIO Buttons ++ */ ++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) ++static struct gpio_keys_button ek_buttons[] = { ++ { ++ .gpio = AT91_PIN_PA30, ++ .code = BTN_3, ++ .desc = "Button 3", ++ .active_low = 1, ++ .wakeup = 1, ++ }, ++ { ++ .gpio = AT91_PIN_PA31, ++ .code = BTN_4, ++ .desc = "Button 4", ++ .active_low = 1, ++ .wakeup = 1, ++ } ++}; ++ ++static struct gpio_keys_platform_data ek_button_data = { ++ .buttons = ek_buttons, ++ .nbuttons = ARRAY_SIZE(ek_buttons), ++}; ++ ++static struct platform_device ek_button_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &ek_button_data, ++ } ++}; ++ ++static void __init ek_add_device_buttons(void) ++{ ++ at91_set_gpio_input(AT91_PIN_PA30, 1); /* btn3 */ ++ at91_set_deglitch(AT91_PIN_PA30, 1); ++ at91_set_gpio_input(AT91_PIN_PA31, 1); /* btn4 */ ++ at91_set_deglitch(AT91_PIN_PA31, 1); ++ ++ platform_device_register(&ek_button_device); ++} ++#else ++static void __init ek_add_device_buttons(void) {} ++#endif ++ ++ + static void __init ek_board_init(void) + { + /* Serial */ +@@ -190,6 +293,16 @@ + at91_add_device_mmc(0, &ek_mmc_data); + /* I2C */ + at91_add_device_i2c(NULL, 0); ++ /* SSC (to AT73C213) */ ++ at73c213_set_clk(&at73c213_data); ++ at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX); ++ /* LEDs */ ++ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); ++ /* Push Buttons */ ++ ek_add_device_buttons(); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); + } + + MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-sam9261ek.c linux-2.6/arch/arm/mach-at91/board-sam9261ek.c +--- linux-2.6.25/arch/arm/mach-at91/board-sam9261ek.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-sam9261ek.c 2008-05-01 23:53:20.000000000 +0200 +@@ -26,6 +26,8 @@ + #include <linux/platform_device.h> + #include <linux/spi/spi.h> + #include <linux/spi/ads7846.h> ++#include <linux/spi/at73c213.h> ++#include <linux/clk.h> + #include <linux/dm9000.h> + #include <linux/fb.h> + #include <linux/gpio_keys.h> +@@ -44,22 +46,12 @@ + + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91sam9_smc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 2 = USART0 .. USART2 +- * 3 = DBGU +- */ +-static struct at91_uart_config __initdata ek_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 1, +- .tty_map = { 3, -1, -1, -1 } /* ttyS0, ..., ttyS3 */ +-}; +- + static void __init ek_map_io(void) + { + /* Initialize processor: 18.432 MHz crystal */ +@@ -68,8 +60,11 @@ + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14); + +- /* Setup the serial ports and console */ +- at91_init_serial(&ek_uart_config); ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init ek_init_irq(void) +@@ -239,6 +234,35 @@ + #endif + + /* ++ * Audio ++ */ ++static struct at73c213_board_info at73c213_data = { ++ .ssc_id = 1, ++ .shortname = "AT91SAM9261-EK external DAC", ++}; ++ ++#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE) ++static void __init at73c213_set_clk(struct at73c213_board_info *info) ++{ ++ struct clk *pck2; ++ struct clk *plla; ++ ++ pck2 = clk_get(NULL, "pck2"); ++ plla = clk_get(NULL, "plla"); ++ ++ /* AT73C213 MCK Clock */ ++ at91_set_B_periph(AT91_PIN_PB31, 0); /* PCK2 */ ++ ++ clk_set_parent(pck2, plla); ++ clk_put(plla); ++ ++ info->dac_clk = pck2; ++} ++#else ++static void __init at73c213_set_clk(struct at73c213_board_info *info) {} ++#endif ++ ++/* + * SPI devices + */ + static struct spi_board_info ek_spi_devices[] = { +@@ -252,10 +276,11 @@ + { + .modalias = "ads7846", + .chip_select = 2, +- .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ ++ .max_speed_hz = 125000 * 16, /* max sample rate * clocks per sample */ + .bus_num = 0, + .platform_data = &ads_info, + .irq = AT91SAM9261_ID_IRQ0, ++ .controller_data = (void *) AT91_PIN_PA28, /* CS pin */ + }, + #endif + #if defined(CONFIG_MTD_AT91_DATAFLASH_CARD) +@@ -271,6 +296,9 @@ + .chip_select = 3, + .max_speed_hz = 10 * 1000 * 1000, + .bus_num = 0, ++ .mode = SPI_MODE_1, ++ .platform_data = &at73c213_data, ++ .controller_data = (void*) AT91_PIN_PA29, /* default for CS3 is PA6, but it must be PA29 */ + }, + #endif + }; +@@ -408,24 +436,28 @@ + .code = BTN_0, + .desc = "Button 0", + .active_low = 1, ++ .wakeup = 1, + }, + { + .gpio = AT91_PIN_PA26, + .code = BTN_1, + .desc = "Button 1", + .active_low = 1, ++ .wakeup = 1, + }, + { + .gpio = AT91_PIN_PA25, + .code = BTN_2, + .desc = "Button 2", + .active_low = 1, ++ .wakeup = 1, + }, + { + .gpio = AT91_PIN_PA24, + .code = BTN_3, + .desc = "Button 3", + .active_low = 1, ++ .wakeup = 1, + } + }; + +@@ -445,13 +477,13 @@ + + static void __init ek_add_device_buttons(void) + { +- at91_set_gpio_input(AT91_PIN_PA27, 0); /* btn0 */ ++ at91_set_gpio_input(AT91_PIN_PA27, 1); /* btn0 */ + at91_set_deglitch(AT91_PIN_PA27, 1); +- at91_set_gpio_input(AT91_PIN_PA26, 0); /* btn1 */ ++ at91_set_gpio_input(AT91_PIN_PA26, 1); /* btn1 */ + at91_set_deglitch(AT91_PIN_PA26, 1); +- at91_set_gpio_input(AT91_PIN_PA25, 0); /* btn2 */ ++ at91_set_gpio_input(AT91_PIN_PA25, 1); /* btn2 */ + at91_set_deglitch(AT91_PIN_PA25, 1); +- at91_set_gpio_input(AT91_PIN_PA24, 0); /* btn3 */ ++ at91_set_gpio_input(AT91_PIN_PA24, 1); /* btn3 */ + at91_set_deglitch(AT91_PIN_PA24, 1); + + platform_device_register(&ek_button_device); +@@ -460,6 +492,29 @@ + static void __init ek_add_device_buttons(void) {} + #endif + ++/* ++ * LEDs ++ */ ++static struct gpio_led ek_leds[] = { ++ { /* "bottom" led, green, userled1 to be defined */ ++ .name = "ds7", ++ .gpio = AT91_PIN_PA14, ++ .active_low = 1, ++ .default_trigger = "none", ++ }, ++ { /* "top" led, green, userled2 to be defined */ ++ .name = "ds8", ++ .gpio = AT91_PIN_PA13, ++ .active_low = 1, ++ .default_trigger = "none", ++ }, ++ { /* "power" led, yellow */ ++ .name = "ds1", ++ .gpio = AT91_PIN_PA23, ++ .default_trigger = "heartbeat", ++ } ++}; ++ + static void __init ek_board_init(void) + { + /* Serial */ +@@ -481,6 +536,9 @@ + at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); + /* Touchscreen */ + ek_add_device_ts(); ++ /* SSC (to AT73C213) */ ++ at73c213_set_clk(&at73c213_data); ++ at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX); + #else + /* MMC */ + at91_add_device_mmc(0, &ek_mmc_data); +@@ -489,6 +547,11 @@ + at91_add_device_lcdc(&ek_lcdc_data); + /* Push Buttons */ + ek_add_device_buttons(); ++ /* LEDs */ ++ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); + } + + MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-sam9263ek.c linux-2.6/arch/arm/mach-at91/board-sam9263ek.c +--- linux-2.6.25/arch/arm/mach-at91/board-sam9263ek.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-sam9263ek.c 2008-05-01 23:53:20.000000000 +0200 +@@ -43,29 +43,24 @@ + + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 2 = USART0 .. USART2 +- * 3 = DBGU +- */ +-static struct at91_uart_config __initdata ek_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 3, 0, -1, -1, } /* ttyS0, ..., ttyS3 */ +-}; +- + static void __init ek_map_io(void) + { + /* Initialize processor: 16.367 MHz crystal */ + at91sam9263_initialize(16367660); + +- /* Setup the serial ports and console */ +- at91_init_serial(&ek_uart_config); ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init ek_init_irq(void) +@@ -141,7 +136,7 @@ + { + .modalias = "ads7846", + .chip_select = 3, +- .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ ++ .max_speed_hz = 125000 * 16, /* max sample rate * clocks per sample */ + .bus_num = 0, + .platform_data = &ads_info, + .irq = AT91SAM9263_ID_IRQ1, +@@ -301,9 +296,9 @@ + + static void __init ek_add_device_buttons(void) + { +- at91_set_GPIO_periph(AT91_PIN_PC5, 0); /* left button */ ++ at91_set_GPIO_periph(AT91_PIN_PC5, 1); /* left button */ + at91_set_deglitch(AT91_PIN_PC5, 1); +- at91_set_GPIO_periph(AT91_PIN_PC4, 0); /* right button */ ++ at91_set_GPIO_periph(AT91_PIN_PC4, 1); /* right button */ + at91_set_deglitch(AT91_PIN_PC4, 1); + + platform_device_register(&ek_button_device); +@@ -341,7 +336,7 @@ + .name = "ds3", + .gpio = AT91_PIN_PB7, + .default_trigger = "heartbeat", +- }, ++ } + }; + + +@@ -374,6 +369,9 @@ + at91_add_device_ac97(&ek_ac97_data); + /* LEDs */ + at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); + } + + MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-sam9rlek.c linux-2.6/arch/arm/mach-at91/board-sam9rlek.c +--- linux-2.6.25/arch/arm/mach-at91/board-sam9rlek.c 2008-05-03 00:15:33.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-sam9rlek.c 2008-04-25 21:15:43.000000000 +0200 +@@ -29,29 +29,24 @@ + + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> +-#include <asm/arch/at91sam926x_mc.h> ++#include <asm/arch/at91_shdwc.h> + + #include "generic.h" + + +-/* +- * Serial port configuration. +- * 0 .. 3 = USART0 .. USART3 +- * 4 = DBGU +- */ +-static struct at91_uart_config __initdata ek_uart_config = { +- .console_tty = 0, /* ttyS0 */ +- .nr_tty = 2, +- .tty_map = { 4, 0, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ +-}; +- + static void __init ek_map_io(void) + { + /* Initialize processor: 12.000 MHz crystal */ + at91sam9rl_initialize(12000000); + +- /* Setup the serial ports and console */ +- at91_init_serial(&ek_uart_config); ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); + } + + static void __init ek_init_irq(void) +@@ -61,6 +56,14 @@ + + + /* ++ * USB HS Device port ++ */ ++static struct usba_platform_data __initdata ek_usba_udc_data = { ++ .vbus_pin = AT91_PIN_PA8, ++}; ++ ++ ++/* + * MCI (SD/MMC) + */ + static struct at91_mmc_data __initdata ek_mmc_data = { +@@ -180,6 +183,8 @@ + { + /* Serial */ + at91_add_device_serial(); ++ /* USB HS */ ++ at91_add_device_usba(&ek_usba_udc_data); + /* I2C */ + at91_add_device_i2c(NULL, 0); + /* NAND */ +@@ -190,6 +195,9 @@ + at91_add_device_mmc(0, &ek_mmc_data); + /* LCD Controller */ + at91_add_device_lcdc(&ek_lcdc_data); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); + } + + MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK") +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-tms.c linux-2.6/arch/arm/mach-at91/board-tms.c +--- linux-2.6.25/arch/arm/mach-at91/board-tms.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-tms.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,198 @@ ++/* ++* linux/arch/arm/mach-at91/board-tms.c ++* ++* Copyright (C) 2005 SAN People ++* ++* Adapted from board-dk to sweda TMS-100 by Luiz de Barros <lboneto@gmail.com> ++* ++* 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. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++* You should have received a copy of the GNU General Public License ++* along with this program; if not, write to the Free Software ++* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/mtd/physmap.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++#include <asm/arch/at91rm9200_mc.h> ++ ++#include "generic.h" ++#include <linux/serial_8250.h> ++ ++ ++#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP| UPF_SHARE_IRQ) ++#define SERIAL_CLK (1843200) ++ ++ ++/*--------------------------------------------------------------------- ++ * External UART ++ */ ++ ++#define PORT(_base, _irq) \ ++ { \ ++ .mapbase = _base, \ ++ .irq = _irq, \ ++ .uartclk = SERIAL_CLK, \ ++ .iotype = UPIO_MEM, \ ++ .regshift = 0, \ ++ .flags = SERIAL_FLAGS, \ ++ } ++ ++static struct plat_serial8250_port tms_data[] = { ++ PORT(0x70000000, AT91_PIN_PC3), ++ PORT(0x80000000, AT91_PIN_PC5), ++ { }, ++}; ++ ++static struct platform_device tms_device = { ++ .name = "serial8250", ++ .id = PLAT8250_DEV_PLATFORM, ++ .dev = ++ { ++ .platform_data = &tms_data, ++ }, ++}; ++ ++static void setup_external_uart(void) ++{ ++ at91_sys_write(AT91_SMC_CSR(2), ++ AT91_SMC_ACSS_STD ++ | AT91_SMC_DBW_8 ++ | AT91_SMC_BAT ++ | AT91_SMC_WSEN ++ | AT91_SMC_NWS_(32) /* wait states */ ++ | AT91_SMC_RWSETUP_(6) /* setup time */ ++ | AT91_SMC_RWHOLD_(4) /* hold time */ ++ ++ ); ++ at91_sys_write(AT91_SMC_CSR(6), ++ AT91_SMC_ACSS_STD ++ | AT91_SMC_DBW_8 ++ | AT91_SMC_BAT ++ | AT91_SMC_WSEN ++ | AT91_SMC_NWS_(32) /* wait states */ ++ | AT91_SMC_RWSETUP_(6) /* setup time */ ++ | AT91_SMC_RWHOLD_(4) /* hold time */ ++ ++ ); ++ at91_sys_write(AT91_SMC_CSR(7), ++ AT91_SMC_ACSS_STD ++ | AT91_SMC_DBW_8 ++ | AT91_SMC_BAT ++ | AT91_SMC_WSEN ++ | AT91_SMC_NWS_(32) /* wait states */ ++ | AT91_SMC_RWSETUP_(6) /* setup time */ ++ | AT91_SMC_RWHOLD_(4) /* hold time */ ++ ); ++ ++ platform_device_register(&tms_device); ++} ++ ++ ++/* ++ * Serial port configuration. ++ * 0 .. 3 = USART0 .. USART3 ++ * 4 = DBGU ++ */ ++static struct at91_uart_config __initdata tms_uart_config = { ++ .console_tty = 0, /* ttyS0 */ ++ .nr_tty = 5, ++ .tty_map = { 4, 0, 1, 2, 3 } /* ttyS0, ..., ttyS4 */ ++}; ++ ++static void __init tms_map_io(void) ++{ ++ /* Initialize processor: 18.432 MHz crystal */ ++ at91rm9200_initialize(18432000, AT91RM9200_BGA); ++ ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); ++ ++ /* Setup the serial ports and console */ ++ at91_init_serial(&tms_uart_config); ++} ++ ++static void __init tms_init_irq(void) ++{ ++ at91rm9200_init_interrupts(NULL); ++} ++ ++ ++static struct at91_eth_data __initdata tms_eth_data = { ++ .phy_irq_pin = AT91_PIN_PC4, ++ .is_rmii = 1, ++}; ++ ++static struct at91_usbh_data __initdata tms_usbh_data = { ++ .ports = 2, ++}; ++ ++static struct spi_board_info tms_spi_devices[] = { ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ }, ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 1, ++ .max_speed_hz = 15 * 1000 * 1000, ++ } ++}; ++ ++static struct i2c_board_info __initdata tms_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("isl1208", 0x6f), ++ } ++}; ++ ++static void __init tms_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* Ethernet */ ++ at91_add_device_eth(&tms_eth_data); ++ at91_add_device_usbh(&tms_usbh_data); ++ /* I2C */ ++ at91_add_device_i2c(tms_i2c_devices, ARRAY_SIZE(tms_i2c_devices)); ++ /* SPI */ ++ at91_add_device_spi(tms_spi_devices, ARRAY_SIZE(tms_spi_devices)); ++ /* Two port external UART */ ++ setup_external_uart(); ++} ++ ++MACHINE_START(SWEDATMS, "Sweda TMS-100 Board") ++ /* Maintainer: Luiz de Barros */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91rm9200_timer, ++ .map_io = tms_map_io, ++ .init_irq = tms_init_irq, ++ .init_machine = tms_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-tt9200.c linux-2.6/arch/arm/mach-at91/board-tt9200.c +--- linux-2.6.25/arch/arm/mach-at91/board-tt9200.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-tt9200.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,192 @@ ++/* ++ * linux/arch/arm/mach-at91rm9200/board-tt9200.c ++ * Copyright (C) 2007 Toptechnology ++ * ++ * Based on board-ecbat91.c ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++ ++#include "generic.h" ++ ++ ++static void __init tt9200_map_io(void) ++{ ++ /* Initialize processor: 18.432 MHz crystal */ ++ at91rm9200_initialize(18432000, AT91RM9200_PQFP); ++ ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB27, AT91_PIN_PB27); ++ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, 0); ++ ++ /* USART1 on ttyS2. (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US1, 2, 0); ++ ++ /* USART2 on ttyS3. (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US2, 3, 0); ++ ++ /* USART3 on ttyS4. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* Console on ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init tt9200_init_irq(void) ++{ ++ at91rm9200_init_interrupts(NULL); ++} ++ ++static struct at91_eth_data __initdata tt9200_eth_data = { ++ .phy_irq_pin = AT91_PIN_PB29, ++ .is_rmii = 0, ++}; ++ ++static struct at91_usbh_data __initdata tt9200_usbh_data = { ++ .ports = 1, ++}; ++ ++static struct i2c_board_info __initdata tt9200_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("rtc-m41t80", 0x68), ++ .type = "m41t80", ++ } ++}; ++ ++static struct at91_mmc_data __initdata tt9200_mmc_data = { ++ .slot_b = 0, ++ .wire4 = 1, ++}; ++ ++ ++#if defined(CONFIG_MTD_DATAFLASH) ++static struct mtd_partition __initdata tt9200_flash_partitions[] = ++{ ++ { ++ .name = "Darrell", ++ .offset = 0, ++ .size = 12 * 1056, ++ }, ++ { ++ .name = "U-boot", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 110 * 1056, ++ }, ++ { ++ .name = "U-boot env", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 8 * 1056, ++ }, ++ { ++ .name = "Kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 1534 * 1056, ++ }, ++ { ++ .name = "Filesystem", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, ++ } ++}; ++ ++static struct flash_platform_data __initdata tt9200_flash_platform = { ++ .name = "SPI Dataflash", ++ .parts = tt9200_flash_partitions, ++ .nr_parts = ARRAY_SIZE(tt9200_flash_partitions) ++}; ++ ++#endif ++ ++static struct spi_board_info __initdata tt9200_spi_devices[] = { ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ /* Errata #13 */ ++ .max_speed_hz = 5 * 1000 * 1000, ++ .bus_num = 0, ++#if defined(CONFIG_MTD_DATAFLASH) ++ .platform_data = &tt9200_flash_platform, ++#endif ++ }, ++}; ++ ++static struct gpio_led tt9200_leds[] = { ++ { ++ .name = "led0", ++ .gpio = AT91_PIN_PB27, ++ .active_low = 1, ++ .default_trigger = "heartbeat", ++ } ++}; ++ ++static void __init tt9200_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ ++ /* Ethernet */ ++ at91_add_device_eth(&tt9200_eth_data); ++ ++ /* USB Host */ ++ at91_add_device_usbh(&tt9200_usbh_data); ++ ++ /* I2C */ ++ at91_add_device_i2c(tt9200_i2c_devices, ARRAY_SIZE(tt9200_i2c_devices)); ++ ++ /* MMC */ ++ at91_add_device_mmc(0, &tt9200_mmc_data); ++ ++ /* LEDS */ ++ at91_gpio_leds(tt9200_leds, ARRAY_SIZE(tt9200_leds)); ++ ++ /* SPI */ ++ at91_add_device_spi(tt9200_spi_devices, ARRAY_SIZE(tt9200_spi_devices)); ++} ++ ++MACHINE_START(TT9200, "Toptech TT9200") ++ /* Maintainer: toptech.com.ar */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91rm9200_timer, ++ .map_io = tt9200_map_io, ++ .init_irq = tt9200_init_irq, ++ .init_machine = tt9200_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-usb-a9260.c linux-2.6/arch/arm/mach-at91/board-usb-a9260.c +--- linux-2.6.25/arch/arm/mach-at91/board-usb-a9260.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-usb-a9260.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,215 @@ ++/* ++ * linux/arch/arm/mach-at91/board-usb-a9260.c ++ * ++ * Copyright (C) 2005 SAN People ++ * Copyright (C) 2006 Atmel ++ * Copyright (C) 2007 Calao-systems ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++#include <linux/clk.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++#include <asm/arch/at91_shdwc.h> ++ ++#include "generic.h" ++ ++ ++static void __init ek_map_io(void) ++{ ++ /* Initialize processor: 12.000 MHz crystal */ ++ at91sam9260_initialize(12000000); ++ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init ek_init_irq(void) ++{ ++ at91sam9260_init_interrupts(NULL); ++} ++ ++ ++/* ++ * USB Host port ++ */ ++static struct at91_usbh_data __initdata ek_usbh_data = { ++ .ports = 2, ++}; ++ ++/* ++ * USB Device port ++ */ ++static struct at91_udc_data __initdata ek_udc_data = { ++ .vbus_pin = AT91_PIN_PC5, ++ .pullup_pin = 0, /* pull-up driven by UDC */ ++}; ++ ++/* ++ * MACB Ethernet device ++ */ ++static struct at91_eth_data __initdata ek_macb_data = { ++ .phy_irq_pin = AT91_PIN_PA31, ++ .is_rmii = 1, ++}; ++ ++/* ++ * NAND flash ++ */ ++static struct mtd_partition __initdata ek_nand_partition[] = { ++ { ++ .name = "Uboot & Kernel", ++ .offset = 0x00000000, ++ .size = 16 * 1024 * 1024, ++ }, ++ { ++ .name = "Root FS", ++ .offset = 0x01000000, ++ .size = 120 * 1024 * 1024, ++ }, ++ { ++ .name = "FS", ++ .offset = 0x08800000, ++ .size = 120 * 1024 * 1024, ++ } ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(ek_nand_partition); ++ return ek_nand_partition; ++} ++ ++static struct at91_nand_data __initdata ek_nand_data = { ++ .ale = 21, ++ .cle = 22, ++// .det_pin = ... not connected ++ .rdy_pin = AT91_PIN_PC13, ++ .enable_pin = AT91_PIN_PC14, ++ .partition_info = nand_partitions, ++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) ++ .bus_width_16 = 1, ++#else ++ .bus_width_16 = 0, ++#endif ++}; ++ ++/* ++ * GPIO Buttons ++ */ ++ ++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) ++static struct gpio_keys_button ek_buttons[] = { ++ { /* USER PUSH BUTTON */ ++ .code = KEY_ENTER, ++ .gpio = AT91_PIN_PB10, ++ .active_low = 1, ++ .desc = "user_pb", ++ .wakeup = 1, ++ } ++}; ++ ++static struct gpio_keys_platform_data ek_button_data = { ++ .buttons = ek_buttons, ++ .nbuttons = ARRAY_SIZE(ek_buttons), ++}; ++ ++static struct platform_device ek_button_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &ek_button_data, ++ } ++}; ++ ++static void __init ek_add_device_buttons(void) ++{ ++ at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* user push button, pull up enabled */ ++ at91_set_deglitch(AT91_PIN_PB10, 1); ++ ++ platform_device_register(&ek_button_device); ++} ++#else ++static void __init ek_add_device_buttons(void) {} ++#endif ++ ++/* ++ * LEDs ++ */ ++static struct gpio_led ek_leds[] = { ++ { /* user_led (green) */ ++ .name = "user_led", ++ .gpio = AT91_PIN_PB21, ++ .active_low = 0, ++ .default_trigger = "heartbeat", ++ } ++}; ++ ++static void __init ek_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* USB Host */ ++ at91_add_device_usbh(&ek_usbh_data); ++ /* USB Device */ ++ at91_add_device_udc(&ek_udc_data); ++ /* NAND */ ++ at91_add_device_nand(&ek_nand_data); ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++ /* Ethernet */ ++ at91_add_device_eth(&ek_macb_data); ++ /* Push Buttons */ ++ ek_add_device_buttons(); ++ /* LEDs */ ++ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); ++} ++ ++MACHINE_START(USB_A9260, "CALAO USB_A9260") ++ /* Maintainer: calao-systems */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91sam926x_timer, ++ .map_io = ek_map_io, ++ .init_irq = ek_init_irq, ++ .init_machine = ek_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/board-usb-a9263.c linux-2.6/arch/arm/mach-at91/board-usb-a9263.c +--- linux-2.6.25/arch/arm/mach-at91/board-usb-a9263.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/board-usb-a9263.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,230 @@ ++/* ++ * linux/arch/arm/mach-at91/board-usb-a9263.c ++ * ++ * Copyright (C) 2005 SAN People ++ * Copyright (C) 2007 Atmel Corporation. ++ * Copyright (C) 2007 Calao-systems ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++#include <asm/arch/at91_shdwc.h> ++ ++#include "generic.h" ++ ++ ++static void __init ek_map_io(void) ++{ ++ /* Initialize processor: 12.00 MHz crystal */ ++ at91sam9263_initialize(12000000); ++ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* set serial console to ttyS0 (ie, DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init ek_init_irq(void) ++{ ++ at91sam9263_init_interrupts(NULL); ++} ++ ++ ++/* ++ * USB Host port ++ */ ++static struct at91_usbh_data __initdata ek_usbh_data = { ++ .ports = 2, ++}; ++ ++/* ++ * USB Device port ++ */ ++static struct at91_udc_data __initdata ek_udc_data = { ++ .vbus_pin = AT91_PIN_PB11, ++ .pullup_pin = 0, /* pull-up driven by UDC */ ++}; ++ ++/* ++ * SPI devices. ++ */ ++static struct spi_board_info ek_spi_devices[] = { ++#if !defined(CONFIG_MMC_AT91) ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ .bus_num = 0, ++ } ++#endif ++}; ++ ++/* ++ * MACB Ethernet device ++ */ ++static struct at91_eth_data __initdata ek_macb_data = { ++ .phy_irq_pin = AT91_PIN_PE31, ++ .is_rmii = 1, ++}; ++ ++/* ++ * NAND flash ++ */ ++static struct mtd_partition __initdata ek_nand_partition[] = { ++ { ++ .name = "Linux Kernel", ++ .offset = 0x00000000, ++ .size = 16 * 1024 * 1024, ++ }, ++ { ++ .name = "Root FS", ++ .offset = 0x01000000, ++ .size = 120 * 1024 * 1024, ++ }, ++ { ++ .name = "FS", ++ .offset = 0x08800000, ++ .size = 120 * 1024 * 1024, ++ } ++}; ++ ++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) ++{ ++ *num_partitions = ARRAY_SIZE(ek_nand_partition); ++ return ek_nand_partition; ++} ++ ++static struct at91_nand_data __initdata ek_nand_data = { ++ .ale = 21, ++ .cle = 22, ++// .det_pin = ... not connected ++ .rdy_pin = AT91_PIN_PA22, ++ .enable_pin = AT91_PIN_PD15, ++ .partition_info = nand_partitions, ++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16) ++ .bus_width_16 = 1, ++#else ++ .bus_width_16 = 0, ++#endif ++}; ++ ++/* ++ * GPIO Buttons ++ */ ++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) ++static struct gpio_keys_button ek_buttons[] = { ++ { /* USER PUSH BUTTON */ ++ .code = KEY_ENTER, ++ .gpio = AT91_PIN_PB10, ++ .active_low = 1, ++ .desc = "user_pb", ++ .wakeup = 1, ++ } ++}; ++ ++static struct gpio_keys_platform_data ek_button_data = { ++ .buttons = ek_buttons, ++ .nbuttons = ARRAY_SIZE(ek_buttons), ++}; ++ ++static struct platform_device ek_button_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &ek_button_data, ++ } ++}; ++ ++static void __init ek_add_device_buttons(void) ++{ ++ at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* user push button, pull up enabled */ ++ at91_set_deglitch(AT91_PIN_PB10, 1); ++ ++ platform_device_register(&ek_button_device); ++} ++#else ++static void __init ek_add_device_buttons(void) {} ++#endif ++ ++/* ++ * LEDs ++ */ ++static struct gpio_led ek_leds[] = { ++ { /* user_led (green) */ ++ .name = "user_led", ++ .gpio = AT91_PIN_PB21, ++ .active_low = 1, ++ .default_trigger = "heartbeat", ++ } ++}; ++ ++ ++static void __init ek_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* USB Host */ ++ at91_add_device_usbh(&ek_usbh_data); ++ /* USB Device */ ++ at91_add_device_udc(&ek_udc_data); ++ /* SPI */ ++ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); ++ /* Ethernet */ ++ at91_add_device_eth(&ek_macb_data); ++ /* NAND */ ++ at91_add_device_nand(&ek_nand_data); ++ /* I2C */ ++ at91_add_device_i2c(NULL, 0); ++ /* Push Buttons */ ++ ek_add_device_buttons(); ++ /* LEDs */ ++ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); ++ /* shutdown controller, wakeup button (5 msec low) */ ++ at91_sys_write(AT91_SHDW_MR, AT91_SHDW_CPTWK0_(10) | AT91_SHDW_WKMODE0_LOW ++ | AT91_SHDW_RTTWKEN); ++} ++ ++MACHINE_START(USB_A9263, "CALAO USB_A9263") ++ /* Maintainer: calao-systems */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91sam926x_timer, ++ .map_io = ek_map_io, ++ .init_irq = ek_init_irq, ++ .init_machine = ek_board_init, ++MACHINE_END +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/clock.c linux-2.6/arch/arm/mach-at91/clock.c +--- linux-2.6.25/arch/arm/mach-at91/clock.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/clock.c 2008-04-25 21:15:43.000000000 +0200 +@@ -32,6 +32,7 @@ + #include <asm/arch/cpu.h> + + #include "clock.h" ++#include "generic.h" + + + /* +@@ -113,12 +114,34 @@ + at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask); + } + ++static void pmc_uckr_mode(struct clk *clk, int is_on) ++{ ++ unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); ++ ++ if (is_on) { ++ is_on = AT91_PMC_LOCKU; ++ at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); ++ } else ++ at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask)); ++ ++ do { ++ cpu_relax(); ++ } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on); ++} ++ + /* USB function clocks (PLLB must be 48 MHz) */ + static struct clk udpck = { + .name = "udpck", + .parent = &pllb, + .mode = pmc_sys_mode, + }; ++static struct clk utmi_clk = { ++ .name = "utmi_clk", ++ .parent = &main_clk, ++ .pmc_mask = AT91_PMC_UPLLEN, /* in CKGR_UCKR */ ++ .mode = pmc_uckr_mode, ++ .type = CLK_TYPE_PLL, ++}; + static struct clk uhpck = { + .name = "uhpck", + .parent = &pllb, +@@ -254,6 +277,23 @@ + + /*------------------------------------------------------------------------*/ + ++#ifdef CONFIG_PM ++ ++int clk_must_disable(struct clk *clk) ++{ ++ if (!at91_suspend_entering_slow_clock()) ++ return 0; ++ ++ while (clk->parent) ++ clk = clk->parent; ++ return clk != &clk32k; ++} ++EXPORT_SYMBOL(clk_must_disable); ++ ++#endif ++ ++/*------------------------------------------------------------------------*/ ++ + #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + + /* +@@ -362,7 +402,7 @@ + + static int at91_clk_show(struct seq_file *s, void *unused) + { +- u32 scsr, pcsr, sr; ++ u32 scsr, pcsr, uckr = 0, sr; + struct clk *clk; + + seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR)); +@@ -370,7 +410,10 @@ + seq_printf(s, "MOR = %8x\n", at91_sys_read(AT91_CKGR_MOR)); + seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); + seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); +- seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); ++ if (!cpu_is_at91sam9rl()) ++ seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); ++ if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) ++ seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR)); + seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); + seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); + +@@ -383,6 +426,8 @@ + state = (scsr & clk->pmc_mask) ? "on" : "off"; + else if (clk->mode == pmc_periph_mode) + state = (pcsr & clk->pmc_mask) ? "on" : "off"; ++ else if (clk->mode == pmc_uckr_mode) ++ state = (uckr & clk->pmc_mask) ? "on" : "off"; + else if (clk->pmc_mask) + state = (sr & clk->pmc_mask) ? "on" : "off"; + else if (clk == &clk32k || clk == &main_clk) +@@ -583,6 +628,17 @@ + uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + + /* ++ * USB HS clock init ++ */ ++ if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) { ++ /* ++ * multiplier is hard-wired to 40 ++ * (obtain the USB High Speed 480 MHz when input is 12 MHz) ++ */ ++ utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; ++ } ++ ++ /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ +@@ -599,6 +655,9 @@ + for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) + list_add_tail(&standard_pmc_clocks[i]->node, &clocks); + ++ if (cpu_is_at91cap9() || cpu_is_at91sam9rl()) ++ list_add_tail(&utmi_clk.node, &clocks); ++ + /* MCK and CPU clock are "always on" */ + clk_enable(&mck); + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/generic.h linux-2.6/arch/arm/mach-at91/generic.h +--- linux-2.6.25/arch/arm/mach-at91/generic.h 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/generic.h 2008-04-25 21:15:43.000000000 +0200 +@@ -41,6 +41,7 @@ + /* Power Management */ + extern void at91_irq_suspend(void); + extern void at91_irq_resume(void); ++extern int at91_suspend_entering_slow_clock(void); + + /* GPIO */ + #define AT91RM9200_PQFP 3 /* AT91RM9200 PQFP package has 3 banks */ +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/gpio.c linux-2.6/arch/arm/mach-at91/gpio.c +--- linux-2.6.25/arch/arm/mach-at91/gpio.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/gpio.c 2008-04-25 21:15:43.000000000 +0200 +@@ -490,7 +490,8 @@ + + /*--------------------------------------------------------------------------*/ + +-/* This lock class tells lockdep that GPIO irqs are in a different ++/* ++ * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ + static struct lock_class_key gpio_lock_class; +@@ -557,6 +558,7 @@ + data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS; + + /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ ++ /* AT91CAP9_ID_PIOABCD groups PIOA, PIOB, PIOC, PIOD */ + if (last && last->id == data->id) + last->next = data; + } +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/ics1523.c linux-2.6/arch/arm/mach-at91/ics1523.c +--- linux-2.6.25/arch/arm/mach-at91/ics1523.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/ics1523.c 2008-04-25 21:15:43.000000000 +0200 +@@ -0,0 +1,208 @@ ++/* ++ * arch/arm/mach-at91rm9200/ics1523.c ++ * ++ * Copyright (C) 2003 ATMEL Rousset ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++ ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++ ++#include <asm/arch/ics1523.h> ++#include <asm/arch/at91_twi.h> ++#include <asm/arch/gpio.h> ++ ++/* TWI Errors */ ++#define AT91_TWI_ERROR (AT91_TWI_NACK | AT91_TWI_UNRE | AT91_TWI_OVRE) ++ ++ ++static void __iomem *twi_base; ++ ++#define at91_twi_read(reg) __raw_readl(twi_base + (reg)) ++#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg)) ++ ++ ++/* ----------------------------------------------------------------------------- ++ * Initialization of TWI CLOCK ++ * ----------------------------------------------------------------------------- */ ++ ++static void at91_ics1523_SetTwiClock(unsigned int mck_khz) ++{ ++ int sclock; ++ ++ /* Here, CKDIV = 1 and CHDIV = CLDIV ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6) */ ++ sclock = (10*mck_khz / ICS_TRANSFER_RATE); ++ if (sclock % 10 >= 5) ++ sclock = (sclock /10) - 5; ++ else ++ sclock = (sclock /10)- 6; ++ sclock = (sclock + (4 - sclock %4)) >> 2; /* div 4 */ ++ ++ at91_twi_write(AT91_TWI_CWGR, 0x00010000 | sclock | (sclock << 8)); ++} ++ ++/* ----------------------------------------------------------------------------- ++ * Read a byte with TWI Interface from the Clock Generator ICS1523 ++ * ----------------------------------------------------------------------------- */ ++ ++static int at91_ics1523_ReadByte(unsigned char reg_address, unsigned char *data_in) ++{ ++ int Status, nb_trial; ++ ++ at91_twi_write(AT91_TWI_MMR, AT91_TWI_MREAD | AT91_TWI_IADRSZ_1 | ((ICS_ADDR << 16) & AT91_TWI_DADR)); ++ at91_twi_write(AT91_TWI_IADR, reg_address); ++ at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP); ++ ++ /* Program temporizing period (300us) */ ++ udelay(300); ++ ++ /* Wait TXcomplete ... */ ++ nb_trial = 0; ++ Status = at91_twi_read(AT91_TWI_SR); ++ while (!(Status & AT91_TWI_TXCOMP) && (nb_trial < 10)) { ++ nb_trial++; ++ Status = at91_twi_read(AT91_TWI_SR); ++ } ++ ++ if (Status & AT91_TWI_TXCOMP) { ++ *data_in = (unsigned char) at91_twi_read(AT91_TWI_RHR); ++ return ICS1523_ACCESS_OK; ++ } ++ else ++ return ICS1523_ACCESS_ERROR; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * Write a byte with TWI Interface to the Clock Generator ICS1523 ++ * ----------------------------------------------------------------------------- */ ++ ++static int at91_ics1523_WriteByte(unsigned char reg_address, unsigned char data_out) ++{ ++ int Status, nb_trial; ++ ++ at91_twi_write(AT91_TWI_MMR, AT91_TWI_IADRSZ_1 | ((ICS_ADDR << 16) & AT91_TWI_DADR)); ++ at91_twi_write(AT91_TWI_IADR, reg_address); ++ at91_twi_write(AT91_TWI_THR, data_out); ++ at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP); ++ ++ /* Program temporizing period (300us) */ ++ udelay(300); ++ ++ nb_trial = 0; ++ Status = at91_twi_read(AT91_TWI_SR); ++ while (!(Status & AT91_TWI_TXCOMP) && (nb_trial < 10)) { ++ nb_trial++; ++ if (Status & AT91_TWI_ERROR) { ++ /* If Underrun OR NACK - Start again */ ++ at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP); ++ ++ /* Program temporizing period (300us) */ ++ udelay(300); ++ } ++ Status = at91_twi_read(AT91_TWI_SR); ++ }; ++ ++ if (Status & AT91_TWI_TXCOMP) ++ return ICS1523_ACCESS_OK; ++ else ++ return ICS1523_ACCESS_ERROR; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * Initialization of the Clock Generator ICS1523 ++ * ----------------------------------------------------------------------------- */ ++ ++int at91_ics1523_init(void) ++{ ++ int nb_trial; ++ int ack = ICS1523_ACCESS_OK; ++ unsigned int status = 0xffffffff; ++ struct clk *twi_clk; ++ ++ /* Map in TWI peripheral */ ++ twi_base = ioremap(AT91RM9200_BASE_TWI, SZ_16K); ++ if (!twi_base) ++ return -ENOMEM; ++ ++ /* pins used for TWI interface */ ++ at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */ ++ at91_set_multi_drive(AT91_PIN_PA25, 1); ++ at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */ ++ at91_set_multi_drive(AT91_PIN_PA26, 1); ++ ++ /* Enable the TWI clock */ ++ twi_clk = clk_get(NULL, "twi_clk"); ++ if (IS_ERR(twi_clk)) ++ return ICS1523_ACCESS_ERROR; ++ clk_enable(twi_clk); ++ ++ /* Disable interrupts */ ++ at91_twi_write(AT91_TWI_IDR, -1); ++ ++ /* Reset peripheral */ ++ at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); ++ ++ /* Set Master mode */ ++ at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); ++ ++ /* Set TWI Clock Waveform Generator Register */ ++ at91_ics1523_SetTwiClock(60000); /* MCK in KHz = 60000 KHz */ ++ ++ /* ICS1523 Initialisation */ ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_ICR, (unsigned char) 0); ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_OE, (unsigned char) (ICS_OEF | ICS_OET2 | ICS_OETCK)); ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_OD, (unsigned char) (ICS_INSEL | 0x7F)); ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_DPAO, (unsigned char) 0); ++ ++ nb_trial = 0; ++ do { ++ nb_trial++; ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_ICR, (unsigned char) (ICS_ENDLS | ICS_ENPLS | ICS_PDEN /*| ICS_FUNCSEL*/)); ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_LCR, (unsigned char) (ICS_PSD | ICS_PFD)); ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_FD0, (unsigned char) 0x39) ; /* 0x7A */ ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_FD1, (unsigned char) 0x00); ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_SWRST, (unsigned char) (ICS_PLLR)); ++ ++ /* Program 1ms temporizing period */ ++ mdelay(1); ++ ++ at91_ics1523_ReadByte ((unsigned char) ICS_SR, (char *)&status); ++ } while (!((unsigned int) status & (unsigned int) ICS_PLLLOCK) && (nb_trial < 10)); ++ ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_DPAC, (unsigned char) 0x03) ; /* 0x01 */ ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_SWRST, (unsigned char) (ICS_DPAR)); ++ ++ /* Program 1ms temporizing period */ ++ mdelay(1); ++ ++ ack |= at91_ics1523_WriteByte ((unsigned char) ICS_DPAO, (unsigned char) 0x00); ++ ++ /* Program 1ms temporizing period */ ++ mdelay(1); ++ ++ /* All done - cleanup */ ++ iounmap(twi_base); ++ clk_disable(twi_clk); ++ clk_put(twi_clk); ++ ++ return ack; ++} +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/pm.c linux-2.6/arch/arm/mach-at91/pm.c +--- linux-2.6.25/arch/arm/mach-at91/pm.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/pm.c 2008-04-25 21:15:43.000000000 +0200 +@@ -26,12 +26,144 @@ + #include <asm/mach-types.h> + + #include <asm/arch/at91_pmc.h> +-#include <asm/arch/at91rm9200_mc.h> + #include <asm/arch/gpio.h> + #include <asm/arch/cpu.h> + + #include "generic.h" + ++#ifdef CONFIG_ARCH_AT91RM9200 ++#include <asm/arch/at91rm9200_mc.h> ++ ++/* ++ * The AT91RM9200 goes into self-refresh mode with this command, and will ++ * terminate self-refresh automatically on the next SDRAM access. ++ */ ++#define sdram_selfrefresh_enable() at91_sys_write(AT91_SDRAMC_SRR, 1) ++#define sdram_selfrefresh_disable() do {} while (0) ++ ++#elif defined(CONFIG_ARCH_AT91CAP9) ++#include <asm/arch/at91cap9_ddrsdr.h> ++ ++static u32 saved_lpr; ++ ++static inline void sdram_selfrefresh_enable(void) ++{ ++ u32 lpr; ++ ++ saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR); ++ ++ lpr = saved_lpr & ~AT91_DDRSDRC_LPCB; ++ at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH); ++} ++ ++#define sdram_selfrefresh_disable() at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr) ++ ++#else ++#include <asm/arch/at91sam9_sdramc.h> ++ ++#ifdef CONFIG_ARCH_AT91SAM9263 ++/* ++ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use; ++ * handle those cases both here and in the Suspend-To-RAM support. ++ */ ++#define AT91_SDRAMC AT91_SDRAMC0 ++#warning Assuming EB1 SDRAM controller is *NOT* used ++#endif ++ ++static u32 saved_lpr; ++ ++static inline void sdram_selfrefresh_enable(void) ++{ ++ u32 lpr; ++ ++ saved_lpr = at91_sys_read(AT91_SDRAMC_LPR); ++ ++ lpr = saved_lpr & ~AT91_SDRAMC_LPCB; ++ at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH); ++} ++ ++#define sdram_selfrefresh_disable() at91_sys_write(AT91_SDRAMC_LPR, saved_lpr) ++ ++/* ++ * FIXME: The AT91SAM9263 has a second EBI controller which may have ++ * additional SDRAM. pm_slowclock.S will require a similar fix. ++ */ ++ ++#endif ++ ++ ++/* ++ * Show the reason for the previous system reset. ++ */ ++#if defined(AT91_SHDWC) ++ ++#include <asm/arch/at91_rstc.h> ++#include <asm/arch/at91_shdwc.h> ++ ++static void __init show_reset_status(void) ++{ ++ static char reset[] __initdata = "reset"; ++ ++ static char general[] __initdata = "general"; ++ static char wakeup[] __initdata = "wakeup"; ++ static char watchdog[] __initdata = "watchdog"; ++ static char software[] __initdata = "software"; ++ static char user[] __initdata = "user"; ++ static char unknown[] __initdata = "unknown"; ++ ++ static char signal[] __initdata = "signal"; ++ static char rtc[] __initdata = "rtc"; ++ static char rtt[] __initdata = "rtt"; ++ static char restore[] __initdata = "power-restored"; ++ ++ char *reason, *r2 = reset; ++ u32 reset_type, wake_type; ++ ++ reset_type = at91_sys_read(AT91_RSTC_SR) & AT91_RSTC_RSTTYP; ++ wake_type = at91_sys_read(AT91_SHDW_SR); ++ ++ switch (reset_type) { ++ case AT91_RSTC_RSTTYP_GENERAL: ++ reason = general; ++ break; ++ case AT91_RSTC_RSTTYP_WAKEUP: ++ /* board-specific code enabled the wakeup sources */ ++ reason = wakeup; ++ ++ /* "wakeup signal" */ ++ if (wake_type & AT91_SHDW_WAKEUP0) ++ r2 = signal; ++ else { ++ r2 = reason; ++ if (wake_type & AT91_SHDW_RTTWK) /* rtt wakeup */ ++ reason = rtt; ++ else if (wake_type & AT91_SHDW_RTCWK) /* rtc wakeup */ ++ reason = rtc; ++ else if (wake_type == 0) /* power-restored wakeup */ ++ reason = restore; ++ else /* unknown wakeup */ ++ reason = unknown; ++ } ++ break; ++ case AT91_RSTC_RSTTYP_WATCHDOG: ++ reason = watchdog; ++ break; ++ case AT91_RSTC_RSTTYP_SOFTWARE: ++ reason = software; ++ break; ++ case AT91_RSTC_RSTTYP_USER: ++ reason = user; ++ break; ++ default: ++ reason = unknown; ++ break; ++ } ++ pr_info("AT91: Starting after %s %s\n", reason, r2); ++} ++#else ++static void __init show_reset_status(void) {} ++#endif ++ + + static int at91_pm_valid_state(suspend_state_t state) + { +@@ -62,6 +194,7 @@ + * Verify that all the clocks are correct before entering + * slow-clock mode. + */ ++#warning "This should probably be moved to clocks.c" + static int at91_pm_verify_clocks(void) + { + unsigned long scsr; +@@ -107,24 +240,24 @@ + } + + /* +- * Call this from platform driver suspend() to see how deeply to suspend. ++ * This is called from clk_must_disable(), to see how deeply to suspend. + * For example, some controllers (like OHCI) need one of the PLL clocks + * in order to act as a wakeup source, and those are not available when + * going into slow clock mode. +- * +- * REVISIT: generalize as clk_will_be_available(clk)? Other platforms have +- * the very same problem (but not using at91 main_clk), and it'd be better +- * to add one generic API rather than lots of platform-specific ones. + */ + int at91_suspend_entering_slow_clock(void) + { + return (target_state == PM_SUSPEND_MEM); + } +-EXPORT_SYMBOL(at91_suspend_entering_slow_clock); + + + static void (*slow_clock)(void); + ++#ifdef CONFIG_AT91_SLOW_CLOCK ++extern void at91_slow_clock(void); ++extern u32 at91_slow_clock_sz; ++#endif ++ + + static int at91_pm_enter(suspend_state_t state) + { +@@ -158,11 +291,14 @@ + * turning off the main oscillator; reverse on wakeup. + */ + if (slow_clock) { ++#ifdef CONFIG_AT91_SLOW_CLOCK ++ /* copy slow_clock handler to SRAM, and call it */ ++ memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz); ++#endif + slow_clock(); + break; + } else { +- /* DEVELOPMENT ONLY */ +- pr_info("AT91: PM - no slow clock mode yet ...\n"); ++ pr_info("AT91: PM - no slow clock mode enabled ...\n"); + /* FALLTHROUGH leaving master clock alone */ + } + +@@ -175,13 +311,15 @@ + case PM_SUSPEND_STANDBY: + /* + * NOTE: the Wait-for-Interrupt instruction needs to be +- * in icache so the SDRAM stays in self-refresh mode until +- * the wakeup IRQ occurs. ++ * in icache so no SDRAM accesses are needed until the ++ * wakeup IRQ occurs and self-refresh is terminated. + */ + asm("b 1f; .align 5; 1:"); + asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ +- at91_sys_write(AT91_SDRAMC_SRR, 1); /* self-refresh mode */ +- /* fall though to next state */ ++ sdram_selfrefresh_enable(); ++ asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ ++ sdram_selfrefresh_disable(); ++ break; + + case PM_SUSPEND_ON: + asm("mcr p15, 0, r0, c7, c0, 4"); /* wait for interrupt */ +@@ -196,6 +334,7 @@ + at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR)); + + error: ++ sdram_selfrefresh_disable(); + target_state = PM_SUSPEND_ON; + at91_irq_resume(); + at91_gpio_resume(); +@@ -220,21 +359,20 @@ + + static int __init at91_pm_init(void) + { +- printk("AT91: Power Management\n"); +- +-#ifdef CONFIG_AT91_PM_SLOW_CLOCK +- /* REVISIT allocations of SRAM should be dynamically managed. +- * FIQ handlers and other components will want SRAM/TCM too... +- */ +- slow_clock = (void *) (AT91_VA_BASE_SRAM + (3 * SZ_4K)); +- memcpy(slow_clock, at91rm9200_slow_clock, at91rm9200_slow_clock_sz); ++#ifdef CONFIG_AT91_SLOW_CLOCK ++ slow_clock = (void *) (AT91_IO_VIRT_BASE - at91_slow_clock_sz); + #endif + +- /* Disable SDRAM low-power mode. Cannot be used with self-refresh. */ ++ pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : "")); ++ ++#ifdef CONFIG_ARCH_AT91RM9200 ++ /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */ + at91_sys_write(AT91_SDRAMC_LPR, 0); ++#endif + + suspend_set_ops(&at91_pm_ops); + ++ show_reset_status(); + return 0; + } + arch_initcall(at91_pm_init); +diff -urN -x CVS linux-2.6.25/arch/arm/mach-at91/pm_slowclock.S linux-2.6/arch/arm/mach-at91/pm_slowclock.S +--- linux-2.6.25/arch/arm/mach-at91/pm_slowclock.S 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-at91/pm_slowclock.S 2008-05-03 01:00:33.000000000 +0200 +@@ -0,0 +1,283 @@ ++/* ++ * arch/arm/mach-at91/pm_slow_clock.S ++ * ++ * Copyright (C) 2006 Savin Zlobec ++ * ++ * AT91SAM9 support: ++ * Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee ++ * ++ * 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 ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/linkage.h> ++#include <asm/hardware.h> ++#include <asm/arch/at91_pmc.h> ++ ++#ifdef CONFIG_ARCH_AT91RM9200 ++#include <asm/arch/at91rm9200_mc.h> ++#elif defined(CONFIG_ARCH_AT91CAP9) ++#include <asm/arch/at91cap9_ddrsdr.h> ++#else ++#include <asm/arch/at91sam9_sdramc.h> ++#endif ++ ++ ++#ifdef CONFIG_ARCH_AT91SAM9263 ++/* ++ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use; ++ * handle those cases both here and in the Suspend-To-RAM support. ++ */ ++#define AT91_SDRAMC AT91_SDRAMC0 ++#warning Assuming EB1 SDRAM controller is *NOT* used ++#endif ++ ++/* ++ * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master ++ * clock during suspend by adjusting its prescalar and divisor. ++ * NOTE: This hasn't been shown to be stable on SAM9s; and on the RM9200 there ++ * are errata regarding adjusting the prescalar and divisor. ++ */ ++#undef SLOWDOWN_MASTER_CLOCK ++ ++#define MCKRDY_TIMEOUT 1000 ++#define MOSCRDY_TIMEOUT 1000 ++#define PLLALOCK_TIMEOUT 1000 ++#define PLLBLOCK_TIMEOUT 1000 ++ ++ ++/* ++ * Wait until master clock is ready (after switching master clock source) ++ */ ++ .macro wait_mckrdy ++ mov r4, #MCKRDY_TIMEOUT ++1: sub r4, r4, #1 ++ cmp r4, #0 ++ beq 2f ++ ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] ++ tst r3, #AT91_PMC_MCKRDY ++ beq 1b ++2: ++ .endm ++ ++/* ++ * Wait until master oscillator has stabilized. ++ */ ++ .macro wait_moscrdy ++ mov r4, #MOSCRDY_TIMEOUT ++1: sub r4, r4, #1 ++ cmp r4, #0 ++ beq 2f ++ ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] ++ tst r3, #AT91_PMC_MOSCS ++ beq 1b ++2: ++ .endm ++ ++/* ++ * Wait until PLLA has locked. ++ */ ++ .macro wait_pllalock ++ mov r4, #PLLALOCK_TIMEOUT ++1: sub r4, r4, #1 ++ cmp r4, #0 ++ beq 2f ++ ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] ++ tst r3, #AT91_PMC_LOCKA ++ beq 1b ++2: ++ .endm ++ ++/* ++ * Wait until PLLB has locked. ++ */ ++ .macro wait_pllblock ++ mov r4, #PLLBLOCK_TIMEOUT ++1: sub r4, r4, #1 ++ cmp r4, #0 ++ beq 2f ++ ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] ++ tst r3, #AT91_PMC_LOCKB ++ beq 1b ++2: ++ .endm ++ ++ .text ++ ++ENTRY(at91_slow_clock) ++ /* Save registers on stack */ ++ stmfd sp!, {r0 - r12, lr} ++ ++ /* ++ * Register usage: ++ * R1 = Base address of AT91_PMC ++ * R2 = Base address of AT91_SDRAMC (or AT91_SYS on AT91RM9200) ++ * R3 = temporary register ++ * R4 = temporary register ++ */ ++ ldr r1, .at91_va_base_pmc ++ ldr r2, .at91_va_base_sdramc ++ ++ /* Drain write buffer */ ++ mcr p15, 0, r0, c7, c10, 4 ++ ++#ifdef CONFIG_ARCH_AT91RM9200 ++ /* Put SDRAM in self-refresh mode */ ++ mov r3, #1 ++ str r3, [r2, #AT91_SDRAMC_SRR] ++#elif defined(CONFIG_ARCH_AT91CAP9) ++ /* Enable SDRAM self-refresh mode */ ++ ldr r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC] ++ str r3, .saved_sam9_lpr ++ ++ mov r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH ++ str r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC] ++#else ++ /* Enable SDRAM self-refresh mode */ ++ ldr r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC] ++ str r3, .saved_sam9_lpr ++ ++ mov r3, #AT91_SDRAMC_LPCB_SELF_REFRESH ++ str r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC] ++#endif ++ ++ /* Save Master clock setting */ ++ ldr r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] ++ str r3, .saved_mckr ++ ++ /* ++ * Set the Master clock source to slow clock ++ */ ++ bic r3, r3, #AT91_PMC_CSS ++ str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] ++ ++ wait_mckrdy ++ ++#ifdef SLOWDOWN_MASTER_CLOCK ++ /* ++ * Set the Master Clock PRES and MDIV fields. ++ * ++ * See AT91RM9200 errata #27 and #28 for details. ++ */ ++ mov r3, #0 ++ str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] ++ ++ wait_mckrdy ++#endif ++ ++ /* Save PLLA setting and disable it */ ++ ldr r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)] ++ str r3, .saved_pllar ++ ++ mov r3, #AT91_PMC_PLLCOUNT ++ orr r3, r3, #(1 << 29) /* bit 29 always set */ ++ str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)] ++ ++ wait_pllalock ++ ++ /* Save PLLB setting and disable it */ ++ ldr r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)] ++ str r3, .saved_pllbr ++ ++ mov r3, #AT91_PMC_PLLCOUNT ++ str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)] ++ ++ wait_pllblock ++ ++ /* Turn off the main oscillator */ ++ ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] ++ bic r3, r3, #AT91_PMC_MOSCEN ++ str r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] ++ ++ /* Wait for interrupt */ ++ mcr p15, 0, r0, c7, c0, 4 ++ ++ /* Turn on the main oscillator */ ++ ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] ++ orr r3, r3, #AT91_PMC_MOSCEN ++ str r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] ++ ++ wait_moscrdy ++ ++ /* Restore PLLB setting */ ++ ldr r3, .saved_pllbr ++ str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)] ++ ++ wait_pllblock ++ ++ /* Restore PLLA setting */ ++ ldr r3, .saved_pllar ++ str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)] ++ ++ wait_pllalock ++ ++#ifdef SLOWDOWN_MASTER_CLOCK ++ /* ++ * First set PRES if it was not 0, ++ * than set CSS and MDIV fields. ++ * ++ * See AT91RM9200 errata #27 and #28 for details. ++ */ ++ ldr r3, .saved_mckr ++ tst r3, #AT91_PMC_PRES ++ beq 2f ++ and r3, r3, #AT91_PMC_PRES ++ str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] ++ ++ wait_mckrdy ++#endif ++ ++ /* ++ * Restore master clock setting ++ */ ++2: ldr r3, .saved_mckr ++ str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] ++ ++ wait_mckrdy ++ ++#ifdef CONFIG_ARCH_AT91RM9200 ++ /* Do nothing - self-refresh is automatically disabled. */ ++#elif defined(CONFIG_ARCH_AT91CAP9) ++ /* Restore LPR on AT91CAP9 */ ++ ldr r3, .saved_sam9_lpr ++ str r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC] ++#else ++ /* Restore LPR on AT91SAM9 */ ++ ldr r3, .saved_sam9_lpr ++ str r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC] ++#endif ++ ++ /* Restore registers, and return */ ++ ldmfd sp!, {r0 - r12, pc} ++ ++ ++.saved_mckr: ++ .word 0 ++ ++.saved_pllar: ++ .word 0 ++ ++.saved_pllbr: ++ .word 0 ++ ++.saved_sam9_lpr: ++ .word 0 ++ ++.at91_va_base_pmc: ++ .word AT91_VA_BASE_SYS + AT91_PMC ++ ++#ifdef CONFIG_ARCH_AT91RM9200 ++.at91_va_base_sdramc: ++ .word AT91_VA_BASE_SYS ++#elif defined(CONFIG_ARCH_AT91CAP9) ++.at91_va_base_sdramc: ++ .word AT91_VA_BASE_SYS + AT91_DDRSDRC ++#else ++.at91_va_base_sdramc: ++ .word AT91_VA_BASE_SYS + AT91_SDRAMC ++#endif ++ ++ENTRY(at91_slow_clock_sz) ++ .word .-at91_slow_clock +diff -urN -x CVS linux-2.6.25/arch/arm/mach-ks8695/Makefile linux-2.6/arch/arm/mach-ks8695/Makefile +--- linux-2.6.25/arch/arm/mach-ks8695/Makefile 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-ks8695/Makefile 2007-12-31 15:04:45.000000000 +0200 +@@ -11,5 +11,8 @@ + # PCI support is optional + obj-$(CONFIG_PCI) += pci.o + ++# LEDs ++obj-$(CONFIG_LEDS) += leds.o ++ + # Board-specific support + obj-$(CONFIG_MACH_KS8695) += board-micrel.o +diff -urN -x CVS linux-2.6.25/arch/arm/mach-ks8695/devices.c linux-2.6/arch/arm/mach-ks8695/devices.c +--- linux-2.6.25/arch/arm/mach-ks8695/devices.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/arch/arm/mach-ks8695/devices.c 2007-12-31 10:43:55.000000000 +0200 +@@ -176,6 +176,27 @@ + #endif + + ++/* -------------------------------------------------------------------- ++ * LEDs ++ * -------------------------------------------------------------------- */ ++ ++#if defined(CONFIG_LEDS) ++short ks8695_leds_cpu = -1; ++short ks8695_leds_timer = -1; ++ ++void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) ++{ ++ /* Enable GPIO to access the LEDs */ ++ gpio_direction_output(cpu_led, 1); ++ gpio_direction_output(timer_led, 1); ++ ++ ks8695_leds_cpu = cpu_led; ++ ks8695_leds_timer = timer_led; ++} ++#else ++void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) {} ++#endif ++ + /* -------------------------------------------------------------------- */ + + /* +diff -urN -x CVS linux-2.6.25/arch/arm/mach-ks8695/gpio.c linux-2.6/arch/arm/mach-ks8695/gpio.c +--- linux-2.6.25/arch/arm/mach-ks8695/gpio.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-ks8695/gpio.c 2007-12-31 14:49:20.000000000 +0200 +@@ -136,9 +136,9 @@ + /* set line state */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + if (state) +- x |= (1 << pin); ++ x |= IOPD_(pin); + else +- x &= ~(1 << pin); ++ x &= ~IOPD_(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); + + /* set pin as output */ +@@ -168,9 +168,9 @@ + /* set output line state */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + if (state) +- x |= (1 << pin); ++ x |= IOPD_(pin); + else +- x &= ~(1 << pin); ++ x &= ~IOPD_(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); + + local_irq_restore(flags); +@@ -189,7 +189,7 @@ + return -EINVAL; + + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); +- return (x & (1 << pin)) != 0; ++ return (x & IOPD_(pin)) != 0; + } + EXPORT_SYMBOL(gpio_get_value); + +diff -urN -x CVS linux-2.6.25/arch/arm/mach-ks8695/leds.c linux-2.6/arch/arm/mach-ks8695/leds.c +--- linux-2.6.25/arch/arm/mach-ks8695/leds.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/arch/arm/mach-ks8695/leds.c 2007-12-31 15:18:25.000000000 +0200 +@@ -0,0 +1,94 @@ ++/* ++ * LED driver for KS8695-based boards. ++ * ++ * Copyright (C) Andrew Victor ++ * ++ * 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 ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++ ++#include <asm/mach-types.h> ++#include <asm/leds.h> ++#include <asm/arch/devices.h> ++#include <asm/arch/gpio.h> ++ ++ ++static inline void ks8695_led_on(unsigned int led) ++{ ++ gpio_set_value(led, 0); ++} ++ ++static inline void ks8695_led_off(unsigned int led) ++{ ++ gpio_set_value(led, 1); ++} ++ ++static inline void ks8695_led_toggle(unsigned int led) ++{ ++ unsigned long is_off = gpio_get_value(led); ++ if (is_off) ++ ks8695_led_on(led); ++ else ++ ks8695_led_off(led); ++} ++ ++ ++/* ++ * Handle LED events. ++ */ ++static void ks8695_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch(evt) { ++ case led_start: /* System startup */ ++ ks8695_led_on(ks8695_leds_cpu); ++ break; ++ ++ case led_stop: /* System stop / suspend */ ++ ks8695_led_off(ks8695_leds_cpu); ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: /* Every 50 timer ticks */ ++ ks8695_led_toggle(ks8695_leds_timer); ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: /* Entering idle state */ ++ ks8695_led_off(ks8695_leds_cpu); ++ break; ++ ++ case led_idle_end: /* Exit idle state */ ++ ks8695_led_on(ks8695_leds_cpu); ++ break; ++#endif ++ ++ default: ++ break; ++ } ++ ++ local_irq_restore(flags); ++} ++ ++ ++static int __init leds_init(void) ++{ ++ if ((ks8695_leds_timer == -1) || (ks8695_leds_cpu == -1)) ++ return -ENODEV; ++ ++ leds_event = ks8695_leds_event; ++ ++ leds_event(led_start); ++ return 0; ++} ++ ++__initcall(leds_init); +diff -urN -x CVS linux-2.6.25/arch/arm/mach-ks8695/pci.c linux-2.6/arch/arm/mach-ks8695/pci.c +--- linux-2.6.25/arch/arm/mach-ks8695/pci.c 2008-05-03 00:15:44.000000000 +0200 ++++ linux-2.6/arch/arm/mach-ks8695/pci.c 2008-05-08 22:03:41.000000000 +0200 +@@ -141,7 +141,7 @@ + .write = ks8695_pci_writeconfig, + }; + +-static struct pci_bus *ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys) ++static struct pci_bus* __init ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys) + { + return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys); + } +diff -urN -x CVS linux-2.6.25/drivers/char/Kconfig linux-2.6/drivers/char/Kconfig +--- linux-2.6.25/drivers/char/Kconfig 2008-05-03 00:15:47.000000000 +0200 ++++ linux-2.6/drivers/char/Kconfig 2008-03-09 15:14:46.000000000 +0200 +@@ -1056,5 +1056,21 @@ + + source "drivers/s390/char/Kconfig" + ++config AT91_SPI ++ bool "SPI driver (legacy) for AT91RM9200 processors" ++ depends on ARCH_AT91RM9200 ++ default y ++ help ++ The SPI driver gives access to this serial bus on the AT91RM9200 ++ processor. ++ ++config AT91_SPIDEV ++ bool "SPI device interface (legacy) for AT91RM9200 processors" ++ depends on ARCH_AT91RM9200 && AT91_SPI ++ default n ++ help ++ The SPI driver gives user mode access to this serial ++ bus on the AT91RM9200 processor. ++ + endmenu + +diff -urN -x CVS linux-2.6.25/drivers/char/Makefile linux-2.6/drivers/char/Makefile +--- linux-2.6.25/drivers/char/Makefile 2008-05-03 00:15:47.000000000 +0200 ++++ linux-2.6/drivers/char/Makefile 2008-03-09 15:14:46.000000000 +0200 +@@ -98,6 +98,8 @@ + obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o + obj-$(CONFIG_GPIO_TB0219) += tb0219.o + obj-$(CONFIG_TELCLOCK) += tlclk.o ++obj-$(CONFIG_AT91_SPI) += at91_spi.o ++obj-$(CONFIG_AT91_SPIDEV) += at91_spidev.o + + obj-$(CONFIG_MWAVE) += mwave/ + obj-$(CONFIG_AGP) += agp/ +diff -urN -x CVS linux-2.6.25/drivers/char/at91_spi.c linux-2.6/drivers/char/at91_spi.c +--- linux-2.6.25/drivers/char/at91_spi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/char/at91_spi.c 2008-04-18 17:38:01.000000000 +0200 +@@ -0,0 +1,337 @@ ++/* ++ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200 (Thunder) ++ * ++ * Copyright (C) SAN People (Pty) Ltd ++ * ++ * 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 <linux/init.h> ++#include <linux/dma-mapping.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/completion.h> ++#include <linux/interrupt.h> ++#include <linux/clk.h> ++#include <linux/platform_device.h> ++#include <linux/atmel_pdc.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++ ++#include <asm/arch/at91_spi.h> ++#include <asm/arch/board.h> ++#include <asm/arch/spi.h> ++ ++#undef DEBUG_SPI ++ ++static struct spi_local spi_dev[NR_SPI_DEVICES]; /* state of the SPI devices */ ++static int spi_enabled = 0; ++static struct semaphore spi_lock; /* protect access to SPI bus */ ++static int current_device = -1; /* currently selected SPI device */ ++static struct clk *spi_clk; /* SPI clock */ ++static void __iomem *spi_base; /* SPI peripheral base-address */ ++ ++DECLARE_COMPLETION(transfer_complete); ++ ++ ++#define at91_spi_read(reg) __raw_readl(spi_base + (reg)) ++#define at91_spi_write(reg, val) __raw_writel((val), spi_base + (reg)) ++ ++ ++/* ......................................................................... */ ++ ++/* ++ * Access and enable the SPI bus. ++ * This MUST be called before any transfers are performed. ++ */ ++void spi_access_bus(short device) ++{ ++ /* Ensure that requested device is valid */ ++ if ((device < 0) || (device >= NR_SPI_DEVICES)) ++ panic("at91_spi: spi_access_bus called with invalid device"); ++ ++ if (spi_enabled == 0) { ++ clk_enable(spi_clk); /* Enable Peripheral clock */ ++ at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIEN); /* Enable SPI */ ++#ifdef DEBUG_SPI ++ printk("SPI on\n"); ++#endif ++ } ++ spi_enabled++; ++ ++ /* Lock the SPI bus */ ++ down(&spi_lock); ++ current_device = device; ++ ++ /* Configure SPI bus for device */ ++ at91_spi_write(AT91_SPI_MR, AT91_SPI_MSTR | AT91_SPI_MODFDIS | (spi_dev[device].pcs << 16)); ++} ++ ++/* ++ * Relinquish control of the SPI bus. ++ */ ++void spi_release_bus(short device) ++{ ++ if (device != current_device) ++ panic("at91_spi: spi_release called with invalid device"); ++ ++ /* Release the SPI bus */ ++ current_device = -1; ++ up(&spi_lock); ++ ++ spi_enabled--; ++ if (spi_enabled == 0) { ++ at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIDIS); /* Disable SPI */ ++ clk_disable(spi_clk); /* Disable Peripheral clock */ ++#ifdef DEBUG_SPI ++ printk("SPI off\n"); ++#endif ++ } ++} ++ ++/* ++ * Perform a data transfer over the SPI bus ++ */ ++int spi_transfer(struct spi_transfer_list* list) ++{ ++ struct spi_local *device = (struct spi_local *) &spi_dev[current_device]; ++ int tx_size; ++ ++ if (!list) ++ panic("at91_spi: spi_transfer called with NULL transfer list"); ++ if (current_device == -1) ++ panic("at91_spi: spi_transfer called without acquiring bus"); ++ ++#ifdef DEBUG_SPI ++ printk("SPI transfer start [%i]\n", list->nr_transfers); ++#endif ++ ++ /* If we are in 16-bit mode, we need to modify what we pass to the PDC */ ++ tx_size = (at91_spi_read(AT91_SPI_CSR(current_device)) & AT91_SPI_BITS_16) ? 2 : 1; ++ ++ /* Store transfer list */ ++ device->xfers = list; ++ list->curr = 0; ++ ++ /* Assume there must be at least one transfer */ ++ device->tx = dma_map_single(NULL, list->tx[0], list->txlen[0], DMA_TO_DEVICE); ++ device->rx = dma_map_single(NULL, list->rx[0], list->rxlen[0], DMA_FROM_DEVICE); ++ ++ /* Program PDC registers */ ++ at91_spi_write(ATMEL_PDC_TPR, device->tx); ++ at91_spi_write(ATMEL_PDC_RPR, device->rx); ++ at91_spi_write(ATMEL_PDC_TCR, list->txlen[0] / tx_size); ++ at91_spi_write(ATMEL_PDC_RCR, list->rxlen[0] / tx_size); ++ ++ /* Is there a second transfer? */ ++ if (list->nr_transfers > 1) { ++ device->txnext = dma_map_single(NULL, list->tx[1], list->txlen[1], DMA_TO_DEVICE); ++ device->rxnext = dma_map_single(NULL, list->rx[1], list->rxlen[1], DMA_FROM_DEVICE); ++ ++ /* Program Next PDC registers */ ++ at91_spi_write(ATMEL_PDC_TNPR, device->txnext); ++ at91_spi_write(ATMEL_PDC_RNPR, device->rxnext); ++ at91_spi_write(ATMEL_PDC_TNCR, list->txlen[1] / tx_size); ++ at91_spi_write(ATMEL_PDC_RNCR, list->rxlen[1] / tx_size); ++ } ++ else { ++ device->txnext = 0; ++ device->rxnext = 0; ++ at91_spi_write(ATMEL_PDC_TNCR, 0); ++ at91_spi_write(ATMEL_PDC_RNCR, 0); ++ } ++ ++ // TODO: If we are doing consecutive transfers (at high speed, or ++ // small buffers), then it might be worth modifying the 'Delay between ++ // Consecutive Transfers' in the CSR registers. ++ // This is an issue if we cannot chain the next buffer fast enough ++ // in the interrupt handler. ++ ++ /* Enable transmitter and receiver */ ++ at91_spi_write(ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN | ATMEL_PDC_TXTEN); ++ ++ at91_spi_write(AT91_SPI_IER, AT91_SPI_ENDRX); /* enable buffer complete interrupt */ ++ wait_for_completion(&transfer_complete); ++ ++#ifdef DEBUG_SPI ++ printk("SPI transfer end\n"); ++#endif ++ ++ return 0; ++} ++ ++/* ......................................................................... */ ++ ++/* ++ * Handle interrupts from the SPI controller. ++ */ ++static irqreturn_t at91spi_interrupt(int irq, void *dev_id) ++{ ++ unsigned int status; ++ struct spi_local *device = (struct spi_local *) &spi_dev[current_device]; ++ struct spi_transfer_list *list = device->xfers; ++ ++#ifdef DEBUG_SPI ++ printk("SPI interrupt %i\n", current_device); ++#endif ++ ++ if (!list) ++ panic("at91_spi: spi_interrupt with a NULL transfer list"); ++ ++ status = at91_spi_read(AT91_SPI_SR) & at91_spi_read(AT91_SPI_IMR); /* read status */ ++ ++ dma_unmap_single(NULL, device->tx, list->txlen[list->curr], DMA_TO_DEVICE); ++ dma_unmap_single(NULL, device->rx, list->rxlen[list->curr], DMA_FROM_DEVICE); ++ ++ device->tx = device->txnext; /* move next transfer to current transfer */ ++ device->rx = device->rxnext; ++ ++ list->curr = list->curr + 1; ++ if (list->curr == list->nr_transfers) { /* all transfers complete */ ++ at91_spi_write(AT91_SPI_IDR, AT91_SPI_ENDRX); /* disable interrupt */ ++ ++ /* Disable transmitter and receiver */ ++ at91_spi_write(ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); ++ ++ device->xfers = NULL; ++ complete(&transfer_complete); ++ } ++ else if (list->curr+1 == list->nr_transfers) { /* no more next transfers */ ++ device->txnext = 0; ++ device->rxnext = 0; ++ at91_spi_write(ATMEL_PDC_TNCR, 0); ++ at91_spi_write(ATMEL_PDC_RNCR, 0); ++ } ++ else { ++ int i = (list->curr)+1; ++ ++ /* If we are in 16-bit mode, we need to modify what we pass to the PDC */ ++ int tx_size = (at91_spi_read(AT91_SPI_CSR(current_device)) & AT91_SPI_BITS_16) ? 2 : 1; ++ ++ device->txnext = dma_map_single(NULL, list->tx[i], list->txlen[i], DMA_TO_DEVICE); ++ device->rxnext = dma_map_single(NULL, list->rx[i], list->rxlen[i], DMA_FROM_DEVICE); ++ at91_spi_write(ATMEL_PDC_TNPR, device->txnext); ++ at91_spi_write(ATMEL_PDC_RNPR, device->rxnext); ++ at91_spi_write(ATMEL_PDC_TNCR, list->txlen[i] / tx_size); ++ at91_spi_write(ATMEL_PDC_RNCR, list->rxlen[i] / tx_size); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ......................................................................... */ ++ ++/* ++ * Initialize the SPI controller ++ */ ++static int __init at91spi_probe(struct platform_device *pdev) ++{ ++ int i; ++ unsigned long scbr; ++ struct resource *res; ++ ++ init_MUTEX(&spi_lock); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENXIO; ++ ++ if (!request_mem_region(res->start, res->end - res->start + 1, "at91_spi")) ++ return -EBUSY; ++ ++ spi_base = ioremap(res->start, res->end - res->start + 1); ++ if (!spi_base) { ++ release_mem_region(res->start, res->end - res->start + 1); ++ return -ENOMEM; ++ } ++ ++ spi_clk = clk_get(NULL, "spi_clk"); ++ if (IS_ERR(spi_clk)) { ++ printk(KERN_ERR "at91_spi: no clock defined\n"); ++ iounmap(spi_base); ++ release_mem_region(res->start, res->end - res->start + 1); ++ return -ENODEV; ++ } ++ ++ at91_spi_write(AT91_SPI_CR, AT91_SPI_SWRST); /* software reset of SPI controller */ ++ ++ /* ++ * Calculate the correct SPI baud-rate divisor. ++ */ ++ scbr = clk_get_rate(spi_clk) / (2 * DEFAULT_SPI_CLK); ++ scbr = scbr + 1; /* round up */ ++ ++ printk(KERN_INFO "at91_spi: Baud rate set to %ld\n", clk_get_rate(spi_clk) / (2 * scbr)); ++ ++ /* Set Chip Select registers to good defaults */ ++ for (i = 0; i < 4; i++) { ++ at91_spi_write(AT91_SPI_CSR(i), AT91_SPI_CPOL | AT91_SPI_BITS_8 | (16 << 16) | (scbr << 8)); ++ } ++ ++ at91_spi_write(ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); ++ ++ memset(&spi_dev, 0, sizeof(spi_dev)); ++ spi_dev[0].pcs = 0xE; ++ spi_dev[1].pcs = 0xD; ++ spi_dev[2].pcs = 0xB; ++ spi_dev[3].pcs = 0x7; ++ ++ if (request_irq(AT91RM9200_ID_SPI, at91spi_interrupt, 0, "spi", NULL)) { ++ clk_put(spi_clk); ++ iounmap(spi_base); ++ release_mem_region(res->start, res->end - res->start + 1); ++ return -EBUSY; ++ } ++ ++ at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIEN); /* Enable SPI */ ++ ++ return 0; ++} ++ ++static int __devexit at91spi_remove(struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIDIS); /* Disable SPI */ ++ clk_put(spi_clk); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ iounmap(spi_base); ++ release_mem_region(res->start, res->end - res->start + 1); ++ ++ free_irq(AT91RM9200_ID_SPI, 0); ++ return 0; ++} ++ ++static struct platform_driver at91spi_driver = { ++ .probe = at91spi_probe, ++ .remove = __devexit_p(at91spi_remove), ++ .driver = { ++ .name = "at91_spi", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init at91spi_init(void) ++{ ++ return platform_driver_register(&at91spi_driver); ++} ++ ++static void __exit at91spi_exit(void) ++{ ++ platform_driver_unregister(&at91spi_driver); ++} ++ ++EXPORT_SYMBOL(spi_access_bus); ++EXPORT_SYMBOL(spi_release_bus); ++EXPORT_SYMBOL(spi_transfer); ++ ++module_init(at91spi_init); ++module_exit(at91spi_exit); ++ ++MODULE_LICENSE("GPL") ++MODULE_AUTHOR("Andrew Victor") ++MODULE_DESCRIPTION("SPI driver for Atmel AT91RM9200") ++MODULE_ALIAS("platform:at91_spi"); +diff -urN -x CVS linux-2.6.25/drivers/char/at91_spidev.c linux-2.6/drivers/char/at91_spidev.c +--- linux-2.6.25/drivers/char/at91_spidev.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/char/at91_spidev.c 2007-12-31 15:18:43.000000000 +0200 +@@ -0,0 +1,233 @@ ++/* ++ * User-space interface to the SPI bus on Atmel AT91RM9200 ++ * ++ * Copyright (C) 2003 SAN People (Pty) Ltd ++ * ++ * Based on SPI driver by Rick Bronson ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/highmem.h> ++#include <linux/pagemap.h> ++#include <asm/arch/spi.h> ++ ++#ifdef CONFIG_DEVFS_FS ++#include <linux/devfs_fs_kernel.h> ++#endif ++ ++ ++#undef DEBUG_SPIDEV ++ ++/* ......................................................................... */ ++ ++/* ++ * Read or Write to SPI bus. ++ */ ++static ssize_t spidev_rd_wr(struct file *file, char *buf, size_t count, loff_t *offset) ++{ ++ unsigned int spi_device = (unsigned int) file->private_data; ++ ++ struct mm_struct * mm; ++ struct page ** maplist; ++ struct spi_transfer_list* list; ++ int pgcount; ++ ++ unsigned int ofs, pagelen; ++ int res, i, err; ++ ++ if (!count) { ++ return 0; ++ } ++ ++ list = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL); ++ if (!list) { ++ return -ENOMEM; ++ } ++ ++ mm = current->mm; ++ ++ pgcount = ((unsigned long)buf+count+PAGE_SIZE-1)/PAGE_SIZE - (unsigned long)buf/PAGE_SIZE; ++ ++ if (pgcount >= MAX_SPI_TRANSFERS) { ++ kfree(list); ++ return -EFBIG; ++ } ++ ++ maplist = kmalloc (pgcount * sizeof (struct page *), GFP_KERNEL); ++ ++ if (!maplist) { ++ kfree(list); ++ return -ENOMEM; ++ } ++ flush_cache_all(); ++ down_read(&mm->mmap_sem); ++ err= get_user_pages(current, mm, (unsigned long)buf, pgcount, 1, 0, maplist, NULL); ++ up_read(&mm->mmap_sem); ++ ++ if (err < 0) { ++ kfree(list); ++ kfree(maplist); ++ return err; ++ } ++ pgcount = err; ++ ++#ifdef DEBUG_SPIDEV ++ printk("spidev_rd_rw: %i %i\n", count, pgcount); ++#endif ++ ++ /* Set default return value = transfer length */ ++ res = count; ++ ++ /* ++ * At this point, the virtual area buf[0] .. buf[count-1] will have ++ * corresponding pages mapped in the physical memory and locked until ++ * we unmap the kiobuf. The pages cannot be swapped out or moved ++ * around. ++ */ ++ ofs = (unsigned long) buf & (PAGE_SIZE -1); ++ pagelen = PAGE_SIZE - ofs; ++ if (count < pagelen) ++ pagelen = count; ++ ++ for (i = 0; i < pgcount; i++) { ++ flush_dcache_page(maplist[i]); ++ ++ list->tx[i] = list->rx[i] = page_address(maplist[i]) + ofs; ++ list->txlen[i] = list->rxlen[i] = pagelen; ++ ++#ifdef DEBUG_SPIDEV ++ printk(" %i: %x (%i)\n", i, list->tx[i], list->txlen[i]); ++#endif ++ ++ ofs = 0; /* all subsequent transfers start at beginning of a page */ ++ count = count - pagelen; ++ pagelen = (count < PAGE_SIZE) ? count : PAGE_SIZE; ++ } ++ list->nr_transfers = pgcount; ++ ++ /* Perform transfer on SPI bus */ ++ spi_access_bus(spi_device); ++ spi_transfer(list); ++ spi_release_bus(spi_device); ++ ++ while (pgcount--) { ++ page_cache_release (maplist[pgcount]); ++ } ++ flush_cache_all(); ++ ++ kfree(maplist); ++ kfree(list); ++ ++ return res; ++} ++ ++static int spidev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int spi_device = MINOR(inode->i_rdev); ++ ++ if (spi_device >= NR_SPI_DEVICES) ++ return -ENODEV; ++ ++ // TODO: This interface can be used to configure the SPI bus. ++ // Configurable options could include: Speed, Clock Polarity, Clock Phase ++ ++ switch(cmd) { ++ default: ++ return -ENOIOCTLCMD; ++ } ++} ++ ++/* ++ * Open the SPI device ++ */ ++static int spidev_open(struct inode *inode, struct file *file) ++{ ++ unsigned int spi_device = MINOR(inode->i_rdev); ++ ++ if (spi_device >= NR_SPI_DEVICES) ++ return -ENODEV; ++ ++ /* ++ * 'private_data' is actually a pointer, but we overload it with the ++ * value we want to store. ++ */ ++ file->private_data = (void *)spi_device; ++ ++ return 0; ++} ++ ++/* ++ * Close the SPI device ++ */ ++static int spidev_close(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++/* ......................................................................... */ ++ ++static struct file_operations spidev_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = spidev_rd_wr, ++ .write = (int (*) (struct file *file, const char *buf, size_t count, loff_t *offset))spidev_rd_wr, ++ .ioctl = spidev_ioctl, ++ .open = spidev_open, ++ .release = spidev_close, ++}; ++ ++/* ++ * Install the SPI /dev interface driver ++ */ ++static int __init at91_spidev_init(void) ++{ ++#ifdef CONFIG_DEVFS_FS ++ int i; ++#endif ++ ++ if (register_chrdev(SPI_MAJOR, "spi", &spidev_fops)) { ++ printk(KERN_ERR "at91_spidev: Unable to get major %d for SPI bus\n", SPI_MAJOR); ++ return -EIO; ++ } ++ ++#ifdef CONFIG_DEVFS_FS ++ devfs_mk_dir("spi"); ++ for (i = 0; i < NR_SPI_DEVICES; i++) { ++ devfs_mk_cdev(MKDEV(SPI_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "spi/%d",i); ++ } ++#endif ++ printk(KERN_INFO "AT91 SPI driver loaded\n"); ++ ++ return 0; ++} ++ ++/* ++ * Remove the SPI /dev interface driver ++ */ ++static void __exit at91_spidev_exit(void) ++{ ++#ifdef CONFIG_DEVFS_FS ++ int i; ++ for (i = 0; i < NR_SPI_DEVICES; i++) { ++ devfs_remove("spi/%d", i); ++ } ++ ++ devfs_remove("spi"); ++#endif ++ ++ unregister_chrdev(SPI_MAJOR, "spi"); ++} ++ ++module_init(at91_spidev_init); ++module_exit(at91_spidev_exit); ++ ++MODULE_LICENSE("GPL") ++MODULE_AUTHOR("Andrew Victor") ++MODULE_DESCRIPTION("SPI /dev interface for Atmel AT91RM9200") +diff -urN -x CVS linux-2.6.25/drivers/i2c/busses/Kconfig linux-2.6/drivers/i2c/busses/Kconfig +--- linux-2.6.25/drivers/i2c/busses/Kconfig 2008-05-03 00:15:47.000000000 +0200 ++++ linux-2.6/drivers/i2c/busses/Kconfig 2008-04-02 22:11:28.000000000 +0200 +@@ -88,6 +88,14 @@ + to support combined I2C messages. Use the i2c-gpio driver + unless your system can cope with those limitations. + ++config I2C_AT91_CLOCKRATE ++ prompt "Atmel AT91 I2C/TWI clock-rate" ++ depends on I2C_AT91 ++ int ++ default 100000 ++ help ++ Set the AT91 I2C/TWI clock-rate. ++ + config I2C_AU1550 + tristate "Au1550/Au1200 SMBus interface" + depends on SOC_AU1550 || SOC_AU1200 +@@ -626,6 +634,14 @@ + This driver can also be built as a module. If so, the module + will be called i2c-voodoo3. + ++config I2C_PCA ++ tristate "PCA9564" ++ depends on I2C ++ select I2C_ALGOPCA ++ help ++ This driver support the Philips PCA 9564 Parallel bus to I2C ++ bus controller. ++ + config I2C_PCA_ISA + tristate "PCA9564 on an ISA bus" + depends on ISA +diff -urN -x CVS linux-2.6.25/drivers/i2c/busses/Makefile linux-2.6/drivers/i2c/busses/Makefile +--- linux-2.6.25/drivers/i2c/busses/Makefile 2008-05-03 00:15:47.000000000 +0200 ++++ linux-2.6/drivers/i2c/busses/Makefile 2008-03-09 15:14:46.000000000 +0200 +@@ -29,6 +29,7 @@ + obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o + obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o + obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o ++obj-$(CONFIG_I2C_PCA) += i2c-pca.o + obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o + obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o + obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o +diff -urN -x CVS linux-2.6.25/drivers/i2c/busses/i2c-at91.c linux-2.6/drivers/i2c/busses/i2c-at91.c +--- linux-2.6.25/drivers/i2c/busses/i2c-at91.c 2008-05-03 00:15:35.000000000 +0200 ++++ linux-2.6/drivers/i2c/busses/i2c-at91.c 2008-01-16 13:15:34.000000000 +0200 +@@ -31,8 +31,11 @@ + #include <asm/arch/board.h> + #include <asm/arch/cpu.h> + +-#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */ + ++/* Clockrate is configurable - max 400 Kbits/sec */ ++static unsigned int clockrate = CONFIG_I2C_AT91_CLOCKRATE; ++module_param(clockrate, uint, 0); ++MODULE_PARM_DESC(clockrate, "The TWI clockrate"); + + static struct clk *twi_clk; + static void __iomem *twi_base; +@@ -53,7 +56,7 @@ + at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */ + + /* Calcuate clock dividers */ +- cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3; ++ cdiv = (clk_get_rate(twi_clk) / (2 * clockrate)) - 3; + cdiv = cdiv + 1; /* round up */ + ckdiv = 0; + while (cdiv > 255) { +@@ -61,11 +64,12 @@ + cdiv = cdiv >> 1; + } + +- if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */ +- if (ckdiv > 5) { +- printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n"); +- ckdiv = 5; +- } ++ if (cpu_is_at91rm9200() && (ckdiv > 5)) { /* AT91RM9200 Errata #22 */ ++ printk(KERN_ERR "AT91 I2C: Invalid TWI clockrate!\n"); ++ ckdiv = 5; ++ } else if (ckdiv > 7) { ++ printk(KERN_ERR "AT91 I2C: Invalid TWI clockrate!\n"); ++ ckdiv = 7; + } + + at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv); +diff -urN -x CVS linux-2.6.25/drivers/i2c/busses/i2c-pca.c linux-2.6/drivers/i2c/busses/i2c-pca.c +--- linux-2.6.25/drivers/i2c/busses/i2c-pca.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/i2c/busses/i2c-pca.c 2007-12-31 15:18:43.000000000 +0200 +@@ -0,0 +1,213 @@ ++/* ++ * Platform driver for PCA9564 I2C bus controller. ++ * ++ * (C) 2006 Andrew Victor ++ * ++ * Based on i2c-pca-isa.c driver for PCA9564 on ISA boards ++ * Copyright (C) 2004 Arcom Control Systems ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/wait.h> ++#include <linux/platform_device.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-algo-pca.h> ++ ++#include <asm/io.h> ++ ++#include "../algos/i2c-algo-pca.h" ++ ++#define PCA_OWN_ADDRESS 0x55 /* our address for slave mode */ ++#define PCA_CLOCK I2C_PCA_CON_59kHz ++ ++//#define REG_SHIFT 2 ++#define REG_SHIFT 0 ++ ++//#define DEBUG_IO ++ ++#define PCA_IO_SIZE 4 ++ ++static void __iomem *base_addr; ++static int irq; ++static wait_queue_head_t pca_wait; ++ ++static int pca_getown(struct i2c_algo_pca_data *adap) ++{ ++ return PCA_OWN_ADDRESS; ++} ++ ++static int pca_getclock(struct i2c_algo_pca_data *adap) ++{ ++ return PCA_CLOCK; ++} ++ ++static void pca_writebyte(struct i2c_algo_pca_data *adap, int reg, int val) ++{ ++#ifdef DEBUG_IO ++ static char *names[] = { "T/O", "DAT", "ADR", "CON" }; ++ printk("*** write %s at %#lx <= %#04x\n", names[reg], (unsigned long) base_addr+reg, val); ++#endif ++ udelay(1); ++ outb(val, base_addr + (reg << REG_SHIFT)); ++} ++ ++static int pca_readbyte(struct i2c_algo_pca_data *adap, int reg) ++{ ++ int res; ++ ++ udelay(1); ++ res = inb(base_addr + (reg << REG_SHIFT)); ++#ifdef DEBUG_IO ++ { ++ static char *names[] = { "STA", "DAT", "ADR", "CON" }; ++ printk("*** read %s => %#04x\n", names[reg], res); ++ } ++#endif ++ return res; ++} ++ ++static int pca_waitforinterrupt(struct i2c_algo_pca_data *adap) ++{ ++ int ret = 0; ++ ++ if (irq > -1) { ++ ret = wait_event_interruptible(pca_wait, ++ pca_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI); ++ } else { ++ while ((pca_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) ++ udelay(100); ++ } ++ return ret; ++} ++ ++static irqreturn_t pca_handler(int this_irq, void *dev_id) ++{ ++ wake_up_interruptible(&pca_wait); ++ return IRQ_HANDLED; ++} ++ ++static struct i2c_algo_pca_data pca_i2c_data = { ++ .get_own = pca_getown, ++ .get_clock = pca_getclock, ++ .write_byte = pca_writebyte, ++ .read_byte = pca_readbyte, ++ .wait_for_interrupt = pca_waitforinterrupt, ++}; ++ ++static struct i2c_adapter pca_i2c_ops = { ++ .owner = THIS_MODULE, ++ .id = I2C_HW_A_PLAT, ++ .algo_data = &pca_i2c_data, ++ .name = "PCA9564", ++ .class = I2C_CLASS_HWMON, ++}; ++ ++static int __devinit pca_i2c_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ init_waitqueue_head(&pca_wait); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENODEV; ++ ++ if (!request_mem_region(res->start, PCA_IO_SIZE, "PCA9564")) ++ return -ENXIO; ++ ++ base_addr = ioremap(res->start, PCA_IO_SIZE); ++ if (base_addr == NULL) ++ goto out_region; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq > -1) { ++ if (request_irq(irq, pca_handler, 0, "pca9564", NULL) < 0) { ++ printk(KERN_ERR "i2c-pca: Request irq%d failed\n", irq); ++ goto out_remap; ++ } ++ } ++ ++ /* set up the driverfs linkage to our parent device */ ++ pca_i2c_ops.dev.parent = &pdev->dev; ++ ++ if (i2c_pca_add_bus(&pca_i2c_ops) < 0) { ++ printk(KERN_ERR "i2c-pca: Failed to add i2c bus\n"); ++ goto out_irq; ++ } ++ ++ return 0; ++ ++ out_irq: ++ if (irq > -1) ++ free_irq(irq, &pca_i2c_ops); ++ ++ out_remap: ++ iounmap(base_addr); ++ ++ out_region: ++ release_mem_region(res->start, PCA_IO_SIZE); ++ return -ENODEV; ++} ++ ++static int __devexit pca_i2c_remove(struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ i2c_del_adapter(&pca_i2c_ops); ++ ++ if (irq > 0) ++ free_irq(irq, NULL); ++ ++ iounmap(base_addr); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, PCA_IO_SIZE); ++ ++ return 0; ++} ++ ++static struct platform_driver pca_i2c_driver = { ++ .probe = pca_i2c_probe, ++ .remove = __devexit_p(pca_i2c_remove), ++ .driver = { ++ .name = "pca9564", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init pca_i2c_init(void) ++{ ++ return platform_driver_register(&pca_i2c_driver); ++} ++ ++static void __exit pca_i2c_exit(void) ++{ ++ platform_driver_unregister(&pca_i2c_driver); ++} ++ ++module_init(pca_i2c_init); ++module_exit(pca_i2c_exit); ++ ++MODULE_AUTHOR("Andrew Victor"); ++MODULE_DESCRIPTION("PCA9564 platform driver"); ++MODULE_LICENSE("GPL"); +diff -urN -x CVS linux-2.6.25/drivers/mmc/host/at91_mci.c linux-2.6/drivers/mmc/host/at91_mci.c +--- linux-2.6.25/drivers/mmc/host/at91_mci.c 2008-05-03 00:15:48.000000000 +0200 ++++ linux-2.6/drivers/mmc/host/at91_mci.c 2008-04-18 17:32:40.000000000 +0200 +@@ -659,13 +659,14 @@ + /* maybe switch power to the card */ + if (host->board->vcc_pin) { + switch (ios->power_mode) { +- case MMC_POWER_OFF: +- gpio_set_value(host->board->vcc_pin, 0); +- break; +- case MMC_POWER_UP: +- case MMC_POWER_ON: +- gpio_set_value(host->board->vcc_pin, 1); +- break; ++ case MMC_POWER_OFF: ++ gpio_set_value(host->board->vcc_pin, 0); ++ break; ++ case MMC_POWER_UP: ++ gpio_set_value(host->board->vcc_pin, 1); ++ break; ++ default: ++ break; + } + } + } +diff -urN -x CVS linux-2.6.25/drivers/mtd/devices/Kconfig linux-2.6/drivers/mtd/devices/Kconfig +--- linux-2.6.25/drivers/mtd/devices/Kconfig 2008-05-03 00:15:36.000000000 +0200 ++++ linux-2.6/drivers/mtd/devices/Kconfig 2007-12-31 10:44:25.000000000 +0200 +@@ -270,5 +270,17 @@ + LinuxBIOS or if you need to recover a DiskOnChip Millennium on which + you have managed to wipe the first block. + +-endmenu ++config MTD_AT91_DATAFLASH ++ tristate "AT91RM9200 DataFlash AT45DBxxx (legacy driver)" ++ depends on MTD && ARCH_AT91RM9200 && AT91_SPI ++ help ++ This enables access to the DataFlash (AT45DBxxx) on the AT91RM9200. ++ If you have such a board, say 'Y'. ++ ++config DATAFLASH_ALWAYS_ADD_DEVICE ++ bool "Register whole DataFlash device" ++ depends on MTD_AT91_DATAFLASH ++ help ++ Always add the whole DataFlash device when using MTD partitions. + ++endmenu +diff -urN -x CVS linux-2.6.25/drivers/mtd/devices/Makefile linux-2.6/drivers/mtd/devices/Makefile +--- linux-2.6.25/drivers/mtd/devices/Makefile 2008-05-03 00:15:36.000000000 +0200 ++++ linux-2.6/drivers/mtd/devices/Makefile 2007-12-31 10:48:27.000000000 +0200 +@@ -17,3 +17,4 @@ + obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o + obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o + obj-$(CONFIG_MTD_M25P80) += m25p80.o ++obj-$(CONFIG_MTD_AT91_DATAFLASH)+= at91_dataflash.o +diff -urN -x CVS linux-2.6.25/drivers/mtd/devices/at91_dataflash.c linux-2.6/drivers/mtd/devices/at91_dataflash.c +--- linux-2.6.25/drivers/mtd/devices/at91_dataflash.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/mtd/devices/at91_dataflash.c 2007-12-31 15:18:43.000000000 +0200 +@@ -0,0 +1,673 @@ ++/* ++ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) ++ * ++ * Copyright (C) SAN People (Pty) Ltd ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/mach-types.h> ++ ++#include <asm/arch/spi.h> ++ ++ ++#undef DEBUG_DATAFLASH ++ ++#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */ ++ ++#define OP_READ_CONTINUOUS 0xE8 ++#define OP_READ_PAGE 0xD2 ++#define OP_READ_BUFFER1 0xD4 ++#define OP_READ_BUFFER2 0xD6 ++#define OP_READ_STATUS 0xD7 ++ ++#define OP_ERASE_PAGE 0x81 ++#define OP_ERASE_BLOCK 0x50 ++ ++#define OP_TRANSFER_BUF1 0x53 ++#define OP_TRANSFER_BUF2 0x55 ++#define OP_COMPARE_BUF1 0x60 ++#define OP_COMPARE_BUF2 0x61 ++ ++#define OP_PROGRAM_VIA_BUF1 0x82 ++#define OP_PROGRAM_VIA_BUF2 0x85 ++ ++struct dataflash_local ++{ ++ int spi; /* SPI chip-select number */ ++ ++ unsigned int page_size; /* number of bytes per page */ ++ unsigned short page_offset; /* page offset in flash address */ ++}; ++ ++ ++/* Detected DataFlash devices */ ++static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES]; ++static int nr_devices = 0; ++ ++/* ......................................................................... */ ++ ++#ifdef CONFIG_MTD_PARTITIONS ++ ++static struct mtd_partition static_partitions_2M[] = ++{ ++ { ++ .name = "bootloader", ++ .offset = 0, ++ .size = 1 * 32 * 8 * 528, /* 1st sector = 32 blocks * 8 pages * 528 bytes */ ++ .mask_flags = MTD_WRITEABLE, /* read-only */ ++ }, ++ { ++ .name = "kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 6 * 32 * 8 * 528, /* 6 sectors */ ++ }, ++ { ++ .name = "filesystem", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, /* rest = 9 sectors */ ++ } ++}; ++ ++static struct mtd_partition static_partitions_4M[] = ++{ ++ { ++ .name = "bootloader", ++ .offset = 0, ++ .size = 1 * 64 * 8 * 528, /* 1st sector = 64 blocks * 8 pages * 528 bytes */ ++ .mask_flags = MTD_WRITEABLE, /* read-only */ ++ }, ++ { ++ .name = "kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 4 * 64 * 8 * 528, /* 4 sectors */ ++ }, ++ { ++ .name = "filesystem", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, /* rest = 11 sectors */ ++ } ++}; ++ ++#if defined(CONFIG_MACH_KAFA) ++static struct mtd_partition static_partitions_8M[] = ++{ ++ { ++ name: "romboot", ++ offset: 0, ++ size: 16 * 1056, /* 160 Kb */ ++ mask_flags: MTD_WRITEABLE, /* read-only */ ++ }, ++ { ++ name: "uboot", ++ offset: MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */ ++ size: 128 * 1056, /* 1 MB */ ++ }, ++ { ++ name: "kernel", ++ offset: MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */ ++ size: 1024 * 1056, /* 1 MB */ ++ }, ++ { ++ name: "filesystem", ++ offset: MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */ ++ size: MTDPART_SIZ_FULL, ++ } ++}; ++ ++#elif defined(CONFIG_MACH_MULTMDP) ++ ++static struct mtd_partition static_partitions_8M[] = ++{ ++ { ++ .name = "bootloader", ++ .offset = 0, ++ .size = 12 * 1056, /* 1st sector = 32 blocks * 8 pages * 1056 bytes */ ++ .mask_flags = MTD_WRITEABLE, /* read-only */ ++ }, ++ { ++ .name = "configuration", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 20 * 1056, ++ }, ++ { ++ .name = "kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 1520 * 1056, ++ }, ++ { ++ .name = "filesystem", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, ++ } ++}; ++ ++#else ++ ++static struct mtd_partition static_partitions_8M[] = ++{ ++ { ++ .name = "bootloader", ++ .offset = 0, ++ .size = 1 * 32 * 8 * 1056, /* 1st sector = 32 blocks * 8 pages * 1056 bytes */ ++ .mask_flags = MTD_WRITEABLE, /* read-only */ ++ }, ++ { ++ .name = "kernel", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = 5 * 32 * 8 * 1056, /* 5 sectors */ ++ }, ++ { ++ .name = "filesystem", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, /* rest = 26 sectors */ ++ } ++}; ++#endif ++ ++static const char *part_probes[] = { "cmdlinepart", NULL, }; ++ ++#endif ++ ++/* ......................................................................... */ ++ ++/* Allocate a single SPI transfer descriptor. We're assuming that if multiple ++ SPI transfers occur at the same time, spi_access_bus() will serialize them. ++ If this is not valid, then either (i) each dataflash 'priv' structure ++ needs it's own transfer descriptor, (ii) we lock this one, or (iii) use ++ another mechanism. */ ++static struct spi_transfer_list* spi_transfer_desc; ++ ++/* ++ * Perform a SPI transfer to access the DataFlash device. ++ */ ++static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, ++ char* txnext, int txnext_len, char* rxnext, int rxnext_len) ++{ ++ struct spi_transfer_list* list = spi_transfer_desc; ++ ++ list->tx[0] = tx; list->txlen[0] = tx_len; ++ list->rx[0] = rx; list->rxlen[0] = rx_len; ++ ++ list->tx[1] = txnext; list->txlen[1] = txnext_len; ++ list->rx[1] = rxnext; list->rxlen[1] = rxnext_len; ++ ++ list->nr_transfers = nr; ++ ++ return spi_transfer(list); ++} ++ ++/* ......................................................................... */ ++ ++/* ++ * Poll the DataFlash device until it is READY. ++ */ ++static void at91_dataflash_waitready(void) ++{ ++ char* command = kmalloc(2, GFP_KERNEL); ++ ++ if (!command) ++ return; ++ ++ do { ++ command[0] = OP_READ_STATUS; ++ command[1] = 0; ++ ++ do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); ++ } while ((command[1] & 0x80) == 0); ++ ++ kfree(command); ++} ++ ++/* ++ * Return the status of the DataFlash device. ++ */ ++static unsigned short at91_dataflash_status(void) ++{ ++ unsigned short status; ++ char* command = kmalloc(2, GFP_KERNEL); ++ ++ if (!command) ++ return 0; ++ ++ command[0] = OP_READ_STATUS; ++ command[1] = 0; ++ ++ do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); ++ status = command[1]; ++ ++ kfree(command); ++ return status; ++} ++ ++/* ......................................................................... */ ++ ++/* ++ * Erase blocks of flash. ++ */ ++static int at91_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; ++ unsigned int pageaddr; ++ char* command; ++ ++#ifdef DEBUG_DATAFLASH ++ printk("dataflash_erase: addr=%i len=%i\n", instr->addr, instr->len); ++#endif ++ ++ /* Sanity checks */ ++ if (instr->addr + instr->len > mtd->size) ++ return -EINVAL; ++ if ((instr->len % mtd->erasesize != 0) || (instr->len % priv->page_size != 0)) ++ return -EINVAL; ++ if ((instr->addr % priv->page_size) != 0) ++ return -EINVAL; ++ ++ command = kmalloc(4, GFP_KERNEL); ++ if (!command) ++ return -ENOMEM; ++ ++ while (instr->len > 0) { ++ /* Calculate flash page address */ ++ pageaddr = (instr->addr / priv->page_size) << priv->page_offset; ++ ++ command[0] = OP_ERASE_PAGE; ++ command[1] = (pageaddr & 0x00FF0000) >> 16; ++ command[2] = (pageaddr & 0x0000FF00) >> 8; ++ command[3] = 0; ++#ifdef DEBUG_DATAFLASH ++ printk("ERASE: (%x) %x %x %x [%i]\n", command[0], command[1], command[2], command[3], pageaddr); ++#endif ++ ++ /* Send command to SPI device */ ++ spi_access_bus(priv->spi); ++ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0); ++ ++ at91_dataflash_waitready(); /* poll status until ready */ ++ spi_release_bus(priv->spi); ++ ++ instr->addr += priv->page_size; /* next page */ ++ instr->len -= priv->page_size; ++ } ++ ++ kfree(command); ++ ++ /* Inform MTD subsystem that erase is complete */ ++ instr->state = MTD_ERASE_DONE; ++ if (instr->callback) ++ instr->callback(instr); ++ ++ return 0; ++} ++ ++/* ++ * Read from the DataFlash device. ++ * from : Start offset in flash device ++ * len : Amount to read ++ * retlen : About of data actually read ++ * buf : Buffer containing the data ++ */ ++static int at91_dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; ++ unsigned int addr; ++ char* command; ++ ++#ifdef DEBUG_DATAFLASH ++ printk("dataflash_read: %lli .. %lli\n", from, from+len); ++#endif ++ ++ *retlen = 0; ++ ++ /* Sanity checks */ ++ if (!len) ++ return 0; ++ if (from + len > mtd->size) ++ return -EINVAL; ++ ++ /* Calculate flash page/byte address */ ++ addr = (((unsigned)from / priv->page_size) << priv->page_offset) + ((unsigned)from % priv->page_size); ++ ++ command = kmalloc(8, GFP_KERNEL); ++ if (!command) ++ return -ENOMEM; ++ ++ command[0] = OP_READ_CONTINUOUS; ++ command[1] = (addr & 0x00FF0000) >> 16; ++ command[2] = (addr & 0x0000FF00) >> 8; ++ command[3] = (addr & 0x000000FF); ++#ifdef DEBUG_DATAFLASH ++ printk("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); ++#endif ++ ++ /* Send command to SPI device */ ++ spi_access_bus(priv->spi); ++ do_spi_transfer(2, command, 8, command, 8, buf, len, buf, len); ++ spi_release_bus(priv->spi); ++ ++ *retlen = len; ++ kfree(command); ++ return 0; ++} ++ ++/* ++ * Write to the DataFlash device. ++ * to : Start offset in flash device ++ * len : Amount to write ++ * retlen : Amount of data actually written ++ * buf : Buffer containing the data ++ */ ++static int at91_dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) ++{ ++ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; ++ unsigned int pageaddr, addr, offset, writelen; ++ size_t remaining; ++ u_char *writebuf; ++ unsigned short status; ++ int res = 0; ++ char* command; ++ char* tmpbuf = NULL; ++ ++#ifdef DEBUG_DATAFLASH ++ printk("dataflash_write: %lli .. %lli\n", to, to+len); ++#endif ++ ++ *retlen = 0; ++ ++ /* Sanity checks */ ++ if (!len) ++ return 0; ++ if (to + len > mtd->size) ++ return -EINVAL; ++ ++ command = kmalloc(4, GFP_KERNEL); ++ if (!command) ++ return -ENOMEM; ++ ++ pageaddr = ((unsigned)to / priv->page_size); ++ offset = ((unsigned)to % priv->page_size); ++ if (offset + len > priv->page_size) ++ writelen = priv->page_size - offset; ++ else ++ writelen = len; ++ writebuf = (u_char *)buf; ++ remaining = len; ++ ++ /* Allocate temporary buffer */ ++ tmpbuf = kmalloc(priv->page_size, GFP_KERNEL); ++ if (!tmpbuf) { ++ kfree(command); ++ return -ENOMEM; ++ } ++ ++ /* Gain access to the SPI bus */ ++ spi_access_bus(priv->spi); ++ ++ while (remaining > 0) { ++#ifdef DEBUG_DATAFLASH ++ printk("write @ %i:%i len=%i\n", pageaddr, offset, writelen); ++#endif ++ ++ /* (1) Transfer to Buffer1 */ ++ if (writelen != priv->page_size) { ++ addr = pageaddr << priv->page_offset; ++ command[0] = OP_TRANSFER_BUF1; ++ command[1] = (addr & 0x00FF0000) >> 16; ++ command[2] = (addr & 0x0000FF00) >> 8; ++ command[3] = 0; ++#ifdef DEBUG_DATAFLASH ++ printk("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); ++#endif ++ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0); ++ at91_dataflash_waitready(); ++ } ++ ++ /* (2) Program via Buffer1 */ ++ addr = (pageaddr << priv->page_offset) + offset; ++ command[0] = OP_PROGRAM_VIA_BUF1; ++ command[1] = (addr & 0x00FF0000) >> 16; ++ command[2] = (addr & 0x0000FF00) >> 8; ++ command[3] = (addr & 0x000000FF); ++#ifdef DEBUG_DATAFLASH ++ printk("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); ++#endif ++ do_spi_transfer(2, command, 4, command, 4, writebuf, writelen, tmpbuf, writelen); ++ at91_dataflash_waitready(); ++ ++ /* (3) Compare to Buffer1 */ ++ addr = pageaddr << priv->page_offset; ++ command[0] = OP_COMPARE_BUF1; ++ command[1] = (addr & 0x00FF0000) >> 16; ++ command[2] = (addr & 0x0000FF00) >> 8; ++ command[3] = 0; ++#ifdef DEBUG_DATAFLASH ++ printk("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); ++#endif ++ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0); ++ at91_dataflash_waitready(); ++ ++ /* Get result of the compare operation */ ++ status = at91_dataflash_status(); ++ if (status & 0x40) { ++ printk("at91_dataflash: Write error on page %i\n", pageaddr); ++ remaining = 0; ++ writelen = 0; ++ res = -EIO; ++ } ++ ++ remaining = remaining - writelen; ++ pageaddr++; ++ offset = 0; ++ writebuf += writelen; ++ *retlen += writelen; ++ ++ if (remaining > priv->page_size) ++ writelen = priv->page_size; ++ else ++ writelen = remaining; ++ } ++ ++ /* Release SPI bus */ ++ spi_release_bus(priv->spi); ++ ++ kfree(tmpbuf); ++ kfree(command); ++ return res; ++} ++ ++/* ......................................................................... */ ++ ++/* ++ * Initialize and register DataFlash device with MTD subsystem. ++ */ ++static int __init add_dataflash(int channel, char *name, int IDsize, ++ int nr_pages, int pagesize, int pageoffset) ++{ ++ struct mtd_info *device; ++ struct dataflash_local *priv; ++#ifdef CONFIG_MTD_PARTITIONS ++ struct mtd_partition *mtd_parts = 0; ++ int mtd_parts_nr = 0; ++#endif ++ ++ if (nr_devices >= DATAFLASH_MAX_DEVICES) { ++ printk(KERN_ERR "at91_dataflash: Too many devices detected\n"); ++ return 0; ++ } ++ ++ device = kmalloc(sizeof(struct mtd_info) + strlen(name) + 8, GFP_KERNEL); ++ if (!device) ++ return -ENOMEM; ++ memset(device, 0, sizeof(struct mtd_info)); ++ ++ device->name = (char *)&device[1]; ++ sprintf(device->name, "%s.spi%d", name, channel); ++ device->size = nr_pages * pagesize; ++ device->erasesize = pagesize; ++ device->writesize = pagesize; ++ device->owner = THIS_MODULE; ++ device->type = MTD_DATAFLASH; ++ device->flags = MTD_WRITEABLE; ++ device->erase = at91_dataflash_erase; ++ device->read = at91_dataflash_read; ++ device->write = at91_dataflash_write; ++ ++ priv = (struct dataflash_local *) kmalloc(sizeof(struct dataflash_local), GFP_KERNEL); ++ if (!priv) { ++ kfree(device); ++ return -ENOMEM; ++ } ++ memset(priv, 0, sizeof(struct dataflash_local)); ++ ++ priv->spi = channel; ++ priv->page_size = pagesize; ++ priv->page_offset = pageoffset; ++ device->priv = priv; ++ ++ mtd_devices[nr_devices] = device; ++ nr_devices++; ++ printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, device->size); ++ ++#ifdef CONFIG_MTD_PARTITIONS ++#ifdef CONFIG_MTD_CMDLINE_PARTS ++ mtd_parts_nr = parse_mtd_partitions(device, part_probes, &mtd_parts, 0); ++#endif ++ if (mtd_parts_nr <= 0) { ++ switch (IDsize) { ++ case SZ_2M: ++ mtd_parts = static_partitions_2M; ++ mtd_parts_nr = ARRAY_SIZE(static_partitions_2M); ++ break; ++ case SZ_4M: ++ mtd_parts = static_partitions_4M; ++ mtd_parts_nr = ARRAY_SIZE(static_partitions_4M); ++ break; ++ case SZ_8M: ++ mtd_parts = static_partitions_8M; ++ mtd_parts_nr = ARRAY_SIZE(static_partitions_8M); ++ break; ++ } ++ } ++ ++ if (mtd_parts_nr > 0) { ++#ifdef CONFIG_DATAFLASH_ALWAYS_ADD_DEVICE ++ add_mtd_device(device); ++#endif ++ return add_mtd_partitions(device, mtd_parts, mtd_parts_nr); ++ } ++#endif ++ return add_mtd_device(device); /* add whole device */ ++} ++ ++/* ++ * Detect and initialize DataFlash device connected to specified SPI channel. ++ * ++ * Device Density ID code Nr Pages Page Size Page offset ++ * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9 ++ * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1025 264 9 ++ * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9 ++ * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9 ++ * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10 ++ * AT45DB0321B 32Mbit (4M) xx1101xx (0x34) 8192 528 10 ++ * AT45DB0642 64Mbit (8M) xx1111xx (0x3c) 8192 1056 11 ++ * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11 ++ */ ++static int __init at91_dataflash_detect(int channel) ++{ ++ int res = 0; ++ unsigned short status; ++ ++ spi_access_bus(channel); ++ status = at91_dataflash_status(); ++ spi_release_bus(channel); ++ if (status != 0xff) { /* no dataflash device there */ ++ switch (status & 0x3c) { ++ case 0x0c: /* 0 0 1 1 */ ++ res = add_dataflash(channel, "AT45DB011B", SZ_128K, 512, 264, 9); ++ break; ++ case 0x14: /* 0 1 0 1 */ ++ res = add_dataflash(channel, "AT45DB021B", SZ_256K, 1025, 264, 9); ++ break; ++ case 0x1c: /* 0 1 1 1 */ ++ res = add_dataflash(channel, "AT45DB041B", SZ_512K, 2048, 264, 9); ++ break; ++ case 0x24: /* 1 0 0 1 */ ++ res = add_dataflash(channel, "AT45DB081B", SZ_1M, 4096, 264, 9); ++ break; ++ case 0x2c: /* 1 0 1 1 */ ++ res = add_dataflash(channel, "AT45DB161B", SZ_2M, 4096, 528, 10); ++ break; ++ case 0x34: /* 1 1 0 1 */ ++ res = add_dataflash(channel, "AT45DB321B", SZ_4M, 8192, 528, 10); ++ break; ++ case 0x3c: /* 1 1 1 1 */ ++ res = add_dataflash(channel, "AT45DB642", SZ_8M, 8192, 1056, 11); ++ break; ++// Currently unsupported since Atmel removed the "Main Memory Program via Buffer" commands. ++// case 0x10: /* 0 1 0 0 */ ++// res = add_dataflash(channel, "AT45DB1282", SZ_16M, 16384, 1056, 11); ++// break; ++ default: ++ printk(KERN_ERR "at91_dataflash: Unknown device (%x)\n", status & 0x3c); ++ } ++ } ++ ++ return res; ++} ++ ++static int __init at91_dataflash_init(void) ++{ ++ spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL); ++ if (!spi_transfer_desc) ++ return -ENOMEM; ++ ++ /* DataFlash (SPI chip select 0) */ ++ at91_dataflash_detect(0); ++ ++ if (machine_is_sweda_tms()) ++ at91_dataflash_detect(1); /* DataFlash device (SPI chip select 1) */ ++ ++#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD ++ /* DataFlash card (SPI chip select 3) */ ++ at91_dataflash_detect(3); ++#endif ++ ++ return 0; ++} ++ ++static void __exit at91_dataflash_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) { ++ if (mtd_devices[i]) { ++#ifdef CONFIG_MTD_PARTITIONS ++ del_mtd_partitions(mtd_devices[i]); ++#else ++ del_mtd_device(mtd_devices[i]); ++#endif ++ kfree(mtd_devices[i]->priv); ++ kfree(mtd_devices[i]); ++ } ++ } ++ nr_devices = 0; ++ kfree(spi_transfer_desc); ++} ++ ++ ++module_init(at91_dataflash_init); ++module_exit(at91_dataflash_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Andrew Victor"); ++MODULE_DESCRIPTION("DataFlash driver for Atmel AT91RM9200"); +diff -urN -x CVS linux-2.6.25/drivers/mtd/nand/Kconfig linux-2.6/drivers/mtd/nand/Kconfig +--- linux-2.6.25/drivers/mtd/nand/Kconfig 2008-05-03 00:15:48.000000000 +0200 ++++ linux-2.6/drivers/mtd/nand/Kconfig 2008-04-18 17:52:53.000000000 +0200 +@@ -273,12 +273,53 @@ + If you say "m", the module will be called "cs553x_nand.ko". + + config MTD_NAND_AT91 +- bool "Support for NAND Flash / SmartMedia on AT91" ++ tristate "Support for NAND Flash / SmartMedia on AT91" + depends on ARCH_AT91 + help + Enables support for NAND Flash / Smart Media Card interface + on Atmel AT91 processors. + ++choice ++ prompt "ECC management for NAND Flash / SmartMedia on AT91" ++ depends on MTD_NAND_AT91 ++ ++config MTD_NAND_AT91_ECC_SOFT ++ bool "Software ECC" ++ depends on MTD_NAND_AT91 ++ help ++ Uses software ECC. ++ ++ NB : hardware and software ECC schemes are incompatible. ++ If you switch from one to another, you'll have to erase your ++ mtd partition. ++ ++config MTD_NAND_AT91_ECC_HW ++ bool "Hardware ECC" ++ depends on MTD_NAND_AT91 && (ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9) ++ help ++ Uses hardware ECC provided by the AT91 processor ++ instead of software ECC. ++ The hardware ECC controller is capable of single bit error ++ correction and 2-bit random detection per page. ++ ++ NB : hardware and software ECC schemes are incompatible. ++ If you switch from one to another, you'll have to erase your ++ mtd partition. ++ ++ If unsure, say Y ++ ++config MTD_NAND_AT91_ECC_NONE ++ bool "No ECC (Testing Only)" ++ depends on MTD_NAND_AT91 ++ help ++ No ECC will be used. ++ It's not a good idea and it should be reserved for testing ++ purpose only. ++ ++ If unsure, say N ++ ++endchoice ++ + config MTD_NAND_CM_X270 + tristate "Support for NAND Flash on CM-X270 modules" + depends on MTD_NAND && MACH_ARMCORE +diff -urN -x CVS linux-2.6.25/drivers/mtd/nand/at91_nand.c linux-2.6/drivers/mtd/nand/at91_nand.c +--- linux-2.6.25/drivers/mtd/nand/at91_nand.c 2008-05-03 00:15:48.000000000 +0200 ++++ linux-2.6/drivers/mtd/nand/at91_nand.c 2008-05-03 00:53:39.000000000 +0200 +@@ -9,6 +9,15 @@ + * Derived from drivers/mtd/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * ++ * ++ * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 ++ * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 ++ * ++ * Derived from Das U-Boot source code ++ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) ++ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas ++ * ++ * + * 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 + * published by the Free Software Foundation. +@@ -28,15 +37,75 @@ + #include <asm/hardware.h> + #include <asm/arch/board.h> + #include <asm/arch/gpio.h> ++#include <asm/arch/at91_ecc.h> ++ ++#ifdef CONFIG_MTD_NAND_AT91_ECC_HW ++#define hard_ecc 1 ++#else ++#define hard_ecc 0 ++#endif ++ ++#ifdef CONFIG_MTD_NAND_AT91_ECC_NONE ++#define no_ecc 1 ++#else ++#define no_ecc 0 ++#endif ++ ++/* Register access macros */ ++#define ecc_readl(base, reg) __raw_readl(base + reg) ++#define ecc_writel(base, reg, value) __raw_writel((value), base + reg) ++ ++ ++/* ++ * OOB layout for large page size. ++ * bad block info is on bytes 0 and 1 ++ * the bytes must be consecutives to avoid several NAND_CMD_RNDOUT during read. ++ */ ++static struct nand_ecclayout at91_oobinfo_large = { ++ .eccbytes = 4, ++ .eccpos = {60, 61, 62, 63}, ++ .oobfree = { {2, 58} }, ++}; ++ ++/* ++ * OOB layout for small page size ++ * bad block info is on bytes 4 and 5 ++ * the bytes must be consecutives to avoid several NAND_CMD_RNDOUT during read. ++ */ ++static struct nand_ecclayout at91_oobinfo_small = { ++ .eccbytes = 4, ++ .eccpos = {0, 1, 2, 3}, ++ .oobfree = { {6, 10} }, ++}; + + struct at91_nand_host { + struct nand_chip nand_chip; + struct mtd_info mtd; + void __iomem *io_base; + struct at91_nand_data *board; ++ struct device *dev; ++ void __iomem *ecc; + }; + + /* ++ * Enable NAND chip-select. ++ */ ++static void at91_nand_enable(struct at91_nand_host *host) ++{ ++ if (host->board->enable_pin) ++ at91_set_gpio_value(host->board->enable_pin, 0); ++} ++ ++/* ++ * Disable NAND chip-select. ++ */ ++static void at91_nand_disable(struct at91_nand_host *host) ++{ ++ if (host->board->enable_pin) ++ at91_set_gpio_value(host->board->enable_pin, 1); ++} ++ ++/* + * Hardware specific access to control-lines + */ + static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +@@ -44,6 +113,13 @@ + struct nand_chip *nand_chip = mtd->priv; + struct at91_nand_host *host = nand_chip->priv; + ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_NCE) ++ at91_nand_enable(host); ++ else ++ at91_nand_disable(host); ++ } ++ + if (cmd == NAND_CMD_NONE) + return; + +@@ -65,27 +141,249 @@ + } + + /* +- * Enable NAND. ++ * write oob for small pages + */ +-static void at91_nand_enable(struct at91_nand_host *host) ++static int at91_nand_write_oob_512(struct mtd_info *mtd, ++ struct nand_chip *chip, int page) + { +- if (host->board->enable_pin) +- at91_set_gpio_value(host->board->enable_pin, 0); ++ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; ++ int eccsize = chip->ecc.size, length = mtd->oobsize; ++ int len, pos, status = 0; ++ const uint8_t *bufpoi = chip->oob_poi; ++ ++ pos = eccsize + chunk; ++ ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); ++ len = min_t(int, length, chunk); ++ chip->write_buf(mtd, bufpoi, len); ++ bufpoi += len; ++ length -= len; ++ if (length > 0) ++ chip->write_buf(mtd, bufpoi, length); ++ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ status = chip->waitfunc(mtd, chip); ++ ++ return status & NAND_STATUS_FAIL ? -EIO : 0; ++ + } + + /* +- * Disable NAND. ++ * read oob for small pages + */ +-static void at91_nand_disable(struct at91_nand_host *host) ++static int at91_nand_read_oob_512(struct mtd_info *mtd, ++ struct nand_chip *chip, int page, int sndcmd) + { +- if (host->board->enable_pin) +- at91_set_gpio_value(host->board->enable_pin, 1); ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ sndcmd = 0; ++ } ++ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); ++ return sndcmd; ++} ++ ++/* ++ * Calculate HW ECC ++ * ++ * mtd: MTD block structure ++ * dat: raw data (unused) ++ * ecc_code: buffer for ECC ++ */ ++static int at91_nand_calculate(struct mtd_info *mtd, ++ const u_char *dat, unsigned char *ecc_code) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct at91_nand_host *host = nand_chip->priv; ++ uint32_t *eccpos = nand_chip->ecc.layout->eccpos; ++ unsigned int ecc_value; ++ ++ /* get the first 2 ECC bytes */ ++ ecc_value = ecc_readl(host->ecc, AT91_ECC_PR) & (AT91_ECC_BITADDR | AT91_ECC_WORDADDR); ++ ++ ecc_code[eccpos[0]] = ecc_value & 0xFF; ++ ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; ++ ++ /* get the last 2 ECC bytes */ ++ ecc_value = ecc_readl(host->ecc, AT91_ECC_NPR) & AT91_ECC_NPARITY; ++ ++ ecc_code[eccpos[2]] = ecc_value & 0xFF; ++ ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; ++ ++ return 0; + } + ++/* ++ * HW ECC read page function ++ * ++ * mtd: mtd info structure ++ * chip: nand chip info structure ++ * buf: buffer to store read data ++ */ ++static int at91_nand_read_page(struct mtd_info *mtd, ++ struct nand_chip *chip, uint8_t *buf) ++{ ++ int eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ uint8_t *p = buf; ++ uint8_t *oob = chip->oob_poi; ++ uint8_t *ecc_pos; ++ int stat; ++ ++ /* read the page */ ++ chip->read_buf(mtd, p, eccsize); ++ ++ /* move to ECC position if needed */ ++ if (eccpos[0] != 0) { ++ /* ++ * This only works on large pages because the ECC controller ++ * waits for NAND_CMD_RNDOUTSTART after the NAND_CMD_RNDOUT. ++ * Anyway, for small pages, the eccpos[0] == 0 ++ */ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, ++ mtd->writesize + eccpos[0], -1); ++ } ++ ++ /* the ECC controller needs to read the ECC just after the data */ ++ ecc_pos = oob + eccpos[0]; ++ chip->read_buf(mtd, ecc_pos, eccbytes); ++ ++ /* check if there's an error */ ++ stat = chip->ecc.correct(mtd, p, oob, NULL); ++ ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ ++ /* get back to oob start (end of page) */ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); ++ ++ /* read the oob */ ++ chip->read_buf(mtd, oob, mtd->oobsize); ++ ++ return 0; ++} ++ ++/* ++ * HW ECC Correction ++ * ++ * mtd: MTD block structure ++ * dat: raw data read from the chip ++ * read_ecc: ECC from the chip (unused) ++ * isnull: unused ++ * ++ * Detect and correct a 1 bit error for a page ++ */ ++static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *isnull) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ struct at91_nand_host *host = nand_chip->priv; ++ unsigned int ecc_status; ++ unsigned int ecc_word, ecc_bit; ++ ++ /* get the status from the Status Register */ ++ ecc_status = ecc_readl(host->ecc, AT91_ECC_SR); ++ ++ /* if there's no error */ ++ if (likely(!(ecc_status & AT91_ECC_RECERR))) ++ return 0; ++ ++ /* get error bit offset (4 bits) */ ++ ecc_bit = ecc_readl(host->ecc, AT91_ECC_PR) & AT91_ECC_BITADDR; ++ /* get word address (12 bits) */ ++ ecc_word = ecc_readl(host->ecc, AT91_ECC_PR) & AT91_ECC_WORDADDR; ++ ecc_word >>= 4; ++ ++ /* if there are multiple errors */ ++ if (ecc_status & AT91_ECC_MULERR) { ++ /* Check if it is a freshly erased block (filled with 0xff) */ ++ if ((ecc_bit == AT91_ECC_BITADDR) ++ && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { ++ /* the block has just been erased, return OK */ ++ return 0; ++ } ++ /* ++ * It doesn't seems to be a freshly-erased block. ++ * We can't correct so many errors. ++ */ ++ dev_dbg(host->dev, "at91_nand : multiple errors detected." ++ " Unable to correct.\n"); ++ return -EIO; ++ } ++ ++ /* if there's a single bit error : we can correct it */ ++ if (ecc_status & AT91_ECC_ECCERR) { ++ /* ++ * There's nothing much to do here. ++ * The bit error is on the ECC itself. ++ */ ++ dev_dbg(host->dev, "at91_nand : one bit error on ECC code." ++ " Nothing to correct\n"); ++ return 0; ++ } ++ ++ dev_dbg(host->dev, "at91_nand : one bit error on data." ++ " (word offset in the page :" ++ " 0x%x bit offset : 0x%x)\n", ++ ecc_word, ecc_bit); ++ /* correct the error */ ++ if (nand_chip->options & NAND_BUSWIDTH_16) { ++ /* 16 bits words */ ++ ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); ++ } else { ++ /* 8 bits words */ ++ dat[ecc_word] ^= (1 << ecc_bit); ++ } ++ dev_dbg(host->dev, "at91_nand : error corrected\n"); ++ return 1; ++} ++ ++/* ++ * Enable HW ECC : unsused ++ */ ++static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } ++ ++/* ++ * Over-ride the standard functions with our optimized versions. ++ * We can use read/write blocks to move data to/from the controller. ++ */ ++static void at91_read_buf8(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_readsb(nand_chip->IO_ADDR_R, buf, len); ++} ++ ++static void at91_read_buf16(struct mtd_info *mtd, u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); ++} ++ ++static void at91_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_writesb(nand_chip->IO_ADDR_W, buf, len); ++} ++ ++static void at91_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) ++{ ++ struct nand_chip *nand_chip = mtd->priv; ++ ++ __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); ++} ++ ++ + #ifdef CONFIG_MTD_PARTITIONS +-const char *part_probes[] = { "cmdlinepart", NULL }; ++static const char *part_probes[] = { "cmdlinepart", NULL }; + #endif + ++static char* ecc_modes[] __initdata = { "No", "Software", "Hardware" }; ++ + /* + * Probe for the NAND device. + */ +@@ -94,6 +392,8 @@ + struct at91_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; ++ struct resource *regs; ++ struct resource *mem; + int res; + + #ifdef CONFIG_MTD_PARTITIONS +@@ -108,8 +408,13 @@ + return -ENOMEM; + } + +- host->io_base = ioremap(pdev->resource[0].start, +- pdev->resource[0].end - pdev->resource[0].start + 1); ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem) { ++ printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); ++ return -ENXIO; ++ } ++ ++ host->io_base = ioremap(mem->start, mem->end - mem->start + 1); + if (host->io_base == NULL) { + printk(KERN_ERR "at91_nand: ioremap failed\n"); + kfree(host); +@@ -119,6 +424,7 @@ + mtd = &host->mtd; + nand_chip = &host->nand_chip; + host->board = pdev->dev.platform_data; ++ host->dev = &pdev->dev; + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; +@@ -132,11 +438,40 @@ + if (host->board->rdy_pin) + nand_chip->dev_ready = at91_nand_device_ready; + ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!regs && hard_ecc) { ++ printk(KERN_ERR "at91_nand: can't get I/O resource " ++ "regs\nFalling back on software ECC\n"); ++ } ++ + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ ++ if (no_ecc) ++ nand_chip->ecc.mode = NAND_ECC_NONE; ++ if (hard_ecc && regs) { ++ host->ecc = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS); ++ host->ecc += regs->start; ++ ++ nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; /* HW SYNDROME ECC */ ++ nand_chip->ecc.calculate = at91_nand_calculate; /* function called after a write */ ++ nand_chip->ecc.correct = at91_nand_correct; /* function called after a read */ ++ nand_chip->ecc.hwctl = at91_nand_hwctl; /* unused */ ++ nand_chip->ecc.read_page = at91_nand_read_page; /* read page function */ ++ nand_chip->ecc.bytes = 4; /* 4 ECC bytes for any page size */ ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.postpad = 0; ++ } ++ + nand_chip->chip_delay = 20; /* 20us command delay time */ + +- if (host->board->bus_width_16) /* 16-bit bus width */ ++ if (host->board->bus_width_16) { /* 16-bit bus width */ + nand_chip->options |= NAND_BUSWIDTH_16; ++ nand_chip->read_buf = at91_read_buf16; ++ nand_chip->write_buf = at91_write_buf16; ++ } ++ else { ++ nand_chip->read_buf = at91_read_buf8; ++ nand_chip->write_buf = at91_write_buf8; ++ } + + platform_set_drvdata(pdev, host); + at91_nand_enable(host); +@@ -149,8 +484,60 @@ + } + } + +- /* Scan to find existance of the device */ +- if (nand_scan(mtd, 1)) { ++ /* first scan to find the device and get the page size */ ++ if (nand_scan_ident(mtd, 1)) { ++ res = -ENXIO; ++ goto out; ++ } ++ ++ if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { ++ /* ECC is calculated for the whole page (1 step) */ ++ nand_chip->ecc.size = mtd->writesize; ++ ++ /* set ECC page size and oob layout */ ++ switch (mtd->writesize) { ++ case 512: ++ nand_chip->ecc.layout = &at91_oobinfo_small; ++ nand_chip->ecc.read_oob = at91_nand_read_oob_512; ++ nand_chip->ecc.write_oob = at91_nand_write_oob_512; ++ ecc_writel(host->ecc, AT91_ECC_MR, AT91_ECC_PAGESIZE_528); ++ break; ++ case 1024: ++ nand_chip->ecc.layout = &at91_oobinfo_large; ++ ecc_writel(host->ecc, AT91_ECC_MR, AT91_ECC_PAGESIZE_1056); ++ break; ++ case 2048: ++ nand_chip->ecc.layout = &at91_oobinfo_large; ++ ecc_writel(host->ecc, AT91_ECC_MR, AT91_ECC_PAGESIZE_2112); ++ break; ++ case 4096: ++ nand_chip->ecc.layout = &at91_oobinfo_large; ++ ecc_writel(host->ecc, AT91_ECC_MR, AT91_ECC_PAGESIZE_4224); ++ break; ++ default: ++ /* ++ * Page size not supported by HW ECC. ++ * So switch back to soft ECC ++ */ ++ nand_chip->ecc.mode = NAND_ECC_SOFT; ++ nand_chip->ecc.calculate = NULL; ++ nand_chip->ecc.correct = NULL; ++ nand_chip->ecc.hwctl = NULL; ++ nand_chip->ecc.read_page = NULL; ++ nand_chip->ecc.postpad = 0; ++ nand_chip->ecc.prepad = 0; ++ nand_chip->ecc.bytes = 0; ++ break; ++ } ++ } ++ ++ printk(KERN_INFO "AT91 NAND: %i-bit, %s ECC\n", ++ (nand_chip->options & NAND_BUSWIDTH_16) ? 16 : 8, ++ ecc_modes[nand_chip->ecc.mode] ++ ); ++ ++ /* second phase scan */ ++ if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto out; + } +@@ -179,8 +566,11 @@ + if (!res) + return res; + ++#ifdef CONFIG_MTD_PARTITIONS + release: ++#endif + nand_release(mtd); ++ + out: + at91_nand_disable(host); + platform_set_drvdata(pdev, NULL); +@@ -192,7 +582,7 @@ + /* + * Remove a NAND device. + */ +-static int __devexit at91_nand_remove(struct platform_device *pdev) ++static int __exit at91_nand_remove(struct platform_device *pdev) + { + struct at91_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; +@@ -208,8 +598,7 @@ + } + + static struct platform_driver at91_nand_driver = { +- .probe = at91_nand_probe, +- .remove = at91_nand_remove, ++ .remove = __exit_p(at91_nand_remove), + .driver = { + .name = "at91_nand", + .owner = THIS_MODULE, +@@ -218,7 +607,7 @@ + + static int __init at91_nand_init(void) + { +- return platform_driver_register(&at91_nand_driver); ++ return platform_driver_probe(&at91_nand_driver, at91_nand_probe); + } + + +@@ -233,4 +622,4 @@ + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Rick Bronson"); +-MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); ++MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9 / AT91CAP9"); +diff -urN -x CVS linux-2.6.25/drivers/net/arm/Kconfig linux-2.6/drivers/net/arm/Kconfig +--- linux-2.6.25/drivers/net/arm/Kconfig 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/drivers/net/arm/Kconfig 2008-03-04 21:52:40.000000000 +0200 +@@ -47,3 +47,10 @@ + help + This is a driver for the ethernet hardware included in EP93xx CPUs. + Say Y if you are building a kernel for EP93xx based devices. ++ ++config ARM_KS8695_ETHER ++ tristate "KS8695 Ethernet support" ++ depends on NET_ETHERNET && ARM && ARCH_KS8695 ++ help ++ If you wish to compile a kernel for an KS8695-based board ++ and enable Ethernet support, then select this option. +diff -urN -x CVS linux-2.6.25/drivers/net/arm/Makefile linux-2.6/drivers/net/arm/Makefile +--- linux-2.6.25/drivers/net/arm/Makefile 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/drivers/net/arm/Makefile 2008-03-04 21:51:41.000000000 +0200 +@@ -9,3 +9,4 @@ + obj-$(CONFIG_ARM_ETHER1) += ether1.o + obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o + obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o ++obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695_ether.o +diff -urN -x CVS linux-2.6.25/drivers/net/arm/at91_ether.c linux-2.6/drivers/net/arm/at91_ether.c +--- linux-2.6.25/drivers/net/arm/at91_ether.c 2008-05-03 00:15:48.000000000 +0200 ++++ linux-2.6/drivers/net/arm/at91_ether.c 2008-05-08 21:47:22.000000000 +0200 +@@ -220,7 +220,7 @@ + if (!(phy & (1 << 0))) + goto done; + } +- else if (lp->phy_type == MII_KS8721_ID) { ++ else if ((lp->phy_type == MII_KS8721_ID) || (lp->phy_type == MII_KSZ8041_ID)) { + read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */ + if (!(phy & ((1 << 2) | 1))) + goto done; +@@ -286,7 +286,7 @@ + dsintr = (1 << 15) | ( 1 << 14); + write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); + } +- else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ ++ else if ((lp->phy_type == MII_KS8721_ID) || (lp->phy_type == MII_KSZ8041_ID)) { /* for Micrel PHY */ + dsintr = (1 << 10) | ( 1 << 8); + write_phy(lp->phy_address, MII_TPISTATUS, dsintr); + } +@@ -341,7 +341,7 @@ + dsintr = ~(1 << 14); + write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); + } +- else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ ++ else if ((lp->phy_type == MII_KS8721_ID) || (lp->phy_type == MII_KSZ8041_ID)) { /* for Micrel PHY */ + read_phy(lp->phy_address, MII_TPISTATUS, &dsintr); + dsintr = ~((1 << 10) | (1 << 8)); + write_phy(lp->phy_address, MII_TPISTATUS, dsintr); +@@ -820,7 +820,7 @@ + lp->skb = skb; + lp->skb_length = skb->len; + lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); +- lp->stats.tx_bytes += skb->len; ++ dev->stats.tx_bytes += skb->len; + + /* Set address of the data in the Transmit Address register */ + at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr); +@@ -843,34 +843,32 @@ + */ + static struct net_device_stats *at91ether_stats(struct net_device *dev) + { +- struct at91_private *lp = netdev_priv(dev); +- int ale, lenerr, seqe, lcol, ecol; ++ int ale, lenerr, seqe, ecol; + + if (netif_running(dev)) { +- lp->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */ ++ dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */ + ale = at91_emac_read(AT91_EMAC_ALE); +- lp->stats.rx_frame_errors += ale; /* Alignment errors */ ++ dev->stats.rx_frame_errors += ale; /* Alignment errors */ + lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF); +- lp->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */ ++ dev->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */ + seqe = at91_emac_read(AT91_EMAC_SEQE); +- lp->stats.rx_crc_errors += seqe; /* CRC error */ +- lp->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */ +- lp->stats.rx_errors += (ale + lenerr + seqe ++ dev->stats.rx_crc_errors += seqe; /* CRC error */ ++ dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */ ++ dev->stats.rx_errors += (ale + lenerr + seqe + + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB)); + +- lp->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */ +- lp->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */ +- lp->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */ +- lp->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */ ++ dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */ ++ dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */ ++ dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */ ++ dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */ + +- lcol = at91_emac_read(AT91_EMAC_LCOL); ++ dev->stats.tx_window_errors += at91_emac_read(AT91_EMAC_LCOL); /* Late collisions */ + ecol = at91_emac_read(AT91_EMAC_ECOL); +- lp->stats.tx_window_errors += lcol; /* Late collisions */ +- lp->stats.tx_aborted_errors += ecol; /* 16 collisions */ ++ dev->stats.tx_aborted_errors += ecol; /* 16 collisions */ + +- lp->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol); ++ dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + ecol); + } +- return &lp->stats; ++ return &dev->stats; + } + + /* +@@ -896,16 +894,16 @@ + + skb->protocol = eth_type_trans(skb, dev); + dev->last_rx = jiffies; +- lp->stats.rx_bytes += pktlen; ++ dev->stats.rx_bytes += pktlen; + netif_rx(skb); + } + else { +- lp->stats.rx_dropped += 1; ++ dev->stats.rx_dropped += 1; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + } + + if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST) +- lp->stats.multicast++; ++ dev->stats.multicast++; + + dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE; /* reset ownership bit */ + if (lp->rxBuffIndex == MAX_RX_DESCR-1) /* wrap after last buffer */ +@@ -934,7 +932,7 @@ + if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */ + /* The TCOM bit is set even if the transmission failed. */ + if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY)) +- lp->stats.tx_errors += 1; ++ dev->stats.tx_errors += 1; + + if (lp->skb) { + dev_kfree_skb_irq(lp->skb); +@@ -978,15 +976,22 @@ + struct net_device *dev; + struct at91_private *lp; + unsigned int val; +- int res; ++ struct resource *res; ++ int ret; + DECLARE_MAC_BUF(mac); + + dev = alloc_etherdev(sizeof(struct at91_private)); + if (!dev) + return -ENOMEM; + +- dev->base_addr = AT91_VA_BASE_EMAC; +- dev->irq = AT91RM9200_ID_EMAC; ++ /* Get I/O base address and IRQ */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ free_netdev(dev); ++ return -ENODEV; ++ } ++ dev->base_addr = res->start; ++ dev->irq = platform_get_irq(pdev, 0); + + /* Install the interrupt handler */ + if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) { +@@ -1043,7 +1048,9 @@ + } else if (machine_is_csb337()) { + /* mix link activity status into LED2 link state */ + write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22); +- } ++ } else if (machine_is_ecbat91()) ++ write_phy(phy_address, MII_LEDCTRL_REG, 0x156A); ++ + disable_mdi(); + spin_unlock_irq(&lp->lock); + +@@ -1058,12 +1065,12 @@ + lp->phy_address = phy_address; /* MDI address of PHY */ + + /* Register the network interface */ +- res = register_netdev(dev); +- if (res) { ++ ret = register_netdev(dev); ++ if (ret) { + free_irq(dev->irq, dev); + free_netdev(dev); + dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); +- return res; ++ return ret; + } + + /* Determine current link speed */ +@@ -1101,6 +1108,8 @@ + printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name); + else if (phy_type == MII_AC101L_ID) + printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name); ++ else if (phy_type == MII_KSZ8041_ID) ++ printk(KERN_INFO "%s: Micrel KSZ8041 PHY\n", dev->name); + else if (phy_type == MII_KS8721_ID) + printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name); + else if (phy_type == MII_T78Q21x3_ID) +@@ -1146,6 +1155,7 @@ + case MII_DP83847_ID: /* National Semiconductor DP83847: */ + case MII_DP83848_ID: /* National Semiconductor DP83848: */ + case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ ++ case MII_KSZ8041_ID: /* Micrel KSZ8041: PHY_ID1 = 0x22, PHY_ID2 = 0x1512 */ + case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ + case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */ + case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */ +@@ -1246,3 +1256,4 @@ + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver"); + MODULE_AUTHOR("Andrew Victor"); ++MODULE_ALIAS("platform:" DRV_NAME); +diff -urN -x CVS linux-2.6.25/drivers/net/arm/at91_ether.h linux-2.6/drivers/net/arm/at91_ether.h +--- linux-2.6.25/drivers/net/arm/at91_ether.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/drivers/net/arm/at91_ether.h 2008-05-08 21:47:31.000000000 +0200 +@@ -48,6 +48,9 @@ + /* Altima AC101L PHY */ + #define MII_AC101L_ID 0x00225520 + ++/* Micrel KSZ8041 PHY */ ++#define MII_KSZ8041_ID 0x00221510 ++ + /* Micrel KS8721 PHY */ + #define MII_KS8721_ID 0x00221610 + +@@ -84,7 +87,6 @@ + + struct at91_private + { +- struct net_device_stats stats; + struct mii_if_info mii; /* ethtool support */ + struct at91_eth_data board_data; /* board-specific configuration */ + struct clk *ether_clk; /* clock */ +diff -urN -x CVS linux-2.6.25/drivers/net/arm/ks8695_ether.c linux-2.6/drivers/net/arm/ks8695_ether.c +--- linux-2.6.25/drivers/net/arm/ks8695_ether.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/net/arm/ks8695_ether.c 2008-05-08 21:52:35.000000000 +0200 +@@ -0,0 +1,1009 @@ ++/* ++ * Ethernet driver for the Kendin/Micrel KS8695. ++ * ++ * Copyright (C) 2006 Andrew Victor ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/mii.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/dma-mapping.h> ++#include <linux/delay.h> ++#include <linux/ethtool.h> ++#include <linux/platform_device.h> ++ ++#include <asm/io.h> ++#include <asm/mach/irq.h> ++#include <asm/uaccess.h> ++#include <asm/arch/regs-wan.h> ++#include <asm/arch/regs-lan.h> ++#include <asm/arch/regs-hpna.h> ++#include <asm/arch/regs-switch.h> ++#include <asm/arch/regs-misc.h> ++ ++#include <asm/arch/regs-irq.h> ++ ++#include "ks8695_ether.h" ++ ++ ++#define DRV_NAME "ks8695_ether" ++#define DRV_VERSION "0.01" ++ ++/* ..................................................................... */ ++ ++static inline unsigned long ks8695_read(struct net_device *dev, unsigned int reg) ++{ ++ return __raw_readl(dev->base_addr + reg); ++} ++ ++static inline void ks8695_write(struct net_device *dev, unsigned int reg, unsigned long value) ++{ ++ __raw_writel(value, dev->base_addr + reg); ++} ++ ++ ++/* ......................... ADDRESS MANAGEMENT ........................ */ ++ ++#define KS8695_NR_ADDRESSES 16 ++ ++/* ++ * Add the specified multicast addresses to the Additional Station ++ * Address registers. ++ */ ++static void ks8695_set_mcast_address(struct net_device *dev, struct dev_mc_list *addr, int nr_addr) ++{ ++ unsigned long low, high; ++ int i; ++ ++ /* Set multicast addresses in Additional Station Address registers */ ++ for (i = 0; i < nr_addr; i++, addr = addr->next) { ++ if (!addr) break; /* unexpected end of list */ ++ else if (i == KS8695_NR_ADDRESSES) break; /* too many addresses */ ++ ++ low = (addr->dmi_addr[2] << 24) | (addr->dmi_addr[3] << 16) | (addr->dmi_addr[4] << 8) | (addr->dmi_addr[5]); ++ high = (addr->dmi_addr[0] << 8) | (addr->dmi_addr[1]); ++ ++ ks8695_write(dev, KS8695_WMAAL_(i), low); ++ ks8695_write(dev, KS8695_WMAAH_(i), WMAAH_E | high); ++ } ++ ++ /* Clear the remaining Additional Station Addresses */ ++ for (; i < KS8695_NR_ADDRESSES; i++) { ++ ks8695_write(dev, KS8695_WMAAL_(i), 0); ++ ks8695_write(dev, KS8695_WMAAH_(i), 0); ++ } ++} ++ ++/* ++ * Enable/Disable promiscuous and multicast modes. ++ */ ++static void ks8695eth_set_multi(struct net_device *dev) ++{ ++ unsigned long ctrl; ++ ++ ctrl = ks8695_read(dev, KS8695_WMDRXC); ++ ++ if (dev->flags & IFF_PROMISC) /* enable promiscuous mode */ ++ ctrl |= WMDRXC_WMRA; ++ else if (dev->flags & ~IFF_PROMISC) /* disable promiscuous mode */ ++ ctrl &= ~WMDRXC_WMRA; ++ ++ if (dev->flags & IFF_ALLMULTI) /* enable all multicast mode */ ++ ctrl |= WMDRXC_WMRM; ++ else if (dev->mc_count > KS8695_NR_ADDRESSES) /* more specific multicast addresses than can be handled in hardware */ ++ ctrl |= WMDRXC_WMRM; ++ else if (dev->mc_count > 0) { /* enable specific multicasts */ ++ ctrl &= ~WMDRXC_WMRM; ++ ks8695_set_mcast_address(dev, dev->mc_list, dev->mc_count); ++ } ++ else if (dev->flags & ~IFF_ALLMULTI) { /* disable multicast mode */ ++ ctrl &= ~WMDRXC_WMRM; ++ ks8695_set_mcast_address(dev, NULL, 0); ++ } ++ ++ ks8695_write(dev, KS8695_WMDRXC, ctrl); ++} ++ ++/* ++ * Program the hardware MAC address from dev->dev_addr. ++ */ ++static void update_mac_address(struct net_device *dev) ++{ ++ unsigned long low, high; ++ ++ low = (dev->dev_addr[2] << 24) | (dev->dev_addr[3] << 16) | (dev->dev_addr[4] << 8) | (dev->dev_addr[5]); ++ high = (dev->dev_addr[0] << 8) | (dev->dev_addr[1]); ++ ++ ks8695_write(dev, KS8695_WMAL, low); ++ ks8695_write(dev, KS8695_WMAH, high); ++} ++ ++/* ++ * Store the new hardware address in dev->dev_addr, and update the MAC. ++ */ ++static int ks8695eth_set_mac(struct net_device *dev, void* addr) ++{ ++ struct sockaddr *address = addr; ++ DECLARE_MAC_BUF(mac); ++ ++ if (!is_valid_ether_addr(address->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ memcpy(dev->dev_addr, address->sa_data, dev->addr_len); ++ update_mac_address(dev); ++ ++ printk("%s: Setting MAC address to %s\n", dev->name, print_mac(mac, dev->dev_addr)); ++ ++ return 0; ++} ++ ++/* ++ * Retrieve the MAC address set by the bootloader. ++ */ ++static void __init get_mac_address(struct net_device *dev) ++{ ++ unsigned char addr[6]; ++ unsigned long low, high; ++ ++ low = ks8695_read(dev, KS8695_WMAL); ++ high = ks8695_read(dev, KS8695_WMAH); ++ ++ addr[0] = (high & 0xff00) >> 8; ++ addr[1] = (high & 0xff); ++ addr[2] = (low & 0xff000000) >> 24; ++ addr[3] = (low & 0xff0000) >> 16; ++ addr[4] = (low & 0xff00) >> 8; ++ addr[5] = (low & 0xff); ++ ++ if (is_valid_ether_addr(addr)) ++ memcpy(dev->dev_addr, &addr, 6); ++} ++ ++ ++/* ......................... ETHTOOL SUPPORT ........................... */ ++ ++/* ++ * Get device-specific settings. ++ */ ++static int ks8695eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ unsigned long ctrl; ++ ++ /* the defaults for all ports */ ++ cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full ++ | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full ++ | SUPPORTED_TP | SUPPORTED_MII; ++ cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; ++ cmd->port = PORT_MII; ++ cmd->transceiver = XCVR_INTERNAL; ++ ++ if (dev->base_addr == KS8695_HPNA_VA) { ++ cmd->phy_address = 0; ++ cmd->autoneg = AUTONEG_DISABLE; /* not supported for HPNA */ ++ ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC); ++ cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10; ++ cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF; ++ } ++ else if (dev->base_addr == KS8695_WAN_VA) { ++ cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause); ++ cmd->phy_address = 0; ++ ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); ++ if ((ctrl & WMC_WAND) == 0) { /* auto-negotiation is enabled */ ++ cmd->advertising |= ADVERTISED_Autoneg; ++ if (ctrl & WMC_WANA100F) ++ cmd->advertising |= ADVERTISED_100baseT_Full; ++ if (ctrl & WMC_WANA100H) ++ cmd->advertising |= ADVERTISED_100baseT_Half; ++ if (ctrl & WMC_WANA10F) ++ cmd->advertising |= ADVERTISED_10baseT_Full; ++ if (ctrl & WMC_WANA10H) ++ cmd->advertising |= ADVERTISED_10baseT_Half; ++ if (ctrl & WMC_WANAP) ++ cmd->advertising |= ADVERTISED_Pause; ++ cmd->autoneg = AUTONEG_ENABLE; ++ ++ cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10; ++ cmd->duplex = (ctrl & WMC_WDS) ? DUPLEX_FULL : DUPLEX_HALF; ++ } ++ else { /* auto-negotiation is disabled */ ++ cmd->autoneg = AUTONEG_DISABLE; ++ ++ cmd->speed = (ctrl & WMC_WANF100) ? SPEED_100 : SPEED_10; ++ cmd->duplex = (ctrl & WMC_WANFF) ? DUPLEX_FULL : DUPLEX_HALF; ++ } ++ } ++ else if (dev->base_addr == KS8695_LAN_VA) { ++ // TODO: Implement for Switch ports ++ } ++ ++ return 0; ++} ++ ++/* ++ * Set device-specific settings. ++ */ ++static int ks8695eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ unsigned long ctrl; ++ ++ if ((cmd->speed != SPEED_10) && (cmd->speed != SPEED_100)) ++ return -EINVAL; ++ if ((cmd->duplex != DUPLEX_HALF) && (cmd->duplex != DUPLEX_FULL)) ++ return -EINVAL; ++ if (cmd->port != PORT_MII) ++ return -EINVAL; ++ if (cmd->transceiver != XCVR_INTERNAL) ++ return -EINVAL; ++ if ((cmd->autoneg != AUTONEG_DISABLE) && (cmd->autoneg != AUTONEG_ENABLE)) ++ return -EINVAL; ++ ++ if (cmd->autoneg == AUTONEG_ENABLE) { ++ if ((cmd->advertising & (ADVERTISED_10baseT_Half | ++ ADVERTISED_10baseT_Full | ++ ADVERTISED_100baseT_Half | ++ ADVERTISED_100baseT_Full)) == 0) ++ return -EINVAL; ++ ++ if (dev->base_addr == KS8695_HPNA_VA) ++ return -EINVAL; /* HPNA does not support auto-negotiation. */ ++ else if (dev->base_addr == KS8695_WAN_VA) { ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); ++ ++ ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H | WMC_WANA10F | WMC_WANA10H); ++ if (cmd->advertising & ADVERTISED_100baseT_Full) ++ ctrl |= WMC_WANA100F; ++ if (cmd->advertising & ADVERTISED_100baseT_Half) ++ ctrl |= WMC_WANA100H; ++ if (cmd->advertising & ADVERTISED_10baseT_Full) ++ ctrl |= WMC_WANA10F; ++ if (cmd->advertising & ADVERTISED_10baseT_Half) ++ ctrl |= WMC_WANA10H; ++ ++ ctrl |= WMC_WANR; /* force a re-negotiation */ ++ __raw_writel(ctrl, KS8695_MISC_VA + KS8695_WMC); ++ } ++ else if (dev->base_addr == KS8695_LAN_VA) { ++ // TODO: Implement for Switch ports ++ } ++ ++ } ++ else { ++ if (dev->base_addr == KS8695_HPNA_VA) { ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC); ++ ++ ctrl &= ~(HMC_HSS | HMC_HDS); ++ if (cmd->speed == SPEED_100) ++ ctrl |= HMC_HSS; ++ if (cmd->duplex == DUPLEX_FULL) ++ ctrl |= HMC_HDS; ++ ++ __raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC); ++ } ++ else if (dev->base_addr == KS8695_WAN_VA) { ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); ++ ++ ctrl |= WMC_WAND; /* disable auto-negotiation */ ++ ctrl &= ~(WMC_WANF100 | WMC_WANFF); ++ if (cmd->speed == SPEED_100) ++ ctrl |= WMC_WANF100; ++ if (cmd->duplex == DUPLEX_FULL) ++ ctrl |= WMC_WANFF; ++ ++ __raw_writel(ctrl, KS8695_MISC_VA + KS8695_WMC); ++ } ++ else if (dev->base_addr == KS8695_LAN_VA) { ++ // TODO: Implement for Switch ports ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Restart the auto-negotiation. ++ */ ++static int ks8695eth_nwayreset(struct net_device *dev) ++{ ++ unsigned long ctrl; ++ ++ if (dev->base_addr == KS8695_HPNA_VA) /* HPNA has no auto-negotiation */ ++ return -EINVAL; ++ else if (dev->base_addr == KS8695_WAN_VA) { ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); ++ ++ if ((ctrl & WMC_WAND) == 0) ++ __raw_writel(ctrl | WMC_WANR, KS8695_MISC_VA + KS8695_WMC); ++ else ++ return -EINVAL; /* auto-negitiation not enabled */ ++ } ++ else if (dev->base_addr == KS8695_LAN_VA) { ++ // TODO: Implement for Switch ports ++ } ++ ++ return 0; ++} ++ ++static void ks8695eth_get_pause(struct net_device *dev, struct ethtool_pauseparam *param) ++{ ++ unsigned long ctrl; ++ ++ if (dev->base_addr == KS8695_HPNA_VA) ++ return; ++ else if (dev->base_addr == KS8695_WAN_VA) { ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); /* advertise Pause */ ++ param->autoneg = (ctrl & WMC_WANAP); ++ ++ ctrl = ks8695_read(dev, KS8695_WMDRXC); /* current Tx Flow-control */ ++ param->rx_pause = (ctrl & WMDRXC_WMRFCE); ++ ++ ctrl = ks8695_read(dev, KS8695_WMDRXC); /* current Rx Flow-control */ ++ param->tx_pause = (ctrl & WMDTXC_WMTFCE); ++ } ++ else if (dev->base_addr == KS8695_LAN_VA) { ++ // TODO: Implement for Switch ports ++ } ++} ++ ++static int ks8695eth_set_pause(struct net_device *dev, struct ethtool_pauseparam *param) ++{ ++ // TODO. ++ ++ return 0; ++} ++ ++static u32 ks8695eth_get_link(struct net_device *dev) ++{ ++ unsigned long ctrl; ++ ++ if (dev->base_addr == KS8695_HPNA_VA) ++ return 1; /* HPNA always has link */ ++ else if (dev->base_addr == KS8695_WAN_VA) { ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); ++ return (ctrl & WMC_WLS); ++ } ++ else if (dev->base_addr == KS8695_LAN_VA) { ++ // TODO: Implement for Switch ports ++ } ++ ++ return 0; ++} ++ ++/* ++ * Report driver information. ++ */ ++static void ks8695eth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) ++{ ++ strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); ++ strlcpy(info->version, DRV_VERSION, sizeof(info->version)); ++ strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); ++} ++ ++static struct ethtool_ops ks8695eth_ethtool_ops = { ++ .get_settings = ks8695eth_get_settings, ++ .set_settings = ks8695eth_set_settings, ++ .get_drvinfo = ks8695eth_get_drvinfo, ++ .nway_reset = ks8695eth_nwayreset, ++ .get_pauseparam = ks8695eth_get_pause, ++ .set_pauseparam = ks8695eth_set_pause, ++ .get_link = ks8695eth_get_link, ++}; ++ ++ ++/* ................................ MAC ................................ */ ++ ++/* ++ * Setup the RX DMA descriptors, and enable and start the DMA receiver. ++ */ ++static void ks8695eth_start_rx(struct net_device *dev) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ unsigned long ctrl; ++ int i; ++ ++ /* Setup the DMA descriptors */ ++ for (i = 0; i < MAX_RX_DESC; i++) { ++ lp->rxdma[i].length = MAX_RXBUF_SIZE; ++ lp->rxdma[i].addr = (unsigned long) lp->rxSkb[i].dma; ++ lp->rxdma[i].next = (unsigned long) lp->rxdma_phys + (sizeof(struct rx_descriptor) * (i+1)); ++ lp->rxdma[i].status = RDES_OWN; ++ } ++ ++ /* Create ring of DMA descriptors */ ++ lp->rxdma[MAX_RX_DESC-1].next = (unsigned long) lp->rxdma_phys; /* phys address of 1st descriptor */ ++ ++ /* Reset receive index (since hardware was reset) */ ++ lp->rx_idx = 0; ++ ++ /* Program address of 1st descriptor in KS8695 */ ++ ks8695_write(dev, KS8695_WRDLB, (unsigned long) lp->rxdma_phys); ++ ++ /* Enable and start the DMA Receiver */ ++ ctrl = ks8695_read(dev, KS8695_WMDRXC); ++ ks8695_write(dev, KS8695_WMDRXC, ctrl | WMDRXC_WMRE); ++ ks8695_write(dev, KS8695_WMDRSC, 0); ++} ++ ++/* ++ * Stop the DMA receiver. ++ */ ++static void ks8695eth_stop_rx(struct net_device *dev) ++{ ++ unsigned long ctrl; ++ ++ /* Disable receive DMA */ ++ ctrl = ks8695_read(dev, KS8695_WMDRXC); ++ ks8695_write(dev, KS8695_WMDRXC, ctrl & ~WMDRXC_WMRE); ++} ++ ++/* ++ * Setup the TX DMA descriptors, and enable DMA transmitter. ++ */ ++static void ks8695eth_start_tx(struct net_device *dev) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ unsigned long ctrl; ++ int i; ++ ++ /* Setup the DMA descriptors */ ++ for (i = 0; i < MAX_TX_DESC; i++) { ++ lp->txdma[i].ownership = 0; ++ lp->txdma[i].status = 0; ++ lp->txdma[i].addr = 0; ++ lp->txdma[i].next = (unsigned long) lp->txdma_phys + (sizeof(struct tx_descriptor) * (i+1)); ++ } ++ ++ /* Create ring of DMA descriptors */ ++ lp->txdma[MAX_TX_DESC-1].next = (unsigned long) lp->txdma_phys; /* phys address of 1st desc */ ++ ++ /* Reset transmit indexes (since hardware was reset) */ ++ lp->tx_head = 0; ++ lp->tx_tail = 0; ++ ++ /* Program address of 1st descriptor in KS8695 */ ++ ks8695_write(dev, KS8695_WTDLB, (unsigned long) lp->txdma_phys); ++ ++ /* Enable the DMA transmitter (will be started on first packet) */ ++ ctrl = ks8695_read(dev, KS8695_WMDTXC); ++ ks8695_write(dev, KS8695_WMDTXC, ctrl | WMDTXC_WMTE); ++} ++ ++/* ++ * Stop the DMA transmitter. ++ */ ++static void ks8695eth_stop_tx(struct net_device *dev) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ unsigned long ctrl; ++ int i; ++ ++ /* Disable transmit DMA */ ++ ctrl = ks8695_read(dev, KS8695_WMDTXC); ++ ks8695_write(dev, KS8695_WMDTXC, ctrl & ~WMDTXC_WMTE); ++ ++ /* Clear any pending skb's still on transmit queue */ ++ for (i = 0; i < MAX_TX_DESC; i++) { ++ lp->txdma[i].ownership = 0; ++ lp->txdma[i].status = 0; ++ lp->txdma[i].addr = 0; ++ ++ if (lp->txSkb[i].skb) { ++ dma_unmap_single(lp->dev, lp->txSkb[i].dma, lp->txSkb[i].length, DMA_TO_DEVICE); ++ dev_kfree_skb_irq(lp->txSkb[i].skb); ++ lp->txSkb[i].skb = NULL; ++ } ++ } ++} ++ ++/* ++ * Reset the MAC hardware. ++ */ ++static void ks8695eth_hw_reset(struct net_device *dev) ++{ ++ /* Perform hardware reset */ ++ ks8695_write(dev, KS8695_WMDTXC, WMDTXC_WMTRST); ++ while (ks8695_read(dev, KS8695_WMDTXC) & WMDTXC_WMTRST) { barrier(); } ++ ++ /* Initialize the hardware */ ++ ks8695_write(dev, KS8695_WMDRXC, WMDRXC_WMRU | WMDRXC_WMRB); /* RX: receive Unicast & Broadcast */ ++ ks8695_write(dev, KS8695_WMDTXC, WMDTXC_WMTEP | WMDTXC_WMTAC); /* TX: add Padding & CRC */ ++ ++ // TODO: Can set Rx/Tx PBL: (Micrel using 8) ++ // TODO: Enable hardware checksumming. ++ // TODO: Enable Rx/Tx flow-control ++} ++ ++/* ++ * Enable or Disable the IRQs associated with a network interface. ++ */ ++static void ks8695eth_set_irq(struct net_device *dev, short enable) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ int i; ++ ++ for (i = 0; i < NR_IRQS; i++) { ++ if (lp->irqs & (1 << i)) { ++ if (enable) ++ enable_irq(i); ++ else ++ disable_irq(i); ++ } ++ } ++} ++ ++/* ++ * Open the ethernet interface. ++ */ ++static int ks8695eth_open(struct net_device *dev) ++{ ++ if (!is_valid_ether_addr(dev->dev_addr)) ++ return -EADDRNOTAVAIL; ++ ++ /* MUST reset hardware in _open() */ ++ ks8695eth_hw_reset(dev); ++ ++ /* Update the MAC address (incase user has changed it) */ ++ update_mac_address(dev); ++ ++ /* Start DMA */ ++ ks8695eth_start_tx(dev); ++ ks8695eth_start_rx(dev); ++ ++ /* Enable interrupts */ ++ ks8695eth_set_irq(dev, 1); ++ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++/* ++ * Close the ethernet interface. ++ */ ++static int ks8695eth_close(struct net_device *dev) ++{ ++ /* Stop DMA */ ++ ks8695eth_stop_rx(dev); ++ ks8695eth_stop_tx(dev); ++ ++ /* Disable interrupts */ ++ ks8695eth_set_irq(dev, 0); ++ ++ netif_stop_queue(dev); ++ return 0; ++} ++ ++/* ++ * Return the current statistics. ++ */ ++static struct net_device_stats *ks8695eth_stats(struct net_device *dev) ++{ ++ return &dev->stats; ++} ++ ++/* ++ * Queue a packet for transmission in next TX DMA descriptor. ++ */ ++static int ks8695eth_xmit_frame(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ int i; ++ ++ /* Packets are added to head of array */ ++ i = lp->tx_head; ++ ++ /* Store packet information */ ++ lp->txSkb[i].skb = skb; ++ lp->txSkb[i].length = skb->len; ++ lp->txSkb[i].dma = dma_map_single(lp->dev, skb->data, skb->len, DMA_TO_DEVICE); ++ ++ spin_lock_irq(&lp->tx_lock); ++ ++ /* Set Tx descriptor information */ ++ lp->txdma[i].addr = lp->txSkb[i].dma; ++ lp->txdma[i].status = TDES_IC | TDES_FS | TDES_LS | (lp->txSkb[i].length & TDES_TBS); ++ lp->txdma[i].ownership = TDES_OWN; ++ ++ /* Start the DMA transmitter (if necessary) */ ++ ks8695_write(dev, KS8695_WMDTSC, 0); ++ ++ lp->tx_head = (lp->tx_head + 1) % MAX_TX_DESC; ++ if (lp->tx_head == lp->tx_tail) /* no more descriptors */ ++ netif_stop_queue(dev); ++ ++ spin_unlock_irq(&lp->tx_lock); ++ ++ dev->trans_start = jiffies; ++ return 0; ++} ++ ++/* ..................................................................... */ ++ ++/* ++ * The link state of the WAN port has changed. ++ * (Called from interrupt context) ++ */ ++static void ks8695eth_wan_link(struct net_device *dev) ++{ ++ unsigned long ctrl; ++ ++ ctrl = __raw_readl(KS8695_MISC_VA + KS8695_WMC); ++ if (ctrl & WMC_WLS) { ++ netif_carrier_on(dev); ++ printk(KERN_INFO "%s: Link is now %s-%s\n", dev->name, ++ (ctrl & WMC_WSS) ? "100" : "10", ++ (ctrl & WMC_WDS) ? "FullDuplex" : "HalfDuplex"); ++ } ++ else { ++ netif_carrier_off(dev); ++ printk(KERN_INFO "%s: Link down.\n", dev->name); ++ } ++} ++ ++/* ..................................................................... */ ++ ++/* ++ * A frame has been received. Exteract from buffer descriptor and deliver to ++ * upper layers. ++ * (Called from interrupt context) ++ */ ++static void ks8695eth_rx_interrupt(struct net_device *dev) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ struct sk_buff *skb; ++ unsigned long flags; ++ unsigned int pktlen; ++ ++ while (!(lp->rxdma[lp->rx_idx].status & RDES_OWN)) { ++ flags = lp->rxdma[lp->rx_idx].status; ++ ++ if ((flags & (RDES_FS | RDES_LS)) != (RDES_FS | RDES_LS)) { ++ printk(KERN_ERR "%s: Spanning packet detected\n", dev->name); ++ goto rx_complete; ++ } ++ ++ /* handle errors */ ++ if (flags & (RDES_ES | RDES_RE)) { ++ dev->stats.rx_errors++; ++ ++ if (flags & RDES_TL) /* Frame too long */ ++ dev->stats.rx_length_errors++; ++ else if (flags & RDES_RF) /* Runt frame */ ++ dev->stats.rx_length_errors++; ++ else if (flags & RDES_CE) /* CRC error */ ++ dev->stats.rx_crc_errors++; ++ else if (flags & RDES_RE) /* MII error */ ++ dev->stats.rx_missed_errors++; ++ // TODO: If hardware checksumming, then check IP/TCP/UDP errors. ++ ++ goto rx_complete; ++ } ++ ++ pktlen = flags & RDES_FLEN; ++ pktlen = pktlen - 4; /* remove CRC */ ++ ++ // OLD CALL: consistent_sync(lp->rxSkb[lp->rx_idx].skb->data, MAX_RXBUF_SIZE, DMA_FROM_DEVICE); ++ dma_sync_single_for_cpu(lp->dev, lp->rxSkb[lp->rx_idx].dma, MAX_RXBUF_SIZE, DMA_FROM_DEVICE); ++ ++ skb = dev_alloc_skb(pktlen+2); /* +2 to align IP header */ ++ if (!skb) { ++ dev->stats.rx_dropped++; ++ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); ++ goto rx_complete; ++ } ++ ++ skb_reserve(skb, 2); /* align IP header */ ++ memcpy(skb_put(skb, pktlen), lp->rxSkb[lp->rx_idx].skb->data, pktlen); ++ ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ ++ /* update statistics */ ++ dev->stats.rx_packets++; ++ dev->stats.rx_bytes += pktlen; ++ if (flags & RDES_MF) ++ dev->stats.multicast++; ++ dev->last_rx = jiffies; ++ ++rx_complete: ++ lp->rxdma[lp->rx_idx].status = RDES_OWN; /* reset ownership bit */ ++ ++ lp->rx_idx = (lp->rx_idx + 1) % MAX_RX_DESC; /* next descriptor */ ++ } ++ ++ /* restart DMA receiver incase it was suspended */ ++ ks8695_write(dev, KS8695_WMDRSC, 0); ++} ++ ++/* ++ * A packet has been transmitted. ++ * (Called from interrupt context) ++ */ ++static void ks8695eth_tx_interrupt(struct net_device *dev) ++{ ++ struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ int i; ++ ++ /* Packets are removed from tail of array */ ++ i = lp->tx_tail; ++ ++ // TODO: Loop through multiple times? ++ ++ if (lp->txSkb[i].skb) { ++ /* update statistics */ ++ dev->stats.tx_packets++; ++ dev->stats.tx_bytes += lp->txSkb[i].length; ++ ++ /* free packet */ ++ dma_unmap_single(lp->dev, lp->txSkb[i].dma, lp->txSkb[i].length, DMA_TO_DEVICE); ++ dev_kfree_skb_irq(lp->txSkb[i].skb); ++ lp->txSkb[i].skb = NULL; ++ ++ /* Not necessary to clear descriptor since we still own it */ ++ } ++ ++ lp->tx_tail = (lp->tx_tail + 1) % MAX_TX_DESC; ++ ++ netif_wake_queue(dev); ++} ++ ++/* ++ * MAC interrupt handler ++ */ ++static irqreturn_t ks8695eth_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = (struct net_device *) dev_id; ++ ++ switch (irq) { ++ case KS8695_IRQ_LAN_RX_STATUS: ++ case KS8695_IRQ_HPNA_RX_STATUS: ++ case KS8695_IRQ_WAN_RX_STATUS: ++ ks8695eth_rx_interrupt(dev); ++ return IRQ_HANDLED; ++ ++ case KS8695_IRQ_LAN_TX_STATUS: ++ case KS8695_IRQ_HPNA_TX_STATUS: ++ case KS8695_IRQ_WAN_TX_STATUS: ++ ks8695eth_tx_interrupt(dev); ++ return IRQ_HANDLED; ++ ++ case KS8695_IRQ_WAN_LINK: ++ ks8695eth_wan_link(dev); ++ return IRQ_HANDLED; ++ ++ default: ++ return IRQ_NONE; ++ } ++} ++ ++ ++/* ..................................................................... */ ++ ++/* ++ * Initialize the WAN hardware to known defaults. ++ */ ++static void __init ks8695eth_init_wan(void) ++{ ++ unsigned long ctrl; ++ ++ /* Support auto-negotiation */ ++ ctrl = WMC_WANAP | WMC_WANA100F | WMC_WANA100H | WMC_WANA10F | WMC_WANA10H; ++ ++ /* LED0 = Activity , LED1 = Link */ ++ ctrl |= (WLED0S_ACTIVITY | WLED1S_LINK); ++ ++ /* Restart Auto-negotiation */ ++ ctrl |= WMC_WANR; ++ ++ __raw_writel(ctrl, KS8695_MISC_VA + KS8695_WMC); ++ ++ __raw_writel(0, KS8695_MISC_VA + KS8695_WPPM); ++ __raw_writel(0, KS8695_MISC_VA + KS8695_PPS); ++} ++ ++/* ++ * Initialize the LAN Switch hardware to known defaults. ++ */ ++static void __init ks8695eth_init_switch(void) ++{ ++ unsigned long ctrl; ++ ++ ctrl = 0x40819e00; /* default */ ++ ++ /* LED0 = Speed LED1 = Link/Activity */ ++ ctrl &= ~(SEC0_LLED1S | SEC0_LLED0S); ++ ctrl |= (LLED0S_LINK | LLED1S_LINK_ACTIVITY); ++ ++ /* Enable Switch */ ++ ctrl |= SEC0_ENABLE; ++ ++ __raw_writel(ctrl, KS8695_SWITCH_VA + KS8695_SEC0); ++ ++ __raw_writel(0x9400100, KS8695_SWITCH_VA + KS8695_SEC1); /* reset defaults */ ++} ++ ++static int ks8695eth_hook_irqs(struct platform_device *pdev, struct net_device *dev, unsigned long *irqset) ++{ ++ struct resource *res; ++ int i = 0, ret; ++ ++ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { ++ set_irq_flags(res->start, IRQF_VALID | IRQF_NOAUTOEN); ++ ++ ret = request_irq(res->start, ks8695eth_interrupt, IRQF_DISABLED | IRQF_SHARED, res->name, dev); ++ if (ret) { ++ printk(KERN_ERR "%s: return_irq %u failed\n", dev->name, res->start); ++ return -EBUSY; ++ } ++ ++ *irqset |= (1 << res->start); ++ ++ // TODO: Can set different priorities for interrupts [0x BB AA FF]. ++ ++ i++; ++ } ++ ++ return 0; ++} ++ ++static int __init ks8695eth_probe(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ struct ks8695eth_priv *lp; ++ struct resource *res; ++ int i = 0, ret, size; ++ DECLARE_MAC_BUF(mac); ++ ++ /* Create ethernet device */ ++ dev = alloc_etherdev(sizeof(struct ks8695eth_priv)); ++ if (!dev) ++ return -ENOMEM; ++ ++ /* Get I/O base address */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ free_netdev(dev); ++ return -ENODEV; ++ } ++ dev->base_addr = res->start; ++ ++ lp = (struct ks8695eth_priv *) dev->priv; ++ ++ /* Retreive MAC address before the MAC registers are reset */ ++ get_mac_address(dev); ++ ++ /* Reset the hardware */ ++ ks8695_write(dev, KS8695_WMDTXC, WMDTXC_WMTRST); ++ while (ks8695_read(dev, KS8695_WMDTXC) & WMDTXC_WMTRST) { barrier(); } ++ ++ /* Get IRQ's */ ++ dev->irq = platform_get_irq(pdev, 0); ++ ret = ks8695eth_hook_irqs(pdev, dev, &lp->irqs); ++ if (ret) { ++ // Cleanup. ++ } ++ ++ /* Allocate DMA-able memory for Tx descriptor */ ++ size = sizeof(struct tx_descriptor) * MAX_TX_DESC; ++ lp->txdma = dma_alloc_coherent(&pdev->dev, size, &lp->txdma_phys, GFP_KERNEL); ++ if (lp->txdma == NULL) { ++ // free IRQs ++ free_netdev(dev); ++ return -ENOMEM; ++ } ++ memset(lp->txdma, 0, size); ++ lp->tx_head = 0; ++ lp->tx_tail = 0; ++ ++ /* Allocate DMA-able memory for Rx descriptor */ ++ size = sizeof(struct rx_descriptor) * MAX_RX_DESC; ++ lp->rxdma = dma_alloc_coherent(&pdev->dev, size, &lp->rxdma_phys, GFP_KERNEL); ++ if (lp->rxdma == NULL) { ++ // free IRQs ++ // Free TX descriptor memory. ++ free_netdev(dev); ++ return -ENOMEM; ++ } ++ memset(lp->rxdma, 0, size); ++ lp->rx_idx = 0; ++ ++ /* Allocate DMA-able memory for Rx Data */ ++ for (i = 0; i < MAX_RX_DESC; i++) { ++ lp->rxSkb[i].skb = alloc_skb(MAX_RXBUF_SIZE, GFP_KERNEL); ++ if (lp->rxSkb[i].skb == NULL) { ++ // Cleanup ++ return -ENOMEM; ++ } ++ lp->rxSkb[i].length = MAX_RXBUF_SIZE; ++ lp->rxSkb[i].dma = dma_map_single(&pdev->dev, lp->rxSkb[i].skb->data, MAX_RXBUF_SIZE, DMA_FROM_DEVICE); ++ } ++ ++ spin_lock_init(&lp->tx_lock); ++ ++ platform_set_drvdata(pdev, dev); ++ ++ ether_setup(dev); ++ dev->open = ks8695eth_open; ++ dev->stop = ks8695eth_close; ++ dev->hard_start_xmit = ks8695eth_xmit_frame; ++ dev->get_stats = ks8695eth_stats; ++ dev->set_multicast_list = ks8695eth_set_multi; ++ dev->set_mac_address = ks8695eth_set_mac; ++ dev->ethtool_ops = &ks8695eth_ethtool_ops; ++ ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ lp->dev = &pdev->dev; ++ ++ if (dev->base_addr == KS8695_WAN_VA) ++ ks8695eth_init_wan(); ++ else if (dev->base_addr == KS8695_LAN_VA) ++ ks8695eth_init_switch(); ++ ++ /* Register the network interface */ ++ ret = register_netdev(dev); ++ if (ret) { ++ // free IRQs ++ free_netdev(dev); ++// dma_free_coherent(&pdev->dev, sizeof(struct ks8695_tx_dma), lp->txdma, lp->txdma_phys); ++// dma_free_coherent(&pdev->dev, sizeof(struct ks8695_rx_dma), lp->rxdma, lp->rxdma_phys); ++ return ret; ++ } ++ ++ printk(KERN_INFO "%s: KS8695 ethernet (%s)\n", dev->name, print_mac(mac, dev->dev_addr)); ++ ++ return 0; ++} ++ ++static int __devexit ks8695eth_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++// struct ks8695eth_priv *lp = (struct ks8695eth_priv *) dev->priv; ++ ++ unregister_netdev(dev); ++ ++ // Free IRQ ++// dma_free_coherent(&pdev->dev, sizeof(struct ks8695_tx_dma), lp->txdma, lp->txdma_phys); ++// dma_free_coherent(&pdev->dev, sizeof(struct ks8695_rx_dma), lp->rxdma, lp->rxdma_phys); ++ ++ platform_set_drvdata(pdev, NULL); ++ free_netdev(dev); ++ return 0; ++} ++ ++static struct platform_driver ks8695ether_driver = { ++ .probe = ks8695eth_probe, ++ .remove = __devexit_p(ks8695eth_remove), ++// .suspend = ++// .resume = ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++ ++static int __init ks8695eth_init(void) ++{ ++ return platform_driver_register(&ks8695ether_driver); ++} ++ ++static void __exit ks8695eth_exit(void) ++{ ++ platform_driver_unregister(&ks8695ether_driver); ++} ++ ++module_init(ks8695eth_init); ++module_exit(ks8695eth_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("KS8695 Ethernet driver"); ++MODULE_AUTHOR("Andrew Victor"); ++MODULE_ALIAS("platform:" DRV_NAME); +diff -urN -x CVS linux-2.6.25/drivers/net/arm/ks8695_ether.h linux-2.6/drivers/net/arm/ks8695_ether.h +--- linux-2.6.25/drivers/net/arm/ks8695_ether.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/net/arm/ks8695_ether.h 2008-05-08 21:51:23.000000000 +0200 +@@ -0,0 +1,92 @@ ++/* ++ * Ethernet driver for the Micrel/Kendin KS8695 (Centaur) ++ * ++ * (C) 2006 Andrew Victor ++ * ++ */ ++ ++#ifndef KS8695_ETHERNET ++#define KS8695_ETHERNET ++ ++/* .... Hardware Descriptors ................................................ */ ++ ++struct rx_descriptor { ++ unsigned long status; ++ unsigned long length; ++ unsigned long addr; ++ unsigned long next; ++}; ++ ++#define RDES_OWN (1 << 31) /* Ownership */ ++#define RDES_FS (1 << 30) /* First Descriptor */ ++#define RDES_LS (1 << 29) /* Last Descriptor */ ++#define RDES_IPE (1 << 28) /* IP Checksum error */ ++#define RDES_TCPE (1 << 27) /* TCP Checksum error */ ++#define RDES_UDPE (1 << 26) /* UDP Checksum error */ ++#define RDES_ES (1 << 25) /* Error summary */ ++#define RDES_MF (1 << 24) /* Multicast Frame */ ++#define RDES_RE (1 << 19) /* MII Error reported */ ++#define RDES_TL (1 << 18) /* Frame too Long */ ++#define RDES_RF (1 << 17) /* Runt Frame */ ++#define RDES_CE (1 << 16) /* CRC error */ ++#define RDES_FT (1 << 15) /* Frame Type */ ++#define RDES_FLEN (0x7ff) /* Frame Length */ ++ ++#define RDES_RER (1 << 25) /* Receive End of Ring */ ++#define RDES_RBS (0x7ff) /* Receive Buffer Size */ ++ ++ ++struct tx_descriptor { ++ unsigned long ownership; ++ unsigned long status; ++ unsigned long addr; ++ unsigned long next; ++}; ++ ++#define TDES_OWN (1 << 31) /* Ownership */ ++ ++#define TDES_IC (1 << 31) /* Interrupt on Completion */ ++#define TDES_FS (1 << 30) /* First Segment */ ++#define TDES_LS (1 << 29) /* Last Segment */ ++#define TDES_IPCKG (1 << 28) /* IP Checksum generate */ ++#define TDES_TCPCKG (1 << 27) /* TCP Checksum generate */ ++#define TDES_UDPCKG (1 << 26) /* UDP Checksum generate */ ++#define TDES_TER (1 << 25) /* Transmit End of Ring */ ++#define TDES_TBS (0x7ff) /* Transmit Buffer Size */ ++ ++ ++/* .... ..................................................................... */ ++ ++#define MAX_RX_DESC 16 /* number of receive descriptors */ ++#define MAX_TX_DESC 8 /* number of transmit descriptors */ ++#define MAX_RXBUF_SIZE 0x600 /* 1518 rounded-up */ ++ ++struct ks8695_buffer ++{ ++ struct sk_buff *skb; ++ dma_addr_t dma; ++ unsigned long length; ++}; ++ ++ ++struct ks8695eth_priv ++{ ++ struct device *dev; ++ unsigned long irqs; /* IRQ bitset */ ++ ++ /* Transmit */ ++ struct tx_descriptor *txdma; /* Tx DMA descriptors */ ++ dma_addr_t txdma_phys; /* TX DMA descriptors (phys address) */ ++ unsigned int tx_head; /* descriptor index (add) */ ++ unsigned int tx_tail; /* descriptor index (remove) */ ++ spinlock_t tx_lock; ++ struct ks8695_buffer txSkb[MAX_TX_DESC]; /* packets being transmitted */ ++ ++ /* Receive */ ++ struct rx_descriptor *rxdma; /* Rx DMA descriptors */ ++ dma_addr_t rxdma_phys; /* Rx DMA descriptors (phys address) */ ++ unsigned int rx_idx; /* descriptor index */ ++ struct ks8695_buffer rxSkb[MAX_RX_DESC]; ++}; ++ ++#endif +diff -urN -x CVS linux-2.6.25/drivers/rtc/Kconfig linux-2.6/drivers/rtc/Kconfig +--- linux-2.6.25/drivers/rtc/Kconfig 2008-05-03 00:15:49.000000000 +0200 ++++ linux-2.6/drivers/rtc/Kconfig 2008-04-15 21:48:11.000000000 +0200 +@@ -487,12 +487,12 @@ + this is powered by the backup power supply. + + config RTC_DRV_AT91SAM9 +- tristate "AT91SAM9x" ++ tristate "AT91SAM9x or AT91CAP9" + depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40) + help +- RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer). +- These timers are powered by the backup power supply (such as a +- small coin cell battery), but do not need to be used as RTCs. ++ RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT (Real ++ Time Timer). These timers are powered by the backup power supply ++ (such as a small coin cell battery), but do not need to be used as RTCs. + + (On AT91SAM9rl chips you probably want to use the dedicated RTC + module and leave the RTT available for other uses.) +diff -urN -x CVS linux-2.6.25/drivers/rtc/rtc-at91rm9200.c linux-2.6/drivers/rtc/rtc-at91rm9200.c +--- linux-2.6.25/drivers/rtc/rtc-at91rm9200.c 2008-05-03 00:15:49.000000000 +0200 ++++ linux-2.6/drivers/rtc/rtc-at91rm9200.c 2008-04-25 23:15:05.000000000 +0200 +@@ -29,9 +29,6 @@ + #include <linux/completion.h> + + #include <asm/uaccess.h> +-#include <asm/rtc.h> +- +-#include <asm/mach/time.h> + + #include <asm/arch/at91_rtc.h> + +@@ -307,12 +304,6 @@ + return ret; + } + +- /* cpu init code should really have flagged this device as +- * being wake-capable; if it didn't, do that here. +- */ +- if (!device_can_wakeup(&pdev->dev)) +- device_init_wakeup(&pdev->dev, 1); +- + rtc = rtc_device_register(pdev->name, &pdev->dev, + &at91_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { +diff -urN -x CVS linux-2.6.25/drivers/rtc/rtc-at91sam9.c linux-2.6/drivers/rtc/rtc-at91sam9.c +--- linux-2.6.25/drivers/rtc/rtc-at91sam9.c 2008-05-03 00:15:49.000000000 +0200 ++++ linux-2.6/drivers/rtc/rtc-at91sam9.c 2008-05-05 22:01:39.000000000 +0200 +@@ -21,6 +21,7 @@ + + #include <asm/mach/time.h> + #include <asm/arch/board.h> ++#include <asm/arch/cpu.h> + #include <asm/arch/at91_rtt.h> + + +@@ -150,6 +151,9 @@ + return 0; + } + ++/* ++ * Read alarm time and date in RTC ++ */ + static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) + { + struct sam9_rtc *rtc = dev_get_drvdata(dev); +@@ -176,6 +180,9 @@ + return 0; + } + ++/* ++ * Set alarm time and date in RTC ++ */ + static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) + { + struct sam9_rtc *rtc = dev_get_drvdata(dev); +@@ -321,10 +328,6 @@ + if (!rtc) + return -ENOMEM; + +- /* platform setup code should have handled this; sigh */ +- if (!device_can_wakeup(&pdev->dev)) +- device_init_wakeup(&pdev->dev, 1); +- + platform_set_drvdata(pdev, rtc); + rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS); + rtc->rtt += r->start; +diff -urN -x CVS linux-2.6.25/drivers/spi/Kconfig linux-2.6/drivers/spi/Kconfig +--- linux-2.6.25/drivers/spi/Kconfig 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/spi/Kconfig 2008-03-09 15:14:53.000000000 +0200 +@@ -105,6 +105,15 @@ + inexpensive battery powered microcontroller evaluation board. + This same cable can be used to flash new firmware. + ++config SPI_AT91 ++ tristate "AT91RM9200 Bitbang SPI Master" ++ depends on SPI_MASTER && ARCH_AT91RM9200 && !SPI_ATMEL && EXPERIMENTAL ++ select SPI_BITBANG ++ help ++ This is dumb PIO bitbanging driver for the Atmel AT91RM9200. ++ The SPI_ATMEL driver will be its replacement, using the native ++ SPI hardware and its DMA controller. ++ + config SPI_IMX + tristate "Freescale iMX SPI controller" + depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL +diff -urN -x CVS linux-2.6.25/drivers/spi/Makefile linux-2.6/drivers/spi/Makefile +--- linux-2.6.25/drivers/spi/Makefile 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/spi/Makefile 2008-03-09 17:54:27.000000000 +0200 +@@ -29,6 +29,7 @@ + obj-$(CONFIG_SPI_TXX9) += spi_txx9.o + obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o + obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o ++obj-$(CONFIG_SPI_AT91) += spi_at91_bitbang.o + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) +diff -urN -x CVS linux-2.6.25/drivers/spi/spi_at91_bitbang.c linux-2.6/drivers/spi/spi_at91_bitbang.c +--- linux-2.6.25/drivers/spi/spi_at91_bitbang.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/spi/spi_at91_bitbang.c 2008-04-18 17:38:19.000000000 +0200 +@@ -0,0 +1,208 @@ ++/* ++ * at91_spi.c - at91 SPI driver (BOOTSTRAP/BITBANG VERSION) ++ * ++ * Copyright (C) 2006 David Brownell ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++ ++#include <linux/spi/spi.h> ++#include <linux/spi/spi_bitbang.h> ++ ++#include <asm/arch/gpio.h> ++ ++ ++/* ++ * FIXME this bitbanging version is just to help bootstrap systems until ++ * there's a native SPI+IRQ+DMA controller driver ... such a driver should ++ * be a drop-in replacement for this one, and much faster. ++ * ++ * remember: ++ * ++ * - other at91 parts (like at91sam9) have multiple controllers ++ * and different pin muxing; this version is at91rm9200 specfic. ++ * ++ * - at91sam9261 SPI0 pins are directly muxed with MMC/SD pins. ++ * ++ * - rm9200 spi chipselects drop wrongly, so the native driver ++ * will need to use gpios much like this does. ++ * ++ * - real hardware only allows 8..16 bits per word, while this ++ * bitbanger allows 1..32 (incompatible superset). ++ * ++ * - this disregards clock parameters. with inlined gpio calls, ++ * gcc 3.4.4 produces about 1.5 mbit/sec, more than 2x faster ++ * than using the subroutined veresion from txrx_word(). ++ * ++ * - suspend/resume and <linux/clk.h> support is missing ... ++ */ ++ ++#define spi_miso_bit AT91_PIN_PA0 ++#define spi_mosi_bit AT91_PIN_PA1 ++#define spi_sck_bit AT91_PIN_PA2 ++ ++struct at91_spi { ++ struct spi_bitbang bitbang; ++ struct platform_device *pdev; ++}; ++ ++/*----------------------------------------------------------------------*/ ++ ++static inline void setsck(struct spi_device *spi, int is_on) ++{ ++ at91_set_gpio_value(spi_sck_bit, is_on); ++} ++ ++static inline void setmosi(struct spi_device *spi, int is_on) ++{ ++ at91_set_gpio_value(spi_mosi_bit, is_on); ++} ++ ++static inline int getmiso(struct spi_device *spi) ++{ ++ return at91_get_gpio_value(spi_miso_bit); ++} ++ ++static void at91_spi_chipselect(struct spi_device *spi, int is_active) ++{ ++ unsigned long cs = (unsigned long) spi->controller_data; ++ ++ /* set default clock polarity */ ++ if (is_active) ++ setsck(spi, spi->mode & SPI_CPOL); ++ ++ /* only support active-low (default) */ ++ at91_set_gpio_value(cs, !is_active); ++} ++ ++/* ++ * NOTE: this is "as fast as we can"; it should be a function of ++ * the device clock ... ++ */ ++#define spidelay(X) do{} while(0) ++ ++#define EXPAND_BITBANG_TXRX ++#include <linux/spi/spi_bitbang.h> ++ ++static u32 at91_spi_txrx_word_mode0(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, 8); ++} ++ ++static u32 at91_spi_txrx_word_mode1(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, 8); ++} ++ ++static u32 at91_spi_txrx_word_mode2(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, 8); ++} ++ ++static u32 at91_spi_txrx_word_mode3(struct spi_device *spi, ++ unsigned nsecs, u32 word, u8 bits) ++{ ++ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, 8); ++} ++ ++/*----------------------------------------------------------------------*/ ++ ++static int __init at91_spi_probe(struct platform_device *pdev) ++{ ++ int status; ++ struct spi_master *master; ++ struct at91_spi *at91_spi; ++ ++ if (pdev->id != 0) /* SPI0 bus */ ++ return -EINVAL; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof *at91_spi); ++ if (!master) ++ return -ENOMEM; ++ ++ at91_spi = spi_master_get_devdata(master); ++ at91_spi->pdev = pdev; ++ platform_set_drvdata(pdev, at91_spi); ++ ++ /* SPI and bitbang hookup */ ++ master->bus_num = 0; ++ master->num_chipselect = 4; ++ ++ at91_spi->bitbang.master = spi_master_get(master); ++ at91_spi->bitbang.chipselect = at91_spi_chipselect; ++ at91_spi->bitbang.txrx_word[SPI_MODE_0] = at91_spi_txrx_word_mode0; ++ at91_spi->bitbang.txrx_word[SPI_MODE_1] = at91_spi_txrx_word_mode1; ++ at91_spi->bitbang.txrx_word[SPI_MODE_2] = at91_spi_txrx_word_mode2; ++ at91_spi->bitbang.txrx_word[SPI_MODE_3] = at91_spi_txrx_word_mode3; ++ ++ status = spi_bitbang_start(&at91_spi->bitbang); ++ if (status < 0) ++ (void) spi_master_put(at91_spi->bitbang.master); ++ ++ return status; ++} ++ ++static int __exit at91_spi_remove(struct platform_device *pdev) ++{ ++ struct at91_spi *at91_spi = platform_get_drvdata(pdev); ++ int status; ++ ++ /* stop() unregisters child devices too */ ++ status = spi_bitbang_stop(&at91_spi->bitbang); ++ (void) spi_master_put(at91_spi->bitbang.master); ++ ++ platform_set_drvdata(pdev, NULL); ++ return status; ++} ++ ++static struct platform_driver at91_spi_driver = { ++ .probe = at91_spi_probe, ++ .remove = __exit_p(at91_spi_remove), ++ .driver = { ++ .name = "at91_spi", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init at91_spi_init(void) ++{ ++ at91_set_gpio_output(spi_sck_bit, 0); ++ at91_set_gpio_output(spi_mosi_bit, 0); ++ at91_set_gpio_input(spi_miso_bit, 1 /* pullup */); ++ ++ /* register driver */ ++ return platform_driver_register(&at91_spi_driver); ++} ++ ++static void __exit at91_spi_exit(void) ++{ ++ platform_driver_unregister(&at91_spi_driver); ++} ++ ++device_initcall(at91_spi_init); ++module_exit(at91_spi_exit); ++ ++MODULE_ALIAS("at91_spi.0"); ++ ++MODULE_DESCRIPTION("AT91 SPI support (BOOTSTRAP/BITBANG VERSION)"); ++MODULE_AUTHOR("David Brownell"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:at91_spi"); +diff -urN -x CVS linux-2.6.25/drivers/usb/gadget/Kconfig linux-2.6/drivers/usb/gadget/Kconfig +--- linux-2.6.25/drivers/usb/gadget/Kconfig 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/usb/gadget/Kconfig 2008-04-18 19:23:34.000000000 +0200 +@@ -118,10 +118,10 @@ + config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED +- depends on AVR32 ++ depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL + help + USBA is the integrated high-speed USB Device controller on +- the AT32AP700x processors from Atmel. ++ the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. + + config USB_ATMEL_USBA + tristate +diff -urN -x CVS linux-2.6.25/drivers/usb/gadget/at91_udc.c linux-2.6/drivers/usb/gadget/at91_udc.c +--- linux-2.6.25/drivers/usb/gadget/at91_udc.c 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/usb/gadget/at91_udc.c 2008-04-15 21:48:12.000000000 +0200 +@@ -1827,7 +1827,7 @@ + */ + if ((!udc->suspended && udc->addr) + || !wake +- || at91_suspend_entering_slow_clock()) { ++ || clk_must_disable(udc->fclk)) { + pullup(udc, 0); + wake = 0; + } else +diff -urN -x CVS linux-2.6.25/drivers/usb/gadget/atmel_usba_udc.c linux-2.6/drivers/usb/gadget/atmel_usba_udc.c +--- linux-2.6.25/drivers/usb/gadget/atmel_usba_udc.c 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/usb/gadget/atmel_usba_udc.c 2008-05-03 01:07:46.000000000 +0200 +@@ -18,6 +18,7 @@ + #include <linux/platform_device.h> + #include <linux/usb/ch9.h> + #include <linux/usb/gadget.h> ++#include <linux/usb/atmel_usba_udc.h> + #include <linux/delay.h> + + #include <asm/gpio.h> +@@ -27,6 +28,7 @@ + + + static struct usba_udc the_udc; ++static struct usba_ep *usba_ep; + + #ifdef CONFIG_USB_GADGET_DEBUG_FS + #include <linux/debugfs.h> +@@ -324,53 +326,6 @@ + return 1; + } + +-static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) +-{ +- unsigned long tmp; +- +- DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); +- for (; len > 0; len -= 4, buf += 4, fifo += 4) { +- tmp = *(unsigned long *)buf; +- if (len >= 4) { +- DBG(DBG_FIFO, " -> %08lx\n", tmp); +- __raw_writel(tmp, fifo); +- } else { +- do { +- DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); +- __raw_writeb(tmp >> 24, fifo); +- fifo++; +- tmp <<= 8; +- } while (--len); +- break; +- } +- } +-} +- +-static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +-{ +- union { +- unsigned long *w; +- unsigned char *b; +- } p; +- unsigned long tmp; +- +- DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); +- for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { +- if (len >= 4) { +- tmp = __raw_readl(fifo); +- *p.w = tmp; +- DBG(DBG_FIFO, " -> %08lx\n", tmp); +- } else { +- do { +- tmp = __raw_readb(fifo); +- *p.b = tmp; +- DBG(DBG_FIFO, " -> %02lx\n", tmp); +- fifo++, p.b++; +- } while (--len); +- } +- } +-} +- + static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) + { + unsigned int transaction_len; +@@ -387,7 +342,7 @@ + ep->ep.name, req, transaction_len, + req->last_transaction ? ", done" : ""); + +- copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); ++ memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + req->req.actual += transaction_len; + } +@@ -476,7 +431,7 @@ + bytecount = req->req.length - req->req.actual; + } + +- copy_from_fifo(req->req.buf + req->req.actual, ++ memcpy_fromio(req->req.buf + req->req.actual, + ep->fifo, bytecount); + req->req.actual += bytecount; + +@@ -1029,33 +984,6 @@ + .set_selfpowered = usba_udc_set_selfpowered, + }; + +-#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ +-{ \ +- .ep = { \ +- .ops = &usba_ep_ops, \ +- .name = nam, \ +- .maxpacket = maxpkt, \ +- }, \ +- .udc = &the_udc, \ +- .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ +- .fifo_size = maxpkt, \ +- .nr_banks = maxbk, \ +- .index = idx, \ +- .can_dma = dma, \ +- .can_isoc = isoc, \ +-} +- +-static struct usba_ep usba_ep[] = { +- EP("ep0", 0, 64, 1, 0, 0), +- EP("ep1in-bulk", 1, 512, 2, 1, 1), +- EP("ep2out-bulk", 2, 512, 2, 1, 1), +- EP("ep3in-int", 3, 64, 3, 1, 0), +- EP("ep4out-int", 4, 64, 3, 1, 0), +- EP("ep5in-iso", 5, 1024, 3, 1, 1), +- EP("ep6out-iso", 6, 1024, 3, 1, 1), +-}; +-#undef EP +- + static struct usb_endpoint_descriptor usba_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, +@@ -1074,7 +1002,6 @@ + static struct usba_udc the_udc = { + .gadget = { + .ops = &usba_udc_ops, +- .ep0 = &usba_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "atmel_usba_udc", +@@ -1231,7 +1158,7 @@ + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + usba_writel(udc, TST, USBA_TST_PKT_MODE); +- copy_to_fifo(ep->fifo, test_packet_buffer, ++ memcpy_toio(ep->fifo, test_packet_buffer, + sizeof(test_packet_buffer)); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + dev_info(dev, "Entering Test_Packet mode...\n"); +@@ -1530,13 +1457,13 @@ + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + pr_warning("udc: Invalid packet length %u " +- "(expected %lu)\n", pkt_len, sizeof(crq)); ++ "(expected %zu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; + } + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); +- copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); ++ memcpy_fromio(crq.data, ep->fifo, sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ +@@ -1908,7 +1835,7 @@ + + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); +- if (!regs || !fifo) ++ if (!regs || !fifo || !pdata) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); +@@ -1956,16 +1883,44 @@ + usba_writel(udc, CTRL, 0); + clk_disable(pclk); + ++ usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep, ++ GFP_KERNEL); ++ if (!usba_ep) ++ goto err_alloc_ep; ++ ++ the_udc.gadget.ep0 = &usba_ep[0].ep; ++ + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); + usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); + usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); + usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); +- for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { ++ usba_ep[0].ep.ops = &usba_ep_ops; ++ usba_ep[0].ep.name = pdata->ep[0].name; ++ usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size; ++ usba_ep[0].udc = &the_udc; ++ INIT_LIST_HEAD(&usba_ep[0].queue); ++ usba_ep[0].fifo_size = pdata->ep[0].fifo_size; ++ usba_ep[0].nr_banks = pdata->ep[0].nr_banks; ++ usba_ep[0].index = pdata->ep[0].index; ++ usba_ep[0].can_dma = pdata->ep[0].can_dma; ++ usba_ep[0].can_isoc = pdata->ep[0].can_isoc; ++ ++ for (i = 1; i < pdata->num_ep; i++) { + struct usba_ep *ep = &usba_ep[i]; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); + ep->fifo = udc->fifo + USBA_FIFO_BASE(i); ++ ep->ep.ops = &usba_ep_ops; ++ ep->ep.name = pdata->ep[i].name; ++ ep->ep.maxpacket = pdata->ep[i].fifo_size; ++ ep->udc = &the_udc; ++ INIT_LIST_HEAD(&ep->queue); ++ ep->fifo_size = pdata->ep[i].fifo_size; ++ ep->nr_banks = pdata->ep[i].nr_banks; ++ ep->index = pdata->ep[i].index; ++ ep->can_dma = pdata->ep[i].can_dma; ++ ep->can_isoc = pdata->ep[i].can_isoc; + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } +@@ -1984,7 +1939,7 @@ + goto err_device_add; + } + +- if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { ++ if (pdata->vbus_pin >= 0) { + if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { + udc->vbus_pin = pdata->vbus_pin; + +@@ -2004,7 +1959,7 @@ + } + + usba_init_debugfs(udc); +- for (i = 1; i < ARRAY_SIZE(usba_ep); i++) ++ for (i = 1; i < pdata->num_ep; i++) + usba_ep_init_debugfs(udc, &usba_ep[i]); + + return 0; +@@ -2012,6 +1967,8 @@ + err_device_add: + free_irq(irq, udc); + err_request_irq: ++ kfree(usba_ep); ++err_alloc_ep: + iounmap(udc->fifo); + err_map_fifo: + iounmap(udc->regs); +@@ -2029,10 +1986,11 @@ + { + struct usba_udc *udc; + int i; ++ struct usba_platform_data *pdata = pdev->dev.platform_data; + + udc = platform_get_drvdata(pdev); + +- for (i = 1; i < ARRAY_SIZE(usba_ep); i++) ++ for (i = 1; i < pdata->num_ep; i++) + usba_ep_cleanup_debugfs(&usba_ep[i]); + usba_cleanup_debugfs(udc); + +diff -urN -x CVS linux-2.6.25/drivers/usb/host/ohci-at91.c linux-2.6/drivers/usb/host/ohci-at91.c +--- linux-2.6.25/drivers/usb/host/ohci-at91.c 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/usb/host/ohci-at91.c 2008-04-15 21:48:12.000000000 +0200 +@@ -330,7 +330,7 @@ + * + * REVISIT: some boards will be able to turn VBUS off... + */ +- if (at91_suspend_entering_slow_clock()) { ++ if (clk_must_disable(fclk)) { + ohci_usb_reset (ohci); + at91_stop_clock(); + } +diff -urN -x CVS linux-2.6.25/drivers/video/Kconfig linux-2.6/drivers/video/Kconfig +--- linux-2.6.25/drivers/video/Kconfig 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/video/Kconfig 2008-04-02 22:11:30.000000000 +0200 +@@ -889,6 +889,17 @@ + framebuffer. Product specs at + <http://www.erd.epson.com/vdc/html/products.htm>. + ++config FB_S1D15605 ++ tristate "Epson S1D15605 framebuffer support" ++ depends on FB ++ default m if MACH_KB9200 ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ Build in support for the S1D15605 Epson Research 128x64 ++ LCD controller as a framebuffer. ++ + config FB_S1D13XXX + tristate "Epson S1D13XXX framebuffer support" + depends on FB +diff -urN -x CVS linux-2.6.25/drivers/video/Makefile linux-2.6/drivers/video/Makefile +--- linux-2.6.25/drivers/video/Makefile 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/video/Makefile 2008-04-02 22:11:30.000000000 +0200 +@@ -87,7 +87,8 @@ + obj-$(CONFIG_FB_SA1100) += sa1100fb.o + obj-$(CONFIG_FB_HIT) += hitfb.o + obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o +-obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o ++obj-$(CONFIG_FB_S1D15605) += s1d15605fb.o ++obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o + obj-$(CONFIG_FB_PVR2) += pvr2fb.o + obj-$(CONFIG_FB_VOODOO1) += sstfb.o + obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o +diff -urN -x CVS linux-2.6.25/drivers/video/atmel_lcdfb.c linux-2.6/drivers/video/atmel_lcdfb.c +--- linux-2.6.25/drivers/video/atmel_lcdfb.c 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/video/atmel_lcdfb.c 2008-04-03 00:27:47.000000000 +0200 +@@ -31,7 +31,7 @@ + #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 + #define ATMEL_LCDC_DMA_BURST_LEN 8 + +-#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) ++#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || defined(CONFIG_ARCH_AT91SAM9RL) + #define ATMEL_LCDC_FIFO_SIZE 2048 + #else + #define ATMEL_LCDC_FIFO_SIZE 512 +@@ -903,11 +903,45 @@ + return 0; + } + +-static struct platform_driver atmel_lcdfb_driver = { +- .remove = __exit_p(atmel_lcdfb_remove), ++#ifdef CONFIG_PM ++ ++static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ struct atmel_lcdfb_info *sinfo = info->par; ++ ++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); ++ if (sinfo->atmel_lcdfb_power_control) ++ sinfo->atmel_lcdfb_power_control(0); ++ atmel_lcdfb_stop_clock(sinfo); + +-// FIXME need suspend, resume ++ return 0; ++} ++ ++static int atmel_lcdfb_resume(struct platform_device *pdev) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ struct atmel_lcdfb_info *sinfo = info->par; + ++ atmel_lcdfb_start_clock(sinfo); ++ if (sinfo->atmel_lcdfb_power_control) ++ sinfo->atmel_lcdfb_power_control(1); ++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); ++ ++ return 0; ++} ++ ++#else ++#define atmel_lcdfb_suspend NULL ++#define atmel_lcdfb_resume NULL ++#endif ++ ++ ++static struct platform_driver atmel_lcdfb_driver = { ++ .remove = __exit_p(atmel_lcdfb_remove), ++ .suspend = atmel_lcdfb_suspend, ++ .resume = atmel_lcdfb_resume, + .driver = { + .name = "atmel_lcdfb", + .owner = THIS_MODULE, +diff -urN -x CVS linux-2.6.25/drivers/video/backlight/Kconfig linux-2.6/drivers/video/backlight/Kconfig +--- linux-2.6.25/drivers/video/backlight/Kconfig 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/video/backlight/Kconfig 2008-03-09 18:51:50.000000000 +0200 +@@ -112,3 +112,11 @@ + help + If you have a Intel LE80578 (Carillo Ranch) say Y to enable the + backlight driver. ++ ++config BACKLIGHT_KB920x ++ tristate "KwikByte KB9202 Backlight Driver" ++ depends on BACKLIGHT_CLASS_DEVICE && MACH_KB9200 ++ default y ++ help ++ If you have a KwikByte KB9202 board, say Y to enable the ++ backlight driver. +diff -urN -x CVS linux-2.6.25/drivers/video/backlight/Makefile linux-2.6/drivers/video/backlight/Makefile +--- linux-2.6.25/drivers/video/backlight/Makefile 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/video/backlight/Makefile 2008-03-09 15:14:55.000000000 +0200 +@@ -10,3 +10,4 @@ + obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o + obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o + obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o ++obj-$(CONFIG_BACKLIGHT_KB920x) += kb920x_bl.o +diff -urN -x CVS linux-2.6.25/drivers/video/backlight/kb920x_bl.c linux-2.6/drivers/video/backlight/kb920x_bl.c +--- linux-2.6.25/drivers/video/backlight/kb920x_bl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/video/backlight/kb920x_bl.c 2008-03-09 21:41:20.000000000 +0200 +@@ -0,0 +1,164 @@ ++/* ++ * Backlight Driver for KB9202 ++ * ++ * Copyright (c) 2006 KwikByte ++ * ++ * Based on Sharp's Corgi Backlight Driver ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/fb.h> ++#include <linux/backlight.h> ++ ++#include <asm/arch/gpio.h> ++ ++/* The backlight is on(1)/off(0) */ ++#define KB9202_DEFAULT_INTENSITY 1 ++#define KB9202_MAX_INTENSITY 1 ++ ++static int kb9202bl_suspended; ++static int current_intensity = 0; ++static DEFINE_SPINLOCK(bl_lock); ++ ++static int kb9202bl_set_intensity(struct backlight_device *bd) ++{ ++ unsigned long flags; ++ int intensity = bd->props.brightness; ++ ++ if (bd->props.power != FB_BLANK_UNBLANK) ++ intensity = 0; ++ if (bd->props.fb_blank != FB_BLANK_UNBLANK) ++ intensity = 0; ++ if (kb9202bl_suspended) ++ intensity = 0; ++ ++ if ((!current_intensity) && (bd->props.power == FB_BLANK_UNBLANK)) ++ intensity = 1; ++ ++ spin_lock_irqsave(&bl_lock, flags); ++ if (intensity) ++ gpio_set_value(AT91_PIN_PC23, 1); ++ else ++ gpio_set_value(AT91_PIN_PC23, 0); ++ spin_unlock_irqrestore(&bl_lock, flags); ++ ++ current_intensity = intensity; ++ ++ return 0; ++} ++ ++static int kb9202bl_get_intensity(struct backlight_device *bd) ++{ ++ return current_intensity; ++} ++ ++static struct backlight_ops kb9202bl_ops = { ++ .get_brightness = kb9202bl_get_intensity, ++ .update_status = kb9202bl_set_intensity, ++}; ++ ++static int __init kb9202bl_probe(struct platform_device *pdev) ++{ ++ struct backlight_device *bd; ++ ++ bd = backlight_device_register ("kb9202-bl", &pdev->dev, NULL, &kb9202bl_ops); ++ if (IS_ERR(bd)) ++ return PTR_ERR(bd); ++ ++ platform_set_drvdata(pdev, bd); ++ ++ bd->props.max_brightness = KB9202_MAX_INTENSITY; ++ bd->props.brightness = KB9202_DEFAULT_INTENSITY; ++ (void) kb9202bl_set_intensity(bd); ++ ++ return 0; ++} ++ ++static int kb9202bl_remove(struct platform_device *pdev) ++{ ++ struct backlight_device *bd = platform_get_drvdata(pdev); ++ ++ bd->props.brightness = 0; ++ bd->props.power = 0; ++ (void) kb9202bl_set_intensity(bd); ++ ++ backlight_device_unregister(bd); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int kb9202bl_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct backlight_device *bd = platform_get_drvdata(pdev); ++ ++ kb9202bl_suspended = 1; ++ (void) kb9202bl_set_intensity(bd); ++ return 0; ++} ++ ++static int kb9202bl_resume(struct platform_device *pdev) ++{ ++ struct backlight_device *bd = platform_get_drvdata(pdev); ++ ++ kb9202bl_suspended = 0; ++ (void) kb9202bl_set_intensity(bd); ++ return 0; ++} ++#else ++#define kb9202bl_suspend NULL ++#define kb9202bl_resume NULL ++#endif ++ ++static struct platform_driver kb9202bl_driver = { ++ .probe = kb9202bl_probe, ++ .remove = kb9202bl_remove, ++ .suspend = kb9202bl_suspend, ++ .resume = kb9202bl_resume, ++ .driver = { ++ .name = "kb9202-bl", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_device *kb9202bl_device; ++ ++static int __init kb9202bl_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&kb9202bl_driver); ++ if (!ret) { ++ kb9202bl_device = platform_device_alloc("kb9202-bl", -1); ++ if (!kb9202bl_device) ++ return -ENOMEM; ++ ++ ret = platform_device_add(kb9202bl_device); ++ if (ret) { ++ platform_device_put(kb9202bl_device); ++ platform_driver_unregister(&kb9202bl_driver); ++ } ++ } ++ return ret; ++} ++ ++static void __exit kb9202bl_exit(void) ++{ ++ platform_device_unregister(kb9202bl_device); ++ platform_driver_unregister(&kb9202bl_driver); ++} ++ ++module_init(kb9202bl_init); ++module_exit(kb9202bl_exit); ++ ++MODULE_AUTHOR("KwikByte <kb9200_dev@kwikbyte.com>"); ++MODULE_DESCRIPTION("KB9202 Backlight Driver"); ++MODULE_LICENSE("GPL"); +diff -urN -x CVS linux-2.6.25/drivers/video/s1d15605fb.c linux-2.6/drivers/video/s1d15605fb.c +--- linux-2.6.25/drivers/video/s1d15605fb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/video/s1d15605fb.c 2008-05-03 00:36:04.000000000 +0200 +@@ -0,0 +1,655 @@ ++/* ++ * drivers/video/s1d15605.c ++ * ++ * Adapted from several sources including: ++ * 1) Driver for AT91 LCD Controller ++ * Copyright (C) 2006 Atmel ++ * ++ * 2) Copyright (C) 2005 S. Kevin Hester ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * This is a basic framebuffer driver for the Optrex F-51320 128x64 mono LCD ++ * display. This display uses a clone of the common Epson SED 1531 display ++ * controller. ++ * ++ * I've heavily borrowed code from the vfb.c driver. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifdef DEBUG ++#define MSG(string, args...) printk("s1d15605fb:" string, ##args) ++#else ++#define MSG(string, args...) ++#endif ++ ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++#include <linux/interrupt.h> ++#include <linux/clk.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/uaccess.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++ ++#ifdef CONFIG_PMAC_BACKLIGHT ++#include <asm/backlight.h> ++#endif ++ ++#define VIDEOWIDTH 128 ++#define VIDEOHEIGHT 64 ++#define VIDEODEPTH 1 /* bits/pixel */ ++#define VIDEOWIDTH_BYTES ((VIDEOWIDTH * VIDEODEPTH) / 8) ++ ++/* The number of bytes that actually go to the device */ ++#define ACTUALVIDEOMEMSIZE (VIDEOWIDTH_BYTES * VIDEOHEIGHT) ++#define VIDEOMEMSIZE PAGE_SIZE ++ ++static struct fb_var_screeninfo s1d15605_default __initdata = { ++ .xres = VIDEOWIDTH, ++ .yres = VIDEOHEIGHT, ++ .xres_virtual = VIDEOWIDTH, ++ .yres_virtual = VIDEOHEIGHT, ++ .bits_per_pixel = VIDEODEPTH, ++ .red = { 0, 1, 0 }, ++ .green = { 0, 1, 0 }, ++ .blue = { 0, 1, 0 }, ++ .activate = FB_ACTIVATE_NOW, ++ .pixclock = 20000, ++ .vmode = FB_VMODE_NONINTERLACED, ++}; ++ ++static struct fb_fix_screeninfo s1d15605_fix __initdata = { ++ .id = "s1d15605", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_MONO10, ++ .xpanstep = 0, ++ .ypanstep = 0, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++struct s1d15605fb_info { ++ struct fb_info *info; ++ char *mmio; ++ unsigned long reset_pin; ++ struct platform_device *pdev; ++}; ++ ++/* ++ * LCD device interface ++ */ ++#define RESET_DISPLAY 0xE2 ++#define LCD_BIAS_1_9 0xA2 ++#define ADC_SELECT_REVERSE 0xA1 ++#define COMMON_OUTPUT_NORMAL 0xC0 ++#define V5_RESISTOR_RATIO 0x26 ++#define ELECTRONIC_VOLUME_SET 0x81 ++#define ELECTRONIC_VOLUME_INIT 0x20 ++#define POWER_CONTROL_SET 0x28 ++#define VOLTAGE_REGULATOR 0x02 ++#define VOLTAGE_FOLLOWER 0x01 ++#define BOOSTER_CIRCUIT 0x04 ++#define DISPLAY_ON 0xAF ++#define START_LINE_SET 0x40 ++#define PAGE_ADDRESS_SET 0xB0 ++#define COLUMN_ADDRESS_HIGH 0x10 ++#define COLUMN_ADDRESS_LOW 0x00 ++#define RESISTOR_RATIO_START 0x20 ++ ++#define NUM_OF_PAGES 8 ++#define NUM_OF_COLUMNS 128 ++ ++#define WRITE_COMMAND(x) __raw_writeb((x), (sinfo)->mmio) ++#define READ_COMMAND __raw_readb((sinfo)->mmio) ++#define WRITE_DATA(x) __raw_writeb((x), (sinfo)->mmio + (0x10000)) ++#define READ_DATA __raw_readb((sinfo)->mmio + (0x10000)) ++ ++ ++/* ++ * s1d15605fb_resize_framebuffer ++ * ++ * Free allocated space if different. Allocate on new of changed. ++ * Returns -ENOMEM if the new framebuffer can not be allocated, ++ * zero on success. ++ */ ++static int s1d15605fb_resize_framebuffer(struct s1d15605fb_info *sinfo) ++{ ++ struct fb_info *info = sinfo->info; ++ struct fb_fix_screeninfo *fix = &info->fix; ++ struct fb_var_screeninfo *var = &info->var; ++ unsigned int new_size; ++ void *new_vaddr; ++ ++ new_size = ((var->xres_virtual * var->yres_virtual * var->bits_per_pixel) / 8); ++ ++ MSG("%s: x (%d) y (%d) bpp (%d): new size 0x%08x\n", __FUNCTION__, ++ var->xres_virtual, var->yres_virtual, var->bits_per_pixel, new_size); ++ ++ if (new_size == fix->smem_len) ++ return 0; ++ ++ if (fix->smem_len) { ++ kfree(info->screen_base); ++ } ++ ++ new_vaddr = kmalloc(new_size, GFP_KERNEL); ++ ++ if (!new_vaddr) { ++ fix->smem_len = 0; ++ return -ENOMEM; ++ } ++ ++ info->screen_base = new_vaddr; ++ fix->smem_start = (unsigned)new_vaddr; ++ fix->smem_len = new_size; ++ fix->line_length = (var->xres_virtual * var->bits_per_pixel) / 8; ++ ++ dev_info(info->device, ++ "%luKiB frame buffer at %08lx (mapped at %p)\n", ++ (unsigned long)info->fix.smem_len / 1024, ++ (unsigned long)info->fix.smem_start, ++ info->screen_base); ++ ++ return 0; ++} ++ ++ ++/* ++ * The s1d15605 seems to be divided into eight 128 pixel wide pages (from top to ++ * bottom) each page seems to be eight pixels high, where these eight pixels are ++ * one byte ++ */ ++static void s1d15605_update(struct fb_info *info) ++{ ++ struct s1d15605fb_info *sinfo = info->par; ++ int page, i, row, colmask; ++ u8 retVal, *rowPtr; ++ ++ WRITE_COMMAND(START_LINE_SET); ++ for (page = 0; page < NUM_OF_PAGES; ++page) { ++ WRITE_COMMAND(PAGE_ADDRESS_SET + page); ++ WRITE_COMMAND(COLUMN_ADDRESS_HIGH); ++ WRITE_COMMAND(COLUMN_ADDRESS_LOW); ++ ++ for (i = 0; i < NUM_OF_COLUMNS; ++i) ++ { ++ /* point of opportunity: optimization */ ++ colmask = (1 << (i & 0x7)); ++ rowPtr = (u8*)(info->screen_base); ++ rowPtr += (VIDEOWIDTH_BYTES * 8 * page); ++ rowPtr += (i >> 3); ++ retVal = 0; ++ for (row = 0; row < 8; ++row) ++ { ++ retVal = (retVal >> 1) | (((*rowPtr) & colmask) ? 0x80 : 0); ++ rowPtr += VIDEOWIDTH_BYTES; ++ } ++ WRITE_DATA(retVal); ++ } ++ } ++ ++ WRITE_COMMAND(DISPLAY_ON); ++} ++ ++ ++/* ++ * Setting the video mode has been split into two parts. ++ * First part, xxxfb_check_var, must not write anything ++ * to hardware, it should only verify and adjust var. ++ * This means it doesn't alter par but it does use hardware ++ * data from it to check this var. ++ */ ++static int s1d15605_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ /* ++ * Some very basic checks ++ */ ++ if (!var->xres) ++ var->xres = 1; ++ if (!var->yres) ++ var->yres = 1; ++ if (var->xres > var->xres_virtual) ++ var->xres_virtual = var->xres; ++ if (var->yres > var->yres_virtual) ++ var->yres_virtual = var->yres; ++ ++ if(var->bits_per_pixel > VIDEODEPTH) ++ return -EINVAL; ++ ++ /* ++ * Memory limit ++ */ ++ if (((var->yres_virtual * var->bits_per_pixel * var->yres_virtual) >> 3) > ++ ACTUALVIDEOMEMSIZE) ++ return -ENOMEM; ++ ++ /* ++ * Now that we checked it we alter var. The reason being is that the video ++ * mode passed in might not work but slight changes to it might make it ++ * work. This way we let the user know what is acceptable. ++ */ ++ switch (var->bits_per_pixel) { ++ case 1: ++ var->red.offset = var->green.offset = var->blue.offset = 0; ++ var->red.length = var->green.length = var->blue.length ++ = var->bits_per_pixel; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ var->xoffset = var->yoffset = 0; ++ var->red.msb_right = var->green.msb_right = var->blue.msb_right = ++ var->transp.msb_right = 0; ++ ++ return 0; ++} ++ ++ ++/* ++ * This routine actually sets the video mode. It's in here where we ++ * the hardware state info->par and fix which can be affected by the ++ * change in par. For this driver it doesn't do much. ++ */ ++static int s1d15605_set_par(struct fb_info *info) ++{ ++ int ret; ++ ++ MSG("%s:\n", __func__); ++ MSG(" * resolution: %ux%u (%ux%u virtual)\n", ++ info->var.xres, info->var.yres, ++ info->var.xres_virtual, info->var.yres_virtual); ++ ++ ret = s1d15605fb_resize_framebuffer(info->par); ++ ++ info->fix.visual = FB_VISUAL_MONO10; ++ return ret; ++} ++ ++ ++/* ++ * Set a single color register. The values supplied are already ++ * rounded down to the hardware's capabilities (according to the ++ * entries in the var structure). Return != 0 for invalid regno. ++ */ ++static int s1d15605_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ if (regno > 1) /* no. of hw registers - we only do mono now */ ++ return 1; ++ ++ return 0; ++} ++ ++ ++/* ++ * Currently, the routine will simply shut-off the backlight and prevent ++ * updates/refreshes. Modify according to application. ++ * ++ * 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off ++ */ ++static int s1d15605_blank(int blank, struct fb_info *info) ++{ ++#ifdef CONFIG_PMAC_BACKLIGHT ++ if (blank) ++ pmac_backlight->props.power = FB_BLANK_POWERDOWN; ++ else ++ pmac_backlight->props.power = FB_BLANK_UNBLANK; ++ backlight_update_status(pmac_backlight); ++#endif ++ return 1; ++} ++ ++ ++/* ++ * Pan or Wrap the Display ++ * ++ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag ++ */ ++/* ++static int s1d15605_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ if (var->vmode & FB_VMODE_YWRAP) { ++ if (var->yoffset < 0 ++ || var->yoffset >= info->var.yres_virtual ++ || var->xoffset) ++ return -EINVAL; ++ } else { ++ if (var->xoffset + var->xres > info->var.xres_virtual || ++ var->yoffset + var->yres > info->var.yres_virtual) ++ return -EINVAL; ++ } ++ info->var.xoffset = var->xoffset; ++ info->var.yoffset = var->yoffset; ++ if (var->vmode & FB_VMODE_YWRAP) ++ info->var.vmode |= FB_VMODE_YWRAP; ++ else ++ info->var.vmode &= ~FB_VMODE_YWRAP; ++ return 0; ++} ++*/ ++ ++ ++static void s1d15605_copyarea(struct fb_info *info, const struct fb_copyarea *region) ++{ ++ cfb_copyarea(info, region); ++ s1d15605_update(info); ++} ++ ++ ++static void s1d15605_fillrect (struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ cfb_fillrect(info, rect); ++ s1d15605_update(info); ++} ++ ++ ++static void s1d15605_imageblit(struct fb_info *p, const struct fb_image *image) ++{ ++ cfb_imageblit(p, image); ++ s1d15605_update(p); ++} ++ ++ ++/* ++ * Write the users data to our framebuffer, and then trigger a psuedo DMA ++ */ ++static ssize_t s1d15605_write(struct fb_info *info, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ int err; ++ ++ if (p > info->fix.smem_len) ++ return -ENOSPC; ++ if (count >= info->fix.smem_len) ++ count = info->fix.smem_len; ++ err = 0; ++ if (count + p > info->fix.smem_len) { ++ count = info->fix.smem_len - p; ++ err = -ENOSPC; ++ } ++ if (count) { ++ char *base_addr; ++ ++ base_addr = info->screen_base; ++ count -= copy_from_user(base_addr+p, buf, count); ++ *ppos += count; ++ err = -EFAULT; ++ } ++ ++ s1d15605_update(info); ++ ++ if (count) ++ return count; ++ ++ return err; ++} ++ ++#ifdef USE_PRIVATE_VMA_FXS ++static void s1d15605_vma_open(struct vm_area_struct *vma) ++{ ++ // FIXME - store stats in the device data via vm_private_data ++} ++ ++ ++static void s1d15605_vma_close(struct vm_area_struct *vma) ++{ ++ // FIXME - store stats in the device data via vm_private_data ++} ++ ++ ++static struct page *s1d15605_vma_nopage(struct vm_area_struct *vma, ++ unsigned long address, int *type) ++{ ++ struct page *page; ++ struct fb_info *info = vma->vm_private_data; ++ ++ page = virt_to_page(info->screen_base); ++ get_page(page); ++ ++ // FIXME - now someone has a link to our page, start periodically blitting ++ // latest updates to the actual device. ++ ++ return page; ++} ++ ++ ++static struct vm_operations_struct s1d15605_vm_ops = { ++ .open = s1d15605_vma_open, ++ .close = s1d15605_vma_close, ++ .nopage = s1d15605_vma_nopage ++}; ++ ++ ++/* We don't do much here - because we have special vm_ops */ ++static int s1d15605_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ vma->vm_ops = &s1d15605_vm_ops; ++ vma->vm_flags |= VM_RESERVED; ++ vma->vm_private_data = info; ++ s1d15605_vma_open(vma); ++ ++ return 0; ++} ++#endif /* USE_PRIVATE_VMA_FXS */ ++ ++ ++static struct fb_ops s1d15605fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = s1d15605_check_var, ++ .fb_set_par = s1d15605_set_par, ++ .fb_setcolreg = s1d15605_setcolreg, ++ .fb_blank = s1d15605_blank, ++// .fb_pan_display = s1d15605_pan_display, ++ .fb_fillrect = s1d15605_fillrect, ++ .fb_copyarea = s1d15605_copyarea, ++ .fb_imageblit = s1d15605_imageblit, ++ .fb_write = s1d15605_write, ++#ifdef USE_PRIVATE_VMA_FXS ++ .fb_mmap = s1d15605_mmap, ++#endif ++}; ++ ++ ++static void s1d15605_device_init(struct s1d15605fb_info *sinfo) { ++ ++ char value; ++ ++ /* release the reset line by reading the device - proto hardware */ ++ value = READ_COMMAND; ++ value = READ_COMMAND; ++ ++#ifdef CONFIG_MACH_KB9200 ++ /* new boards have dedicated reset line */ ++ gpio_set_value(sinfo->reset_pin, 1); ++#endif ++ ++ /* initialize the device within 5ms */ ++ WRITE_COMMAND(RESET_DISPLAY); ++ WRITE_COMMAND(LCD_BIAS_1_9); ++ WRITE_COMMAND(ADC_SELECT_REVERSE); ++ WRITE_COMMAND(COMMON_OUTPUT_NORMAL); ++ WRITE_COMMAND(V5_RESISTOR_RATIO); ++ WRITE_COMMAND(ELECTRONIC_VOLUME_SET); ++ WRITE_COMMAND(ELECTRONIC_VOLUME_INIT); ++ WRITE_COMMAND(POWER_CONTROL_SET | VOLTAGE_REGULATOR | VOLTAGE_FOLLOWER | BOOSTER_CIRCUIT); ++ WRITE_COMMAND(DISPLAY_ON); ++ ++ WRITE_COMMAND(RESISTOR_RATIO_START + 4); ++ WRITE_COMMAND(ELECTRONIC_VOLUME_SET); ++ WRITE_COMMAND(0x33); ++} ++ ++ ++static int __init s1d15605fb_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct fb_info *info; ++ struct s1d15605fb_info *sinfo; ++ int ret; ++ ++ MSG("%s\n", __func__); ++ ++ if (!(info = framebuffer_alloc(sizeof(struct s1d15605fb_info), dev))) { ++ dev_err(dev, "Cannot allocate framebuffer struct\n"); ++ return -ENOMEM; ++ } ++ ++ sinfo = info->par; ++ sinfo->info = info; ++ sinfo->pdev = pdev; ++ ++ if (pdev->num_resources < 2) { ++ dev_err(dev, "Resources unusable\n"); ++ ret = -ENODEV; ++ goto free_info; ++ } ++ ++ info->fbops = &s1d15605fb_ops; ++ strcpy(info->fix.id, pdev->name); ++ ++ info->fix.mmio_start = pdev->resource[0].start; ++ info->fix.mmio_len = pdev->resource[0].end - pdev->resource[0].start + 1; ++ sinfo->reset_pin = pdev->resource[1].start; ++ ++ ret = s1d15605fb_resize_framebuffer(sinfo); ++ if (ret < 0) { ++ dev_err(dev, "Cannot resize framebuffer: %d\n", ret); ++ goto free_fb; ++ } ++ ++ if (!request_mem_region(info->fix.mmio_start, ++ info->fix.mmio_len, pdev->name)) { ++ ret = -EBUSY; ++ goto free_fb; ++ } ++ ++ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); ++ if (!sinfo->mmio) { ++ dev_err(dev, "Cannot map LCD memory region\n"); ++ goto release_mem; ++ } ++ ++ s1d15605_device_init(sinfo); ++ ++ ret = fb_find_mode(&info->var, info, NULL, NULL, 0, NULL, 1); ++ ++ if (!ret || (ret == 4)) ++ info->var = s1d15605_default; ++ ++ info->fix = s1d15605_fix; ++ info->flags = FBINFO_FLAG_DEFAULT | ++/* FBINFO_HWACCEL_YPAN | */ ++ FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; ++ ++ ret = register_framebuffer(info); ++ if (ret < 0) { ++ dev_err(dev, "Failed to register framebuffer device: %d\n", ret); ++ goto unmap_mmio; ++ } ++ ++ dev_set_drvdata(dev, info); ++ ++ memset(info->screen_base, 0, info->fix.smem_len); ++ info->var.activate |= FB_ACTIVATE_NOW; ++ ret = fb_set_var(info, &info->var); ++ if (ret) { ++ dev_warn(dev, "Unable to set display parameters\n"); ++ } ++ ++ info->var.activate &= ~(FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW); ++ ++ dev_dbg(dev, "%s SUCCESS\n", __func__); ++ ++ dev_info(dev, "Driver $Revision: 1.1 $\n"); ++ ++ return 0; ++ ++unmap_mmio: ++ iounmap(sinfo->mmio); ++release_mem: ++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len); ++free_fb: ++ kfree(info->screen_base); ++ ++free_info: ++ framebuffer_release(info); ++ ++ dev_dbg(dev, "%s FAILED\n", __func__); ++ return ret; ++} ++ ++ ++static int __exit s1d15605fb_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct fb_info *info = dev_get_drvdata(dev); ++ struct s1d15605fb_info *sinfo = info->par; ++ ++ if (!sinfo) ++ return 0; ++ ++ unregister_framebuffer(info); ++ ++ iounmap(sinfo->mmio); ++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len); ++ ++ kfree(info->screen_base); ++ ++ dev_set_drvdata(dev, NULL); ++ framebuffer_release(info); ++ return 0; ++} ++ ++ ++static struct platform_driver s1d15605fb_driver = { ++ .remove = __exit_p(s1d15605fb_remove), ++ .driver = { ++ .name = "s1d15605fb", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++ ++static int __init s1d15605fb_init(void) ++{ ++ return platform_driver_probe(&s1d15605fb_driver, s1d15605fb_probe); ++} ++ ++ ++static void __exit s1d15605fb_exit(void) ++{ ++ platform_driver_unregister(&s1d15605fb_driver); ++} ++ ++ ++module_init(s1d15605fb_init); ++module_exit(s1d15605fb_exit); ++ ++ ++MODULE_AUTHOR("KwikByte"); ++MODULE_DESCRIPTION("Epson S1D15605 LCD Controller framebuffer driver"); ++MODULE_LICENSE("GPL"); +diff -urN -x CVS linux-2.6.25/drivers/watchdog/Kconfig linux-2.6/drivers/watchdog/Kconfig +--- linux-2.6.25/drivers/watchdog/Kconfig 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/watchdog/Kconfig 2008-03-09 15:14:55.000000000 +0200 +@@ -66,6 +66,14 @@ + Watchdog timer embedded into AT91RM9200 chips. This will reboot your + system when the timeout is reached. + ++config AT91SAM9_WATCHDOG ++ tristate "AT91SAM9 watchdog" ++ depends on ARCH_AT91 && !ARCH_AT91RM9200 ++ select WATCHDOG_NOWAYOUT ++ help ++ Watchdog timer embedded into AT91SAM9 chips. This will reboot your ++ system when the timeout is reached. ++ + config 21285_WATCHDOG + tristate "DC21285 watchdog" + depends on FOOTBRIDGE +diff -urN -x CVS linux-2.6.25/drivers/watchdog/Makefile linux-2.6/drivers/watchdog/Makefile +--- linux-2.6.25/drivers/watchdog/Makefile 2008-05-03 00:15:50.000000000 +0200 ++++ linux-2.6/drivers/watchdog/Makefile 2008-03-09 15:14:55.000000000 +0200 +@@ -26,6 +26,7 @@ + + # ARM Architecture + obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o ++obj-$(CONFIG_AT91SAM9_WATCHDOG) += at91sam9_wdt.o + obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o + obj-$(CONFIG_21285_WATCHDOG) += wdt285.o + obj-$(CONFIG_977_WATCHDOG) += wdt977.o +diff -urN -x CVS linux-2.6.25/drivers/watchdog/at91sam9_wdt.c linux-2.6/drivers/watchdog/at91sam9_wdt.c +--- linux-2.6.25/drivers/watchdog/at91sam9_wdt.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/drivers/watchdog/at91sam9_wdt.c 2008-04-15 21:53:41.000000000 +0200 +@@ -0,0 +1,259 @@ ++/* ++ * Watchdog driver for Atmel AT91SAM9x processors. ++ * ++ * Copyright (C) 2007 Renaud CERRATO r.cerrato@til-technologies.fr ++ * ++ * 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. ++ */ ++ ++/* ++ * The Watchdog Timer Mode Register can be only written to once. If the ++ * timeout need to be set from Linux, be sure that the bootstrap or the ++ * bootloader doesn't write to this register. ++ */ ++ ++#include <linux/errno.h> ++#include <linux/fs.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++#include <linux/watchdog.h> ++#include <linux/bitops.h> ++#include <linux/uaccess.h> ++ ++#include <asm/arch/at91_wdt.h> ++ ++ ++#define WDT_MAX_TIME 16 /* seconds */ ++ ++static int wdt_timeout = -1; /* invalid */ ++ ++module_param(wdt_timeout, int, 0); ++MODULE_PARM_DESC(wdt_timeout, "Watchdog time in seconds. (default = disabled)"); ++ ++ ++static unsigned long at91wdt_busy; ++ ++/* ......................................................................... */ ++ ++/* ++ * Reload the watchdog timer. (ie, pat the watchdog) ++ */ ++static void inline at91_wdt_reload(void) ++{ ++ at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); ++} ++ ++/* ......................................................................... */ ++ ++/* ++ * Watchdog device is opened, and watchdog starts running. ++ */ ++static int at91_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &at91wdt_busy)) ++ return -EBUSY; ++ ++ return nonseekable_open(inode, file); ++} ++ ++/* ++ * Close the watchdog device. ++ */ ++static int at91_wdt_close(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &at91wdt_busy); ++ return 0; ++} ++ ++/* ++ * Change the watchdog time interval. ++ */ ++static int at91_wdt_settimeout(int new_time) ++{ ++ unsigned int reg, mr; ++ /* ++ * All counting occurs at SLOW_CLOCK / 128 = 256 Hz ++ * ++ * Since WDV is a 12-bit counter, the maximum period is ++ * 4096 / 256 = 16 seconds. ++ */ ++ if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) ++ return -EINVAL; ++ ++ wdt_timeout = new_time; ++ ++ /* Program the Watchdog */ ++ reg = AT91_WDT_WDRSTEN /* causes watchdog reset */ ++ | AT91_WDT_WDRPROC /* causes processor reset */ ++ | AT91_WDT_WDDBGHLT /* disabled in debug mode */ ++ | AT91_WDT_WDD /* restart at any time */ ++ | (((wdt_timeout * 256) - 1) & AT91_WDT_WDV); /* timer value */ ++ at91_sys_write(AT91_WDT_MR, reg); ++ ++ /* Check if watchdog could be programmed */ ++ mr = at91_sys_read(AT91_WDT_MR); ++ if (mr != reg) { ++ printk(KERN_ERR "at91sam9_wdt: Watchdog register already programmed.\n"); ++ return -EIO; ++ } ++ ++ at91_wdt_reload(); ++ ++ printk(KERN_INFO "AT91SAM9 Watchdog enabled (%d seconds, nowayout)\n", wdt_timeout); ++ return 0; ++} ++ ++static struct watchdog_info at91_wdt_info = { ++ .identity = "at91sam9 watchdog", ++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, ++}; ++ ++/* ++ * Handle commands from user-space. ++ */ ++static int at91_wdt_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = argp; ++ int new_value, err; ++ ++ switch (cmd) { ++ case WDIOC_KEEPALIVE: ++ at91_wdt_reload(); /* pat the watchdog */ ++ return 0; ++ ++ case WDIOC_GETSUPPORT: ++ return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0; ++ ++ case WDIOC_SETTIMEOUT: ++ if (get_user(new_value, p)) ++ return -EFAULT; ++ ++ err = at91_wdt_settimeout(new_value); ++ if (err) ++ return err; ++ ++ return put_user(wdt_timeout, p); /* return current value */ ++ ++ case WDIOC_GETTIMEOUT: ++ return put_user(wdt_timeout, p); ++ ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ return put_user(0, p); ++ } ++ return -ENOTTY; ++} ++ ++/* ++ * Pat the watchdog whenever device is written to. ++ */ ++static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) ++{ ++ at91_wdt_reload(); /* pat the watchdog */ ++ return len; ++} ++ ++/* ......................................................................... */ ++ ++static const struct file_operations at91wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .ioctl = at91_wdt_ioctl, ++ .open = at91_wdt_open, ++ .release = at91_wdt_close, ++ .write = at91_wdt_write, ++}; ++ ++static struct miscdevice at91wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &at91wdt_fops, ++}; ++ ++static int __init at91wdt_probe(struct platform_device *pdev) ++{ ++ int res; ++ ++ if (at91wdt_miscdev.parent) ++ return -EBUSY; ++ at91wdt_miscdev.parent = &pdev->dev; ++ ++ res = misc_register(&at91wdt_miscdev); ++ if (res) ++ return res; ++ ++ /* Set watchdog */ ++ if (at91_wdt_settimeout(wdt_timeout) == -EINVAL) { ++ pr_info("at91sam9_wdt: invalid timeout (must be between 1 and %d)\n", WDT_MAX_TIME); ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int __exit at91wdt_remove(struct platform_device *pdev) ++{ ++ int res; ++ ++ res = misc_deregister(&at91wdt_miscdev); ++ if (!res) ++ at91wdt_miscdev.parent = NULL; ++ ++ return res; ++} ++ ++#ifdef CONFIG_PM ++ ++static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message) ++{ ++ return 0; ++} ++ ++static int at91wdt_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++#else ++#define at91wdt_suspend NULL ++#define at91wdt_resume NULL ++#endif ++ ++static struct platform_driver at91wdt_driver = { ++ .remove = __exit_p(at91wdt_remove), ++ .suspend = at91wdt_suspend, ++ .resume = at91wdt_resume, ++ .driver = { ++ .name = "at91_wdt", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init at91sam_wdt_init(void) ++{ ++ return platform_driver_probe(&at91wdt_driver, at91wdt_probe); ++} ++ ++static void __exit at91sam_wdt_exit(void) ++{ ++ platform_driver_unregister(&at91wdt_driver); ++} ++ ++module_init(at91sam_wdt_init); ++module_exit(at91sam_wdt_exit); ++ ++MODULE_AUTHOR("Renaud CERRATO"); ++MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:at91_wdt"); +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_ecc.h linux-2.6/include/asm-arm/arch-at91/at91_ecc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_ecc.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_ecc.h 2008-05-07 23:49:32.000000000 +0200 +@@ -1,6 +1,9 @@ + /* + * include/asm-arm/arch-at91/at91_ecc.h + * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Error Corrected Code Controller (ECC) - System peripherals regsters. + * Based on AT91SAM9260 datasheet revision B. + * +@@ -13,26 +16,26 @@ + #ifndef AT91_ECC_H + #define AT91_ECC_H + +-#define AT91_ECC_CR (AT91_ECC + 0x00) /* Control register */ ++#define AT91_ECC_CR 0x00 /* Control register */ + #define AT91_ECC_RST (1 << 0) /* Reset parity */ + +-#define AT91_ECC_MR (AT91_ECC + 0x04) /* Mode register */ ++#define AT91_ECC_MR 0x04 /* Mode register */ + #define AT91_ECC_PAGESIZE (3 << 0) /* Page Size */ + #define AT91_ECC_PAGESIZE_528 (0) + #define AT91_ECC_PAGESIZE_1056 (1) + #define AT91_ECC_PAGESIZE_2112 (2) + #define AT91_ECC_PAGESIZE_4224 (3) + +-#define AT91_ECC_SR (AT91_ECC + 0x08) /* Status register */ ++#define AT91_ECC_SR 0x08 /* Status register */ + #define AT91_ECC_RECERR (1 << 0) /* Recoverable Error */ + #define AT91_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ + #define AT91_ECC_MULERR (1 << 2) /* Multiple Errors */ + +-#define AT91_ECC_PR (AT91_ECC + 0x0c) /* Parity register */ ++#define AT91_ECC_PR 0x0c /* Parity register */ + #define AT91_ECC_BITADDR (0xf << 0) /* Bit Error Address */ + #define AT91_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ + +-#define AT91_ECC_NPR (AT91_ECC + 0x10) /* NParity register */ ++#define AT91_ECC_NPR 0x10 /* NParity register */ + #define AT91_ECC_NPARITY (0xffff << 0) /* NParity */ + + #endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_pit.h linux-2.6/include/asm-arm/arch-at91/at91_pit.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_pit.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_pit.h 2008-05-07 23:49:57.000000000 +0200 +@@ -1,6 +1,9 @@ + /* + * include/asm-arm/arch-at91/at91_pit.h + * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Periodic Interval Timer (PIT) - System peripherals regsters. + * Based on AT91SAM9261 datasheet revision D. + * +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_pmc.h linux-2.6/include/asm-arm/arch-at91/at91_pmc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_pmc.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_pmc.h 2008-05-05 22:01:39.000000000 +0200 +@@ -23,6 +23,7 @@ + #define AT91_PMC_PCK (1 << 0) /* Processor Clock */ + #define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */ + #define AT91RM9200_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */ ++#define AT91CAP9_PMC_DDR (1 << 2) /* DDR Clock [AT91CAP9 revC only] */ + #define AT91RM9200_PMC_UHP (1 << 4) /* USB Host Port Clock [AT91RM9200 only] */ + #define AT91SAM926x_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91SAM926x only] */ + #define AT91CAP9_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91CAP9 only] */ +@@ -39,10 +40,14 @@ + #define AT91_PMC_PCSR (AT91_PMC + 0x18) /* Peripheral Clock Status Register */ + + #define AT91_CKGR_UCKR (AT91_PMC + 0x1C) /* UTMI Clock Register [SAM9RL, CAP9] */ ++#define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */ ++#define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */ ++#define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */ ++#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI PLL Start-up Time */ + + #define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register [not on SAM9RL] */ + #define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ +-#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [AT91SAM926x only] */ ++#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x, CAP9] */ + #define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ + + #define AT91_CKGR_MCFR (AT91_PMC + 0x24) /* Main Clock Frequency Register */ +@@ -56,6 +61,7 @@ + #define AT91_PMC_OUT (3 << 14) /* PLL Clock Frequency Range */ + #define AT91_PMC_MUL (0x7ff << 16) /* PLL Multiplier */ + #define AT91_PMC_USBDIV (3 << 28) /* USB Divisor (PLLB only) */ ++#define AT91CAP9_PMC_USBDIV (0xf << 28) /* USB Divisor (PLLB only) [AT91CAP9 revC only] */ + #define AT91_PMC_USBDIV_1 (0 << 28) + #define AT91_PMC_USBDIV_2 (1 << 28) + #define AT91_PMC_USBDIV_4 (2 << 28) +@@ -76,10 +82,13 @@ + #define AT91_PMC_PRES_32 (5 << 2) + #define AT91_PMC_PRES_64 (6 << 2) + #define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */ +-#define AT91_PMC_MDIV_1 (0 << 8) +-#define AT91_PMC_MDIV_2 (1 << 8) +-#define AT91_PMC_MDIV_3 (2 << 8) +-#define AT91_PMC_MDIV_4 (3 << 8) ++#define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */ ++#define AT91RM9200_PMC_MDIV_2 (1 << 8) ++#define AT91RM9200_PMC_MDIV_3 (2 << 8) ++#define AT91RM9200_PMC_MDIV_4 (3 << 8) ++#define AT91SAM9_PMC_MDIV_1 (0 << 8) /* [SAM9,CAP9 only] */ ++#define AT91SAM9_PMC_MDIV_2 (1 << 8) ++#define AT91SAM9_PMC_MDIV_4 (2 << 8) + + #define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-3 Registers */ + +@@ -90,10 +99,17 @@ + #define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ + #define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ + #define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ ++#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [AT91CAP9 only] */ ++#define AT91_PMC_OSCSEL (1 << 7) /* Slow Clock Oscillator [AT91CAP9 revC only] */ + #define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ + #define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ + #define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ + #define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */ + #define AT91_PMC_IMR (AT91_PMC + 0x6c) /* Interrupt Mask Register */ + ++#define AT91_PMC_PROT (AT91_PMC + 0xe4) /* Protect Register [AT91CAP9 revC only] */ ++#define AT91_PMC_PROTKEY 0x504d4301 /* Activation Code */ ++ ++#define AT91_PMC_VER (AT91_PMC + 0xfc) /* PMC Module Version [AT91CAP9 only] */ ++ + #endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_rstc.h linux-2.6/include/asm-arm/arch-at91/at91_rstc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_rstc.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_rstc.h 2008-05-07 23:50:10.000000000 +0200 +@@ -1,6 +1,9 @@ + /* + * include/asm-arm/arch-at91/at91_rstc.h + * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Reset Controller (RSTC) - System peripherals regsters. + * Based on AT91SAM9261 datasheet revision D. + * +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_rtt.h linux-2.6/include/asm-arm/arch-at91/at91_rtt.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_rtt.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_rtt.h 2008-05-07 23:51:11.000000000 +0200 +@@ -1,6 +1,9 @@ + /* + * include/asm-arm/arch-at91/at91_rtt.h + * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Real-time Timer (RTT) - System peripherals regsters. + * Based on AT91SAM9261 datasheet revision D. + * +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_shdwc.h linux-2.6/include/asm-arm/arch-at91/at91_shdwc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_shdwc.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_shdwc.h 2008-05-07 23:50:23.000000000 +0200 +@@ -1,6 +1,9 @@ + /* + * include/asm-arm/arch-at91/at91_shdwc.h + * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Shutdown Controller (SHDWC) - System peripherals regsters. + * Based on AT91SAM9261 datasheet revision D. + * +@@ -24,10 +27,12 @@ + #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_(x) ((x) << 4) + #define AT91_SHDW_RTTWKEN (1 << 16) /* Real Time Timer Wake-up Enable */ + + #define AT91_SHDW_SR (AT91_SHDWC + 0x08) /* Shut Down Status Register */ + #define AT91_SHDW_WAKEUP0 (1 << 0) /* Wake-up 0 Status */ + #define AT91_SHDW_RTTWK (1 << 16) /* Real-time Timer Wake-up */ ++#define AT91_SHDW_RTCWK (1 << 17) /* Real-time Clock Wake-up [SAM9RL] */ + + #endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_tsc.h linux-2.6/include/asm-arm/arch-at91/at91_tsc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_tsc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_tsc.h 2008-05-07 23:51:32.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* ++ * include/asm-arm/arch-at91/at91_tsc.h ++ * ++ * Copyright (C) 2008 Andrew Victor ++ * ++ * Touch Screen ADC Controller (TSC) ++ * Based on AT91SAM9RL64 preliminary draft datasheet. ++ * ++ * 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. ++ */ ++ ++#ifndef AT91_TSC_H ++#define AT91_TSC_H ++ ++#define AT91_TSADCC_CR 0x00 /* Control register */ ++#define AT91_TSADCC_SWRST (1 << 0) /* Software Reset*/ ++#define AT91_TSADCC_START (1 << 1) /* Start conversion */ ++ ++#define AT91_TSADCC_MR 0x04 /* Mode register */ ++#define AT91_TSADCC_TSAMOD (3 << 0) /* ADC mode */ ++#define AT91_TSADCC_LOWRES (1 << 4) /* Resolution selection */ ++#define AT91_TSADCC_SLEEP (1 << 5) /* Sleep mode */ ++#define AT91_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ ++#define AT91_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ ++#define AT91_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ ++#define AT91_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ ++#define AT91_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ ++ ++#define AT91_TSADCC_TRGR 0x08 /* Trigger register */ ++#define AT91_TSADCC_TRGMOD (7 << 0) /* Trigger mode */ ++#define AT91_TSADCC_TRGMOD_NONE (0 << 0) ++#define AT91_TSADCC_TRGMOD_EXT_RISING (1 << 0) ++#define AT91_TSADCC_TRGMOD_EXT_FALLING (2 << 0) ++#define AT91_TSADCC_TRGMOD_EXT_ANY (3 << 0) ++#define AT91_TSADCC_TRGMOD_PENDET (4 << 0) ++#define AT91_TSADCC_TRGMOD_PERIOD (5 << 0) ++#define AT91_TSADCC_TRGMOD_CONTINUOUS (6 << 0) ++#define AT91_TSADCC_TRGPER (0xffff << 16) /* Trigger period */ ++ ++#define AT91_TSADCC_TSR 0x0C /* Touch Screen register */ ++#define AT91_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */ ++#define AT91_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */ ++ ++#define AT91_TSADCC_CHER 0x10 /* Channel Enable register */ ++#define AT91_TSADCC_CHDR 0x14 /* Channel Disable register */ ++#define AT91_TSADCC_CHSR 0x18 /* Channel Status register */ ++#define AT91_TSADCC_CH(n) (1 << (n)) /* Channel number */ ++ ++#define AT91_TSADCC_SR 0x1C /* Status register */ ++#define AT91_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */ ++#define AT91_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */ ++#define AT91_TSADCC_DRDY (1 << 16) /* Data Ready */ ++#define AT91_TSADCC_GOVRE (1 << 17) /* General Overrun Error */ ++#define AT91_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */ ++#define AT91_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */ ++#define AT91_TSADCC_PENCNT (1 << 20) /* Pen contact */ ++#define AT91_TSADCC_NOCNT (1 << 21) /* No contact */ ++ ++#define AT91_TSADCC_LCDR 0x20 /* Last Converted Data register */ ++#define AT91_TSADCC_DATA (0x3ff << 0) /* Channel data */ ++ ++#define AT91_TSADCC_IER 0x24 /* Interrupt Enable register */ ++#define AT91_TSADCC_IDR 0x28 /* Interrupt Disable register */ ++#define AT91_TSADCC_IMR 0x2C /* Interrupt Mask register */ ++#define AT91_TSADCC_CDR0 0x30 /* Channel Data 0 */ ++#define AT91_TSADCC_CDR1 0x34 /* Channel Data 1 */ ++#define AT91_TSADCC_CDR2 0x38 /* Channel Data 2 */ ++#define AT91_TSADCC_CDR3 0x3C /* Channel Data 3 */ ++#define AT91_TSADCC_CDR4 0x40 /* Channel Data 4 */ ++#define AT91_TSADCC_CDR5 0x44 /* Channel Data 5 */ ++ ++#endif ++ +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91_wdt.h linux-2.6/include/asm-arm/arch-at91/at91_wdt.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91_wdt.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91_wdt.h 2008-05-07 23:51:43.000000000 +0200 +@@ -1,6 +1,9 @@ + /* + * include/asm-arm/arch-at91/at91_wdt.h + * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Watchdog Timer (WDT) - System peripherals regsters. + * Based on AT91SAM9261 datasheet revision D. + * +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91cap9.h linux-2.6/include/asm-arm/arch-at91/at91cap9.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91cap9.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91cap9.h 2008-05-05 22:01:39.000000000 +0200 +@@ -101,7 +101,10 @@ + #define AT91_RTT (0xfffffd20 - AT91_BASE_SYS) + #define AT91_PIT (0xfffffd30 - AT91_BASE_SYS) + #define AT91_WDT (0xfffffd40 - AT91_BASE_SYS) +-#define AT91_GPBR (0xfffffd50 - AT91_BASE_SYS) ++#define AT91_SCKCR (0xfffffd50 - AT91_BASE_SYS) ++#define AT91_GPBR (cpu_is_at91cap9_revB() ? \ ++ (0xfffffd50 - AT91_BASE_SYS) : \ ++ (0xfffffd60 - AT91_BASE_SYS)) + + #define AT91_USART0 AT91CAP9_BASE_US0 + #define AT91_USART1 AT91CAP9_BASE_US1 +@@ -118,7 +121,7 @@ + #define AT91CAP9_ROM_SIZE (32 * SZ_1K) /* Internal ROM size (32Kb) */ + + #define AT91CAP9_LCDC_BASE 0x00500000 /* LCD Controller */ +-#define AT91CAP9_UDPHS_BASE 0x00600000 /* USB High Speed Device Port */ ++#define AT91CAP9_UDPHS_FIFO 0x00600000 /* USB High Speed Device Port */ + #define AT91CAP9_UHP_BASE 0x00700000 /* USB Host controller */ + + #define CONFIG_DRAM_BASE AT91_CHIPSELECT_6 +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91cap9_ddrsdr.h linux-2.6/include/asm-arm/arch-at91/at91cap9_ddrsdr.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91cap9_ddrsdr.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91cap9_ddrsdr.h 2008-05-07 21:33:47.000000000 +0200 +@@ -0,0 +1,102 @@ ++/* ++ * include/asm-arm/arch-at91/at91cap9_ddrsdr.h ++ * ++ * (C) 2008 Andrew Victor ++ * ++ * DDR/SDR Controller (DDRSDRC) - System peripherals registers. ++ * Based on AT91CAP9 datasheet revision B. ++ * ++ * 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. ++ */ ++ ++#ifndef AT91CAP9_DDRSDR_H ++#define AT91CAP9_DDRSDR_H ++ ++#define AT91_DDRSDRC_MR (AT91_DDRSDRC + 0x00) /* Mode Register */ ++#define AT91_DDRSDRC_MODE (0xf << 0) /* Command Mode */ ++#define AT91_DDRSDRC_MODE_NORMAL 0 ++#define AT91_DDRSDRC_MODE_NOP 1 ++#define AT91_DDRSDRC_MODE_PRECHARGE 2 ++#define AT91_DDRSDRC_MODE_LMR 3 ++#define AT91_DDRSDRC_MODE_REFRESH 4 ++#define AT91_DDRSDRC_MODE_EXT_LMR 5 ++#define AT91_DDRSDRC_MODE_DEEP 6 ++ ++#define AT91_DDRSDRC_RTR (AT91_DDRSDRC + 0x04) /* Refresh Timer Register */ ++#define AT91_DDRSDRC_COUNT (0xfff << 0) /* Refresh Timer Counter */ ++ ++#define AT91_DDRSDRC_CR (AT91_DDRSDRC + 0x08) /* Configuration Register */ ++#define AT91_DDRSDRC_NC (3 << 0) /* Number of Column Bits */ ++#define AT91_DDRSDRC_NC_SDR8 (0 << 0) ++#define AT91_DDRSDRC_NC_SDR9 (1 << 0) ++#define AT91_DDRSDRC_NC_SDR10 (2 << 0) ++#define AT91_DDRSDRC_NC_SDR11 (3 << 0) ++#define AT91_DDRSDRC_NC_DDR9 (0 << 0) ++#define AT91_DDRSDRC_NC_DDR10 (1 << 0) ++#define AT91_DDRSDRC_NC_DDR11 (2 << 0) ++#define AT91_DDRSDRC_NC_DDR12 (3 << 0) ++#define AT91_DDRSDRC_NR (3 << 2) /* Number of Row Bits */ ++#define AT91_DDRSDRC_NR_11 (0 << 2) ++#define AT91_DDRSDRC_NR_12 (1 << 2) ++#define AT91_DDRSDRC_NR_13 (2 << 2) ++#define AT91_DDRSDRC_CAS (7 << 4) /* CAS Latency */ ++#define AT91_DDRSDRC_CAS_2 (2 << 4) ++#define AT91_DDRSDRC_CAS_3 (3 << 4) ++#define AT91_DDRSDRC_CAS_25 (6 << 4) ++#define AT91_DDRSDRC_DLL (1 << 7) /* Reset DLL */ ++#define AT91_DDRSDRC_DICDS (1 << 8) /* Output impedance control */ ++ ++#define AT91_DDRSDRC_T0PR (AT91_DDRSDRC + 0x0C) /* Timing 0 Register */ ++#define AT91_DDRSDRC_TRAS (0xf << 0) /* Active to Precharge delay */ ++#define AT91_DDRSDRC_TRCD (0xf << 4) /* Row to Column delay */ ++#define AT91_DDRSDRC_TWR (0xf << 8) /* Write recovery delay */ ++#define AT91_DDRSDRC_TRC (0xf << 12) /* Row cycle delay */ ++#define AT91_DDRSDRC_TRP (0xf << 16) /* Row precharge delay */ ++#define AT91_DDRSDRC_TRRD (0xf << 20) /* Active BankA to BankB */ ++#define AT91_DDRSDRC_TWTR (1 << 24) /* Internal Write to Read delay */ ++#define AT91_DDRSDRC_TMRD (0xf << 28) /* Load mode to active/refresh delay */ ++ ++#define AT91_DDRSDRC_T1PR (AT91_DDRSDRC + 0x10) /* Timing 1 Register */ ++#define AT91_DDRSDRC_TRFC (0x1f << 0) /* Row Cycle Delay */ ++#define AT91_DDRSDRC_TXSNR (0xff << 8) /* Exit self-refresh to non-read */ ++#define AT91_DDRSDRC_TXSRD (0xff << 16) /* Exit self-refresh to read */ ++#define AT91_DDRSDRC_TXP (0xf << 24) /* Exit power-down delay */ ++ ++#define AT91_DDRSDRC_LPR (AT91_DDRSDRC + 0x18) /* Low Power Register */ ++#define AT91_DDRSDRC_LPCB (3 << 0) /* Low-power Configurations */ ++#define AT91_DDRSDRC_LPCB_DISABLE 0 ++#define AT91_DDRSDRC_LPCB_SELF_REFRESH 1 ++#define AT91_DDRSDRC_LPCB_POWER_DOWN 2 ++#define AT91_DDRSDRC_LPCB_DEEP_POWER_DOWN 3 ++#define AT91_DDRSDRC_CLKFR (1 << 2) /* Clock Frozen */ ++#define AT91_DDRSDRC_PASR (7 << 4) /* Partial Array Self Refresh */ ++#define AT91_DDRSDRC_TCSR (3 << 8) /* Temperature Compensated Self Refresh */ ++#define AT91_DDRSDRC_DS (3 << 10) /* Drive Strength */ ++#define AT91_DDRSDRC_TIMEOUT (3 << 12) /* Time to define when Low Power Mode is enabled */ ++#define AT91_DDRSDRC_TIMEOUT_0_CLK_CYCLES (0 << 12) ++#define AT91_DDRSDRC_TIMEOUT_64_CLK_CYCLES (1 << 12) ++#define AT91_DDRSDRC_TIMEOUT_128_CLK_CYCLES (2 << 12) ++ ++#define AT91_DDRSDRC_MDR (AT91_DDRSDRC + 0x1C) /* Memory Device Register */ ++#define AT91_DDRSDRC_MD (3 << 0) /* Memory Device Type */ ++#define AT91_DDRSDRC_MD_SDR 0 ++#define AT91_DDRSDRC_MD_LOW_POWER_SDR 1 ++#define AT91_DDRSDRC_MD_DDR 2 ++#define AT91_DDRSDRC_MD_LOW_POWER_DDR 3 ++ ++#define AT91_DDRSDRC_DLLR (AT91_DDRSDRC + 0x20) /* DLL Information Register */ ++#define AT91_DDRSDRC_MDINC (1 << 0) /* Master Delay increment */ ++#define AT91_DDRSDRC_MDDEC (1 << 1) /* Master Delay decrement */ ++#define AT91_DDRSDRC_MDOVF (1 << 2) /* Master Delay Overflow */ ++#define AT91_DDRSDRC_SDCOVF (1 << 3) /* Slave Delay Correction Overflow */ ++#define AT91_DDRSDRC_SDCUDF (1 << 4) /* Slave Delay Correction Underflow */ ++#define AT91_DDRSDRC_SDERF (1 << 5) /* Slave Delay Correction error */ ++#define AT91_DDRSDRC_MDVAL (0xff << 8) /* Master Delay value */ ++#define AT91_DDRSDRC_SDVAL (0xff << 16) /* Slave Delay value */ ++#define AT91_DDRSDRC_SDCVAL (0xff << 24) /* Slave Delay Correction value */ ++ ++ ++#endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91cap9_matrix.h linux-2.6/include/asm-arm/arch-at91/at91cap9_matrix.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91cap9_matrix.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91cap9_matrix.h 2008-04-18 19:20:34.000000000 +0200 +@@ -106,6 +106,11 @@ + #define AT91_MPBS0_SFR (AT91_MATRIX + 0x114) /* MPBlock Slave 0 Special Function Register */ + #define AT91_MPBS1_SFR (AT91_MATRIX + 0x11C) /* MPBlock Slave 1 Special Function Register */ + ++#define AT91_MATRIX_UDPHS (AT91_MATRIX + 0x118) /* USBHS Special Function Register [AT91CAP9 only] */ ++#define AT91_MATRIX_SELECT_UDPHS (0 << 31) /* select High Speed UDP */ ++#define AT91_MATRIX_SELECT_UDP (1 << 31) /* select standard UDP */ ++#define AT91_MATRIX_UDPHS_BYPASS_LOCK (1 << 30) /* bypass lock bit */ ++ + #define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x120) /* EBI Chip Select Assignment Register */ + #define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */ + #define AT91_MATRIX_EBI_CS1A_SMC (0 << 1) +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91sam9260_matrix.h linux-2.6/include/asm-arm/arch-at91/at91sam9260_matrix.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91sam9260_matrix.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91sam9260_matrix.h 2008-05-07 12:07:13.000000000 +0200 +@@ -1,6 +1,8 @@ + /* + * include/asm-arm/arch-at91/at91sam9260_matrix.h + * ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Memory Controllers (MATRIX, EBI) - System peripherals registers. + * Based on AT91SAM9260 datasheet revision B. + * +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91sam9261_matrix.h linux-2.6/include/asm-arm/arch-at91/at91sam9261_matrix.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91sam9261_matrix.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91sam9261_matrix.h 2008-05-07 12:07:24.000000000 +0200 +@@ -1,6 +1,8 @@ + /* + * include/asm-arm/arch-at91/at91sam9261_matrix.h + * ++ * Copyright (C) 2007 Atmel Corporation. ++ * + * Memory Controllers (MATRIX, EBI) - System peripherals registers. + * Based on AT91SAM9261 datasheet revision D. + * +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91sam926x_mc.h linux-2.6/include/asm-arm/arch-at91/at91sam926x_mc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91sam926x_mc.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91sam926x_mc.h 1970-01-01 02:00:00.000000000 +0200 +@@ -1,141 +0,0 @@ +-/* +- * include/asm-arm/arch-at91/at91sam926x_mc.h +- * +- * Memory Controllers (SMC, SDRAMC) - System peripherals registers. +- * Based on AT91SAM9261 datasheet revision D. +- * +- * 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. +- */ +- +-#ifndef AT91SAM926x_MC_H +-#define AT91SAM926x_MC_H +- +-/* SDRAM Controller (SDRAMC) registers */ +-#define AT91_SDRAMC_MR (AT91_SDRAMC + 0x00) /* SDRAM Controller Mode Register */ +-#define AT91_SDRAMC_MODE (0xf << 0) /* Command Mode */ +-#define AT91_SDRAMC_MODE_NORMAL 0 +-#define AT91_SDRAMC_MODE_NOP 1 +-#define AT91_SDRAMC_MODE_PRECHARGE 2 +-#define AT91_SDRAMC_MODE_LMR 3 +-#define AT91_SDRAMC_MODE_REFRESH 4 +-#define AT91_SDRAMC_MODE_EXT_LMR 5 +-#define AT91_SDRAMC_MODE_DEEP 6 +- +-#define AT91_SDRAMC_TR (AT91_SDRAMC + 0x04) /* SDRAM Controller Refresh Timer Register */ +-#define AT91_SDRAMC_COUNT (0xfff << 0) /* Refresh Timer Counter */ +- +-#define AT91_SDRAMC_CR (AT91_SDRAMC + 0x08) /* SDRAM Controller Configuration Register */ +-#define AT91_SDRAMC_NC (3 << 0) /* Number of Column Bits */ +-#define AT91_SDRAMC_NC_8 (0 << 0) +-#define AT91_SDRAMC_NC_9 (1 << 0) +-#define AT91_SDRAMC_NC_10 (2 << 0) +-#define AT91_SDRAMC_NC_11 (3 << 0) +-#define AT91_SDRAMC_NR (3 << 2) /* Number of Row Bits */ +-#define AT91_SDRAMC_NR_11 (0 << 2) +-#define AT91_SDRAMC_NR_12 (1 << 2) +-#define AT91_SDRAMC_NR_13 (2 << 2) +-#define AT91_SDRAMC_NB (1 << 4) /* Number of Banks */ +-#define AT91_SDRAMC_NB_2 (0 << 4) +-#define AT91_SDRAMC_NB_4 (1 << 4) +-#define AT91_SDRAMC_CAS (3 << 5) /* CAS Latency */ +-#define AT91_SDRAMC_CAS_1 (1 << 5) +-#define AT91_SDRAMC_CAS_2 (2 << 5) +-#define AT91_SDRAMC_CAS_3 (3 << 5) +-#define AT91_SDRAMC_DBW (1 << 7) /* Data Bus Width */ +-#define AT91_SDRAMC_DBW_32 (0 << 7) +-#define AT91_SDRAMC_DBW_16 (1 << 7) +-#define AT91_SDRAMC_TWR (0xf << 8) /* Write Recovery Delay */ +-#define AT91_SDRAMC_TRC (0xf << 12) /* Row Cycle Delay */ +-#define AT91_SDRAMC_TRP (0xf << 16) /* Row Precharge Delay */ +-#define AT91_SDRAMC_TRCD (0xf << 20) /* Row to Column Delay */ +-#define AT91_SDRAMC_TRAS (0xf << 24) /* Active to Precharge Delay */ +-#define AT91_SDRAMC_TXSR (0xf << 28) /* Exit Self Refresh to Active Delay */ +- +-#define AT91_SDRAMC_LPR (AT91_SDRAMC + 0x10) /* SDRAM Controller Low Power Register */ +-#define AT91_SDRAMC_LPCB (3 << 0) /* Low-power Configurations */ +-#define AT91_SDRAMC_LPCB_DISABLE 0 +-#define AT91_SDRAMC_LPCB_SELF_REFRESH 1 +-#define AT91_SDRAMC_LPCB_POWER_DOWN 2 +-#define AT91_SDRAMC_LPCB_DEEP_POWER_DOWN 3 +-#define AT91_SDRAMC_PASR (7 << 4) /* Partial Array Self Refresh */ +-#define AT91_SDRAMC_TCSR (3 << 8) /* Temperature Compensated Self Refresh */ +-#define AT91_SDRAMC_DS (3 << 10) /* Drive Strenght */ +-#define AT91_SDRAMC_TIMEOUT (3 << 12) /* Time to define when Low Power Mode is enabled */ +-#define AT91_SDRAMC_TIMEOUT_0_CLK_CYCLES (0 << 12) +-#define AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES (1 << 12) +-#define AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES (2 << 12) +- +-#define AT91_SDRAMC_IER (AT91_SDRAMC + 0x14) /* SDRAM Controller Interrupt Enable Register */ +-#define AT91_SDRAMC_IDR (AT91_SDRAMC + 0x18) /* SDRAM Controller Interrupt Disable Register */ +-#define AT91_SDRAMC_IMR (AT91_SDRAMC + 0x1C) /* SDRAM Controller Interrupt Mask Register */ +-#define AT91_SDRAMC_ISR (AT91_SDRAMC + 0x20) /* SDRAM Controller Interrupt Status Register */ +-#define AT91_SDRAMC_RES (1 << 0) /* Refresh Error Status */ +- +-#define AT91_SDRAMC_MDR (AT91_SDRAMC + 0x24) /* SDRAM Memory Device Register */ +-#define AT91_SDRAMC_MD (3 << 0) /* Memory Device Type */ +-#define AT91_SDRAMC_MD_SDRAM 0 +-#define AT91_SDRAMC_MD_LOW_POWER_SDRAM 1 +- +- +-/* Static Memory Controller (SMC) registers */ +-#define AT91_SMC_SETUP(n) (AT91_SMC + 0x00 + ((n)*0x10)) /* Setup Register for CS n */ +-#define AT91_SMC_NWESETUP (0x3f << 0) /* NWE Setup Length */ +-#define AT91_SMC_NWESETUP_(x) ((x) << 0) +-#define AT91_SMC_NCS_WRSETUP (0x3f << 8) /* NCS Setup Length in Write Access */ +-#define AT91_SMC_NCS_WRSETUP_(x) ((x) << 8) +-#define AT91_SMC_NRDSETUP (0x3f << 16) /* NRD Setup Length */ +-#define AT91_SMC_NRDSETUP_(x) ((x) << 16) +-#define AT91_SMC_NCS_RDSETUP (0x3f << 24) /* NCS Setup Length in Read Access */ +-#define AT91_SMC_NCS_RDSETUP_(x) ((x) << 24) +- +-#define AT91_SMC_PULSE(n) (AT91_SMC + 0x04 + ((n)*0x10)) /* Pulse Register for CS n */ +-#define AT91_SMC_NWEPULSE (0x7f << 0) /* NWE Pulse Length */ +-#define AT91_SMC_NWEPULSE_(x) ((x) << 0) +-#define AT91_SMC_NCS_WRPULSE (0x7f << 8) /* NCS Pulse Length in Write Access */ +-#define AT91_SMC_NCS_WRPULSE_(x)((x) << 8) +-#define AT91_SMC_NRDPULSE (0x7f << 16) /* NRD Pulse Length */ +-#define AT91_SMC_NRDPULSE_(x) ((x) << 16) +-#define AT91_SMC_NCS_RDPULSE (0x7f << 24) /* NCS Pulse Length in Read Access */ +-#define AT91_SMC_NCS_RDPULSE_(x)((x) << 24) +- +-#define AT91_SMC_CYCLE(n) (AT91_SMC + 0x08 + ((n)*0x10)) /* Cycle Register for CS n */ +-#define AT91_SMC_NWECYCLE (0x1ff << 0 ) /* Total Write Cycle Length */ +-#define AT91_SMC_NWECYCLE_(x) ((x) << 0) +-#define AT91_SMC_NRDCYCLE (0x1ff << 16) /* Total Read Cycle Length */ +-#define AT91_SMC_NRDCYCLE_(x) ((x) << 16) +- +-#define AT91_SMC_MODE(n) (AT91_SMC + 0x0c + ((n)*0x10)) /* Mode Register for CS n */ +-#define AT91_SMC_READMODE (1 << 0) /* Read Mode */ +-#define AT91_SMC_WRITEMODE (1 << 1) /* Write Mode */ +-#define AT91_SMC_EXNWMODE (3 << 4) /* NWAIT Mode */ +-#define AT91_SMC_EXNWMODE_DISABLE (0 << 4) +-#define AT91_SMC_EXNWMODE_FROZEN (2 << 4) +-#define AT91_SMC_EXNWMODE_READY (3 << 4) +-#define AT91_SMC_BAT (1 << 8) /* Byte Access Type */ +-#define AT91_SMC_BAT_SELECT (0 << 8) +-#define AT91_SMC_BAT_WRITE (1 << 8) +-#define AT91_SMC_DBW (3 << 12) /* Data Bus Width */ +-#define AT91_SMC_DBW_8 (0 << 12) +-#define AT91_SMC_DBW_16 (1 << 12) +-#define AT91_SMC_DBW_32 (2 << 12) +-#define AT91_SMC_TDF (0xf << 16) /* Data Float Time. */ +-#define AT91_SMC_TDF_(x) ((x) << 16) +-#define AT91_SMC_TDFMODE (1 << 20) /* TDF Optimization - Enabled */ +-#define AT91_SMC_PMEN (1 << 24) /* Page Mode Enabled */ +-#define AT91_SMC_PS (3 << 28) /* Page Size */ +-#define AT91_SMC_PS_4 (0 << 28) +-#define AT91_SMC_PS_8 (1 << 28) +-#define AT91_SMC_PS_16 (2 << 28) +-#define AT91_SMC_PS_32 (3 << 28) +- +-#if defined(AT91_SMC1) /* The AT91SAM9263 has 2 Static Memory contollers */ +-#define AT91_SMC1_SETUP(n) (AT91_SMC1 + 0x00 + ((n)*0x10)) /* Setup Register for CS n */ +-#define AT91_SMC1_PULSE(n) (AT91_SMC1 + 0x04 + ((n)*0x10)) /* Pulse Register for CS n */ +-#define AT91_SMC1_CYCLE(n) (AT91_SMC1 + 0x08 + ((n)*0x10)) /* Cycle Register for CS n */ +-#define AT91_SMC1_MODE(n) (AT91_SMC1 + 0x0c + ((n)*0x10)) /* Mode Register for CS n */ +-#endif +- +-#endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91sam9_sdramc.h linux-2.6/include/asm-arm/arch-at91/at91sam9_sdramc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91sam9_sdramc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91sam9_sdramc.h 2008-05-07 23:51:59.000000000 +0200 +@@ -0,0 +1,86 @@ ++/* ++ * include/asm-arm/arch-at91/at91sam9_sdramc.h ++ * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * ++ * SDRAM Controllers (SDRAMC) - System peripherals registers. ++ * Based on AT91SAM9261 datasheet revision D. ++ * ++ * 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. ++ */ ++ ++#ifndef AT91SAM9_SDRAMC_H ++#define AT91SAM9_SDRAMC_H ++ ++/* SDRAM Controller (SDRAMC) registers */ ++#define AT91_SDRAMC_MR (AT91_SDRAMC + 0x00) /* SDRAM Controller Mode Register */ ++#define AT91_SDRAMC_MODE (0xf << 0) /* Command Mode */ ++#define AT91_SDRAMC_MODE_NORMAL 0 ++#define AT91_SDRAMC_MODE_NOP 1 ++#define AT91_SDRAMC_MODE_PRECHARGE 2 ++#define AT91_SDRAMC_MODE_LMR 3 ++#define AT91_SDRAMC_MODE_REFRESH 4 ++#define AT91_SDRAMC_MODE_EXT_LMR 5 ++#define AT91_SDRAMC_MODE_DEEP 6 ++ ++#define AT91_SDRAMC_TR (AT91_SDRAMC + 0x04) /* SDRAM Controller Refresh Timer Register */ ++#define AT91_SDRAMC_COUNT (0xfff << 0) /* Refresh Timer Counter */ ++ ++#define AT91_SDRAMC_CR (AT91_SDRAMC + 0x08) /* SDRAM Controller Configuration Register */ ++#define AT91_SDRAMC_NC (3 << 0) /* Number of Column Bits */ ++#define AT91_SDRAMC_NC_8 (0 << 0) ++#define AT91_SDRAMC_NC_9 (1 << 0) ++#define AT91_SDRAMC_NC_10 (2 << 0) ++#define AT91_SDRAMC_NC_11 (3 << 0) ++#define AT91_SDRAMC_NR (3 << 2) /* Number of Row Bits */ ++#define AT91_SDRAMC_NR_11 (0 << 2) ++#define AT91_SDRAMC_NR_12 (1 << 2) ++#define AT91_SDRAMC_NR_13 (2 << 2) ++#define AT91_SDRAMC_NB (1 << 4) /* Number of Banks */ ++#define AT91_SDRAMC_NB_2 (0 << 4) ++#define AT91_SDRAMC_NB_4 (1 << 4) ++#define AT91_SDRAMC_CAS (3 << 5) /* CAS Latency */ ++#define AT91_SDRAMC_CAS_1 (1 << 5) ++#define AT91_SDRAMC_CAS_2 (2 << 5) ++#define AT91_SDRAMC_CAS_3 (3 << 5) ++#define AT91_SDRAMC_DBW (1 << 7) /* Data Bus Width */ ++#define AT91_SDRAMC_DBW_32 (0 << 7) ++#define AT91_SDRAMC_DBW_16 (1 << 7) ++#define AT91_SDRAMC_TWR (0xf << 8) /* Write Recovery Delay */ ++#define AT91_SDRAMC_TRC (0xf << 12) /* Row Cycle Delay */ ++#define AT91_SDRAMC_TRP (0xf << 16) /* Row Precharge Delay */ ++#define AT91_SDRAMC_TRCD (0xf << 20) /* Row to Column Delay */ ++#define AT91_SDRAMC_TRAS (0xf << 24) /* Active to Precharge Delay */ ++#define AT91_SDRAMC_TXSR (0xf << 28) /* Exit Self Refresh to Active Delay */ ++ ++#define AT91_SDRAMC_LPR (AT91_SDRAMC + 0x10) /* SDRAM Controller Low Power Register */ ++#define AT91_SDRAMC_LPCB (3 << 0) /* Low-power Configurations */ ++#define AT91_SDRAMC_LPCB_DISABLE 0 ++#define AT91_SDRAMC_LPCB_SELF_REFRESH 1 ++#define AT91_SDRAMC_LPCB_POWER_DOWN 2 ++#define AT91_SDRAMC_LPCB_DEEP_POWER_DOWN 3 ++#define AT91_SDRAMC_PASR (7 << 4) /* Partial Array Self Refresh */ ++#define AT91_SDRAMC_TCSR (3 << 8) /* Temperature Compensated Self Refresh */ ++#define AT91_SDRAMC_DS (3 << 10) /* Drive Strength */ ++#define AT91_SDRAMC_TIMEOUT (3 << 12) /* Time to define when Low Power Mode is enabled */ ++#define AT91_SDRAMC_TIMEOUT_0_CLK_CYCLES (0 << 12) ++#define AT91_SDRAMC_TIMEOUT_64_CLK_CYCLES (1 << 12) ++#define AT91_SDRAMC_TIMEOUT_128_CLK_CYCLES (2 << 12) ++ ++#define AT91_SDRAMC_IER (AT91_SDRAMC + 0x14) /* SDRAM Controller Interrupt Enable Register */ ++#define AT91_SDRAMC_IDR (AT91_SDRAMC + 0x18) /* SDRAM Controller Interrupt Disable Register */ ++#define AT91_SDRAMC_IMR (AT91_SDRAMC + 0x1C) /* SDRAM Controller Interrupt Mask Register */ ++#define AT91_SDRAMC_ISR (AT91_SDRAMC + 0x20) /* SDRAM Controller Interrupt Status Register */ ++#define AT91_SDRAMC_RES (1 << 0) /* Refresh Error Status */ ++ ++#define AT91_SDRAMC_MDR (AT91_SDRAMC + 0x24) /* SDRAM Memory Device Register */ ++#define AT91_SDRAMC_MD (3 << 0) /* Memory Device Type */ ++#define AT91_SDRAMC_MD_SDRAM 0 ++#define AT91_SDRAMC_MD_LOW_POWER_SDRAM 1 ++ ++ ++#endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91sam9_smc.h linux-2.6/include/asm-arm/arch-at91/at91sam9_smc.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91sam9_smc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91sam9_smc.h 2008-05-07 23:52:15.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* ++ * include/asm-arm/arch-at91/at91sam9_smc.h ++ * ++ * Copyright (C) 2007 Andrew Victor ++ * Copyright (C) 2007 Atmel Corporation. ++ * ++ * Static Memory Controllers (SMC) - System peripherals registers. ++ * Based on AT91SAM9261 datasheet revision D. ++ * ++ * 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. ++ */ ++ ++#ifndef AT91SAM9_SMC_H ++#define AT91SAM9_SMC_H ++ ++#define AT91_SMC_SETUP(n) (AT91_SMC + 0x00 + ((n)*0x10)) /* Setup Register for CS n */ ++#define AT91_SMC_NWESETUP (0x3f << 0) /* NWE Setup Length */ ++#define AT91_SMC_NWESETUP_(x) ((x) << 0) ++#define AT91_SMC_NCS_WRSETUP (0x3f << 8) /* NCS Setup Length in Write Access */ ++#define AT91_SMC_NCS_WRSETUP_(x) ((x) << 8) ++#define AT91_SMC_NRDSETUP (0x3f << 16) /* NRD Setup Length */ ++#define AT91_SMC_NRDSETUP_(x) ((x) << 16) ++#define AT91_SMC_NCS_RDSETUP (0x3f << 24) /* NCS Setup Length in Read Access */ ++#define AT91_SMC_NCS_RDSETUP_(x) ((x) << 24) ++ ++#define AT91_SMC_PULSE(n) (AT91_SMC + 0x04 + ((n)*0x10)) /* Pulse Register for CS n */ ++#define AT91_SMC_NWEPULSE (0x7f << 0) /* NWE Pulse Length */ ++#define AT91_SMC_NWEPULSE_(x) ((x) << 0) ++#define AT91_SMC_NCS_WRPULSE (0x7f << 8) /* NCS Pulse Length in Write Access */ ++#define AT91_SMC_NCS_WRPULSE_(x)((x) << 8) ++#define AT91_SMC_NRDPULSE (0x7f << 16) /* NRD Pulse Length */ ++#define AT91_SMC_NRDPULSE_(x) ((x) << 16) ++#define AT91_SMC_NCS_RDPULSE (0x7f << 24) /* NCS Pulse Length in Read Access */ ++#define AT91_SMC_NCS_RDPULSE_(x)((x) << 24) ++ ++#define AT91_SMC_CYCLE(n) (AT91_SMC + 0x08 + ((n)*0x10)) /* Cycle Register for CS n */ ++#define AT91_SMC_NWECYCLE (0x1ff << 0 ) /* Total Write Cycle Length */ ++#define AT91_SMC_NWECYCLE_(x) ((x) << 0) ++#define AT91_SMC_NRDCYCLE (0x1ff << 16) /* Total Read Cycle Length */ ++#define AT91_SMC_NRDCYCLE_(x) ((x) << 16) ++ ++#define AT91_SMC_MODE(n) (AT91_SMC + 0x0c + ((n)*0x10)) /* Mode Register for CS n */ ++#define AT91_SMC_READMODE (1 << 0) /* Read Mode */ ++#define AT91_SMC_WRITEMODE (1 << 1) /* Write Mode */ ++#define AT91_SMC_EXNWMODE (3 << 4) /* NWAIT Mode */ ++#define AT91_SMC_EXNWMODE_DISABLE (0 << 4) ++#define AT91_SMC_EXNWMODE_FROZEN (2 << 4) ++#define AT91_SMC_EXNWMODE_READY (3 << 4) ++#define AT91_SMC_BAT (1 << 8) /* Byte Access Type */ ++#define AT91_SMC_BAT_SELECT (0 << 8) ++#define AT91_SMC_BAT_WRITE (1 << 8) ++#define AT91_SMC_DBW (3 << 12) /* Data Bus Width */ ++#define AT91_SMC_DBW_8 (0 << 12) ++#define AT91_SMC_DBW_16 (1 << 12) ++#define AT91_SMC_DBW_32 (2 << 12) ++#define AT91_SMC_TDF (0xf << 16) /* Data Float Time. */ ++#define AT91_SMC_TDF_(x) ((x) << 16) ++#define AT91_SMC_TDFMODE (1 << 20) /* TDF Optimization - Enabled */ ++#define AT91_SMC_PMEN (1 << 24) /* Page Mode Enabled */ ++#define AT91_SMC_PS (3 << 28) /* Page Size */ ++#define AT91_SMC_PS_4 (0 << 28) ++#define AT91_SMC_PS_8 (1 << 28) ++#define AT91_SMC_PS_16 (2 << 28) ++#define AT91_SMC_PS_32 (3 << 28) ++ ++#if defined(AT91_SMC1) /* The AT91SAM9263 has 2 Static Memory contollers */ ++#define AT91_SMC1_SETUP(n) (AT91_SMC1 + 0x00 + ((n)*0x10)) /* Setup Register for CS n */ ++#define AT91_SMC1_PULSE(n) (AT91_SMC1 + 0x04 + ((n)*0x10)) /* Pulse Register for CS n */ ++#define AT91_SMC1_CYCLE(n) (AT91_SMC1 + 0x08 + ((n)*0x10)) /* Cycle Register for CS n */ ++#define AT91_SMC1_MODE(n) (AT91_SMC1 + 0x0c + ((n)*0x10)) /* Mode Register for CS n */ ++#endif ++ ++#endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/at91sam9rl.h linux-2.6/include/asm-arm/arch-at91/at91sam9rl.h +--- linux-2.6.25/include/asm-arm/arch-at91/at91sam9rl.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/at91sam9rl.h 2008-04-18 19:22:02.000000000 +0200 +@@ -110,6 +110,6 @@ + #define AT91SAM9RL_ROM_SIZE (2 * SZ_16K) /* Internal ROM size (32Kb) */ + + #define AT91SAM9RL_LCDC_BASE 0x00500000 /* LCD Controller */ +-#define AT91SAM9RL_UDPHS_BASE 0x00600000 /* USB Device HS controller */ ++#define AT91SAM9RL_UDPHS_FIFO 0x00600000 /* USB Device HS controller */ + + #endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/board.h linux-2.6/include/asm-arm/arch-at91/board.h +--- linux-2.6.25/include/asm-arm/arch-at91/board.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/board.h 2008-05-02 00:40:32.000000000 +0200 +@@ -36,6 +36,7 @@ + #include <linux/i2c.h> + #include <linux/leds.h> + #include <linux/spi/spi.h> ++#include <linux/usb/atmel_usba_udc.h> + + /* USB Device */ + struct at91_udc_data { +@@ -45,6 +46,9 @@ + }; + extern void __init at91_add_device_udc(struct at91_udc_data *data); + ++ /* USB High Speed Device */ ++extern void __init at91_add_device_usba(struct usba_platform_data *data); ++ + /* Compact Flash */ + struct at91_cf_data { + u8 irq_pin; /* I/O IRQ */ +@@ -158,6 +162,9 @@ + /* ISI */ + extern void __init at91_add_device_isi(void); + ++ /* Touchscreen Controller */ ++extern void __init at91_add_device_tsadcc(void); ++ + /* LEDs */ + extern void __init at91_init_leds(u8 cpu_led, u8 timer_led); + extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/cpu.h linux-2.6/include/asm-arm/arch-at91/cpu.h +--- linux-2.6.25/include/asm-arm/arch-at91/cpu.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/cpu.h 2008-05-05 22:10:58.000000000 +0200 +@@ -48,6 +48,17 @@ + return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH); + } + ++#ifdef CONFIG_ARCH_AT91CAP9 ++#include <asm/arch/at91_pmc.h> ++ ++#define ARCH_REVISION_CAP9_B 0x399 ++#define ARCH_REVISION_CAP9_C 0x601 ++ ++static inline unsigned long at91cap9_rev_identify(void) ++{ ++ return (at91_sys_read(AT91_PMC_VER)); ++} ++#endif + + #ifdef CONFIG_ARCH_AT91RM9200 + #define cpu_is_at91rm9200() (at91_cpu_identify() == ARCH_ID_AT91RM9200) +@@ -83,8 +94,12 @@ + + #ifdef CONFIG_ARCH_AT91CAP9 + #define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9) ++#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B) ++#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C) + #else + #define cpu_is_at91cap9() (0) ++#define cpu_is_at91cap9_revB() (0) ++#define cpu_is_at91cap9_revC() (0) + #endif + + /* +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/ics1523.h linux-2.6/include/asm-arm/arch-at91/ics1523.h +--- linux-2.6.25/include/asm-arm/arch-at91/ics1523.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/ics1523.h 2008-01-16 21:24:29.000000000 +0200 +@@ -0,0 +1,154 @@ ++//*---------------------------------------------------------------------------- ++//* ATMEL Microcontroller Software Support - ROUSSET - ++//*---------------------------------------------------------------------------- ++//* The software is delivered "AS IS" without warranty or condition of any ++//* kind, either express, implied or statutory. This includes without ++//* limitation any warranty or condition with respect to merchantability or ++//* fitness for any particular purpose, or against the infringements of ++//* intellectual property rights of others. ++//*---------------------------------------------------------------------------- ++//* File Name : ics1523.h ++//* Object : Clock Generator Prototyping File. ++//* ++//* 1.0 08/28/02 ED : Creation ++//* 1.2 13/01/03 FB : Update on lib V3 ++//*---------------------------------------------------------------------------- ++ ++#ifndef ics1523_h ++#define ics1523_h ++ ++/*-------------------------------------------*/ ++/* ICS1523 TWI Serial Clock Definition */ ++/*-------------------------------------------*/ ++ ++#define ICS_MIN_CLOCK 100 /* Min Frequency Access Clock KHz */ ++#define ICS_MAX_CLOCK 400 /* Max Frequency Access Clock KHz */ ++#define ICS_TRANSFER_RATE ICS_MAX_CLOCK /* Transfer speed to apply */ ++ ++#define ICS_WRITE_CLK_PNB 30 /* TWCK Clock Periods required to write */ ++#define ICS_READ_CLK_PNB 40 /* TWCK Clock Periods required to read */ ++ ++/*-------------------------------------------*/ ++/* ICS1523 Write Operation Definition */ ++/*-------------------------------------------*/ ++ ++#define ICS1523_ACCESS_OK 0 /* OK */ ++#define ICS1523_ACCESS_ERROR -1 /* NOK */ ++ ++/*-------------------------------------------*/ ++/* ICS1523 Device Addresses Definition */ ++/*-------------------------------------------*/ ++ ++#define ICS_ADDR 0x26 /* Device Address */ ++ ++/*--------------------------------------------------*/ ++/* ICS1523 Registers Internal Addresses Definition */ ++/*--------------------------------------------------*/ ++ ++#define ICS_ICR 0x0 /* Input Control Register */ ++#define ICS_LCR 0x1 /* Loop Control Register */ ++#define ICS_FD0 0x2 /* PLL FeedBack Divider LSBs */ ++#define ICS_FD1 0x3 /* PLL FeedBack Divider MSBs */ ++#define ICS_DPAO 0x4 /* Dynamic Phase Aligner Offset */ ++#define ICS_DPAC 0x5 /* Dynamic Phase Aligner Resolution */ ++#define ICS_OE 0x6 /* Output Enables Register */ ++#define ICS_OD 0x7 /* Osc Divider Register */ ++#define ICS_SWRST 0x8 /* DPA & PLL Reset Register */ ++#define ICS_VID 0x10 /* Chip Version Register */ ++#define ICS_RID 0x11 /* Chip Revision Register */ ++#define ICS_SR 0x12 /* Status Register */ ++ ++/*------------------------------------------------------*/ ++/* ICS1523 Input Control Register Bits Definition */ ++/*------------------------------------------------------*/ ++ ++#define ICS_PDEN 0x1 /* Phase Detector Enable */ ++#define ICS_PDPOL 0x2 /* Phase Detector Enable Polarity */ ++#define ICS_REFPOL 0x4 /* External Reference Polarity */ ++#define ICS_FBKPOL 0x8 /* External Feedback Polarity */ ++#define ICS_FBKSEL 0x10 /* External Feedback Select */ ++#define ICS_FUNCSEL 0x20 /* Function Out Select */ ++#define ICS_ENPLS 0x40 /* Enable PLL Lock/Ref Status Output */ ++#define ICS_ENDLS 0x80 /* Enable DPA Lock/Ref Status Output */ ++ ++/*-----------------------------------------------------*/ ++/* ICS1523 Loop Control Register Bits Definition */ ++/*-----------------------------------------------------*/ ++ ++#define ICS_PFD 0x7 /* Phase Detector Gain */ ++#define ICS_PSD 0x30 /* Post-Scaler Divider */ ++ ++/*----------------------------------------------------*/ ++/* ICS1523 PLL FeedBack Divider LSBs Definition */ ++/*----------------------------------------------------*/ ++ ++#define ICS_FBDL 0xFF /* PLL FeedBack Divider LSBs */ ++ ++/*----------------------------------------------------*/ ++/* ICS1523 PLL FeedBack Divider MSBs Definition */ ++/*----------------------------------------------------*/ ++ ++#define ICS_FBDM 0xF /* PLL FeedBack Divider MSBs */ ++ ++/*------------------------------------------------------------*/ ++/* ICS1523 Dynamic Phase Aligner Offset Bits Definition */ ++/*------------------------------------------------------------*/ ++ ++#define ICS_DPAOS 0x2F /* Dynamic Phase Aligner Offset */ ++#define ICS_FILSEL 0x80 /* Loop Filter Select */ ++ ++/*----------------------------------------------------------------*/ ++/* ICS1523 Dynamic Phase Aligner Resolution Bits Definition */ ++/*----------------------------------------------------------------*/ ++ ++#define ICS_DPARES 0x3 /* Dynamic Phase Aligner Resolution */ ++#define ICS_MMREV 0xFC /* Metal Mask Revision Number */ ++ ++/*-------------------------------------------------------*/ ++/* ICS1523 Output Enables Register Bits Definition */ ++/*-------------------------------------------------------*/ ++ ++#define ICS_OEPCK 0x1 /* Output Enable for PECL PCLK Outputs */ ++#define ICS_OETCK 0x2 /* Output Enable for STTL CLK Output */ ++#define ICS_OEP2 0x4 /* Output Enable for PECL CLK/2 Outputs */ ++#define ICS_OET2 0x8 /* Output Enable for STTL CLK/2 Output */ ++#define ICS_OEF 0x10 /* Output Enable for STTL FUNC Output */ ++#define ICS_CLK2INV 0x20 /* CLK/2 Invert */ ++#define ICS_OSCL 0xC0 /* SSTL Clock Scaler */ ++ ++/*----------------------------------------------------*/ ++/* ICS1523 Osc Divider Register Bits Definition */ ++/*----------------------------------------------------*/ ++ ++#define ICS_OSCDIV 0x7F /* Oscillator Divider Modulus */ ++#define ICS_INSEL 0x80 /* Input Select */ ++ ++/*---------------------------------------------------*/ ++/* ICS1523 DPA & PLL Reset Register Definition */ ++/*---------------------------------------------------*/ ++ ++#define ICS_DPAR 0x0A /* DPA Reset Command */ ++#define ICS_PLLR 0x50 /* PLL Reset Command */ ++ ++/*------------------------------------------------*/ ++/* ICS1523 Chip Version Register Definition */ ++/*------------------------------------------------*/ ++ ++#define ICS_CHIPV 0xFF /* Chip Version */ ++ ++/*-------------------------------------------------*/ ++/* ICS1523 Chip Revision Register Definition */ ++/*-------------------------------------------------*/ ++ ++#define ICS_CHIPR 0xFF /* Chip Revision */ ++ ++/*------------------------------------------*/ ++/* ICS1523 Status Register Definition */ ++/*------------------------------------------*/ ++ ++#define ICS_DPALOCK 0x1 /* DPA Lock Status */ ++#define ICS_PLLLOCK 0x2 /* PLL Lock Status */ ++ ++int at91_ics1523_init(void); ++ ++#endif /* ics1523_h */ +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/spi.h linux-2.6/include/asm-arm/arch-at91/spi.h +--- linux-2.6.25/include/asm-arm/arch-at91/spi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/spi.h 2008-01-16 21:24:29.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* ++ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200 ++ * ++ * (c) SAN People (Pty) Ltd ++ * ++ * 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. ++ */ ++ ++#ifndef AT91_LEGACY_SPI_H ++#define AT91_LEGACY_SPI_H ++ ++#define SPI_MAJOR 153 /* registered device number */ ++ ++#define DEFAULT_SPI_CLK 6000000 ++ ++ ++/* Maximum number of buffers in a single SPI transfer. ++ * DataFlash uses maximum of 2 ++ * spidev interface supports up to 8. ++ */ ++#define MAX_SPI_TRANSFERS 8 ++#define NR_SPI_DEVICES 4 /* number of devices on SPI bus */ ++ ++/* ++ * Describes the buffers for a SPI transfer. ++ * A transmit & receive buffer must be specified for each transfer ++ */ ++struct spi_transfer_list { ++ void* tx[MAX_SPI_TRANSFERS]; /* transmit */ ++ int txlen[MAX_SPI_TRANSFERS]; ++ void* rx[MAX_SPI_TRANSFERS]; /* receive */ ++ int rxlen[MAX_SPI_TRANSFERS]; ++ int nr_transfers; /* number of transfers */ ++ int curr; /* current transfer */ ++}; ++ ++struct spi_local { ++ unsigned int pcs; /* Peripheral Chip Select value */ ++ ++ struct spi_transfer_list *xfers; /* current transfer list */ ++ dma_addr_t tx, rx; /* DMA address for current transfer */ ++ dma_addr_t txnext, rxnext; /* DMA address for next transfer */ ++}; ++ ++ ++/* Exported functions */ ++extern void spi_access_bus(short device); ++extern void spi_release_bus(short device); ++extern int spi_transfer(struct spi_transfer_list* list); ++ ++#endif +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-at91/timex.h linux-2.6/include/asm-arm/arch-at91/timex.h +--- linux-2.6.25/include/asm-arm/arch-at91/timex.h 2008-05-03 00:15:51.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-at91/timex.h 2008-04-18 18:30:40.000000000 +0200 +@@ -27,14 +27,29 @@ + + #define CLOCK_TICK_RATE (AT91_SLOW_CLOCK) + +-#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261) ++#elif defined(CONFIG_ARCH_AT91SAM9260) ++ ++#if defined(CONFIG_MACH_USB_A9260) || defined(CONFIG_MACH_QIL_A9260) ++#define AT91SAM9_MASTER_CLOCK 90000000 ++#else ++#define AT91SAM9_MASTER_CLOCK 99300000 ++#endif ++ ++#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) ++ ++#elif defined(CONFIG_ARCH_AT91SAM9261) + + #define AT91SAM9_MASTER_CLOCK 99300000 + #define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) + + #elif defined(CONFIG_ARCH_AT91SAM9263) + ++#if defined(CONFIG_MACH_USB_A9263) ++#define AT91SAM9_MASTER_CLOCK 90000000 ++#else + #define AT91SAM9_MASTER_CLOCK 99959500 ++#endif ++ + #define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16) + + #elif defined(CONFIG_ARCH_AT91SAM9RL) +diff -urN -x CVS linux-2.6.25/include/asm-arm/arch-ks8695/devices.h linux-2.6/include/asm-arm/arch-ks8695/devices.h +--- linux-2.6.25/include/asm-arm/arch-ks8695/devices.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/asm-arm/arch-ks8695/devices.h 2007-12-31 10:44:34.000000000 +0200 +@@ -18,6 +18,11 @@ + extern void __init ks8695_add_device_lan(void); + extern void __init ks8695_add_device_hpna(void); + ++ /* LEDs */ ++extern short ks8695_leds_cpu; ++extern short ks8695_leds_timer; ++extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led); ++ + /* PCI */ + #define KS8695_MODE_PCI 0 + #define KS8695_MODE_MINIPCI 1 +diff -urN -x CVS linux-2.6.25/include/linux/clk.h linux-2.6/include/linux/clk.h +--- linux-2.6.25/include/linux/clk.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6/include/linux/clk.h 2007-12-31 10:44:34.000000000 +0200 +@@ -121,4 +121,24 @@ + */ + struct clk *clk_get_parent(struct clk *clk); + ++/** ++ * clk_must_disable - report whether a clock's users must disable it ++ * @clk: one node in the clock tree ++ * ++ * This routine returns true only if the upcoming system state requires ++ * disabling the specified clock. ++ * ++ * It's common for platform power states to constrain certain clocks (and ++ * their descendants) to be unavailable, while other states allow that ++ * clock to be active. A platform's power states often include an "all on" ++ * mode; system wide sleep states like "standby" or "suspend-to-RAM"; and ++ * operating states which sacrifice functionality for lower power usage. ++ * ++ * The constraint value is commonly tested in device driver suspend(), to ++ * leave clocks active if they are needed for features like wakeup events. ++ * On platforms that support reduced functionality operating states, the ++ * constraint may also need to be tested during resume() and probe() calls. ++ */ ++int clk_must_disable(struct clk *clk); ++ + #endif +diff -urN -x CVS linux-2.6.25/include/linux/i2c-id.h linux-2.6/include/linux/i2c-id.h +--- linux-2.6.25/include/linux/i2c-id.h 2008-05-03 00:15:52.000000000 +0200 ++++ linux-2.6/include/linux/i2c-id.h 2008-03-09 15:43:48.000000000 +0200 +@@ -131,6 +131,7 @@ + + /* --- PCA 9564 based algorithms */ + #define I2C_HW_A_ISA 0x1a0000 /* generic ISA Bus interface card */ ++#define I2C_HW_A_PLAT 0x1a0001 /* generic platform_bus interface */ + + /* --- PowerPC on-chip adapters */ + #define I2C_HW_OCP 0x120000 /* IBM on-chip I2C adapter */ +diff -urN -x CVS linux-2.6.25/include/linux/usb/atmel_usba_udc.h linux-2.6/include/linux/usb/atmel_usba_udc.h +--- linux-2.6.25/include/linux/usb/atmel_usba_udc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6/include/linux/usb/atmel_usba_udc.h 2008-05-03 00:31:09.000000000 +0200 +@@ -0,0 +1,23 @@ ++/* ++* Platform data definitions for Atmel USBA gadget driver. ++*/ ++#ifndef __LINUX_USB_USBA_H ++#define __LINUX_USB_USBA_H ++ ++struct usba_ep_data { ++ char* name; ++ int index; ++ int fifo_size; ++ int nr_banks; ++ int can_dma; ++ int can_isoc; ++}; ++ ++struct usba_platform_data { ++ int vbus_pin; ++ int num_ep; ++ struct usba_ep_data ep[0]; ++}; ++ ++#endif /* __LINUX_USB_USBA_H */ ++ +diff -urN -x CVS linux-2.6.25/include/video/atmel_lcdc.h linux-2.6/include/video/atmel_lcdc.h +--- linux-2.6.25/include/video/atmel_lcdc.h 2008-05-03 00:15:53.000000000 +0200 ++++ linux-2.6/include/video/atmel_lcdc.h 2008-03-09 15:53:40.000000000 +0200 +@@ -39,6 +39,7 @@ + u8 bl_power; + #endif + bool lcdcon_is_backlight; ++ u8 saved_lcdcon; + + u8 default_bpp; + unsigned int default_lcdcon2; +diff -urN -x CVS linux-2.6.25/sound/soc/at91/eti_b1_wm8731.c linux-2.6/sound/soc/at91/eti_b1_wm8731.c +--- linux-2.6.25/sound/soc/at91/eti_b1_wm8731.c 2008-05-03 00:15:56.000000000 +0200 ++++ linux-2.6/sound/soc/at91/eti_b1_wm8731.c 2008-03-09 15:15:07.000000000 +0200 +@@ -33,8 +33,7 @@ + #include <sound/soc.h> + #include <sound/soc-dapm.h> + +-#include <asm/arch/hardware.h> +-#include <asm/arch/at91_pio.h> ++#include <asm/hardware.h> + #include <asm/arch/gpio.h> + + #include "../codecs/wm8731.h" +@@ -47,13 +46,6 @@ + #define DBG(x...) + #endif + +-#define AT91_PIO_TF1 (1 << (AT91_PIN_PB6 - PIN_BASE) % 32) +-#define AT91_PIO_TK1 (1 << (AT91_PIN_PB7 - PIN_BASE) % 32) +-#define AT91_PIO_TD1 (1 << (AT91_PIN_PB8 - PIN_BASE) % 32) +-#define AT91_PIO_RD1 (1 << (AT91_PIN_PB9 - PIN_BASE) % 32) +-#define AT91_PIO_RK1 (1 << (AT91_PIN_PB10 - PIN_BASE) % 32) +-#define AT91_PIO_RF1 (1 << (AT91_PIN_PB11 - PIN_BASE) % 32) +- + static struct clk *pck1_clk; + static struct clk *pllb_clk; + +@@ -276,7 +268,6 @@ + static int __init eti_b1_init(void) + { + int ret; +- u32 ssc_pio_lines; + struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data; + + if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) { +@@ -310,19 +301,12 @@ + goto fail_io_unmap; + } + +- ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1 +- | AT91_PIO_RD1 /* | AT91_PIO_RK1 */ | AT91_PIO_RF1; +- +- /* Reset all PIO registers and assign lines to peripheral A */ +- at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_ODR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_IDR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_ASR, ssc_pio_lines); +- at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines); ++ at91_set_A_periph(AT91_PIN_PB6, 0); /* TF1 */ ++ at91_set_A_periph(AT91_PIN_PB7, 0); /* TK1 */ ++ at91_set_A_periph(AT91_PIN_PB8, 0); /* TD1 */ ++ at91_set_A_periph(AT91_PIN_PB9, 0); /* RD1 */ ++/* at91_set_A_periph(AT91_PIN_PB10, 0);*/ /* RK1 */ ++ at91_set_A_periph(AT91_PIN_PB11, 0); /* RF1 */ + + /* + * Set PCK1 parent to PLLB and its rate to 12 Mhz. +diff -urN -x CVS linux-2.6.25/sound/spi/at73c213.c linux-2.6/sound/spi/at73c213.c +--- linux-2.6.25/sound/spi/at73c213.c 2008-05-03 00:15:56.000000000 +0200 ++++ linux-2.6/sound/spi/at73c213.c 2008-03-09 15:15:07.000000000 +0200 +@@ -114,7 +114,11 @@ + static struct snd_pcm_hardware snd_at73c213_playback_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, ++#ifdef __BIG_ENDIAN + .formats = SNDRV_PCM_FMTBIT_S16_BE, ++#else ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++#endif + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, /* Replaced by chip->bitrate later. */ + .rate_max = 50000, /* Replaced by chip->bitrate later. */ diff --git a/target/linux/at91/patches-2.6.25/001-vlink-machine.patch b/target/linux/at91/patches-2.6.25/001-vlink-machine.patch new file mode 100644 index 0000000..9f5673b --- /dev/null +++ b/target/linux/at91/patches-2.6.25/001-vlink-machine.patch @@ -0,0 +1,229 @@ +--- linux-2.6.25.10.n/arch/arm/mach-at91/Kconfig 2008-07-04 13:07:01.000000000 +0200 ++++ linux-2.6.25.10/arch/arm/mach-at91/Kconfig 2008-07-03 13:44:35.000000000 +0200 +@@ -151,6 +151,12 @@ + help + Select this if you are using Toptech's TT9200 board. + ++config MACH_VLINK ++ bool "Figment Design Labs VersaLink" ++ depends on ARCH_AT91RM9200 ++ help ++ Select this if you are using FDL's VersaLink board ++ + endif + + # ---------------------------------------------------------- +--- linux-2.6.25.10.n/arch/arm/mach-at91/Makefile 2008-07-04 13:05:05.000000000 +0200 ++++ linux-2.6.25.10/arch/arm/mach-at91/Makefile 2008-07-03 13:44:35.000000000 +0200 +@@ -29,6 +29,7 @@ + obj-$(CONFIG_MACH_ATEB9200) += board-eb9200.o + obj-$(CONFIG_MACH_KAFA) += board-kafa.o + obj-$(CONFIG_MACH_CHUB) += board-chub.o ++obj-$(CONFIG_MACH_VLINK) += board-vlink.o + obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o + obj-$(CONFIG_MACH_HOMEMATIC) += board-homematic.o + obj-$(CONFIG_MACH_ECBAT91) += board-ecbat91.o +--- linux-2.6.25.10.n/arch/arm/mach-at91/board-vlink.c 2008-07-04 13:06:19.000000000 +0200 ++++ linux-2.6.25.10/arch/arm/mach-at91/board-vlink.c 2008-07-04 12:45:48.000000000 +0200 +@@ -0,0 +1,201 @@ ++/* ++ * linux/arch/arm/mach-at91/board-vlink.c ++ * ++ * Copyright (C) 2005 SAN People ++ * Copyright (C) 2006,2007 Guthrie Consulting ++ * ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/mtd/physmap.h> ++ ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/board.h> ++#include <asm/arch/gpio.h> ++#include <asm/arch/at91rm9200_mc.h> ++ ++#include "generic.h" ++ ++ ++static void __init vlink_map_io(void) ++{ ++ /* Initialize processor: 18.432 MHz crystal */ ++ at91rm9200_initialize(18432000, AT91RM9200_PQFP); ++ ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PC14, AT91_PIN_PC15); ++ ++ /* Setup serial ports */ ++ ++ /* DBGU on ttyS0. (RX and TX only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DSR, DTR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS ++ | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR ++ | ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART0 on ttys2. (Rx, Tx, CTS, RTS, DTR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US0, 2, ATMEL_UART_CTS ++ | ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART3 on ttyS3. (Rx, Tx, CTS, RTS, DTR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS ++ | ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART2 on ttyS4. (Rx and Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US2, 4, 0); ++ ++ /* Console on ttyS0 (ie DBGU) */ ++ at91_set_serial_console(0); ++} ++ ++static void __init vlink_init_irq(void) ++{ ++ at91rm9200_init_interrupts(NULL); ++} ++ ++static struct at91_eth_data __initdata vlink_eth_data = { ++ .phy_irq_pin = AT91_PIN_PC4, ++ .is_rmii = 1, ++}; ++ ++static struct at91_usbh_data __initdata vlink_usbh_data = { ++ .ports = 1, ++}; ++ ++/* ++static struct at91_udc_data __initdata vlink_udc_data = { ++ .vbus_pin = AT91_PIN_PD4, ++ .pullup_pin = AT91_PIN_PD5, ++}; ++*/ ++ ++static struct at91_mmc_data __initdata vlink_mmc_data = { ++// .det_pin = AT91_PIN_PB27, ++ .slot_b = 0, ++ .wire4 = 1, ++// .wp_pin = AT91_PIN_PA17, ++}; ++ ++static struct spi_board_info vlink_spi_devices[] = { ++ { /* DataFlash chip */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 0, ++ .max_speed_hz = 15 * 1000 * 1000, ++ }, ++#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD ++ { /* DataFlash card */ ++ .modalias = "mtd_dataflash", ++ .chip_select = 3, ++ .max_speed_hz = 15 * 1000 * 1000, ++ }, ++#endif ++}; ++ ++/*static struct at91_gpio_led vlink_leds[] = { ++ { ++ .name = "led0", ++ .gpio = AT91_PIN_PC14, ++ .trigger = "heartbeat", ++ }, ++ { ++ .name = "led1", ++ .gpio = AT91_PIN_PC15, ++ .trigger = "timer", ++ } ++}; ++*/ ++ ++static void __init vlink_board_init(void) ++{ ++ /* Serial */ ++ at91_add_device_serial(); ++ /* Ethernet */ ++ at91_add_device_eth(&vlink_eth_data); ++ /* USB Host */ ++ at91_add_device_usbh(&vlink_usbh_data); ++ /* USB Device */ ++// at91_add_device_udc(&vlink_udc_data); ++// at91_set_multi_drive(vlink_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */ ++ /* I2C */ ++// at91_add_device_i2c(); ++ /* SPI */ ++ at91_add_device_spi(vlink_spi_devices, ARRAY_SIZE(vlink_spi_devices)); ++#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD ++ /* DataFlash card */ ++// at91_set_gpio_output(AT91_PIN_PB22, 0); ++#else ++ /* MMC */ ++// at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ ++ at91_add_device_mmc(0, &vlink_mmc_data); ++#endif ++ /* LEDs */ ++// at91_gpio_leds(vlink_leds, ARRAY_SIZE(vlink_leds)); ++ ++/* Other LED's */ ++ at91_set_gpio_output(AT91_PIN_PC7, 1); // LED FRONT AP1 ++ at91_set_gpio_output(AT91_PIN_PC8, 1); // LED FRONT BP1 ++ at91_set_gpio_output(AT91_PIN_PB14, 1); // LED BACK AP1 ++ at91_set_gpio_output(AT91_PIN_PB15, 1); // LED BACK BP1 ++ at91_set_gpio_output(AT91_PIN_PB16, 1); // LED BACK AP2 ++ at91_set_gpio_output(AT91_PIN_PB17, 1); // LED BACK BP2 ++ ++/* SIM Cards */ ++ at91_set_gpio_output(AT91_PIN_PB9, 1); // ENBSC3 ++ at91_set_gpio_output(AT91_PIN_PB10, 1); // ENBSC2 ++ at91_set_gpio_output(AT91_PIN_PB11, 1); // ENBSC1 ++ ++/* GSM Module Control */ ++ at91_set_gpio_output(AT91_PIN_PB12, 1); // GSMONOFF ++ ++/* Test jig presence detection */ ++ at91_set_gpio_input(AT91_PIN_PB8, 1); // JIGPRESENT ++ ++/* Power indicator */ ++ at91_set_gpio_input(AT91_PIN_PB22, 1); // PWR_IND ++ ++/* USB Device control */ ++ at91_set_gpio_input(AT91_PIN_PB27, 1); // UDB_CNX ++ at91_set_gpio_output(AT91_PIN_PB28, 1); // UDB_PUP ++ at91_set_multi_drive(AT91_PIN_PB28, 1); // Set to multi-drive ++ ++} ++ ++MACHINE_START(VLINK, "FDL VersaLink") ++ /* Maintainer: Guthrie Consulting */ ++ .phys_io = AT91_BASE_SYS, ++ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc, ++ .boot_params = AT91_SDRAM_BASE + 0x100, ++ .timer = &at91rm9200_timer, ++ .map_io = vlink_map_io, ++ .init_irq = vlink_init_irq, ++ .init_machine = vlink_board_init, ++MACHINE_END diff --git a/target/linux/at91/patches-2.6.25/007-mtd-partition.patch b/target/linux/at91/patches-2.6.25/007-mtd-partition.patch new file mode 100644 index 0000000..5c0cd3e --- /dev/null +++ b/target/linux/at91/patches-2.6.25/007-mtd-partition.patch @@ -0,0 +1,42 @@ +Index: linux-2.6.22.19/drivers/mtd/devices/at91_dataflash.c +=================================================================== +--- linux-2.6.22.19.orig/drivers/mtd/devices/at91_dataflash.c ++++ linux-2.6.22.19/drivers/mtd/devices/at91_dataflash.c +@@ -175,7 +175,7 @@ static struct mtd_partition static_parti + }; + #endif + +-static const char *part_probes[] = { "cmdlinepart", NULL, }; ++static const char *part_probes[] = { "cmdlinepart", "at91part", NULL, }; + + #endif + +Index: linux-2.6.22.19/drivers/mtd/Kconfig +=================================================================== +--- linux-2.6.22.19.orig/drivers/mtd/Kconfig ++++ linux-2.6.22.19/drivers/mtd/Kconfig +@@ -168,6 +168,12 @@ config MTD_AFS_PARTS + the partition map from the children of the flash node, + as described in Documentation/powerpc/booting-without-of.txt. + ++config MTD_AT91_PARTS ++ tristate "Atmel AT91 partitioning support" ++ depends on MTD_PARTITIONS && ARCH_AT91RM9200 && AT91_SPI ++ ---help--- ++ Atmel AT91 partitioning support ++ + comment "User Modules And Translation Layers" + + config MTD_CHAR +Index: linux-2.6.22.19/drivers/mtd/Makefile +=================================================================== +--- linux-2.6.22.19.orig/drivers/mtd/Makefile ++++ linux-2.6.22.19/drivers/mtd/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o + obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o ++obj-$(CONFIG_MTD_AT91_PARTS) += at91part.o + + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_CHAR) += mtdchar.o diff --git a/target/linux/at91/patches-2.6.25/008-fdl-serial.patch b/target/linux/at91/patches-2.6.25/008-fdl-serial.patch new file mode 100644 index 0000000..3cdbec2 --- /dev/null +++ b/target/linux/at91/patches-2.6.25/008-fdl-serial.patch @@ -0,0 +1,161 @@ +--- linux-2.6.25.10.old/drivers/serial/atmel_serial.c 2008-07-04 14:21:12.000000000 +0200 ++++ linux-2.6.25.10/drivers/serial/atmel_serial.c 2008-07-04 14:55:37.000000000 +0200 +@@ -214,6 +214,34 @@ + at91_set_gpio_value(AT91_PIN_PA21, 0); + else + at91_set_gpio_value(AT91_PIN_PA21, 1); ++ ++ /* ++ * FDL VersaLink adds GPIOS to provide full modem ++ * control on USART 0 - Drive DTR and RI pins manually ++ */ ++ if (mctrl & TIOCM_DTR) ++ at91_set_gpio_value(AT91_PIN_PB6, 0); ++ else ++ at91_set_gpio_value(AT91_PIN_PB6, 1); ++ if (mctrl & TIOCM_RI) ++ at91_set_gpio_value(AT91_PIN_PB7, 0); ++ else ++ at91_set_gpio_value(AT91_PIN_PB7, 1); ++ } ++ ++ /* ++ * FDL VersaLink adds GPIOS to provide full modem control on ++ * USART 3 - Drive DTR and RI pins manually ++ */ ++ if (port->mapbase == AT91RM9200_BASE_US3) { ++ if (mctrl & TIOCM_DTR) ++ at91_set_gpio_value(AT91_PIN_PB29, 0); ++ else ++ at91_set_gpio_value(AT91_PIN_PB29, 1); ++ if (mctrl & TIOCM_RI) ++ at91_set_gpio_value(AT91_PIN_PB2, 0); ++ else ++ at91_set_gpio_value(AT91_PIN_PB2, 1); + } + } + #endif +@@ -251,8 +279,10 @@ + /* + * The control signals are active low. + */ +- if (!(status & ATMEL_US_DCD)) +- ret |= TIOCM_CD; ++ ++ if (!(port->mapbase == AT91RM9200_BASE_US0 || port->mapbase == AT91RM9200_BASE_US3)) ++ if (!(status & ATMEL_US_DCD)) ++ ret |= TIOCM_CD; + if (!(status & ATMEL_US_CTS)) + ret |= TIOCM_CTS; + if (!(status & ATMEL_US_DSR)) +@@ -260,6 +290,16 @@ + if (!(status & ATMEL_US_RI)) + ret |= TIOCM_RI; + ++ /* ++ * Read the GPIO's for the FDL VersaLink special case ++ */ ++ if (port->mapbase == AT91RM9200_BASE_US0) ++ if (!(at91_get_gpio_value(AT91_PIN_PA19))) ++ ret |= TIOCM_CD; ++ if (port->mapbase == AT91RM9200_BASE_US3) ++ if (!(at91_get_gpio_value(AT91_PIN_PA24))) ++ ret |= TIOCM_CD; ++ + return ret; + } + +@@ -453,6 +493,34 @@ + } + + /* ++ * USART0 DCD Interrupt handler ++ */ ++ ++static irqreturn_t atmel_u0_DCD_interrupt(int irq, void *dev_id) ++{ ++ struct uart_port *port = dev_id; ++ int status = at91_get_gpio_value(irq); ++ ++ uart_handle_dcd_change(port, !(status)); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * USART3 DCD Interrupt handler ++ */ ++ ++static irqreturn_t atmel_u3_DCD_interrupt(int irq, void *dev_id) ++{ ++ struct uart_port *port = dev_id; ++ int status = at91_get_gpio_value(irq); ++ ++ uart_handle_dcd_change(port, !(status)); ++ ++ return IRQ_HANDLED; ++} ++ ++/* + * receive interrupt handler. + */ + static void +@@ -815,6 +883,23 @@ + return retval; + } + ++ if (port->mapbase == AT91RM9200_BASE_US0) { ++ retval = request_irq(AT91_PIN_PA19, atmel_u0_DCD_interrupt, 0, "atmel_serial", port); ++ if (retval) { ++ printk("atmel_serial: atmel_startup - Can't get u0DCD irq\n"); ++ free_irq(port->irq, port); ++ return retval; ++ } ++ } ++ if (port->mapbase == AT91RM9200_BASE_US3) { ++ retval = request_irq(AT91_PIN_PA24, atmel_u3_DCD_interrupt, 0, "atmel_serial", port); ++ if (retval) { ++ printk("atmel_serial: atmel_startup - Can't get u3DCD irq\n"); ++ free_irq(port->irq, port); ++ return retval; ++ } ++ } ++ + /* + * Initialize DMA (if necessary) + */ +@@ -834,6 +919,10 @@ + kfree(atmel_port->pdc_rx[0].buf); + } + free_irq(port->irq, port); ++ if (port->mapbase == AT91RM9200_BASE_US0) ++ free_irq(AT91_PIN_PA19, port); ++ if (port->mapbase == AT91RM9200_BASE_US3) ++ free_irq(AT91_PIN_PA24, port); + return -ENOMEM; + } + pdc->dma_addr = dma_map_single(port->dev, +@@ -873,7 +962,11 @@ + retval = atmel_open_hook(port); + if (retval) { + free_irq(port->irq, port); +- return retval; ++ if (port->mapbase == AT91RM9200_BASE_US0) ++ free_irq(AT91_PIN_PA19, port); ++ if (port->mapbase == AT91RM9200_BASE_US3) ++ free_irq(AT91_PIN_PA24, port); ++ return retval; + } + } + +@@ -947,6 +1040,10 @@ + * Free the interrupt + */ + free_irq(port->irq, port); ++ if (port->mapbase == AT91RM9200_BASE_US0) ++ free_irq(AT91_PIN_PA19, port); ++ if (port->mapbase == AT91RM9200_BASE_US3) ++ free_irq(AT91_PIN_PA24, port); + + /* + * If there is a specific "close" function (to unregister diff --git a/target/linux/at91/patches-2.6.25/009-fdl-uartinit.patch b/target/linux/at91/patches-2.6.25/009-fdl-uartinit.patch new file mode 100644 index 0000000..64bb3ec --- /dev/null +++ b/target/linux/at91/patches-2.6.25/009-fdl-uartinit.patch @@ -0,0 +1,34 @@ +--- linux-2.6.25.10.old/arch/arm/mach-at91/at91rm9200_devices.c 2008-07-04 15:04:13.000000000 +0200 ++++ linux-2.6.25.10/arch/arm/mach-at91/at91rm9200_devices.c 2008-07-04 15:11:44.000000000 +0200 +@@ -981,7 +981,15 @@ + * We need to drive the pin manually. Default is off (RTS is active low). + */ + at91_set_gpio_output(AT91_PIN_PA21, 1); +- } ++ } ++ if (pins & ATMEL_UART_DTR) ++ at91_set_gpio_output(AT91_PIN_PB6, 1); /* DTR0 */ ++ if (pins & ATMEL_UART_RI) ++ at91_set_gpio_output(AT91_PIN_PB7, 1); /* RI0 */ ++ if (pins & ATMEL_UART_DCD) { ++ at91_set_gpio_input(AT91_PIN_PA19, 1); /* DCD0 */ ++ at91_set_deglitch(AT91_PIN_PA19, 1); ++ } + } + + static struct resource uart1_resources[] = { +@@ -1119,6 +1127,14 @@ + at91_set_B_periph(AT91_PIN_PB1, 0); /* CTS3 */ + if (pins & ATMEL_UART_RTS) + at91_set_B_periph(AT91_PIN_PB0, 0); /* RTS3 */ ++ if (pins & ATMEL_UART_DTR) ++ at91_set_gpio_output(AT91_PIN_PB29, 1); /* DTR0 */ ++ if (pins & ATMEL_UART_RI) ++ at91_set_gpio_output(AT91_PIN_PB2, 1); /* RI0 */ ++ if (pins & ATMEL_UART_DCD) { ++ at91_set_gpio_input(AT91_PIN_PA24, 1); /* DCD0 */ ++ at91_set_deglitch(AT91_PIN_PA24, 1); ++ } + } + + static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */ diff --git a/target/linux/at91/patches-2.6.25/010-dm9161a-phyfix.patch b/target/linux/at91/patches-2.6.25/010-dm9161a-phyfix.patch new file mode 100644 index 0000000..120c32e --- /dev/null +++ b/target/linux/at91/patches-2.6.25/010-dm9161a-phyfix.patch @@ -0,0 +1,30 @@ +Index: linux-2.6.22.19/drivers/net/arm/at91_ether.c +=================================================================== +--- linux-2.6.22.19.orig/drivers/net/arm/at91_ether.c ++++ linux-2.6.22.19/drivers/net/arm/at91_ether.c +@@ -146,6 +146,7 @@ static void update_linkspeed(struct net_ + struct at91_private *lp = netdev_priv(dev); + unsigned int bmsr, bmcr, lpa, mac_cfg; + unsigned int speed, duplex; ++ unsigned long timeout = jiffies + HZ; + + if (!mii_link_ok(&lp->mii)) { /* no link */ + netif_carrier_off(dev); +@@ -158,8 +159,15 @@ static void update_linkspeed(struct net_ + read_phy(lp->phy_address, MII_BMSR, &bmsr); + read_phy(lp->phy_address, MII_BMCR, &bmcr); + if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */ +- if (!(bmsr & BMSR_ANEGCOMPLETE)) +- return; /* Do nothing - another interrupt generated when negotiation complete */ ++ while (!(bmsr & BMSR_ANEGCOMPLETE)) { ++ if (time_after(jiffies, timeout)) { ++ printk("at91_ether: Auto-negotiate timeout\n"); ++ return; ++ } ++ read_phy(lp->phy_address, MII_BMSR, &bmsr); ++ read_phy(lp->phy_address, MII_BMCR, &bmcr); ++ cpu_relax(); ++ } + + read_phy(lp->phy_address, MII_LPA, &lpa); + if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100; diff --git a/target/linux/at91/patches-2.6.25/014-initpartition.patch b/target/linux/at91/patches-2.6.25/014-initpartition.patch new file mode 100644 index 0000000..1c49db5 --- /dev/null +++ b/target/linux/at91/patches-2.6.25/014-initpartition.patch @@ -0,0 +1,20 @@ +Index: linux-2.6.22.19/drivers/mtd/devices/at91_dataflash.c +=================================================================== +--- linux-2.6.22.19.orig/drivers/mtd/devices/at91_dataflash.c ++++ linux-2.6.22.19/drivers/mtd/devices/at91_dataflash.c +@@ -163,12 +163,12 @@ static struct mtd_partition static_parti + .mask_flags = MTD_WRITEABLE, /* read-only */ + }, + { +- .name = "kernel", ++ .name = "knlroot", + .offset = MTDPART_OFS_NXTBLK, +- .size = 5 * 32 * 8 * 1056, /* 5 sectors */ ++ .size = 0x320400, + }, + { +- .name = "filesystem", ++ .name = "jffs2", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, /* rest = 26 sectors */ + } |