1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-09-12 17:21:30 +03:00
openwrt-xburst/target/linux/avr32/patches/100-git_sync.patch
kaloz 4a605b0d93 upgrade AVR32 to 2.6.24 - sync with 2.6.24.atmel.1
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@10412 3c298f89-4303-0410-b956-a3cf2f4a3e73
2008-02-07 20:08:19 +00:00

18840 lines
490 KiB
Diff

Documentation/kernel-parameters.txt | 5 +
MAINTAINERS | 6 +
Makefile | 2 +-
arch/arm/mach-at91/at91sam9261_devices.c | 14 +
arch/arm/mach-at91/at91sam9rl_devices.c | 14 +
arch/arm/mach-at91/board-sam9261ek.c | 1 +
arch/arm/mach-at91/board-sam9263ek.c | 1 +
arch/avr32/Kconfig | 54 +-
arch/avr32/Kconfig.debug | 10 -
arch/avr32/Makefile | 4 +-
arch/avr32/boards/atngw100/Kconfig | 12 +
arch/avr32/boards/atngw100/setup.c | 14 +-
arch/avr32/boards/atstk1000/Kconfig | 101 ++-
arch/avr32/boards/atstk1000/Makefile | 2 +
arch/avr32/boards/atstk1000/atstk1000.h | 2 +
arch/avr32/boards/atstk1000/atstk1002.c | 129 +--
arch/avr32/boards/atstk1000/atstk1003.c | 181 +++
arch/avr32/boards/atstk1000/atstk1004.c | 152 +++
arch/avr32/boards/atstk1000/setup.c | 64 +
arch/avr32/configs/atngw100_defconfig | 423 +++++---
arch/avr32/configs/atstk1002_defconfig | 661 ++++++++---
arch/avr32/configs/atstk1003_defconfig | 1032 ++++++++++++++++
arch/avr32/configs/atstk1004_defconfig | 627 ++++++++++
arch/avr32/drivers/Makefile | 1 +
arch/avr32/drivers/dw-dmac.c | 761 ++++++++++++
arch/avr32/drivers/dw-dmac.h | 42 +
arch/avr32/kernel/Makefile | 4 +-
arch/avr32/kernel/cpu.c | 96 ++-
arch/avr32/kernel/dma-controller.c | 34 +
arch/avr32/kernel/irq.c | 11 +
arch/avr32/kernel/kprobes.c | 5 +-
arch/avr32/kernel/nmi_debug.c | 82 ++
arch/avr32/kernel/ocd.c | 163 +++
arch/avr32/kernel/process.c | 5 +-
arch/avr32/kernel/ptrace.c | 5 +-
arch/avr32/kernel/setup.c | 2 +
arch/avr32/kernel/signal.c | 7 -
arch/avr32/kernel/traps.c | 21 +-
arch/avr32/mach-at32ap/Kconfig | 19 +-
arch/avr32/mach-at32ap/Makefile | 5 +-
arch/avr32/mach-at32ap/at32ap7000.c | 1730 --------------------------
arch/avr32/mach-at32ap/at32ap700x.c | 1809 ++++++++++++++++++++++++++++
arch/avr32/mach-at32ap/extint.c | 59 +-
arch/avr32/mach-at32ap/gpio-dev.c | 573 +++++++++
arch/avr32/mach-at32ap/pio.c | 76 ++
arch/avr32/mm/dma-coherent.c | 7 +
arch/avr32/mm/tlb.c | 2 +-
arch/avr32/oprofile/Makefile | 8 +
arch/avr32/oprofile/op_model_avr32.c | 235 ++++
drivers/i2c/busses/Kconfig | 8 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-atmeltwi.c | 436 +++++++
drivers/i2c/busses/i2c-atmeltwi.h | 117 ++
drivers/leds/Kconfig | 7 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-atmel-pwm.c | 155 +++
drivers/misc/Kconfig | 9 +
drivers/misc/Makefile | 1 +
drivers/misc/atmel_pwm.c | 409 +++++++
drivers/mmc/host/Kconfig | 10 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/atmel-mci.c | 1176 ++++++++++++++++++
drivers/mmc/host/atmel-mci.h | 192 +++
drivers/mtd/chips/cfi_cmdset_0001.c | 43 +
drivers/mtd/chips/cfi_cmdset_0002.c | 6 +-
drivers/pcmcia/Kconfig | 7 +
drivers/pcmcia/Makefile | 1 +
drivers/pcmcia/at32_cf.c | 533 ++++++++
drivers/serial/Kconfig | 15 +
drivers/serial/atmel_serial.c | 884 +++++++++++---
drivers/spi/atmel_spi.c | 173 ++-
drivers/video/atmel_lcdfb.c | 149 +++-
drivers/video/backlight/Kconfig | 13 +
drivers/video/console/Kconfig | 2 +-
drivers/watchdog/Kconfig | 2 +-
include/asm-avr32/arch-at32ap/at32ap7000.h | 35 -
include/asm-avr32/arch-at32ap/at32ap700x.h | 35 +
include/asm-avr32/arch-at32ap/board.h | 11 +-
include/asm-avr32/arch-at32ap/cpu.h | 2 +-
include/asm-avr32/arch-at32ap/io.h | 4 +-
include/asm-avr32/arch-at32ap/portmux.h | 12 +
include/asm-avr32/dma-controller.h | 166 +++
include/asm-avr32/irq.h | 5 +
include/asm-avr32/kdebug.h | 1 +
include/asm-avr32/ocd.h | 5 +
include/asm-avr32/processor.h | 14 +
include/asm-avr32/ptrace.h | 13 +-
include/asm-avr32/thread_info.h | 1 +
include/linux/atmel_pwm.h | 70 ++
include/video/atmel_lcdc.h | 25 +-
kernel/ptrace.c | 2 +
sound/Kconfig | 2 +
sound/Makefile | 2 +-
sound/avr32/Kconfig | 11 +
sound/avr32/Makefile | 3 +
sound/avr32/ac97c.c | 914 ++++++++++++++
sound/avr32/ac97c.h | 71 ++
sound/oss/Kconfig | 4 +
sound/oss/Makefile | 1 +
sound/oss/at32_abdac.c | 722 +++++++++++
sound/oss/at32_abdac.h | 59 +
101 files changed, 13294 insertions(+), 2520 deletions(-)
create mode 100644 arch/avr32/boards/atngw100/Kconfig
create mode 100644 arch/avr32/boards/atstk1000/atstk1003.c
create mode 100644 arch/avr32/boards/atstk1000/atstk1004.c
create mode 100644 arch/avr32/configs/atstk1003_defconfig
create mode 100644 arch/avr32/configs/atstk1004_defconfig
create mode 100644 arch/avr32/drivers/Makefile
create mode 100644 arch/avr32/drivers/dw-dmac.c
create mode 100644 arch/avr32/drivers/dw-dmac.h
create mode 100644 arch/avr32/kernel/dma-controller.c
create mode 100644 arch/avr32/kernel/nmi_debug.c
create mode 100644 arch/avr32/kernel/ocd.c
delete mode 100644 arch/avr32/mach-at32ap/at32ap7000.c
create mode 100644 arch/avr32/mach-at32ap/at32ap700x.c
create mode 100644 arch/avr32/mach-at32ap/gpio-dev.c
create mode 100644 arch/avr32/oprofile/Makefile
create mode 100644 arch/avr32/oprofile/op_model_avr32.c
create mode 100644 drivers/i2c/busses/i2c-atmeltwi.c
create mode 100644 drivers/i2c/busses/i2c-atmeltwi.h
create mode 100644 drivers/leds/leds-atmel-pwm.c
create mode 100644 drivers/misc/atmel_pwm.c
create mode 100644 drivers/mmc/host/atmel-mci.c
create mode 100644 drivers/mmc/host/atmel-mci.h
create mode 100644 drivers/pcmcia/at32_cf.c
delete mode 100644 include/asm-avr32/arch-at32ap/at32ap7000.h
create mode 100644 include/asm-avr32/arch-at32ap/at32ap700x.h
create mode 100644 include/asm-avr32/dma-controller.h
create mode 100644 include/linux/atmel_pwm.h
create mode 100644 sound/avr32/Kconfig
create mode 100644 sound/avr32/Makefile
create mode 100644 sound/avr32/ac97c.c
create mode 100644 sound/avr32/ac97c.h
create mode 100644 sound/oss/at32_abdac.c
create mode 100644 sound/oss/at32_abdac.h
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c417877..17fc60e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -34,6 +34,7 @@ parameter is applicable:
ALSA ALSA sound support is enabled.
APIC APIC support is enabled.
APM Advanced Power Management support is enabled.
+ AVR32 AVR32 architecture is enabled.
AX25 Appropriate AX.25 support is enabled.
BLACKFIN Blackfin architecture is enabled.
DRM Direct Rendering Management support is enabled.
@@ -1123,6 +1124,10 @@ and is between 256 and 4096 characters. It is defined in the file
of returning the full 64-bit number.
The default is to return 64-bit inode numbers.
+ nmi_debug= [KNL,AVR32] Specify one or more actions to take
+ when a NMI is triggered.
+ Format: [state][,regs][,debounce][,die]
+
nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels
no387 [BUGS=X86-32] Tells the kernel to use the 387 maths
diff --git a/MAINTAINERS b/MAINTAINERS
index 2340cfb..e349a9e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -671,6 +671,12 @@ W: http://www.atmel.com/products/AT91/
W: http://www.at91.com/
S: Maintained
+ATMEL AT91 / AT32 SERIAL DRIVER
+P: Haavard Skinnemoen
+M: hskinnemoen@atmel.com
+L: linux-kernel@vger.kernel.org
+S: Supported
+
ATMEL LCDFB DRIVER
P: Nicolas Ferre
M: nicolas.ferre@atmel.com
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 64979a9..bfa3d18 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -530,6 +530,20 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
at91_set_B_periph(AT91_PIN_PB27, 0); /* LCDD22 */
at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */
+#ifdef CONFIG_FB_INTSRAM
+ {
+ void __iomem *fb;
+ struct resource *fb_res = &lcdc_resources[2];
+ size_t fb_len = fb_res->end - fb_res->start + 1;
+
+ fb = ioremap_writecombine(fb_res->start, fb_len);
+ if (fb) {
+ memset(fb, 0, fb_len);
+ iounmap(fb, fb_len);
+ }
+ }
+#endif
+
lcdc_data = *data;
platform_device_register(&at91_lcdc_device);
}
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 2bd60a3..84ee029 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -375,6 +375,20 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
at91_set_B_periph(AT91_PIN_PC24, 0); /* LCDD22 */
at91_set_B_periph(AT91_PIN_PC25, 0); /* LCDD23 */
+#ifdef CONFIG_FB_INTSRAM
+ {
+ void __iomem *fb;
+ struct resource *fb_res = &lcdc_resources[2];
+ size_t fb_len = fb_res->end - fb_res->start + 1;
+
+ fb = ioremap_writecombine(fb_res->start, fb_len);
+ if (fb) {
+ memset(fb, 0, fb_len);
+ iounmap(fb, fb_len);
+ }
+ }
+#endif
+
lcdc_data = *data;
platform_device_register(&at91_lcdc_device);
}
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 550ae59..0d275bb 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -322,6 +322,7 @@ static void at91_lcdc_power_control(int on)
/* Driver datas */
static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcdcon_is_backlight = true,
.default_bpp = 16,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9261_DEFAULT_LCDCON2,
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index ab9dcc0..39bded2 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -250,6 +250,7 @@ static void at91_lcdc_power_control(int on)
/* Driver datas */
static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcdcon_is_backlight = true,
.default_bpp = 16,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2,
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index b77abce..3f09270 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -54,6 +54,9 @@ config ARCH_HAS_ILOG2_U32
config ARCH_HAS_ILOG2_U64
def_bool n
+config ARCH_SUPPORTS_OPROFILE
+ def_bool y
+
config GENERIC_HWEIGHT
def_bool y
@@ -81,19 +84,23 @@ config PLATFORM_AT32AP
select MMU
select PERFORMANCE_COUNTERS
-choice
- prompt "AVR32 CPU type"
- default CPU_AT32AP7000
+#
+# CPU types
+#
-config CPU_AT32AP7000
- bool "AT32AP7000"
+# AP7000 derivatives
+config CPU_AT32AP700X
+ bool
select PLATFORM_AT32AP
-endchoice
-
-#
-# CPU Daughterboards for ATSTK1000
-config BOARD_ATSTK1002
+config CPU_AT32AP7000
+ bool
+ select CPU_AT32AP700X
+config CPU_AT32AP7001
+ bool
+ select CPU_AT32AP700X
+config CPU_AT32AP7002
bool
+ select CPU_AT32AP700X
choice
prompt "AVR32 board type"
@@ -101,15 +108,18 @@ choice
config BOARD_ATSTK1000
bool "ATSTK1000 evaluation board"
- select BOARD_ATSTK1002 if CPU_AT32AP7000
config BOARD_ATNGW100
bool "ATNGW100 Network Gateway"
+ select CPU_AT32AP7000
endchoice
if BOARD_ATSTK1000
source "arch/avr32/boards/atstk1000/Kconfig"
endif
+if BOARD_ATNGW100
+source "arch/avr32/boards/atngw100/Kconfig"
+endif
choice
prompt "Boot loader type"
@@ -123,15 +133,15 @@ source "arch/avr32/mach-at32ap/Kconfig"
config LOAD_ADDRESS
hex
- default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
+ default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
config ENTRY_ADDRESS
hex
- default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
+ default 0x90000000 if LOADER_U_BOOT=y && CPU_AT32AP700X=y
config PHYS_OFFSET
hex
- default 0x10000000 if CPU_AT32AP7000=y
+ default 0x10000000 if CPU_AT32AP700X=y
source "kernel/Kconfig.preempt"
@@ -163,6 +173,20 @@ config OWNERSHIP_TRACE
enabling Nexus-compliant debuggers to keep track of the PID of the
currently executing task.
+config NMI_DEBUGGING
+ bool "NMI Debugging"
+ default n
+ help
+ Say Y here and pass the nmi_debug command-line parameter to
+ the kernel to turn on NMI debugging. Depending on the value
+ of the nmi_debug option, various pieces of information will
+ be dumped to the console when a Non-Maskable Interrupt
+ happens.
+
+config DW_DMAC
+ tristate "Synopsys DesignWare DMA Controller support"
+ default y if CPU_AT32AP7000
+
# FPU emulation goes here
source "kernel/Kconfig.hz"
@@ -219,6 +243,8 @@ source "drivers/Kconfig"
source "fs/Kconfig"
+source "kernel/Kconfig.instrumentation"
+
source "arch/avr32/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/avr32/Kconfig.debug b/arch/avr32/Kconfig.debug
index 64ace00..2283933 100644
--- a/arch/avr32/Kconfig.debug
+++ b/arch/avr32/Kconfig.debug
@@ -6,14 +6,4 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-config KPROBES
- bool "Kprobes"
- depends on DEBUG_KERNEL
- help
- Kprobes allows you to trap at almost any kernel address and
- execute a callback function. register_kprobe() establishes
- a probepoint and specifies the callback. Kprobes is useful
- for kernel debugging, non-intrusive instrumentation and testing.
- If in doubt, say "N".
-
endmenu
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 8791864..2d7bacd 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -16,7 +16,7 @@ KBUILD_AFLAGS += -mrelax -mno-pic
CFLAGS_MODULE += -mno-relax
LDFLAGS_vmlinux += --relax
-cpuflags-$(CONFIG_CPU_AT32AP7000) += -mcpu=ap7000
+cpuflags-$(CONFIG_PLATFORM_AT32AP) += -march=ap
KBUILD_CFLAGS += $(cpuflags-y)
KBUILD_AFLAGS += $(cpuflags-y)
@@ -31,6 +31,8 @@ core-$(CONFIG_BOARD_ATNGW100) += arch/avr32/boards/atngw100/
core-$(CONFIG_LOADER_U_BOOT) += arch/avr32/boot/u-boot/
core-y += arch/avr32/kernel/
core-y += arch/avr32/mm/
+drivers-$(CONFIG_OPROFILE) += arch/avr32/oprofile/
+drivers-y += arch/avr32/drivers/
libs-y += arch/avr32/lib/
archincdir-$(CONFIG_PLATFORM_AT32AP) := arch-at32ap
diff --git a/arch/avr32/boards/atngw100/Kconfig b/arch/avr32/boards/atngw100/Kconfig
new file mode 100644
index 0000000..5d922df
--- /dev/null
+++ b/arch/avr32/boards/atngw100/Kconfig
@@ -0,0 +1,12 @@
+# NGW100 customization
+
+config BOARD_ATNGW100_I2C_GPIO
+ bool "Use GPIO for i2c instead of built-in TWI module"
+ help
+ The driver for the built-in TWI module has been plagued by
+ various problems, while the i2c-gpio driver is based on the
+ trusty old i2c-algo-bit bitbanging engine, making it work
+ on pretty much any setup.
+
+ Choose 'Y' here if you're having i2c-related problems and
+ want to rule out the i2c bus driver.
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index 52987c8..383b825 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -20,7 +20,7 @@
#include <asm/io.h>
#include <asm/setup.h>
-#include <asm/arch/at32ap7000.h>
+#include <asm/arch/at32ap700x.h>
#include <asm/arch/board.h>
#include <asm/arch/init.h>
#include <asm/arch/portmux.h>
@@ -42,6 +42,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
},
};
+static struct mci_platform_data __initdata mci0_data = {
+ .detect_pin = GPIO_PIN_PC(25),
+ .wp_pin = GPIO_PIN_PE(0),
+};
+
/*
* The next two functions should go away as the boot loader is
* supposed to initialize the macb address registers with a valid
@@ -124,6 +129,7 @@ static struct platform_device ngw_gpio_leds = {
}
};
+#ifdef CONFIG_BOARD_ATNGW100_I2C_GPIO
static struct i2c_gpio_platform_data i2c_gpio_data = {
.sda_pin = GPIO_PIN_PA(6),
.scl_pin = GPIO_PIN_PA(7),
@@ -139,6 +145,7 @@ static struct platform_device i2c_gpio_device = {
.platform_data = &i2c_gpio_data,
},
};
+#endif
static int __init atngw100_init(void)
{
@@ -157,6 +164,7 @@ static int __init atngw100_init(void)
set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+ at32_add_device_mci(0, &mci0_data);
at32_add_device_usba(0, NULL);
for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
@@ -165,11 +173,15 @@ static int __init atngw100_init(void)
}
platform_device_register(&ngw_gpio_leds);
+#ifdef CONFIG_BOARD_ATNGW100_I2C_GPIO
at32_select_gpio(i2c_gpio_data.sda_pin,
AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
at32_select_gpio(i2c_gpio_data.scl_pin,
AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
platform_device_register(&i2c_gpio_device);
+#else
+ at32_add_device_twi(0);
+#endif
return 0;
}
diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
index 718578f..56a8d8e 100644
--- a/arch/avr32/boards/atstk1000/Kconfig
+++ b/arch/avr32/boards/atstk1000/Kconfig
@@ -1,34 +1,53 @@
# STK1000 customization
-if BOARD_ATSTK1002
+if BOARD_ATSTK1000
-config BOARD_ATSTK1002_CUSTOM
- bool "Non-default STK-1002 jumper settings"
+choice
+ prompt "ATSTK1000 CPU daughterboard type"
+ default BOARD_ATSTK1002
+
+config BOARD_ATSTK1002
+ bool "ATSTK1002"
+ select CPU_AT32AP7000
+
+config BOARD_ATSTK1003
+ bool "ATSTK1003"
+ select CPU_AT32AP7001
+
+config BOARD_ATSTK1004
+ bool "ATSTK1004"
+ select CPU_AT32AP7002
+
+endchoice
+
+
+config BOARD_ATSTK100X_CUSTOM
+ bool "Non-default STK1002/STK1003/STK1004 jumper settings"
help
You will normally leave the jumpers on the CPU card at their
default settings. If you need to use certain peripherals,
you will need to change some of those jumpers.
-if BOARD_ATSTK1002_CUSTOM
+if BOARD_ATSTK100X_CUSTOM
-config BOARD_ATSTK1002_SW1_CUSTOM
+config BOARD_ATSTK100X_SW1_CUSTOM
bool "SW1: use SSC1 (not SPI0)"
help
This also prevents using the external DAC as an audio interface,
and means you can't initialize the on-board QVGA display.
-config BOARD_ATSTK1002_SW2_CUSTOM
+config BOARD_ATSTK100X_SW2_CUSTOM
bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
help
If you change this you'll want an updated boot loader putting
the console on UART-C not UART-A.
-config BOARD_ATSTK1002_SW3_CUSTOM
+config BOARD_ATSTK100X_SW3_CUSTOM
bool "SW3: use TIMER1 (not SSC0 and GCLK)"
help
This also prevents using the external DAC as an audio interface.
-config BOARD_ATSTK1002_SW4_CUSTOM
+config BOARD_ATSTK100X_SW4_CUSTOM
bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
help
To use the camera interface you'll need a custom card (on the
@@ -36,27 +55,29 @@ config BOARD_ATSTK1002_SW4_CUSTOM
config BOARD_ATSTK1002_SW5_CUSTOM
bool "SW5: use MACB1 (not LCDC)"
+ depends on BOARD_ATSTK1002
config BOARD_ATSTK1002_SW6_CUSTOM
bool "SW6: more GPIOs (not MACB0)"
+ depends on BOARD_ATSTK1002
endif # custom
-config BOARD_ATSTK1002_SPI1
+config BOARD_ATSTK100X_SPI1
bool "Configure SPI1 controller"
- depends on !BOARD_ATSTK1002_SW4_CUSTOM
+ depends on !BOARD_ATSTK100X_SW4_CUSTOM
help
All the signals for the second SPI controller are available on
GPIO lines and accessed through the J1 jumper block. Say "y"
here to configure that SPI controller.
-config BOARD_ATSTK1002_J2_LED
+config BOARD_ATSTK1000_J2_LED
bool
- default BOARD_ATSTK1002_J2_LED8 || BOARD_ATSTK1002_J2_RGB
+ default BOARD_ATSTK1000_J2_LED8 || BOARD_ATSTK1000_J2_RGB
choice
prompt "LEDs connected to J2:"
- depends on LEDS_GPIO && !BOARD_ATSTK1002_SW4_CUSTOM
+ depends on LEDS_GPIO && !BOARD_ATSTK100X_SW4_CUSTOM
optional
help
Select this if you have jumpered the J2 jumper block to the
@@ -64,16 +85,64 @@ choice
IDC cable. A default "heartbeat" trigger is provided, but
you can of course override this.
-config BOARD_ATSTK1002_J2_LED8
+config BOARD_ATSTK1000_J2_LED8
bool "LED0..LED7"
help
Select this if J2 is jumpered to LED0..LED7 amber leds.
-config BOARD_ATSTK1002_J2_RGB
+config BOARD_ATSTK1000_J2_RGB
bool "RGB leds"
help
Select this if J2 is jumpered to the RGB leds.
endchoice
-endif # stk 1002
+config BOARD_ATSTK1000_EXTDAC
+ bool
+ depends on !BOARD_ATSTK100X_SW1_CUSTOM && !BOARD_ATSTK100X_SW3_CUSTOM
+ default y
+
+config BOARD_ATSTK100X_ENABLE_AC97
+ bool "Use AC97C instead of ABDAC"
+ help
+ Select this if you want to use the built-in AC97 controller
+ instead of the built-in Audio Bitstream DAC. These share
+ the same I/O pins on the AP7000, so both can't be enabled
+ at the same time.
+
+ Note that the STK1000 kit doesn't ship with an AC97 codec on
+ board, so say N unless you've got an expansion board with an
+ AC97 codec on it that you want to use.
+
+config BOARD_ATSTK1000_CF_HACKS
+ bool "ATSTK1000 CompactFlash hacks"
+ depends on !BOARD_ATSTK100X_SW4_CUSTOM
+ help
+ Select this if you have re-routed the CompactFlash RESET and
+ CD signals to GPIOs on your STK1000. This is necessary for
+ reset and card detection to work properly, although some CF
+ cards may be able to cope without reset.
+
+config BOARD_ATSTK1000_CF_RESET_PIN
+ hex "CompactFlash RESET pin"
+ default 0x30
+ depends on BOARD_ATSTK1000_CF_HACKS
+ help
+ Select which GPIO pin to use for the CompactFlash RESET
+ signal. This is specified as a hexadecimal number and should
+ be defined as 0x20 * gpio_port + pin.
+
+ The default is 0x30, which is pin 16 on PIOB, aka GPIO14.
+
+config BOARD_ATSTK1000_CF_DETECT_PIN
+ hex "CompactFlash DETECT pin"
+ default 0x3e
+ depends on BOARD_ATSTK1000_CF_HACKS
+ help
+ Select which GPIO pin to use for the CompactFlash CD
+ signal. This is specified as a hexadecimal number and should
+ be defined as 0x20 * gpio_port + pin.
+
+ The default is 0x3e, which is pin 30 on PIOB, aka GPIO15.
+
+endif # stk 1000
diff --git a/arch/avr32/boards/atstk1000/Makefile b/arch/avr32/boards/atstk1000/Makefile
index 8e09922..beead86 100644
--- a/arch/avr32/boards/atstk1000/Makefile
+++ b/arch/avr32/boards/atstk1000/Makefile
@@ -1,2 +1,4 @@
obj-y += setup.o flash.o
obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o
+obj-$(CONFIG_BOARD_ATSTK1003) += atstk1003.o
+obj-$(CONFIG_BOARD_ATSTK1004) += atstk1004.o
diff --git a/arch/avr32/boards/atstk1000/atstk1000.h b/arch/avr32/boards/atstk1000/atstk1000.h
index 9a49ed0..9392d32 100644
--- a/arch/avr32/boards/atstk1000/atstk1000.h
+++ b/arch/avr32/boards/atstk1000/atstk1000.h
@@ -12,4 +12,6 @@
extern struct atmel_lcdfb_info atstk1000_lcdc_data;
+void atstk1000_setup_j2_leds(void);
+
#endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 5be0d13..90436fa 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -11,7 +11,6 @@
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -22,7 +21,7 @@
#include <asm/io.h>
#include <asm/setup.h>
-#include <asm/arch/at32ap7000.h>
+#include <asm/arch/at32ap700x.h>
#include <asm/arch/board.h>
#include <asm/arch/init.h>
#include <asm/arch/portmux.h>
@@ -49,18 +48,16 @@ static struct eth_platform_data __initdata eth_data[2] = {
},
};
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
static struct at73c213_board_info at73c213_data = {
.ssc_id = 0,
.shortname = "AVR32 STK1000 external DAC",
};
#endif
-#endif
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
static struct spi_board_info spi0_board_info[] __initdata = {
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
{
/* AT73C213 */
.modalias = "at73c213",
@@ -80,12 +77,25 @@ static struct spi_board_info spi0_board_info[] __initdata = {
};
#endif
-#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
static struct spi_board_info spi1_board_info[] __initdata = { {
/* patch in custom entries here */
} };
#endif
+static struct cf_platform_data __initdata cf0_data = {
+#ifdef CONFIG_BOARD_ATSTK1000_CF_HACKS
+ .detect_pin = CONFIG_BOARD_ATSTK1000_CF_DETECT_PIN,
+ .reset_pin = CONFIG_BOARD_ATSTK1000_CF_RESET_PIN,
+#else
+ .detect_pin = GPIO_PIN_NONE,
+ .reset_pin = GPIO_PIN_NONE,
+#endif
+ .vcc_pin = GPIO_PIN_NONE,
+ .ready_pin = GPIO_PIN_PB(27),
+ .cs = 4,
+};
+
/*
* The next two functions should go away as the boot loader is
* supposed to initialize the macb address registers with a valid
@@ -141,68 +151,8 @@ static void __init set_hw_addr(struct platform_device *pdev)
clk_put(pclk);
}
-#ifdef CONFIG_BOARD_ATSTK1002_J2_LED
-
-static struct gpio_led stk_j2_led[] = {
-#ifdef CONFIG_BOARD_ATSTK1002_J2_LED8
-#define LEDSTRING "J2 jumpered to LED8"
- { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
- { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
- { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
- { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
- { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
- { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
- { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
- { .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
- .default_trigger = "heartbeat", },
-#else /* RGB */
-#define LEDSTRING "J2 jumpered to RGB LEDs"
- { .name = "r1:red", .gpio = GPIO_PIN_PB( 8), },
- { .name = "g1:green", .gpio = GPIO_PIN_PB(10), },
- { .name = "b1:blue", .gpio = GPIO_PIN_PB(14), },
-
- { .name = "r2:red", .gpio = GPIO_PIN_PB( 9),
- .default_trigger = "heartbeat", },
- { .name = "g2:green", .gpio = GPIO_PIN_PB(13), },
- { .name = "b2:blue", .gpio = GPIO_PIN_PB(15),
- .default_trigger = "heartbeat", },
- /* PB16, PB30 unused */
-#endif
-};
-
-static struct gpio_led_platform_data stk_j2_led_data = {
- .num_leds = ARRAY_SIZE(stk_j2_led),
- .leds = stk_j2_led,
-};
-
-static struct platform_device stk_j2_led_dev = {
- .name = "leds-gpio",
- .id = 2, /* gpio block J2 */
- .dev = {
- .platform_data = &stk_j2_led_data,
- },
-};
-
-static void setup_j2_leds(void)
-{
- unsigned i;
-
- for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++)
- at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
-
- printk("STK1002: " LEDSTRING "\n");
- platform_device_register(&stk_j2_led_dev);
-}
-
-#else
-static void setup_j2_leds(void)
-{
-}
-#endif
-
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-static void __init at73c213_set_clk(struct at73c213_board_info *info)
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static void __init atstk1002_setup_extdac(void)
{
struct clk *gclk;
struct clk *pll;
@@ -220,7 +170,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info)
}
at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
- info->dac_clk = gclk;
+ at73c213_data.dac_clk = gclk;
err_set_clk:
clk_put(pll);
@@ -229,12 +179,16 @@ err_pll:
err_gclk:
return;
}
-#endif
-#endif
+#else
+static void __init atstk1002_setup_extdac(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
void __init setup_board(void)
{
-#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */
#else
at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */
@@ -271,7 +225,7 @@ static int __init atstk1002_init(void)
at32_add_system_devices();
-#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
at32_add_device_usart(1);
#else
at32_add_device_usart(0);
@@ -281,12 +235,16 @@ static int __init atstk1002_init(void)
#ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
#endif
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
#endif
-#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
#endif
+ at32_add_device_twi(0);
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_add_device_mci(0, NULL);
+#endif
#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
#else
@@ -294,17 +252,18 @@ static int __init atstk1002_init(void)
fbmem_start, fbmem_size);
#endif
at32_add_device_usba(0, NULL);
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97
+ at32_add_device_ac97c(0);
+#else
+ at32_add_device_abdac(0);
+#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
at32_add_device_ssc(0, ATMEL_SSC_TX);
#endif
+ at32_add_device_cf(0, 2, &cf0_data);
- setup_j2_leds();
-
-#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
-#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
- at73c213_set_clk(&at73c213_data);
-#endif
-#endif
+ atstk1000_setup_j2_leds();
+ atstk1002_setup_extdac();
return 0;
}
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
new file mode 100644
index 0000000..768d204
--- /dev/null
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -0,0 +1,181 @@
+/*
+ * ATSTK1003 daughterboard-specific init code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/spi/at73c213.h>
+#include <linux/spi/spi.h>
+
+#include <asm/setup.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/board.h>
+#include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
+
+#include "atstk1000.h"
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static struct at73c213_board_info at73c213_data = {
+ .ssc_id = 0,
+ .shortname = "AVR32 STK1000 external DAC",
+};
+#endif
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+static struct spi_board_info spi0_board_info[] __initdata = {
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ {
+ /* AT73C213 */
+ .modalias = "at73c213",
+ .max_speed_hz = 200000,
+ .chip_select = 0,
+ .mode = SPI_MODE_1,
+ .platform_data = &at73c213_data,
+ },
+#endif
+ /*
+ * We can control the LTV350QV LCD panel, but it isn't much
+ * point since we don't have an LCD controller...
+ */
+};
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+ /* patch in custom entries here */
+} };
+#endif
+
+static struct cf_platform_data __initdata cf0_data = {
+#ifdef CONFIG_BOARD_ATSTK1000_CF_HACKS
+ .detect_pin = CONFIG_BOARD_ATSTK1000_CF_DETECT_PIN,
+ .reset_pin = CONFIG_BOARD_ATSTK1000_CF_RESET_PIN,
+#else
+ .detect_pin = GPIO_PIN_NONE,
+ .reset_pin = GPIO_PIN_NONE,
+#endif
+ .vcc_pin = GPIO_PIN_NONE,
+ .ready_pin = GPIO_PIN_PB(27),
+ .cs = 4,
+};
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static void __init atstk1003_setup_extdac(void)
+{
+ struct clk *gclk;
+ struct clk *pll;
+
+ gclk = clk_get(NULL, "gclk0");
+ if (IS_ERR(gclk))
+ goto err_gclk;
+ pll = clk_get(NULL, "pll0");
+ if (IS_ERR(pll))
+ goto err_pll;
+
+ if (clk_set_parent(gclk, pll)) {
+ pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
+ goto err_set_clk;
+ }
+
+ at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at73c213_data.dac_clk = gclk;
+
+err_set_clk:
+ clk_put(pll);
+err_pll:
+ clk_put(gclk);
+err_gclk:
+ return;
+}
+#else
+static void __init atstk1003_setup_extdac(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
+
+void __init setup_board(void)
+{
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+ at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */
+#endif
+ /* USART 2/unused: expansion connector */
+ at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */
+
+ at32_setup_serial_console(0);
+}
+
+static int __init atstk1003_init(void)
+{
+ /*
+ * ATSTK1000 uses 32-bit SDRAM interface. Reserve the
+ * SDRAM-specific pins so that nobody messes with them.
+ */
+ at32_reserve_pin(GPIO_PIN_PE(0)); /* DATA[16] */
+ at32_reserve_pin(GPIO_PIN_PE(1)); /* DATA[17] */
+ at32_reserve_pin(GPIO_PIN_PE(2)); /* DATA[18] */
+ at32_reserve_pin(GPIO_PIN_PE(3)); /* DATA[19] */
+ at32_reserve_pin(GPIO_PIN_PE(4)); /* DATA[20] */
+ at32_reserve_pin(GPIO_PIN_PE(5)); /* DATA[21] */
+ at32_reserve_pin(GPIO_PIN_PE(6)); /* DATA[22] */
+ at32_reserve_pin(GPIO_PIN_PE(7)); /* DATA[23] */
+ at32_reserve_pin(GPIO_PIN_PE(8)); /* DATA[24] */
+ at32_reserve_pin(GPIO_PIN_PE(9)); /* DATA[25] */
+ at32_reserve_pin(GPIO_PIN_PE(10)); /* DATA[26] */
+ at32_reserve_pin(GPIO_PIN_PE(11)); /* DATA[27] */
+ at32_reserve_pin(GPIO_PIN_PE(12)); /* DATA[28] */
+ at32_reserve_pin(GPIO_PIN_PE(13)); /* DATA[29] */
+ at32_reserve_pin(GPIO_PIN_PE(14)); /* DATA[30] */
+ at32_reserve_pin(GPIO_PIN_PE(15)); /* DATA[31] */
+ at32_reserve_pin(GPIO_PIN_PE(26)); /* SDCS */
+
+ at32_add_system_devices();
+
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_add_device_usart(1);
+#else
+ at32_add_device_usart(0);
+#endif
+ at32_add_device_usart(2);
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+ at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+ at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_add_device_mci(0, NULL);
+#endif
+ at32_add_device_usba(0, NULL);
+#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97
+ at32_add_device_ac97c(0);
+#else
+ at32_add_device_abdac(0);
+#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+ at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
+ at32_add_device_cf(0, 2, &cf0_data);
+
+ atstk1000_setup_j2_leds();
+ atstk1003_setup_extdac();
+
+ return 0;
+}
+postcore_initcall(atstk1003_init);
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
new file mode 100644
index 0000000..96015dd
--- /dev/null
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -0,0 +1,152 @@
+/*
+ * ATSTK1003 daughterboard-specific init code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/spi/at73c213.h>
+#include <linux/spi/spi.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/setup.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/board.h>
+#include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
+
+#include "atstk1000.h"
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static struct at73c213_board_info at73c213_data = {
+ .ssc_id = 0,
+ .shortname = "AVR32 STK1000 external DAC",
+};
+#endif
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+static struct spi_board_info spi0_board_info[] __initdata = {
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+ {
+ /* AT73C213 */
+ .modalias = "at73c213",
+ .max_speed_hz = 200000,
+ .chip_select = 0,
+ .mode = SPI_MODE_1,
+ .platform_data = &at73c213_data,
+ },
+#endif
+ {
+ /* QVGA display */
+ .modalias = "ltv350qv",
+ .max_speed_hz = 16000000,
+ .chip_select = 1,
+ .mode = SPI_MODE_3,
+ },
+};
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+ /* patch in custom entries here */
+} };
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
+static void __init atstk1004_setup_extdac(void)
+{
+ struct clk *gclk;
+ struct clk *pll;
+
+ gclk = clk_get(NULL, "gclk0");
+ if (IS_ERR(gclk))
+ goto err_gclk;
+ pll = clk_get(NULL, "pll0");
+ if (IS_ERR(pll))
+ goto err_pll;
+
+ if (clk_set_parent(gclk, pll)) {
+ pr_debug("STK1000: failed to set pll0 as parent for DAC clock\n");
+ goto err_set_clk;
+ }
+
+ at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ at73c213_data.dac_clk = gclk;
+
+err_set_clk:
+ clk_put(pll);
+err_pll:
+ clk_put(gclk);
+err_gclk:
+ return;
+}
+#else
+static void __init atstk1004_setup_extdac(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_EXTDAC */
+
+void __init setup_board(void)
+{
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+ at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */
+#endif
+ /* USART 2/unused: expansion connector */
+ at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */
+
+ at32_setup_serial_console(0);
+}
+
+static int __init atstk1004_init(void)
+{
+ at32_add_system_devices();
+
+#ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_add_device_usart(1);
+#else
+ at32_add_device_usart(0);
+#endif
+ at32_add_device_usart(2);
+
+#ifndef CONFIG_BOARD_ATSTK100X_SW1_CUSTOM
+ at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK100X_SPI1
+ at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+ at32_add_device_mci(0, NULL);
+#endif
+ at32_add_device_lcdc(0, &atstk1000_lcdc_data,
+ fbmem_start, fbmem_size);
+ at32_add_device_usba(0, NULL);
+#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97
+ at32_add_device_ac97c(0);
+#else
+ at32_add_device_abdac(0);
+#endif
+#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
+ at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
+
+ atstk1000_setup_j2_leds();
+ atstk1004_setup_extdac();
+
+ return 0;
+}
+postcore_initcall(atstk1004_init);
diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
index c9af409..8bedf93 100644
--- a/arch/avr32/boards/atstk1000/setup.c
+++ b/arch/avr32/boards/atstk1000/setup.c
@@ -10,13 +10,17 @@
#include <linux/bootmem.h>
#include <linux/fb.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/linkage.h>
#include <video/atmel_lcdc.h>
#include <asm/setup.h>
+
+#include <asm/arch/at32ap700x.h>
#include <asm/arch/board.h>
+#include <asm/arch/portmux.h>
#include "atstk1000.h"
@@ -61,3 +65,63 @@ struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
.default_monspecs = &atstk1000_default_monspecs,
.guard_time = 2,
};
+
+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED
+#include <linux/leds.h>
+
+static struct gpio_led stk1000_j2_led[] = {
+#ifdef CONFIG_BOARD_ATSTK1000_J2_LED8
+#define LEDSTRING "J2 jumpered to LED8"
+ { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), },
+ { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), },
+ { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), },
+ { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), },
+ { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), },
+ { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), },
+ { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), },
+ { .name = "led7:amber", .gpio = GPIO_PIN_PB(30),
+ .default_trigger = "heartbeat", },
+#else /* RGB */
+#define LEDSTRING "J2 jumpered to RGB LEDs"
+ { .name = "r1:red", .gpio = GPIO_PIN_PB( 8), },
+ { .name = "g1:green", .gpio = GPIO_PIN_PB(10), },
+ { .name = "b1:blue", .gpio = GPIO_PIN_PB(14), },
+
+ { .name = "r2:red", .gpio = GPIO_PIN_PB( 9),
+ .default_trigger = "heartbeat", },
+ { .name = "g2:green", .gpio = GPIO_PIN_PB(13), },
+ { .name = "b2:blue", .gpio = GPIO_PIN_PB(15),
+ .default_trigger = "heartbeat", },
+ /* PB16, PB30 unused */
+#endif
+};
+
+static struct gpio_led_platform_data stk1000_j2_led_data = {
+ .num_leds = ARRAY_SIZE(stk1000_j2_led),
+ .leds = stk1000_j2_led,
+};
+
+static struct platform_device stk1000_j2_led_dev = {
+ .name = "leds-gpio",
+ .id = 2, /* gpio block J2 */
+ .dev = {
+ .platform_data = &stk1000_j2_led_data,
+ },
+};
+
+void __init atstk1000_setup_j2_leds(void)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(stk1000_j2_led); i++)
+ at32_select_gpio(stk1000_j2_led[i].gpio, AT32_GPIOF_OUTPUT);
+
+ printk("STK1000: " LEDSTRING "\n");
+ platform_device_register(&stk1000_j2_led_dev);
+}
+#else /* CONFIG_BOARD_ATSTK1000_J2_LED */
+void __init atstk1000_setup_j2_leds(void)
+{
+
+}
+#endif /* CONFIG_BOARD_ATSTK1000_J2_LED */
diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
index b799a68..2ddc6f5 100644
--- a/arch/avr32/configs/atngw100_defconfig
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -1,46 +1,51 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc5
-# Sat Jun 23 15:40:05 2007
+# Linux kernel version: 2.6.24
+# Tue Feb 5 16:37:27 2008
#
CONFIG_AVR32=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_BUG=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_BLK_DEV_INITRD=y
@@ -61,35 +66,28 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_SLUB_DEBUG is not set
+CONFIG_SLUB_DEBUG=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -111,17 +109,20 @@ CONFIG_SUBARCH_AVR32B=y
CONFIG_MMU=y
CONFIG_PERFORMANCE_COUNTERS=y
CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
CONFIG_CPU_AT32AP7000=y
# CONFIG_BOARD_ATSTK1000 is not set
CONFIG_BOARD_ATNGW100=y
+CONFIG_BOARD_ATNGW100_I2C_GPIO=y
CONFIG_LOADER_U_BOOT=y
#
# Atmel AVR32 AP options
#
-# CONFIG_AP7000_32_BIT_SMC is not set
-CONFIG_AP7000_16_BIT_SMC=y
-# CONFIG_AP7000_8_BIT_SMC is not set
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_GPIO_DEV=y
CONFIG_LOAD_ADDRESS=0x10000000
CONFIG_ENTRY_ADDRESS=0x90000000
CONFIG_PHYS_OFFSET=0x10000000
@@ -141,10 +142,14 @@ CONFIG_FLATMEM_MANUAL=y
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_NMI_DEBUGGING is not set
+CONFIG_DW_DMAC=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
@@ -153,13 +158,31 @@ CONFIG_HZ=250
CONFIG_CMDLINE=""
#
-# Bus options
+# Power management options
#
-# CONFIG_ARCH_SUPPORTS_MSI is not set
#
-# PCCARD (PCMCIA/CardBus) support
+# CPU Frequency scaling
#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
# CONFIG_PCCARD is not set
#
@@ -213,6 +236,7 @@ CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -240,6 +264,7 @@ CONFIG_IPV6_SIT=y
# CONFIG_NETWORK_SECMARK is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
#
# Core Netfilter Configuration
@@ -252,6 +277,7 @@ CONFIG_NF_CONNTRACK_MARK=y
# CONFIG_NF_CONNTRACK_EVENTS is not set
CONFIG_NF_CT_PROTO_GRE=m
# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
@@ -269,9 +295,11 @@ CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NFLOG=m
# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
@@ -284,6 +312,7 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
@@ -292,6 +321,8 @@ CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
#
@@ -359,13 +390,19 @@ CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
+CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
# CONFIG_DECNET is not set
+CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
@@ -373,10 +410,6 @@ CONFIG_VLAN_8021Q=m
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
# CONFIG_NET_SCHED is not set
CONFIG_NET_CLS_ROUTE=y
@@ -384,6 +417,7 @@ CONFIG_NET_CLS_ROUTE=y
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
@@ -397,6 +431,7 @@ CONFIG_NET_CLS_ROUTE=y
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -405,16 +440,13 @@ CONFIG_NET_CLS_ROUTE=y
#
# Generic Driver Options
#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
@@ -434,6 +466,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
@@ -493,20 +526,8 @@ CONFIG_MTD_DATAFLASH=y
# UBI - Unsorted block images
#
# CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=m
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -517,11 +538,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+# CONFIG_MISC_DEVICES is not set
# CONFIG_IDE is not set
#
@@ -529,30 +546,42 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
# CONFIG_MD is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=m
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
+# CONFIG_MII is not set
CONFIG_MACB=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -571,21 +600,14 @@ CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_MPPE=m
CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
# CONFIG_SLIP is not set
CONFIG_SLHC=m
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -615,28 +637,57 @@ CONFIG_SLHC=m
#
CONFIG_SERIAL_ATMEL=y
CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_RTC is not set
# CONFIG_GEN_RTC is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
#
-# TPM devices
+# I2C Algorithms
#
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ATMELTWI=m
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
#
# SPI support
@@ -655,13 +706,25 @@ CONFIG_SPI_ATMEL=y
# SPI Protocol Masters
#
# CONFIG_SPI_AT25 is not set
-# CONFIG_SPI_SPIDEV is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
#
-# Dallas's 1-wire bus
+# Watchdog Device Drivers
#
-# CONFIG_W1 is not set
-# CONFIG_HWMON is not set
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
#
# Multifunction device drivers
@@ -678,23 +741,21 @@ CONFIG_SPI_ATMEL=y
#
# Graphics support
#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
#
# Sound
#
# CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
# CONFIG_USB_ARCH_HAS_EHCI is not set
@@ -706,12 +767,48 @@ CONFIG_SPI_ATMEL=y
#
# USB Gadget Support
#
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_ATMELMCI=y
+CONFIG_MMC_SPI=m
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
@@ -726,53 +823,71 @@ CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-
-
-#
-# LED drivers
-#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
#
-# LED Triggers
-#
-
-#
-# InfiniBand support
+# RTC interfaces
#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# I2C RTC drivers
#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
#
-# Real Time Clock
+# SPI RTC drivers
#
-# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
#
-# DMA Engine support
+# Platform RTC drivers
#
-# CONFIG_DMA_ENGINE is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
#
-# DMA Clients
+# on-CPU RTC drivers
#
+CONFIG_RTC_DRV_AT32AP700X=y
#
-# DMA Devices
+# Userspace I/O
#
+# CONFIG_UIO is not set
#
# File systems
#
-CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS=m
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS=m
# CONFIG_EXT3_FS_XATTR is not set
# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD=m
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
@@ -781,7 +896,8 @@ CONFIG_JBD=y
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
-# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
@@ -814,7 +930,6 @@ CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
CONFIG_CONFIGFS_FS=y
#
@@ -830,10 +945,12 @@ CONFIG_CONFIGFS_FS=y
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
# CONFIG_JFFS2_SUMMARY is not set
# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
@@ -842,19 +959,21 @@ CONFIG_JFFS2_RTIME=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_BIND34 is not set
@@ -871,23 +990,18 @@ CONFIG_CIFS=m
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
+CONFIG_NLS=m
CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=m
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
-CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_850=m
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
@@ -908,7 +1022,7 @@ CONFIG_NLS_CODEPAGE_850=y
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_1=m
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
@@ -921,18 +1035,19 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=y
-
-#
-# Distributed Lock Manager
-#
+CONFIG_NLS_UTF8=m
# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
#
# Kernel hacking
#
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
@@ -941,12 +1056,17 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -954,21 +1074,21 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
CONFIG_FRAME_POINTER=y
# CONFIG_FORCED_INLINING is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
-# CONFIG_KPROBES is not set
+# CONFIG_SAMPLES is not set
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
@@ -989,6 +1109,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
@@ -1002,15 +1123,14 @@ CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_ARC4=m
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
CONFIG_CRYPTO_DEFLATE=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_HW=y
#
# Library routines
@@ -1018,8 +1138,9 @@ CONFIG_CRYPTO_DEFLATE=y
CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
CONFIG_CRC32=y
+CONFIG_CRC7=m
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
index 3b977fd..46e1c78 100644
--- a/arch/avr32/configs/atstk1002_defconfig
+++ b/arch/avr32/configs/atstk1002_defconfig
@@ -1,48 +1,48 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc5
-# Sat Jun 23 15:32:08 2007
+# Linux kernel version: 2.6.24
+# Tue Feb 5 18:00:06 2008
#
CONFIG_AVR32=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_BUG=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-# CONFIG_TASK_XACCT is not set
-# CONFIG_UTS_NS is not set
-CONFIG_AUDIT=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
@@ -63,35 +63,28 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_SLUB_DEBUG is not set
+CONFIG_SLUB_DEBUG=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=1
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -99,12 +92,12 @@ CONFIG_BLOCK=y
CONFIG_IOSCHED_NOOP=y
# CONFIG_IOSCHED_AS is not set
# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_CFQ=y
# CONFIG_DEFAULT_AS is not set
# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-CONFIG_DEFAULT_NOOP=y
-CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
#
# System Type and features
@@ -113,18 +106,30 @@ CONFIG_SUBARCH_AVR32B=y
CONFIG_MMU=y
CONFIG_PERFORMANCE_COUNTERS=y
CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
CONFIG_CPU_AT32AP7000=y
-CONFIG_BOARD_ATSTK1002=y
CONFIG_BOARD_ATSTK1000=y
# CONFIG_BOARD_ATNGW100 is not set
+CONFIG_BOARD_ATSTK1002=y
+# CONFIG_BOARD_ATSTK1003 is not set
+# CONFIG_BOARD_ATSTK1004 is not set
+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
+# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
CONFIG_LOADER_U_BOOT=y
#
# Atmel AVR32 AP options
#
-# CONFIG_AP7000_32_BIT_SMC is not set
-CONFIG_AP7000_16_BIT_SMC=y
-# CONFIG_AP7000_8_BIT_SMC is not set
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_GPIO_DEV=y
CONFIG_LOAD_ADDRESS=0x10000000
CONFIG_ENTRY_ADDRESS=0x90000000
CONFIG_PHYS_OFFSET=0x10000000
@@ -144,10 +149,14 @@ CONFIG_FLATMEM_MANUAL=y
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
# CONFIG_OWNERSHIP_TRACE is not set
+CONFIG_NMI_DEBUGGING=y
+CONFIG_DW_DMAC=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
@@ -156,13 +165,31 @@ CONFIG_HZ=250
CONFIG_CMDLINE=""
#
-# Bus options
+# Power management options
#
-# CONFIG_ARCH_SUPPORTS_MSI is not set
#
-# PCCARD (PCMCIA/CardBus) support
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
# CONFIG_PCCARD is not set
#
@@ -182,7 +209,12 @@ CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
@@ -191,36 +223,52 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
+CONFIG_BRIDGE=m
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
+CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
@@ -228,16 +276,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
@@ -251,6 +296,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -259,16 +305,13 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
#
# Generic Driver Options
#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
@@ -288,6 +331,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
#
# RAM/ROM/Flash chip drivers
@@ -327,6 +371,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
#
# Self-contained MTD device drivers
#
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_M25P80=m
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
@@ -345,20 +391,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# UBI - Unsorted block images
#
# CONFIG_MTD_UBI is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=m
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -369,42 +403,88 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=m
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ATMEL_SSC=m
# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
-# CONFIG_ATA is not set
+# CONFIG_SCSI_PROC_FS is not set
#
-# Multi-device support (RAID and LVM)
+# SCSI support type (disk, tape, CD-ROM)
#
-# CONFIG_MD is not set
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
#
-# Network device support
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_AT32=m
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=m
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
+# CONFIG_MII is not set
CONFIG_MACB=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -423,27 +503,54 @@ CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
# CONFIG_SLIP is not set
CONFIG_SLHC=m
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
-# ISDN subsystem
+# Input device support
#
-# CONFIG_ISDN is not set
+CONFIG_INPUT=m
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=m
#
-# Telephony Support
+# Userland interfaces
#
-# CONFIG_PHONE is not set
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
#
-# Input device support
+# Input Device Drivers
#
-# CONFIG_INPUT is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_MOUSE_GPIO=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
@@ -467,40 +574,94 @@ CONFIG_SLHC=m
#
CONFIG_SERIAL_ATMEL=y
CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_RTC is not set
# CONFIG_GEN_RTC is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
#
-# TPM devices
+# I2C Algorithms
#
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ATMELTWI=m
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
#
# SPI support
#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
#
-# Dallas's 1-wire bus
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
#
# Multifunction device drivers
@@ -517,23 +678,104 @@ CONFIG_UNIX98_PTYS=y
#
# Graphics support
#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_LTV350QV=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
+# CONFIG_LOGO is not set
#
# Sound
#
-# CONFIG_SOUND is not set
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# AVR32 devices
+#
+CONFIG_SND_ATMEL_AC97=m
+
+#
+# SPI devices
+#
+CONFIG_SND_AT73C213=m
+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
#
-# USB support
+# Open Sound System
#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_AT32_ABDAC=m
+CONFIG_AC97_BUS=m
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
# CONFIG_USB_ARCH_HAS_EHCI is not set
@@ -545,63 +787,137 @@ CONFIG_UNIX98_PTYS=y
#
# USB Gadget Support
#
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_ATMELMCI=y
+CONFIG_MMC_SPI=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
#
# LED drivers
#
+CONFIG_LEDS_ATMEL_PWM=m
+CONFIG_LEDS_GPIO=m
#
# LED Triggers
#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
#
-# InfiniBand support
+# RTC interfaces
#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+# I2C RTC drivers
#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
#
-# Real Time Clock
+# SPI RTC drivers
#
-# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
#
-# DMA Engine support
+# Platform RTC drivers
#
-# CONFIG_DMA_ENGINE is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
#
-# DMA Clients
+# on-CPU RTC drivers
#
+CONFIG_RTC_DRV_AT32AP700X=y
#
-# DMA Devices
+# Userspace I/O
#
+# CONFIG_UIO is not set
#
# File systems
#
-CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
-CONFIG_MINIX_FS=m
+# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -609,7 +925,7 @@ CONFIG_INOTIFY_USER=y
# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
+CONFIG_FUSE_FS=m
#
# CD-ROM/DVD Filesystems
@@ -637,8 +953,7 @@ CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-CONFIG_CONFIGFS_FS=m
+CONFIG_CONFIGFS_FS=y
#
# Miscellaneous filesystems
@@ -652,11 +967,12 @@ CONFIG_CONFIGFS_FS=m
# CONFIG_EFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
-CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
# CONFIG_JFFS2_SUMMARY is not set
# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
@@ -665,10 +981,7 @@ CONFIG_JFFS2_RTIME=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
@@ -688,17 +1001,12 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
CONFIG_NLS=m
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=m
@@ -739,17 +1047,18 @@ CONFIG_NLS_ISO8859_1=m
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
CONFIG_NLS_UTF8=m
-
-#
-# Distributed Lock Manager
-#
# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
#
# Kernel hacking
#
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
@@ -758,12 +1067,17 @@ CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -771,22 +1085,63 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
CONFIG_FRAME_POINTER=y
CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
-# CONFIG_KPROBES is not set
+# CONFIG_SAMPLES is not set
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_HW is not set
#
# Library routines
@@ -794,10 +1149,10 @@ CONFIG_FORCED_INLINING=y
CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=m
# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC_ITU_T=m
CONFIG_CRC32=y
+CONFIG_CRC7=m
# CONFIG_LIBCRC32C is not set
-CONFIG_AUDIT_GENERIC=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig
new file mode 100644
index 0000000..d8a6595
--- /dev/null
+++ b/arch/avr32/configs/atstk1003_defconfig
@@ -0,0 +1,1032 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24
+# Tue Feb 5 18:08:36 2008
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+# CONFIG_TASK_XACCT is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type and features
+#
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
+CONFIG_CPU_AT32AP7001=y
+CONFIG_BOARD_ATSTK1000=y
+# CONFIG_BOARD_ATNGW100 is not set
+# CONFIG_BOARD_ATSTK1002 is not set
+CONFIG_BOARD_ATSTK1003=y
+# CONFIG_BOARD_ATSTK1004 is not set
+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED8 is not set
+# CONFIG_BOARD_ATSTK1000_J2_RGB is not set
+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
+# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+CONFIG_GPIO_DEV=y
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_OWNERSHIP_TRACE is not set
+CONFIG_NMI_DEBUGGING=y
+CONFIG_DW_DMAC=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_CMDLINE=""
+
+#
+# Power management options
+#
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=m
+CONFIG_MTD_M25P80=m
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=m
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ATMEL_SSC=m
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_AT32=m
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=m
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_MOUSE_GPIO=m
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_PDC=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_ATMELTWI=m
+CONFIG_I2C_GPIO=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# AVR32 devices
+#
+CONFIG_SND_ATMEL_AC97=m
+
+#
+# SPI devices
+#
+CONFIG_SND_AT73C213=m
+CONFIG_SND_AT73C213_TARGET_BITRATE=48000
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_ATMELMCI=y
+CONFIG_MMC_SPI=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_ATMEL_PWM=m
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_AT32AP700X=y
+
+#
+# Userspace I/O
+#
+CONFIG_UIO=m
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+CONFIG_CRC7=m
+# CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig
new file mode 100644
index 0000000..559b065
--- /dev/null
+++ b/arch/avr32/configs/atstk1004_defconfig
@@ -0,0 +1,627 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24
+# Tue Feb 5 18:13:33 2008
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
+CONFIG_SLOB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_MODULES is not set
+# CONFIG_BLOCK is not set
+
+#
+# System Type and features
+#
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP700X=y
+CONFIG_CPU_AT32AP7002=y
+CONFIG_BOARD_ATSTK1000=y
+# CONFIG_BOARD_ATNGW100 is not set
+# CONFIG_BOARD_ATSTK1002 is not set
+# CONFIG_BOARD_ATSTK1003 is not set
+CONFIG_BOARD_ATSTK1004=y
+# CONFIG_BOARD_ATSTK100X_CUSTOM is not set
+# CONFIG_BOARD_ATSTK100X_SPI1 is not set
+# CONFIG_BOARD_ATSTK1000_J2_LED is not set
+CONFIG_BOARD_ATSTK1000_EXTDAC=y
+# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set
+# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP700X_32_BIT_SMC is not set
+CONFIG_AP700X_16_BIT_SMC=y
+# CONFIG_AP700X_8_BIT_SMC is not set
+# CONFIG_GPIO_DEV is not set
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_NMI_DEBUGGING is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_CMDLINE=""
+
+#
+# Power management options
+#
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_AT32AP=y
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_MISC_DEVICES is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_PDC is not set
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT32AP700X_WDT=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_LTV350QV=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=y
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_AT32AP700X=y
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_WRITEBUFFER is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+# CONFIG_INSTRUMENTATION is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/avr32/drivers/Makefile b/arch/avr32/drivers/Makefile
new file mode 100644
index 0000000..b429b75
--- /dev/null
+++ b/arch/avr32/drivers/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DW_DMAC) += dw-dmac.o
diff --git a/arch/avr32/drivers/dw-dmac.c b/arch/avr32/drivers/dw-dmac.c
new file mode 100644
index 0000000..224eb30
--- /dev/null
+++ b/arch/avr32/drivers/dw-dmac.c
@@ -0,0 +1,761 @@
+/*
+ * Driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/dma-controller.h>
+#include <asm/io.h>
+
+#include "dw-dmac.h"
+
+#define DMAC_NR_CHANNELS 3
+#define DMAC_MAX_BLOCKSIZE 4095
+
+enum {
+ CH_STATE_FREE = 0,
+ CH_STATE_ALLOCATED,
+ CH_STATE_BUSY,
+};
+
+struct dw_dma_lli {
+ dma_addr_t sar;
+ dma_addr_t dar;
+ dma_addr_t llp;
+ u32 ctllo;
+ u32 ctlhi;
+ u32 sstat;
+ u32 dstat;
+};
+
+struct dw_dma_block {
+ struct dw_dma_lli *lli_vaddr;
+ dma_addr_t lli_dma_addr;
+};
+
+struct dw_dma_channel {
+ unsigned int state;
+ int is_cyclic;
+ struct dma_request_sg *req_sg;
+ struct dma_request_cyclic *req_cyclic;
+ unsigned int nr_blocks;
+ int direction;
+ struct dw_dma_block *block;
+};
+
+struct dw_dma_controller {
+ spinlock_t lock;
+ void * __iomem regs;
+ struct dma_pool *lli_pool;
+ struct clk *hclk;
+ struct dma_controller dma;
+ struct dw_dma_channel channel[DMAC_NR_CHANNELS];
+};
+#define to_dw_dmac(dmac) container_of(dmac, struct dw_dma_controller, dma)
+
+#define dmac_writel_hi(dmac, reg, value) \
+ __raw_writel((value), (dmac)->regs + DW_DMAC_##reg + 4)
+#define dmac_readl_hi(dmac, reg) \
+ __raw_readl((dmac)->regs + DW_DMAC_##reg + 4)
+#define dmac_writel_lo(dmac, reg, value) \
+ __raw_writel((value), (dmac)->regs + DW_DMAC_##reg)
+#define dmac_readl_lo(dmac, reg) \
+ __raw_readl((dmac)->regs + DW_DMAC_##reg)
+#define dmac_chan_writel_hi(dmac, chan, reg, value) \
+ __raw_writel((value), ((dmac)->regs + 0x58 * (chan) \
+ + DW_DMAC_CHAN_##reg + 4))
+#define dmac_chan_readl_hi(dmac, chan, reg) \
+ __raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg + 4)
+#define dmac_chan_writel_lo(dmac, chan, reg, value) \
+ __raw_writel((value), (dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
+#define dmac_chan_readl_lo(dmac, chan, reg) \
+ __raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
+#define set_channel_bit(dmac, reg, chan) \
+ dmac_writel_lo(dmac, reg, (1 << (chan)) | (1 << ((chan) + 8)))
+#define clear_channel_bit(dmac, reg, chan) \
+ dmac_writel_lo(dmac, reg, (0 << (chan)) | (1 << ((chan) + 8)))
+
+static int dmac_alloc_channel(struct dma_controller *_dmac)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+ struct dw_dma_channel *chan;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dmac->lock, flags);
+ for (i = 0; i < DMAC_NR_CHANNELS; i++)
+ if (dmac->channel[i].state == CH_STATE_FREE)
+ break;
+
+ if (i < DMAC_NR_CHANNELS) {
+ chan = &dmac->channel[i];
+ chan->state = CH_STATE_ALLOCATED;
+ } else {
+ i = -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&dmac->lock, flags);
+
+ return i;
+}
+
+static void dmac_release_channel(struct dma_controller *_dmac, int channel)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+
+ BUG_ON(channel >= DMAC_NR_CHANNELS
+ || dmac->channel[channel].state != CH_STATE_ALLOCATED);
+
+ dmac->channel[channel].state = CH_STATE_FREE;
+}
+
+static struct dw_dma_block *allocate_blocks(struct dw_dma_controller *dmac,
+ unsigned int nr_blocks)
+{
+ struct dw_dma_block *block;
+ void *p;
+ unsigned int i;
+
+ block = kmalloc(nr_blocks * sizeof(*block),
+ GFP_KERNEL);
+ if (unlikely(!block))
+ return NULL;
+
+ for (i = 0; i < nr_blocks; i++) {
+ p = dma_pool_alloc(dmac->lli_pool, GFP_KERNEL,
+ &block[i].lli_dma_addr);
+ block[i].lli_vaddr = p;
+ if (unlikely(!p))
+ goto fail;
+ }
+
+ return block;
+
+fail:
+ for (i = 0; i < nr_blocks; i++) {
+ if (!block[i].lli_vaddr)
+ break;
+ dma_pool_free(dmac->lli_pool, block[i].lli_vaddr,
+ block[i].lli_dma_addr);
+ }
+ kfree(block);
+ return NULL;
+}
+
+static void cleanup_channel(struct dw_dma_controller *dmac,
+ struct dw_dma_channel *chan)
+{
+ unsigned int i;
+
+ if (chan->nr_blocks > 1) {
+ for (i = 0; i < chan->nr_blocks; i++)
+ dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr,
+ chan->block[i].lli_dma_addr);
+ kfree(chan->block);
+ }
+
+ chan->state = CH_STATE_ALLOCATED;
+}
+
+static int dmac_prepare_request_sg(struct dma_controller *_dmac,
+ struct dma_request_sg *req)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+ struct dw_dma_channel *chan;
+ unsigned long ctlhi, ctllo, cfghi, cfglo;
+ unsigned long block_size;
+ unsigned int nr_blocks;
+ int ret, i, direction;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dmac->lock, flags);
+
+ ret = -EINVAL;
+ if (req->req.channel >= DMAC_NR_CHANNELS
+ || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
+ || req->block_size > DMAC_MAX_BLOCKSIZE) {
+ spin_unlock_irqrestore(&dmac->lock, flags);
+ return -EINVAL;
+ }
+
+ chan = &dmac->channel[req->req.channel];
+ chan->state = CH_STATE_BUSY;
+ chan->req_sg = req;
+ chan->is_cyclic = 0;
+
+ /*
+ * We have marked the channel as busy, so no need to keep the
+ * lock as long as we only touch the channel-specific
+ * registers
+ */
+ spin_unlock_irqrestore(&dmac->lock, flags);
+
+ /*
+ * There may be limitations in the driver and/or the DMA
+ * controller that prevents us from sending a whole
+ * scatterlist item in one go. Taking this into account,
+ * calculate the number of block transfers we need to set up.
+ *
+ * FIXME: Let the peripheral driver know about the maximum
+ * block size we support. We really don't want to use a
+ * different block size than what was suggested by the
+ * peripheral.
+ *
+ * Each block will get its own Linked List Item (LLI) below.
+ */
+ block_size = req->block_size;
+ nr_blocks = req->nr_blocks;
+ pr_debug("block_size %lu, nr_blocks %u nr_sg = %u\n",
+ block_size, nr_blocks, req->nr_sg);
+
+ BUG_ON(nr_blocks == 0);
+ chan->nr_blocks = nr_blocks;
+
+ ret = -EINVAL;
+ cfglo = cfghi = 0;
+ switch (req->direction) {
+ case DMA_DIR_MEM_TO_PERIPH:
+ direction = DMA_TO_DEVICE;
+ cfghi = req->periph_id << (43 - 32);
+ break;
+
+ case DMA_DIR_PERIPH_TO_MEM:
+ direction = DMA_FROM_DEVICE;
+ cfghi = req->periph_id << (39 - 32);
+ break;
+ default:
+ goto out_unclaim_channel;
+ }
+
+ chan->direction = direction;
+
+ dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
+ dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
+
+ ctlhi = block_size >> req->width;
+ ctllo = ((req->direction << 20)
+ // | (1 << 14) | (1 << 11) // source/dest burst trans len
+ | (req->width << 4) | (req->width << 1)
+ | (1 << 0)); // interrupt enable
+
+ if (nr_blocks == 1) {
+ /* Only one block: No need to use block chaining */
+ if (direction == DMA_TO_DEVICE) {
+ dmac_chan_writel_lo(dmac, req->req.channel, SAR,
+ req->sg->dma_address);
+ dmac_chan_writel_lo(dmac, req->req.channel, DAR,
+ req->data_reg);
+ ctllo |= 2 << 7; // no dst increment
+ } else {
+ dmac_chan_writel_lo(dmac, req->req.channel, SAR,
+ req->data_reg);
+ dmac_chan_writel_lo(dmac, req->req.channel, DAR,
+ req->sg->dma_address);
+ ctllo |= 2 << 9; // no src increment
+ }
+ dmac_chan_writel_lo(dmac, req->req.channel, CTL, ctllo);
+ dmac_chan_writel_hi(dmac, req->req.channel, CTL, ctlhi);
+ pr_debug("ctl hi:lo 0x%lx:%lx\n", ctlhi, ctllo);
+ } else {
+ struct dw_dma_lli *lli, *lli_prev = NULL;
+ int j = 0, offset = 0;
+
+ ret = -ENOMEM;
+ chan->block = allocate_blocks(dmac, nr_blocks);
+ if (!chan->block)
+ goto out_unclaim_channel;
+
+ if (direction == DMA_TO_DEVICE)
+ ctllo |= 1 << 28 | 1 << 27 | 2 << 7;
+ else
+ ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
+
+ /*
+ * Map scatterlist items to blocks. One scatterlist
+ * item may need more than one block for the reasons
+ * mentioned above.
+ */
+ for (i = 0; i < nr_blocks; i++) {
+ lli = chan->block[i].lli_vaddr;
+ if (lli_prev) {
+ lli_prev->llp = chan->block[i].lli_dma_addr;
+ pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ i - 1, chan->block[i - 1].lli_vaddr,
+ chan->block[i - 1].lli_dma_addr,
+ lli_prev->sar, lli_prev->dar, lli_prev->llp,
+ lli_prev->ctllo, lli_prev->ctlhi);
+ }
+ lli->llp = 0;
+ lli->ctllo = ctllo;
+ lli->ctlhi = ctlhi;
+ if (direction == DMA_TO_DEVICE) {
+ lli->sar = req->sg[j].dma_address + offset;
+ lli->dar = req->data_reg;
+ } else {
+ lli->sar = req->data_reg;
+ lli->dar = req->sg[j].dma_address + offset;
+ }
+ lli_prev = lli;
+
+ offset += block_size;
+ if (offset > req->sg[j].length) {
+ j++;
+ offset = 0;
+ }
+ }
+
+ pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ i - 1, chan->block[i - 1].lli_vaddr,
+ chan->block[i - 1].lli_dma_addr, lli_prev->sar,
+ lli_prev->dar, lli_prev->llp,
+ lli_prev->ctllo, lli_prev->ctlhi);
+
+ /*
+ * SAR, DAR and CTL are initialized from the LLI. We
+ * only have to enable the LLI bits in CTL.
+ */
+ dmac_chan_writel_hi(dmac, req->req.channel, CTL, 0);
+ dmac_chan_writel_lo(dmac, req->req.channel, LLP,
+ chan->block[0].lli_dma_addr);
+ dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27);
+ }
+
+ set_channel_bit(dmac, MASK_XFER, req->req.channel);
+ set_channel_bit(dmac, MASK_ERROR, req->req.channel);
+ if (req->req.block_complete)
+ set_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+ else
+ clear_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+
+ return 0;
+
+out_unclaim_channel:
+ chan->state = CH_STATE_ALLOCATED;
+ return ret;
+}
+
+static int dmac_prepare_request_cyclic(struct dma_controller *_dmac,
+ struct dma_request_cyclic *req)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+ struct dw_dma_channel *chan;
+ unsigned long ctlhi, ctllo, cfghi, cfglo;
+ unsigned long block_size;
+ int ret, i, direction;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dmac->lock, flags);
+
+ block_size = (req->buffer_size/req->periods) >> req->width;
+
+ ret = -EINVAL;
+ if (req->req.channel >= DMAC_NR_CHANNELS
+ || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
+ || (req->periods == 0)
+ || block_size > DMAC_MAX_BLOCKSIZE) {
+ spin_unlock_irqrestore(&dmac->lock, flags);
+ return -EINVAL;
+ }
+
+ chan = &dmac->channel[req->req.channel];
+ chan->state = CH_STATE_BUSY;
+ chan->is_cyclic = 1;
+ chan->req_cyclic = req;
+
+ /*
+ * We have marked the channel as busy, so no need to keep the
+ * lock as long as we only touch the channel-specific
+ * registers
+ */
+ spin_unlock_irqrestore(&dmac->lock, flags);
+
+ /*
+ Setup
+ */
+ BUG_ON(req->buffer_size % req->periods);
+ /* printk(KERN_INFO "block_size = %lu, periods = %u\n", block_size, req->periods); */
+
+ chan->nr_blocks = req->periods;
+
+ ret = -EINVAL;
+ cfglo = cfghi = 0;
+ switch (req->direction) {
+ case DMA_DIR_MEM_TO_PERIPH:
+ direction = DMA_TO_DEVICE;
+ cfghi = req->periph_id << (43 - 32);
+ break;
+
+ case DMA_DIR_PERIPH_TO_MEM:
+ direction = DMA_FROM_DEVICE;
+ cfghi = req->periph_id << (39 - 32);
+ break;
+ default:
+ goto out_unclaim_channel;
+ }
+
+ chan->direction = direction;
+
+ dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
+ dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
+
+ ctlhi = block_size;
+ ctllo = ((req->direction << 20)
+ | (req->width << 4) | (req->width << 1)
+ | (1 << 0)); // interrupt enable
+
+ {
+ struct dw_dma_lli *lli = NULL, *lli_prev = NULL;
+
+ ret = -ENOMEM;
+ chan->block = allocate_blocks(dmac, req->periods);
+ if (!chan->block)
+ goto out_unclaim_channel;
+
+ if (direction == DMA_TO_DEVICE)
+ ctllo |= 1 << 28 | 1 << 27 | 2 << 7;
+ else
+ ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
+
+ /*
+ * Set up a linked list items where each period gets
+ * an item. The linked list item for the last period
+ * points back to the star of the buffer making a
+ * cyclic buffer.
+ */
+ for (i = 0; i < req->periods; i++) {
+ lli = chan->block[i].lli_vaddr;
+ if (lli_prev) {
+ lli_prev->llp = chan->block[i].lli_dma_addr;
+ /* printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ i - 1, chan->block[i - 1].lli_vaddr,
+ chan->block[i - 1].lli_dma_addr,
+ lli_prev->sar, lli_prev->dar, lli_prev->llp,
+ lli_prev->ctllo, lli_prev->ctlhi);*/
+ }
+ lli->llp = 0;
+ lli->ctllo = ctllo;
+ lli->ctlhi = ctlhi;
+ if (direction == DMA_TO_DEVICE) {
+ lli->sar = req->buffer_start + i*(block_size << req->width);
+ lli->dar = req->data_reg;
+ } else {
+ lli->sar = req->data_reg;
+ lli->dar = req->buffer_start + i*(block_size << req->width);
+ }
+ lli_prev = lli;
+ }
+ lli->llp = chan->block[0].lli_dma_addr;
+
+ /*printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ i - 1, chan->block[i - 1].lli_vaddr,
+ chan->block[i - 1].lli_dma_addr, lli_prev->sar,
+ lli_prev->dar, lli_prev->llp,
+ lli_prev->ctllo, lli_prev->ctlhi); */
+
+ /*
+ * SAR, DAR and CTL are initialized from the LLI. We
+ * only have to enable the LLI bits in CTL.
+ */
+ dmac_chan_writel_lo(dmac, req->req.channel, LLP,
+ chan->block[0].lli_dma_addr);
+ dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27);
+ }
+
+ clear_channel_bit(dmac, MASK_XFER, req->req.channel);
+ set_channel_bit(dmac, MASK_ERROR, req->req.channel);
+ if (req->req.block_complete)
+ set_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+ else
+ clear_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+
+ return 0;
+
+out_unclaim_channel:
+ chan->state = CH_STATE_ALLOCATED;
+ return ret;
+}
+
+static int dmac_start_request(struct dma_controller *_dmac,
+ unsigned int channel)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+
+ BUG_ON(channel >= DMAC_NR_CHANNELS);
+
+ set_channel_bit(dmac, CH_EN, channel);
+
+ return 0;
+}
+
+static dma_addr_t dmac_get_current_pos(struct dma_controller *_dmac,
+ unsigned int channel)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+ struct dw_dma_channel *chan;
+ dma_addr_t current_pos;
+
+ BUG_ON(channel >= DMAC_NR_CHANNELS);
+
+ chan = &dmac->channel[channel];
+
+ switch (chan->direction) {
+ case DMA_TO_DEVICE:
+ current_pos = dmac_chan_readl_lo(dmac, channel, SAR);
+ break;
+ case DMA_FROM_DEVICE:
+ current_pos = dmac_chan_readl_lo(dmac, channel, DAR);
+ break;
+ default:
+ return 0;
+ }
+
+
+ if (!current_pos) {
+ if (chan->is_cyclic) {
+ current_pos = chan->req_cyclic->buffer_start;
+ } else {
+ current_pos = chan->req_sg->sg->dma_address;
+ }
+ }
+
+ return current_pos;
+}
+
+
+static int dmac_stop_request(struct dma_controller *_dmac,
+ unsigned int channel)
+{
+ struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+ struct dw_dma_channel *chan;
+
+ BUG_ON(channel >= DMAC_NR_CHANNELS);
+
+ chan = &dmac->channel[channel];
+ pr_debug("stop: st%u s%08x d%08x l%08x ctl0x%08x:0x%08x\n",
+ chan->state, dmac_chan_readl_lo(dmac, channel, SAR),
+ dmac_chan_readl_lo(dmac, channel, DAR),
+ dmac_chan_readl_lo(dmac, channel, LLP),
+ dmac_chan_readl_hi(dmac, channel, CTL),
+ dmac_chan_readl_lo(dmac, channel, CTL));
+
+ if (chan->state == CH_STATE_BUSY) {
+ clear_channel_bit(dmac, CH_EN, channel);
+ cleanup_channel(dmac, &dmac->channel[channel]);
+ }
+
+ return 0;
+}
+
+
+static void dmac_block_complete(struct dw_dma_controller *dmac)
+{
+ struct dw_dma_channel *chan;
+ unsigned long status, chanid;
+
+ status = dmac_readl_lo(dmac, STATUS_BLOCK);
+
+ while (status) {
+ struct dma_request *req;
+ chanid = __ffs(status);
+ chan = &dmac->channel[chanid];
+
+ if (chan->is_cyclic) {
+ BUG_ON(!chan->req_cyclic
+ || !chan->req_cyclic->req.block_complete);
+ req = &chan->req_cyclic->req;
+ } else {
+ BUG_ON(!chan->req_sg || !chan->req_sg->req.block_complete);
+ req = &chan->req_sg->req;
+ }
+ dmac_writel_lo(dmac, CLEAR_BLOCK, 1 << chanid);
+ req->block_complete(req);
+ status = dmac_readl_lo(dmac, STATUS_BLOCK);
+ }
+}
+
+static void dmac_xfer_complete(struct dw_dma_controller *dmac)
+{
+ struct dw_dma_channel *chan;
+ struct dma_request *req;
+ unsigned long status, chanid;
+
+ status = dmac_readl_lo(dmac, STATUS_XFER);
+
+ while (status) {
+ chanid = __ffs(status);
+ chan = &dmac->channel[chanid];
+
+ dmac_writel_lo(dmac, CLEAR_XFER, 1 << chanid);
+
+ req = &chan->req_sg->req;
+ BUG_ON(!req);
+ cleanup_channel(dmac, chan);
+ if (req->xfer_complete)
+ req->xfer_complete(req);
+
+ status = dmac_readl_lo(dmac, STATUS_XFER);
+ }
+}
+
+static void dmac_error(struct dw_dma_controller *dmac)
+{
+ struct dw_dma_channel *chan;
+ unsigned long status, chanid;
+
+ status = dmac_readl_lo(dmac, STATUS_ERROR);
+
+ while (status) {
+ struct dma_request *req;
+
+ chanid = __ffs(status);
+ chan = &dmac->channel[chanid];
+
+ dmac_writel_lo(dmac, CLEAR_ERROR, 1 << chanid);
+ clear_channel_bit(dmac, CH_EN, chanid);
+
+ if (chan->is_cyclic) {
+ BUG_ON(!chan->req_cyclic);
+ req = &chan->req_cyclic->req;
+ } else {
+ BUG_ON(!chan->req_sg);
+ req = &chan->req_sg->req;
+ }
+
+ cleanup_channel(dmac, chan);
+ if (req->error)
+ req->error(req);
+
+ status = dmac_readl_lo(dmac, STATUS_XFER);
+ }
+}
+
+static irqreturn_t dmac_interrupt(int irq, void *dev_id)
+{
+ struct dw_dma_controller *dmac = dev_id;
+ unsigned long status;
+ int ret = IRQ_NONE;
+
+ spin_lock(&dmac->lock);
+
+ status = dmac_readl_lo(dmac, STATUS_INT);
+
+ while (status) {
+ ret = IRQ_HANDLED;
+ if (status & 0x10)
+ dmac_error(dmac);
+ if (status & 0x02)
+ dmac_block_complete(dmac);
+ if (status & 0x01)
+ dmac_xfer_complete(dmac);
+
+ status = dmac_readl_lo(dmac, STATUS_INT);
+ }
+
+ spin_unlock(&dmac->lock);
+ return ret;
+}
+
+static int __devinit dmac_probe(struct platform_device *pdev)
+{
+ struct dw_dma_controller *dmac;
+ struct resource *regs;
+ int ret;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+
+ dmac = kmalloc(sizeof(*dmac), GFP_KERNEL);
+ if (!dmac)
+ return -ENOMEM;
+ memset(dmac, 0, sizeof(*dmac));
+
+ dmac->hclk = clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(dmac->hclk)) {
+ ret = PTR_ERR(dmac->hclk);
+ goto out_free_dmac;
+ }
+ clk_enable(dmac->hclk);
+
+ ret = -ENOMEM;
+ dmac->lli_pool = dma_pool_create("dmac", &pdev->dev,
+ sizeof(struct dw_dma_lli), 4, 0);
+ if (!dmac->lli_pool)
+ goto out_disable_clk;
+
+ spin_lock_init(&dmac->lock);
+ dmac->dma.dev = &pdev->dev;
+ dmac->dma.alloc_channel = dmac_alloc_channel;
+ dmac->dma.release_channel = dmac_release_channel;
+ dmac->dma.prepare_request_sg = dmac_prepare_request_sg;
+ dmac->dma.prepare_request_cyclic = dmac_prepare_request_cyclic;
+ dmac->dma.start_request = dmac_start_request;
+ dmac->dma.stop_request = dmac_stop_request;
+ dmac->dma.get_current_pos = dmac_get_current_pos;
+
+ dmac->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!dmac->regs)
+ goto out_free_pool;
+
+ ret = request_irq(platform_get_irq(pdev, 0), dmac_interrupt,
+ IRQF_SAMPLE_RANDOM, pdev->name, dmac);
+ if (ret)
+ goto out_unmap_regs;
+
+ /* Enable the DMA controller */
+ dmac_writel_lo(dmac, CFG, 1);
+
+ register_dma_controller(&dmac->dma);
+
+ printk(KERN_INFO
+ "dmac%d: DesignWare DMA controller at 0x%p irq %d\n",
+ dmac->dma.id, dmac->regs, platform_get_irq(pdev, 0));
+
+ return 0;
+
+out_unmap_regs:
+ iounmap(dmac->regs);
+out_free_pool:
+ dma_pool_destroy(dmac->lli_pool);
+out_disable_clk:
+ clk_disable(dmac->hclk);
+ clk_put(dmac->hclk);
+out_free_dmac:
+ kfree(dmac);
+ return ret;
+}
+
+static struct platform_driver dmac_driver = {
+ .probe = dmac_probe,
+ .driver = {
+ .name = "dmaca",
+ },
+};
+
+static int __init dmac_init(void)
+{
+ return platform_driver_register(&dmac_driver);
+}
+subsys_initcall(dmac_init);
+
+static void __exit dmac_exit(void)
+{
+ platform_driver_unregister(&dmac_driver);
+}
+module_exit(dmac_exit);
+
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/avr32/drivers/dw-dmac.h b/arch/avr32/drivers/dw-dmac.h
new file mode 100644
index 0000000..1f67921
--- /dev/null
+++ b/arch/avr32/drivers/dw-dmac.h
@@ -0,0 +1,42 @@
+/*
+ * Driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __AVR32_DW_DMAC_H__
+#define __AVR32_DW_DMAC_H__
+
+#define DW_DMAC_CFG 0x398
+#define DW_DMAC_CH_EN 0x3a0
+
+#define DW_DMAC_STATUS_XFER 0x2e8
+#define DW_DMAC_STATUS_BLOCK 0x2f0
+#define DW_DMAC_STATUS_ERROR 0x308
+
+#define DW_DMAC_MASK_XFER 0x310
+#define DW_DMAC_MASK_BLOCK 0x318
+#define DW_DMAC_MASK_ERROR 0x330
+
+#define DW_DMAC_CLEAR_XFER 0x338
+#define DW_DMAC_CLEAR_BLOCK 0x340
+#define DW_DMAC_CLEAR_ERROR 0x358
+
+#define DW_DMAC_STATUS_INT 0x360
+
+#define DW_DMAC_CHAN_SAR 0x000
+#define DW_DMAC_CHAN_DAR 0x008
+#define DW_DMAC_CHAN_LLP 0x010
+#define DW_DMAC_CHAN_CTL 0x018
+#define DW_DMAC_CHAN_SSTAT 0x020
+#define DW_DMAC_CHAN_DSTAT 0x028
+#define DW_DMAC_CHAN_SSTATAR 0x030
+#define DW_DMAC_CHAN_DSTATAR 0x038
+#define DW_DMAC_CHAN_CFG 0x040
+#define DW_DMAC_CHAN_SGR 0x048
+#define DW_DMAC_CHAN_DSR 0x050
+
+#endif /* __AVR32_DW_DMAC_H__ */
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile
index 2d6d48f..88226b6 100644
--- a/arch/avr32/kernel/Makefile
+++ b/arch/avr32/kernel/Makefile
@@ -6,9 +6,11 @@ extra-y := head.o vmlinux.lds
obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o
obj-y += syscall_table.o syscall-stubs.o irq.o
-obj-y += setup.o traps.o semaphore.o ptrace.o
+obj-y += setup.o traps.o semaphore.o ocd.o ptrace.o
obj-y += signal.o sys_avr32.o process.o time.o
obj-y += init_task.o switch_to.o cpu.o
+obj-y += dma-controller.o
obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
+obj-$(CONFIG_NMI_DEBUGGING) += nmi_debug.o
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 2714cf6..b8409ca 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -13,6 +13,7 @@
#include <linux/percpu.h>
#include <linux/param.h>
#include <linux/errno.h>
+#include <linux/clk.h>
#include <asm/setup.h>
#include <asm/sysreg.h>
@@ -187,9 +188,20 @@ static int __init topology_init(void)
subsys_initcall(topology_init);
+struct chip_id_map {
+ u16 mid;
+ u16 pn;
+ const char *name;
+};
+
+static const struct chip_id_map chip_names[] = {
+ { .mid = 0x1f, .pn = 0x1e82, .name = "AT32AP700x" },
+};
+#define NR_CHIP_NAMES ARRAY_SIZE(chip_names)
+
static const char *cpu_names[] = {
"Morgan",
- "AP7000",
+ "AP7",
};
#define NR_CPU_NAMES ARRAY_SIZE(cpu_names)
@@ -206,12 +218,32 @@ static const char *mmu_types[] = {
"MPU"
};
+static const char *cpu_feature_flags[] = {
+ "rmw", "dsp", "simd", "ocd", "perfctr", "java", "fpu",
+};
+
+static const char *get_chip_name(struct avr32_cpuinfo *cpu)
+{
+ unsigned int i;
+ unsigned int mid = avr32_get_manufacturer_id(cpu);
+ unsigned int pn = avr32_get_product_number(cpu);
+
+ for (i = 0; i < NR_CHIP_NAMES; i++) {
+ if (chip_names[i].mid == mid && chip_names[i].pn == pn)
+ return chip_names[i].name;
+ }
+
+ return "(unknown)";
+}
+
void __init setup_processor(void)
{
unsigned long config0, config1;
unsigned long features;
unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
+ unsigned device_id;
unsigned tmp;
+ unsigned i;
config0 = sysreg_read(CONFIG0);
config1 = sysreg_read(CONFIG1);
@@ -221,11 +253,14 @@ void __init setup_processor(void)
arch_rev = SYSREG_BFEXT(AR, config0);
mmu_type = SYSREG_BFEXT(MMUT, config0);
+ device_id = ocd_read(DID);
+
boot_cpu_data.arch_type = arch_id;
boot_cpu_data.cpu_type = cpu_id;
boot_cpu_data.arch_revision = arch_rev;
boot_cpu_data.cpu_revision = cpu_rev;
boot_cpu_data.tlb_config = mmu_type;
+ boot_cpu_data.device_id = device_id;
tmp = SYSREG_BFEXT(ILSZ, config1);
if (tmp) {
@@ -247,41 +282,34 @@ void __init setup_processor(void)
return;
}
- printk ("CPU: %s [%02x] revision %d (%s revision %d)\n",
+ printk ("CPU: %s chip revision %c\n", get_chip_name(&boot_cpu_data),
+ avr32_get_chip_revision(&boot_cpu_data) + 'A');
+ printk ("CPU: %s [%02x] core revision %d (%s arch revision %d)\n",
cpu_names[cpu_id], cpu_id, cpu_rev,
arch_names[arch_id], arch_rev);
printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
printk ("CPU: features:");
features = 0;
- if (config0 & SYSREG_BIT(CONFIG0_R)) {
+ if (config0 & SYSREG_BIT(CONFIG0_R))
features |= AVR32_FEATURE_RMW;
- printk(" rmw");
- }
- if (config0 & SYSREG_BIT(CONFIG0_D)) {
+ if (config0 & SYSREG_BIT(CONFIG0_D))
features |= AVR32_FEATURE_DSP;
- printk(" dsp");
- }
- if (config0 & SYSREG_BIT(CONFIG0_S)) {
+ if (config0 & SYSREG_BIT(CONFIG0_S))
features |= AVR32_FEATURE_SIMD;
- printk(" simd");
- }
- if (config0 & SYSREG_BIT(CONFIG0_O)) {
+ if (config0 & SYSREG_BIT(CONFIG0_O))
features |= AVR32_FEATURE_OCD;
- printk(" ocd");
- }
- if (config0 & SYSREG_BIT(CONFIG0_P)) {
+ if (config0 & SYSREG_BIT(CONFIG0_P))
features |= AVR32_FEATURE_PCTR;
- printk(" perfctr");
- }
- if (config0 & SYSREG_BIT(CONFIG0_J)) {
+ if (config0 & SYSREG_BIT(CONFIG0_J))
features |= AVR32_FEATURE_JAVA;
- printk(" java");
- }
- if (config0 & SYSREG_BIT(CONFIG0_F)) {
+ if (config0 & SYSREG_BIT(CONFIG0_F))
features |= AVR32_FEATURE_FPU;
- printk(" fpu");
- }
+
+ for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
+ if (features & (1 << i))
+ printk(" %s", cpu_feature_flags[i]);
+
printk("\n");
boot_cpu_data.features = features;
}
@@ -291,6 +319,8 @@ static int c_show(struct seq_file *m, void *v)
{
unsigned int icache_size, dcache_size;
unsigned int cpu = smp_processor_id();
+ unsigned int freq;
+ unsigned int i;
icache_size = boot_cpu_data.icache.ways *
boot_cpu_data.icache.sets *
@@ -301,15 +331,21 @@ static int c_show(struct seq_file *m, void *v)
seq_printf(m, "processor\t: %d\n", cpu);
+ seq_printf(m, "chip type\t: %s revision %c\n",
+ get_chip_name(&boot_cpu_data),
+ avr32_get_chip_revision(&boot_cpu_data) + 'A');
if (boot_cpu_data.arch_type < NR_ARCH_NAMES)
- seq_printf(m, "cpu family\t: %s revision %d\n",
+ seq_printf(m, "cpu arch\t: %s revision %d\n",
arch_names[boot_cpu_data.arch_type],
boot_cpu_data.arch_revision);
if (boot_cpu_data.cpu_type < NR_CPU_NAMES)
- seq_printf(m, "cpu type\t: %s revision %d\n",
+ seq_printf(m, "cpu core\t: %s revision %d\n",
cpu_names[boot_cpu_data.cpu_type],
boot_cpu_data.cpu_revision);
+ freq = (clk_get_rate(boot_cpu_data.clk) + 500) / 1000;
+ seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, freq % 1000);
+
seq_printf(m, "i-cache\t\t: %dK (%u ways x %u sets x %u)\n",
icache_size >> 10,
boot_cpu_data.icache.ways,
@@ -320,7 +356,13 @@ static int c_show(struct seq_file *m, void *v)
boot_cpu_data.dcache.ways,
boot_cpu_data.dcache.sets,
boot_cpu_data.dcache.linesz);
- seq_printf(m, "bogomips\t: %lu.%02lu\n",
+
+ seq_printf(m, "features\t:");
+ for (i = 0; i < ARRAY_SIZE(cpu_feature_flags); i++)
+ if (boot_cpu_data.features & (1 << i))
+ seq_printf(m, " %s", cpu_feature_flags[i]);
+
+ seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
boot_cpu_data.loops_per_jiffy / (500000/HZ),
(boot_cpu_data.loops_per_jiffy / (5000/HZ)) % 100);
@@ -343,7 +385,7 @@ static void c_stop(struct seq_file *m, void *v)
}
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
diff --git a/arch/avr32/kernel/dma-controller.c b/arch/avr32/kernel/dma-controller.c
new file mode 100644
index 0000000..fb654b3
--- /dev/null
+++ b/arch/avr32/kernel/dma-controller.c
@@ -0,0 +1,34 @@
+/*
+ * Preliminary DMA controller framework for AVR32
+ *
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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 <asm/dma-controller.h>
+
+static LIST_HEAD(controllers);
+
+int register_dma_controller(struct dma_controller *dmac)
+{
+ static int next_id;
+
+ dmac->id = next_id++;
+ list_add_tail(&dmac->list, &controllers);
+
+ return 0;
+}
+EXPORT_SYMBOL(register_dma_controller);
+
+struct dma_controller *find_dma_controller(int id)
+{
+ struct dma_controller *dmac;
+
+ list_for_each_entry(dmac, &controllers, list)
+ if (dmac->id == id)
+ return dmac;
+ return NULL;
+}
+EXPORT_SYMBOL(find_dma_controller);
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
index 61f2de2..a8e767d 100644
--- a/arch/avr32/kernel/irq.c
+++ b/arch/avr32/kernel/irq.c
@@ -25,6 +25,17 @@ void ack_bad_irq(unsigned int irq)
printk("unexpected IRQ %u\n", irq);
}
+/* May be overridden by platform code */
+int __weak nmi_enable(void)
+{
+ return -ENOSYS;
+}
+
+void __weak nmi_disable(void)
+{
+
+}
+
#ifdef CONFIG_PROC_FS
int show_interrupts(struct seq_file *p, void *v)
{
diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
index 799ba89..f820e9f 100644
--- a/arch/avr32/kernel/kprobes.c
+++ b/arch/avr32/kernel/kprobes.c
@@ -48,6 +48,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
pr_debug("arming kprobe at %p\n", p->addr);
+ ocd_enable(NULL);
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long)p->addr,
(unsigned long)p->addr + sizeof(kprobe_opcode_t));
@@ -56,6 +57,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
pr_debug("disarming kprobe at %p\n", p->addr);
+ ocd_disable(NULL);
*p->addr = p->opcode;
flush_icache_range((unsigned long)p->addr,
(unsigned long)p->addr + sizeof(kprobe_opcode_t));
@@ -260,9 +262,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
int __init arch_init_kprobes(void)
{
- printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
- ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
-
/* TODO: Register kretprobe trampoline */
return 0;
}
diff --git a/arch/avr32/kernel/nmi_debug.c b/arch/avr32/kernel/nmi_debug.c
new file mode 100644
index 0000000..3414b85
--- /dev/null
+++ b/arch/avr32/kernel/nmi_debug.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/delay.h>
+#include <linux/kdebug.h>
+#include <linux/notifier.h>
+#include <linux/sched.h>
+
+#include <asm/irq.h>
+
+enum nmi_action {
+ NMI_SHOW_STATE = 1 << 0,
+ NMI_SHOW_REGS = 1 << 1,
+ NMI_DIE = 1 << 2,
+ NMI_DEBOUNCE = 1 << 3,
+};
+
+static unsigned long nmi_actions;
+
+static int nmi_debug_notify(struct notifier_block *self,
+ unsigned long val, void *data)
+{
+ struct die_args *args = data;
+
+ if (likely(val != DIE_NMI))
+ return NOTIFY_DONE;
+
+ if (nmi_actions & NMI_SHOW_STATE)
+ show_state();
+ if (nmi_actions & NMI_SHOW_REGS)
+ show_regs(args->regs);
+ if (nmi_actions & NMI_DEBOUNCE)
+ mdelay(10);
+ if (nmi_actions & NMI_DIE)
+ return NOTIFY_BAD;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block nmi_debug_nb = {
+ .notifier_call = nmi_debug_notify,
+};
+
+static int __init nmi_debug_setup(char *str)
+{
+ char *p, *sep;
+
+ register_die_notifier(&nmi_debug_nb);
+ if (nmi_enable()) {
+ printk(KERN_WARNING "Unable to enable NMI.\n");
+ return 0;
+ }
+
+ if (*str != '=')
+ return 0;
+
+ for (p = str + 1; *p; p = sep + 1) {
+ sep = strchr(p, ',');
+ if (sep)
+ *sep = 0;
+ if (strcmp(p, "state") == 0)
+ nmi_actions |= NMI_SHOW_STATE;
+ else if (strcmp(p, "regs") == 0)
+ nmi_actions |= NMI_SHOW_REGS;
+ else if (strcmp(p, "debounce") == 0)
+ nmi_actions |= NMI_DEBOUNCE;
+ else if (strcmp(p, "die") == 0)
+ nmi_actions |= NMI_DIE;
+ else
+ printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
+ p);
+ if (!sep)
+ break;
+ }
+
+ return 0;
+}
+__setup("nmi_debug", nmi_debug_setup);
diff --git a/arch/avr32/kernel/ocd.c b/arch/avr32/kernel/ocd.c
new file mode 100644
index 0000000..c4f0232
--- /dev/null
+++ b/arch/avr32/kernel/ocd.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/ocd.h>
+
+static long ocd_count;
+static spinlock_t ocd_lock;
+
+/**
+ * ocd_enable - enable on-chip debugging
+ * @child: task to be debugged
+ *
+ * If @child is non-NULL, ocd_enable() first checks if debugging has
+ * already been enabled for @child, and if it has, does nothing.
+ *
+ * If @child is NULL (e.g. when debugging the kernel), or debugging
+ * has not already been enabled for it, ocd_enable() increments the
+ * reference count and enables the debugging hardware.
+ */
+void ocd_enable(struct task_struct *child)
+{
+ u32 dc;
+
+ if (child)
+ pr_debug("ocd_enable: child=%s [%u]\n",
+ child->comm, child->pid);
+ else
+ pr_debug("ocd_enable (no child)\n");
+
+ if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
+ spin_lock(&ocd_lock);
+ ocd_count++;
+ dc = ocd_read(DC);
+ dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
+ ocd_write(DC, dc);
+ spin_unlock(&ocd_lock);
+ }
+}
+
+/**
+ * ocd_disable - disable on-chip debugging
+ * @child: task that was being debugged, but isn't anymore
+ *
+ * If @child is non-NULL, ocd_disable() checks if debugging is enabled
+ * for @child, and if it isn't, does nothing.
+ *
+ * If @child is NULL (e.g. when debugging the kernel), or debugging is
+ * enabled, ocd_disable() decrements the reference count, and if it
+ * reaches zero, disables the debugging hardware.
+ */
+void ocd_disable(struct task_struct *child)
+{
+ u32 dc;
+
+ if (!child)
+ pr_debug("ocd_disable (no child)\n");
+ else if (test_tsk_thread_flag(child, TIF_DEBUG))
+ pr_debug("ocd_disable: child=%s [%u]\n",
+ child->comm, child->pid);
+
+ if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
+ spin_lock(&ocd_lock);
+ ocd_count--;
+
+ WARN_ON(ocd_count < 0);
+
+ if (ocd_count <= 0) {
+ dc = ocd_read(DC);
+ dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
+ ocd_write(DC, dc);
+ }
+ spin_unlock(&ocd_lock);
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+static struct dentry *ocd_debugfs_root;
+static struct dentry *ocd_debugfs_DC;
+static struct dentry *ocd_debugfs_DS;
+static struct dentry *ocd_debugfs_count;
+
+static u64 ocd_DC_get(void *data)
+{
+ return ocd_read(DC);
+}
+static void ocd_DC_set(void *data, u64 val)
+{
+ ocd_write(DC, val);
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
+
+static u64 ocd_DS_get(void *data)
+{
+ return ocd_read(DS);
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
+
+static u64 ocd_count_get(void *data)
+{
+ return ocd_count;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
+
+static void ocd_debugfs_init(void)
+{
+ struct dentry *root;
+
+ root = debugfs_create_dir("ocd", NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+ ocd_debugfs_root = root;
+
+ ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
+ root, NULL, &fops_DC);
+ if (!ocd_debugfs_DC)
+ goto err_DC;
+
+ ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
+ NULL, &fops_DS);
+ if (!ocd_debugfs_DS)
+ goto err_DS;
+
+ ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
+ NULL, &fops_count);
+ if (!ocd_debugfs_count)
+ goto err_count;
+
+ return;
+
+err_count:
+ debugfs_remove(ocd_debugfs_DS);
+err_DS:
+ debugfs_remove(ocd_debugfs_DC);
+err_DC:
+ debugfs_remove(ocd_debugfs_root);
+err_root:
+ printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
+}
+#else
+static inline void ocd_debugfs_init(void)
+{
+
+}
+#endif
+
+static int __init ocd_init(void)
+{
+ spin_lock_init(&ocd_lock);
+ ocd_debugfs_init();
+ return 0;
+}
+arch_initcall(ocd_init);
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 9d6dac8..eaaa69b 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -103,7 +103,7 @@ EXPORT_SYMBOL(kernel_thread);
*/
void exit_thread(void)
{
- /* nothing to do */
+ ocd_disable(current);
}
void flush_thread(void)
@@ -345,6 +345,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
p->thread.cpu_context.ksp = (unsigned long)childregs;
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
+ if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
+ ocd_enable(p);
+
return 0;
}
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 002369e..1fed38f 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -58,6 +58,7 @@ void ptrace_disable(struct task_struct *child)
{
clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
clear_tsk_thread_flag(child, TIF_BREAKPOINT);
+ ocd_disable(child);
}
/*
@@ -144,10 +145,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret;
- pr_debug("ptrace: Enabling monitor mode...\n");
- ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
- | (1 << OCD_DC_DBE_BIT));
-
switch (request) {
/* Read the word at location addr in the child process */
case PTRACE_PEEKTEXT:
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index 4b4c188..488078d 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -273,6 +273,8 @@ static int __init early_parse_fbmem(char *p)
printk(KERN_WARNING
"Failed to allocate framebuffer memory\n");
fbmem_size = 0;
+ } else {
+ memset(__va(fbmem_start), 0, fbmem_size);
}
}
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 0ec1485..5616a00 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -270,19 +270,12 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall)
if (!user_mode(regs))
return 0;
- if (try_to_freeze()) {
- signr = 0;
- if (!signal_pending(current))
- goto no_signal;
- }
-
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask;
else if (!oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-no_signal:
if (syscall) {
switch (regs->r12) {
case -ERESTART_RESTARTBLOCK:
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 870c075..cf6f686 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -9,6 +9,7 @@
#include <linux/bug.h>
#include <linux/init.h>
#include <linux/kallsyms.h>
+#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/sched.h>
@@ -107,9 +108,23 @@ void _exception(long signr, struct pt_regs *regs, int code,
asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
{
- printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
- show_regs_log_lvl(regs, KERN_ALERT);
- show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
+ int ret;
+
+ nmi_enter();
+
+ ret = notify_die(DIE_NMI, "NMI", regs, 0, ecr, SIGINT);
+ switch (ret) {
+ case NOTIFY_OK:
+ case NOTIFY_STOP:
+ return;
+ case NOTIFY_BAD:
+ die("Fatal Non-Maskable Interrupt", regs, SIGINT);
+ default:
+ break;
+ }
+
+ printk(KERN_ALERT "Got NMI, but nobody cared. Disabling...\n");
+ nmi_disable();
}
asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig
index eb30783..0eb590a 100644
--- a/arch/avr32/mach-at32ap/Kconfig
+++ b/arch/avr32/mach-at32ap/Kconfig
@@ -3,9 +3,9 @@ if PLATFORM_AT32AP
menu "Atmel AVR32 AP options"
choice
- prompt "AT32AP7000 static memory bus width"
- depends on CPU_AT32AP7000
- default AP7000_16_BIT_SMC
+ prompt "AT32AP700x static memory bus width"
+ depends on CPU_AT32AP700X
+ default AP700X_16_BIT_SMC
help
Define the width of the AP7000 external static memory interface.
This is used to determine how to mangle the address and/or data
@@ -15,17 +15,24 @@ choice
width for all chip selects, excluding the flash (which is using
raw access and is thus not affected by any of this.)
-config AP7000_32_BIT_SMC
+config AP700X_32_BIT_SMC
bool "32 bit"
-config AP7000_16_BIT_SMC
+config AP700X_16_BIT_SMC
bool "16 bit"
-config AP7000_8_BIT_SMC
+config AP700X_8_BIT_SMC
bool "8 bit"
endchoice
+config GPIO_DEV
+ bool "GPIO /dev interface"
+ select CONFIGFS_FS
+ default n
+ help
+ Say `Y' to enable a /dev interface to the GPIO pins.
+
endmenu
endif # PLATFORM_AT32AP
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index a8b4450..0f6162e 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,4 +1,5 @@
obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
-obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o
-obj-$(CONFIG_CPU_AT32AP7000) += time-tc.o
+obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o
+obj-$(CONFIG_CPU_AT32AP700X) += time-tc.o
obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
+obj-$(CONFIG_GPIO_DEV) += gpio-dev.o
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
deleted file mode 100644
index 7c4388f..0000000
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ /dev/null
@@ -1,1730 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Atmel Corporation
- *
- * 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/clk.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/spi/spi.h>
-
-#include <asm/io.h>
-
-#include <asm/arch/at32ap7000.h>
-#include <asm/arch/board.h>
-#include <asm/arch/portmux.h>
-
-#include <video/atmel_lcdc.h>
-
-#include "clock.h"
-#include "hmatrix.h"
-#include "pio.h"
-#include "pm.h"
-
-
-#define PBMEM(base) \
- { \
- .start = base, \
- .end = base + 0x3ff, \
- .flags = IORESOURCE_MEM, \
- }
-#define IRQ(num) \
- { \
- .start = num, \
- .end = num, \
- .flags = IORESOURCE_IRQ, \
- }
-#define NAMED_IRQ(num, _name) \
- { \
- .start = num, \
- .end = num, \
- .name = _name, \
- .flags = IORESOURCE_IRQ, \
- }
-
-/* REVISIT these assume *every* device supports DMA, but several
- * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
- */
-#define DEFINE_DEV(_name, _id) \
-static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \
-static struct platform_device _name##_id##_device = { \
- .name = #_name, \
- .id = _id, \
- .dev = { \
- .dma_mask = &_name##_id##_dma_mask, \
- .coherent_dma_mask = DMA_32BIT_MASK, \
- }, \
- .resource = _name##_id##_resource, \
- .num_resources = ARRAY_SIZE(_name##_id##_resource), \
-}
-#define DEFINE_DEV_DATA(_name, _id) \
-static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \
-static struct platform_device _name##_id##_device = { \
- .name = #_name, \
- .id = _id, \
- .dev = { \
- .dma_mask = &_name##_id##_dma_mask, \
- .platform_data = &_name##_id##_data, \
- .coherent_dma_mask = DMA_32BIT_MASK, \
- }, \
- .resource = _name##_id##_resource, \
- .num_resources = ARRAY_SIZE(_name##_id##_resource), \
-}
-
-#define select_peripheral(pin, periph, flags) \
- at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
-
-#define DEV_CLK(_name, devname, bus, _index) \
-static struct clk devname##_##_name = { \
- .name = #_name, \
- .dev = &devname##_device.dev, \
- .parent = &bus##_clk, \
- .mode = bus##_clk_mode, \
- .get_rate = bus##_clk_get_rate, \
- .index = _index, \
-}
-
-static DEFINE_SPINLOCK(pm_lock);
-
-unsigned long at32ap7000_osc_rates[3] = {
- [0] = 32768,
- /* FIXME: these are ATSTK1002-specific */
- [1] = 20000000,
- [2] = 12000000,
-};
-
-static unsigned long osc_get_rate(struct clk *clk)
-{
- return at32ap7000_osc_rates[clk->index];
-}
-
-static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
-{
- unsigned long div, mul, rate;
-
- if (!(control & PM_BIT(PLLEN)))
- return 0;
-
- div = PM_BFEXT(PLLDIV, control) + 1;
- mul = PM_BFEXT(PLLMUL, control) + 1;
-
- rate = clk->parent->get_rate(clk->parent);
- rate = (rate + div / 2) / div;
- rate *= mul;
-
- return rate;
-}
-
-static unsigned long pll0_get_rate(struct clk *clk)
-{
- u32 control;
-
- control = pm_readl(PLL0);
-
- return pll_get_rate(clk, control);
-}
-
-static unsigned long pll1_get_rate(struct clk *clk)
-{
- u32 control;
-
- control = pm_readl(PLL1);
-
- return pll_get_rate(clk, control);
-}
-
-/*
- * The AT32AP7000 has five primary clock sources: One 32kHz
- * oscillator, two crystal oscillators and two PLLs.
- */
-static struct clk osc32k = {
- .name = "osc32k",
- .get_rate = osc_get_rate,
- .users = 1,
- .index = 0,
-};
-static struct clk osc0 = {
- .name = "osc0",
- .get_rate = osc_get_rate,
- .users = 1,
- .index = 1,
-};
-static struct clk osc1 = {
- .name = "osc1",
- .get_rate = osc_get_rate,
- .index = 2,
-};
-static struct clk pll0 = {
- .name = "pll0",
- .get_rate = pll0_get_rate,
- .parent = &osc0,
-};
-static struct clk pll1 = {
- .name = "pll1",
- .get_rate = pll1_get_rate,
- .parent = &osc0,
-};
-
-/*
- * The main clock can be either osc0 or pll0. The boot loader may
- * have chosen one for us, so we don't really know which one until we
- * have a look at the SM.
- */
-static struct clk *main_clock;
-
-/*
- * Synchronous clocks are generated from the main clock. The clocks
- * must satisfy the constraint
- * fCPU >= fHSB >= fPB
- * i.e. each clock must not be faster than its parent.
- */
-static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
-{
- return main_clock->get_rate(main_clock) >> shift;
-};
-
-static void cpu_clk_mode(struct clk *clk, int enabled)
-{
- unsigned long flags;
- u32 mask;
-
- spin_lock_irqsave(&pm_lock, flags);
- mask = pm_readl(CPU_MASK);
- if (enabled)
- mask |= 1 << clk->index;
- else
- mask &= ~(1 << clk->index);
- pm_writel(CPU_MASK, mask);
- spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long cpu_clk_get_rate(struct clk *clk)
-{
- unsigned long cksel, shift = 0;
-
- cksel = pm_readl(CKSEL);
- if (cksel & PM_BIT(CPUDIV))
- shift = PM_BFEXT(CPUSEL, cksel) + 1;
-
- return bus_clk_get_rate(clk, shift);
-}
-
-static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
-{
- u32 control;
- unsigned long parent_rate, child_div, actual_rate, div;
-
- parent_rate = clk->parent->get_rate(clk->parent);
- control = pm_readl(CKSEL);
-
- if (control & PM_BIT(HSBDIV))
- child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
- else
- child_div = 1;
-
- if (rate > 3 * (parent_rate / 4) || child_div == 1) {
- actual_rate = parent_rate;
- control &= ~PM_BIT(CPUDIV);
- } else {
- unsigned int cpusel;
- div = (parent_rate + rate / 2) / rate;
- if (div > child_div)
- div = child_div;
- cpusel = (div > 1) ? (fls(div) - 2) : 0;
- control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
- actual_rate = parent_rate / (1 << (cpusel + 1));
- }
-
- pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
- clk->name, rate, actual_rate);
-
- if (apply)
- pm_writel(CKSEL, control);
-
- return actual_rate;
-}
-
-static void hsb_clk_mode(struct clk *clk, int enabled)
-{
- unsigned long flags;
- u32 mask;
-
- spin_lock_irqsave(&pm_lock, flags);
- mask = pm_readl(HSB_MASK);
- if (enabled)
- mask |= 1 << clk->index;
- else
- mask &= ~(1 << clk->index);
- pm_writel(HSB_MASK, mask);
- spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long hsb_clk_get_rate(struct clk *clk)
-{
- unsigned long cksel, shift = 0;
-
- cksel = pm_readl(CKSEL);
- if (cksel & PM_BIT(HSBDIV))
- shift = PM_BFEXT(HSBSEL, cksel) + 1;
-
- return bus_clk_get_rate(clk, shift);
-}
-
-static void pba_clk_mode(struct clk *clk, int enabled)
-{
- unsigned long flags;
- u32 mask;
-
- spin_lock_irqsave(&pm_lock, flags);
- mask = pm_readl(PBA_MASK);
- if (enabled)
- mask |= 1 << clk->index;
- else
- mask &= ~(1 << clk->index);
- pm_writel(PBA_MASK, mask);
- spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long pba_clk_get_rate(struct clk *clk)
-{
- unsigned long cksel, shift = 0;
-
- cksel = pm_readl(CKSEL);
- if (cksel & PM_BIT(PBADIV))
- shift = PM_BFEXT(PBASEL, cksel) + 1;
-
- return bus_clk_get_rate(clk, shift);
-}
-
-static void pbb_clk_mode(struct clk *clk, int enabled)
-{
- unsigned long flags;
- u32 mask;
-
- spin_lock_irqsave(&pm_lock, flags);
- mask = pm_readl(PBB_MASK);
- if (enabled)
- mask |= 1 << clk->index;
- else
- mask &= ~(1 << clk->index);
- pm_writel(PBB_MASK, mask);
- spin_unlock_irqrestore(&pm_lock, flags);
-}
-
-static unsigned long pbb_clk_get_rate(struct clk *clk)
-{
- unsigned long cksel, shift = 0;
-
- cksel = pm_readl(CKSEL);
- if (cksel & PM_BIT(PBBDIV))
- shift = PM_BFEXT(PBBSEL, cksel) + 1;
-
- return bus_clk_get_rate(clk, shift);
-}
-
-static struct clk cpu_clk = {
- .name = "cpu",
- .get_rate = cpu_clk_get_rate,
- .set_rate = cpu_clk_set_rate,
- .users = 1,
-};
-static struct clk hsb_clk = {
- .name = "hsb",
- .parent = &cpu_clk,
- .get_rate = hsb_clk_get_rate,
-};
-static struct clk pba_clk = {
- .name = "pba",
- .parent = &hsb_clk,
- .mode = hsb_clk_mode,
- .get_rate = pba_clk_get_rate,
- .index = 1,
-};
-static struct clk pbb_clk = {
- .name = "pbb",
- .parent = &hsb_clk,
- .mode = hsb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .users = 1,
- .index = 2,
-};
-
-/* --------------------------------------------------------------------
- * Generic Clock operations
- * -------------------------------------------------------------------- */
-
-static void genclk_mode(struct clk *clk, int enabled)
-{
- u32 control;
-
- control = pm_readl(GCCTRL(clk->index));
- if (enabled)
- control |= PM_BIT(CEN);
- else
- control &= ~PM_BIT(CEN);
- pm_writel(GCCTRL(clk->index), control);
-}
-
-static unsigned long genclk_get_rate(struct clk *clk)
-{
- u32 control;
- unsigned long div = 1;
-
- control = pm_readl(GCCTRL(clk->index));
- if (control & PM_BIT(DIVEN))
- div = 2 * (PM_BFEXT(DIV, control) + 1);
-
- return clk->parent->get_rate(clk->parent) / div;
-}
-
-static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
-{
- u32 control;
- unsigned long parent_rate, actual_rate, div;
-
- parent_rate = clk->parent->get_rate(clk->parent);
- control = pm_readl(GCCTRL(clk->index));
-
- if (rate > 3 * parent_rate / 4) {
- actual_rate = parent_rate;
- control &= ~PM_BIT(DIVEN);
- } else {
- div = (parent_rate + rate) / (2 * rate) - 1;
- control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
- actual_rate = parent_rate / (2 * (div + 1));
- }
-
- dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
- clk->name, rate, actual_rate);
-
- if (apply)
- pm_writel(GCCTRL(clk->index), control);
-
- return actual_rate;
-}
-
-int genclk_set_parent(struct clk *clk, struct clk *parent)
-{
- u32 control;
-
- dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
- clk->name, parent->name, clk->parent->name);
-
- control = pm_readl(GCCTRL(clk->index));
-
- if (parent == &osc1 || parent == &pll1)
- control |= PM_BIT(OSCSEL);
- else if (parent == &osc0 || parent == &pll0)
- control &= ~PM_BIT(OSCSEL);
- else
- return -EINVAL;
-
- if (parent == &pll0 || parent == &pll1)
- control |= PM_BIT(PLLSEL);
- else
- control &= ~PM_BIT(PLLSEL);
-
- pm_writel(GCCTRL(clk->index), control);
- clk->parent = parent;
-
- return 0;
-}
-
-static void __init genclk_init_parent(struct clk *clk)
-{
- u32 control;
- struct clk *parent;
-
- BUG_ON(clk->index > 7);
-
- control = pm_readl(GCCTRL(clk->index));
- if (control & PM_BIT(OSCSEL))
- parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
- else
- parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
-
- clk->parent = parent;
-}
-
-/* --------------------------------------------------------------------
- * System peripherals
- * -------------------------------------------------------------------- */
-static struct resource at32_pm0_resource[] = {
- {
- .start = 0xfff00000,
- .end = 0xfff0007f,
- .flags = IORESOURCE_MEM,
- },
- IRQ(20),
-};
-
-static struct resource at32ap700x_rtc0_resource[] = {
- {
- .start = 0xfff00080,
- .end = 0xfff000af,
- .flags = IORESOURCE_MEM,
- },
- IRQ(21),
-};
-
-static struct resource at32_wdt0_resource[] = {
- {
- .start = 0xfff000b0,
- .end = 0xfff000cf,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct resource at32_eic0_resource[] = {
- {
- .start = 0xfff00100,
- .end = 0xfff0013f,
- .flags = IORESOURCE_MEM,
- },
- IRQ(19),
-};
-
-DEFINE_DEV(at32_pm, 0);
-DEFINE_DEV(at32ap700x_rtc, 0);
-DEFINE_DEV(at32_wdt, 0);
-DEFINE_DEV(at32_eic, 0);
-
-/*
- * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
- * is always running.
- */
-static struct clk at32_pm_pclk = {
- .name = "pclk",
- .dev = &at32_pm0_device.dev,
- .parent = &pbb_clk,
- .mode = pbb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .users = 1,
- .index = 0,
-};
-
-static struct resource intc0_resource[] = {
- PBMEM(0xfff00400),
-};
-struct platform_device at32_intc0_device = {
- .name = "intc",
- .id = 0,
- .resource = intc0_resource,
- .num_resources = ARRAY_SIZE(intc0_resource),
-};
-DEV_CLK(pclk, at32_intc0, pbb, 1);
-
-static struct clk ebi_clk = {
- .name = "ebi",
- .parent = &hsb_clk,
- .mode = hsb_clk_mode,
- .get_rate = hsb_clk_get_rate,
- .users = 1,
-};
-static struct clk hramc_clk = {
- .name = "hramc",
- .parent = &hsb_clk,
- .mode = hsb_clk_mode,
- .get_rate = hsb_clk_get_rate,
- .users = 1,
- .index = 3,
-};
-
-static struct resource smc0_resource[] = {
- PBMEM(0xfff03400),
-};
-DEFINE_DEV(smc, 0);
-DEV_CLK(pclk, smc0, pbb, 13);
-DEV_CLK(mck, smc0, hsb, 0);
-
-static struct platform_device pdc_device = {
- .name = "pdc",
- .id = 0,
-};
-DEV_CLK(hclk, pdc, hsb, 4);
-DEV_CLK(pclk, pdc, pba, 16);
-
-static struct clk pico_clk = {
- .name = "pico",
- .parent = &cpu_clk,
- .mode = cpu_clk_mode,
- .get_rate = cpu_clk_get_rate,
- .users = 1,
-};
-
-static struct resource dmaca0_resource[] = {
- {
- .start = 0xff200000,
- .end = 0xff20ffff,
- .flags = IORESOURCE_MEM,
- },
- IRQ(2),
-};
-DEFINE_DEV(dmaca, 0);
-DEV_CLK(hclk, dmaca0, hsb, 10);
-
-/* --------------------------------------------------------------------
- * HMATRIX
- * -------------------------------------------------------------------- */
-
-static struct clk hmatrix_clk = {
- .name = "hmatrix_clk",
- .parent = &pbb_clk,
- .mode = pbb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .index = 2,
- .users = 1,
-};
-#define HMATRIX_BASE ((void __iomem *)0xfff00800)
-
-#define hmatrix_readl(reg) \
- __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
-#define hmatrix_writel(reg,value) \
- __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
-
-/*
- * Set bits in the HMATRIX Special Function Register (SFR) used by the
- * External Bus Interface (EBI). This can be used to enable special
- * features like CompactFlash support, NAND Flash support, etc. on
- * certain chipselects.
- */
-static inline void set_ebi_sfr_bits(u32 mask)
-{
- u32 sfr;
-
- clk_enable(&hmatrix_clk);
- sfr = hmatrix_readl(SFR4);
- sfr |= mask;
- hmatrix_writel(SFR4, sfr);
- clk_disable(&hmatrix_clk);
-}
-
-/* --------------------------------------------------------------------
- * System Timer/Counter (TC)
- * -------------------------------------------------------------------- */
-static struct resource at32_systc0_resource[] = {
- PBMEM(0xfff00c00),
- IRQ(22),
-};
-struct platform_device at32_systc0_device = {
- .name = "systc",
- .id = 0,
- .resource = at32_systc0_resource,
- .num_resources = ARRAY_SIZE(at32_systc0_resource),
-};
-DEV_CLK(pclk, at32_systc0, pbb, 3);
-
-/* --------------------------------------------------------------------
- * PIO
- * -------------------------------------------------------------------- */
-
-static struct resource pio0_resource[] = {
- PBMEM(0xffe02800),
- IRQ(13),
-};
-DEFINE_DEV(pio, 0);
-DEV_CLK(mck, pio0, pba, 10);
-
-static struct resource pio1_resource[] = {
- PBMEM(0xffe02c00),
- IRQ(14),
-};
-DEFINE_DEV(pio, 1);
-DEV_CLK(mck, pio1, pba, 11);
-
-static struct resource pio2_resource[] = {
- PBMEM(0xffe03000),
- IRQ(15),
-};
-DEFINE_DEV(pio, 2);
-DEV_CLK(mck, pio2, pba, 12);
-
-static struct resource pio3_resource[] = {
- PBMEM(0xffe03400),
- IRQ(16),
-};
-DEFINE_DEV(pio, 3);
-DEV_CLK(mck, pio3, pba, 13);
-
-static struct resource pio4_resource[] = {
- PBMEM(0xffe03800),
- IRQ(17),
-};
-DEFINE_DEV(pio, 4);
-DEV_CLK(mck, pio4, pba, 14);
-
-void __init at32_add_system_devices(void)
-{
- platform_device_register(&at32_pm0_device);
- platform_device_register(&at32_intc0_device);
- platform_device_register(&at32ap700x_rtc0_device);
- platform_device_register(&at32_wdt0_device);
- platform_device_register(&at32_eic0_device);
- platform_device_register(&smc0_device);
- platform_device_register(&pdc_device);
- platform_device_register(&dmaca0_device);
-
- platform_device_register(&at32_systc0_device);
-
- platform_device_register(&pio0_device);
- platform_device_register(&pio1_device);
- platform_device_register(&pio2_device);
- platform_device_register(&pio3_device);
- platform_device_register(&pio4_device);
-}
-
-/* --------------------------------------------------------------------
- * USART
- * -------------------------------------------------------------------- */
-
-static struct atmel_uart_data atmel_usart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-static struct resource atmel_usart0_resource[] = {
- PBMEM(0xffe00c00),
- IRQ(6),
-};
-DEFINE_DEV_DATA(atmel_usart, 0);
-DEV_CLK(usart, atmel_usart0, pba, 3);
-
-static struct atmel_uart_data atmel_usart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-static struct resource atmel_usart1_resource[] = {
- PBMEM(0xffe01000),
- IRQ(7),
-};
-DEFINE_DEV_DATA(atmel_usart, 1);
-DEV_CLK(usart, atmel_usart1, pba, 4);
-
-static struct atmel_uart_data atmel_usart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-static struct resource atmel_usart2_resource[] = {
- PBMEM(0xffe01400),
- IRQ(8),
-};
-DEFINE_DEV_DATA(atmel_usart, 2);
-DEV_CLK(usart, atmel_usart2, pba, 5);
-
-static struct atmel_uart_data atmel_usart3_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-static struct resource atmel_usart3_resource[] = {
- PBMEM(0xffe01800),
- IRQ(9),
-};
-DEFINE_DEV_DATA(atmel_usart, 3);
-DEV_CLK(usart, atmel_usart3, pba, 6);
-
-static inline void configure_usart0_pins(void)
-{
- select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
- select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
-}
-
-static inline void configure_usart1_pins(void)
-{
- select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
- select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
-}
-
-static inline void configure_usart2_pins(void)
-{
- select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
- select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
-}
-
-static inline void configure_usart3_pins(void)
-{
- select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
- select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
-}
-
-static struct platform_device *__initdata at32_usarts[4];
-
-void __init at32_map_usart(unsigned int hw_id, unsigned int line)
-{
- struct platform_device *pdev;
-
- switch (hw_id) {
- case 0:
- pdev = &atmel_usart0_device;
- configure_usart0_pins();
- break;
- case 1:
- pdev = &atmel_usart1_device;
- configure_usart1_pins();
- break;
- case 2:
- pdev = &atmel_usart2_device;
- configure_usart2_pins();
- break;
- case 3:
- pdev = &atmel_usart3_device;
- configure_usart3_pins();
- break;
- default:
- return;
- }
-
- if (PXSEG(pdev->resource[0].start) == P4SEG) {
- /* Addresses in the P4 segment are permanently mapped 1:1 */
- struct atmel_uart_data *data = pdev->dev.platform_data;
- data->regs = (void __iomem *)pdev->resource[0].start;
- }
-
- pdev->id = line;
- at32_usarts[line] = pdev;
-}
-
-struct platform_device *__init at32_add_device_usart(unsigned int id)
-{
- platform_device_register(at32_usarts[id]);
- return at32_usarts[id];
-}
-
-struct platform_device *atmel_default_console_device;
-
-void __init at32_setup_serial_console(unsigned int usart_id)
-{
- atmel_default_console_device = at32_usarts[usart_id];
-}
-
-/* --------------------------------------------------------------------
- * Ethernet
- * -------------------------------------------------------------------- */
-
-static struct eth_platform_data macb0_data;
-static struct resource macb0_resource[] = {
- PBMEM(0xfff01800),
- IRQ(25),
-};
-DEFINE_DEV_DATA(macb, 0);
-DEV_CLK(hclk, macb0, hsb, 8);
-DEV_CLK(pclk, macb0, pbb, 6);
-
-static struct eth_platform_data macb1_data;
-static struct resource macb1_resource[] = {
- PBMEM(0xfff01c00),
- IRQ(26),
-};
-DEFINE_DEV_DATA(macb, 1);
-DEV_CLK(hclk, macb1, hsb, 9);
-DEV_CLK(pclk, macb1, pbb, 7);
-
-struct platform_device *__init
-at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
-{
- struct platform_device *pdev;
-
- switch (id) {
- case 0:
- pdev = &macb0_device;
-
- select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
- select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
- select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
- select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
- select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
- select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
- select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
- select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
- select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
- select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
-
- if (!data->is_rmii) {
- select_peripheral(PC(0), PERIPH_A, 0); /* COL */
- select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
- select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
- select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
- select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
- select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
- select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
- select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
- select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
- }
- break;
-
- case 1:
- pdev = &macb1_device;
-
- select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */
- select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */
- select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */
- select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */
- select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */
- select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */
- select_peripheral(PD(5), PERIPH_B, 0); /* RXER */
- select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */
- select_peripheral(PD(3), PERIPH_B, 0); /* MDC */
- select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */
-
- if (!data->is_rmii) {
- select_peripheral(PC(19), PERIPH_B, 0); /* COL */
- select_peripheral(PC(23), PERIPH_B, 0); /* CRS */
- select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
- select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
- select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
- select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
- select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
- select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
- select_peripheral(PD(15), PERIPH_B, 0); /* SPD */
- }
- break;
-
- default:
- return NULL;
- }
-
- memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
- platform_device_register(pdev);
-
- return pdev;
-}
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-static struct resource atmel_spi0_resource[] = {
- PBMEM(0xffe00000),
- IRQ(3),
-};
-DEFINE_DEV(atmel_spi, 0);
-DEV_CLK(spi_clk, atmel_spi0, pba, 0);
-
-static struct resource atmel_spi1_resource[] = {
- PBMEM(0xffe00400),
- IRQ(4),
-};
-DEFINE_DEV(atmel_spi, 1);
-DEV_CLK(spi_clk, atmel_spi1, pba, 1);
-
-static void __init
-at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
- unsigned int n, const u8 *pins)
-{
- unsigned int pin, mode;
-
- for (; n; n--, b++) {
- b->bus_num = bus_num;
- if (b->chip_select >= 4)
- continue;
- pin = (unsigned)b->controller_data;
- if (!pin) {
- pin = pins[b->chip_select];
- b->controller_data = (void *)pin;
- }
- mode = AT32_GPIOF_OUTPUT;
- if (!(b->mode & SPI_CS_HIGH))
- mode |= AT32_GPIOF_HIGH;
- at32_select_gpio(pin, mode);
- }
-}
-
-struct platform_device *__init
-at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
-{
- /*
- * Manage the chipselects as GPIOs, normally using the same pins
- * the SPI controller expects; but boards can use other pins.
- */
- static u8 __initdata spi0_pins[] =
- { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
- GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
- static u8 __initdata spi1_pins[] =
- { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
- GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
- struct platform_device *pdev;
-
- switch (id) {
- case 0:
- pdev = &atmel_spi0_device;
- select_peripheral(PA(0), PERIPH_A, 0); /* MISO */
- select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
- select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
- at32_spi_setup_slaves(0, b, n, spi0_pins);
- break;
-
- case 1:
- pdev = &atmel_spi1_device;
- select_peripheral(PB(0), PERIPH_B, 0); /* MISO */
- select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
- select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
- at32_spi_setup_slaves(1, b, n, spi1_pins);
- break;
-
- default:
- return NULL;
- }
-
- spi_register_board_info(b, n);
- platform_device_register(pdev);
- return pdev;
-}
-
-/* --------------------------------------------------------------------
- * TWI
- * -------------------------------------------------------------------- */
-static struct resource atmel_twi0_resource[] __initdata = {
- PBMEM(0xffe00800),
- IRQ(5),
-};
-static struct clk atmel_twi0_pclk = {
- .name = "twi_pclk",
- .parent = &pba_clk,
- .mode = pba_clk_mode,
- .get_rate = pba_clk_get_rate,
- .index = 2,
-};
-
-struct platform_device *__init at32_add_device_twi(unsigned int id)
-{
- struct platform_device *pdev;
-
- if (id != 0)
- return NULL;
-
- pdev = platform_device_alloc("atmel_twi", id);
- if (!pdev)
- return NULL;
-
- if (platform_device_add_resources(pdev, atmel_twi0_resource,
- ARRAY_SIZE(atmel_twi0_resource)))
- goto err_add_resources;
-
- select_peripheral(PA(6), PERIPH_A, 0); /* SDA */
- select_peripheral(PA(7), PERIPH_A, 0); /* SDL */
-
- atmel_twi0_pclk.dev = &pdev->dev;
-
- platform_device_add(pdev);
- return pdev;
-
-err_add_resources:
- platform_device_put(pdev);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * MMC
- * -------------------------------------------------------------------- */
-static struct resource atmel_mci0_resource[] __initdata = {
- PBMEM(0xfff02400),
- IRQ(28),
-};
-static struct clk atmel_mci0_pclk = {
- .name = "mci_clk",
- .parent = &pbb_clk,
- .mode = pbb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .index = 9,
-};
-
-struct platform_device *__init at32_add_device_mci(unsigned int id)
-{
- struct platform_device *pdev;
-
- if (id != 0)
- return NULL;
-
- pdev = platform_device_alloc("atmel_mci", id);
- if (!pdev)
- return NULL;
-
- if (platform_device_add_resources(pdev, atmel_mci0_resource,
- ARRAY_SIZE(atmel_mci0_resource)))
- goto err_add_resources;
-
- select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
- select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
- select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
- select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
-
- atmel_mci0_pclk.dev = &pdev->dev;
-
- platform_device_add(pdev);
- return pdev;
-
-err_add_resources:
- platform_device_put(pdev);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * LCDC
- * -------------------------------------------------------------------- */
-static struct atmel_lcdfb_info atmel_lcdfb0_data;
-static struct resource atmel_lcdfb0_resource[] = {
- {
- .start = 0xff000000,
- .end = 0xff000fff,
- .flags = IORESOURCE_MEM,
- },
- IRQ(1),
- {
- /* Placeholder for pre-allocated fb memory */
- .start = 0x00000000,
- .end = 0x00000000,
- .flags = 0,
- },
-};
-DEFINE_DEV_DATA(atmel_lcdfb, 0);
-DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
-static struct clk atmel_lcdfb0_pixclk = {
- .name = "lcdc_clk",
- .dev = &atmel_lcdfb0_device.dev,
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 7,
-};
-
-struct platform_device *__init
-at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
- unsigned long fbmem_start, unsigned long fbmem_len)
-{
- struct platform_device *pdev;
- struct atmel_lcdfb_info *info;
- struct fb_monspecs *monspecs;
- struct fb_videomode *modedb;
- unsigned int modedb_size;
-
- /*
- * Do a deep copy of the fb data, monspecs and modedb. Make
- * sure all allocations are done before setting up the
- * portmux.
- */
- monspecs = kmemdup(data->default_monspecs,
- sizeof(struct fb_monspecs), GFP_KERNEL);
- if (!monspecs)
- return NULL;
-
- modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
- modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
- if (!modedb)
- goto err_dup_modedb;
- monspecs->modedb = modedb;
-
- switch (id) {
- case 0:
- pdev = &atmel_lcdfb0_device;
- select_peripheral(PC(19), PERIPH_A, 0); /* CC */
- select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
- select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
- select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
- select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
- select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
- select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
- select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
- select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
- select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
- select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
- select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
- select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
- select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
- select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
- select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
- select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
- select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
- select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
- select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
- select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
- select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
- select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
- select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
- select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
- select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
- select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
- select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
- select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-
- clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
- clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
- break;
-
- default:
- goto err_invalid_id;
- }
-
- if (fbmem_len) {
- pdev->resource[2].start = fbmem_start;
- pdev->resource[2].end = fbmem_start + fbmem_len - 1;
- pdev->resource[2].flags = IORESOURCE_MEM;
- }
-
- info = pdev->dev.platform_data;
- memcpy(info, data, sizeof(struct atmel_lcdfb_info));
- info->default_monspecs = monspecs;
-
- platform_device_register(pdev);
- return pdev;
-
-err_invalid_id:
- kfree(modedb);
-err_dup_modedb:
- kfree(monspecs);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * SSC
- * -------------------------------------------------------------------- */
-static struct resource ssc0_resource[] = {
- PBMEM(0xffe01c00),
- IRQ(10),
-};
-DEFINE_DEV(ssc, 0);
-DEV_CLK(pclk, ssc0, pba, 7);
-
-static struct resource ssc1_resource[] = {
- PBMEM(0xffe02000),
- IRQ(11),
-};
-DEFINE_DEV(ssc, 1);
-DEV_CLK(pclk, ssc1, pba, 8);
-
-static struct resource ssc2_resource[] = {
- PBMEM(0xffe02400),
- IRQ(12),
-};
-DEFINE_DEV(ssc, 2);
-DEV_CLK(pclk, ssc2, pba, 9);
-
-struct platform_device *__init
-at32_add_device_ssc(unsigned int id, unsigned int flags)
-{
- struct platform_device *pdev;
-
- switch (id) {
- case 0:
- pdev = &ssc0_device;
- if (flags & ATMEL_SSC_RF)
- select_peripheral(PA(21), PERIPH_A, 0); /* RF */
- if (flags & ATMEL_SSC_RK)
- select_peripheral(PA(22), PERIPH_A, 0); /* RK */
- if (flags & ATMEL_SSC_TK)
- select_peripheral(PA(23), PERIPH_A, 0); /* TK */
- if (flags & ATMEL_SSC_TF)
- select_peripheral(PA(24), PERIPH_A, 0); /* TF */
- if (flags & ATMEL_SSC_TD)
- select_peripheral(PA(25), PERIPH_A, 0); /* TD */
- if (flags & ATMEL_SSC_RD)
- select_peripheral(PA(26), PERIPH_A, 0); /* RD */
- break;
- case 1:
- pdev = &ssc1_device;
- if (flags & ATMEL_SSC_RF)
- select_peripheral(PA(0), PERIPH_B, 0); /* RF */
- if (flags & ATMEL_SSC_RK)
- select_peripheral(PA(1), PERIPH_B, 0); /* RK */
- if (flags & ATMEL_SSC_TK)
- select_peripheral(PA(2), PERIPH_B, 0); /* TK */
- if (flags & ATMEL_SSC_TF)
- select_peripheral(PA(3), PERIPH_B, 0); /* TF */
- if (flags & ATMEL_SSC_TD)
- select_peripheral(PA(4), PERIPH_B, 0); /* TD */
- if (flags & ATMEL_SSC_RD)
- select_peripheral(PA(5), PERIPH_B, 0); /* RD */
- break;
- case 2:
- pdev = &ssc2_device;
- if (flags & ATMEL_SSC_TD)
- select_peripheral(PB(13), PERIPH_A, 0); /* TD */
- if (flags & ATMEL_SSC_RD)
- select_peripheral(PB(14), PERIPH_A, 0); /* RD */
- if (flags & ATMEL_SSC_TK)
- select_peripheral(PB(15), PERIPH_A, 0); /* TK */
- if (flags & ATMEL_SSC_TF)
- select_peripheral(PB(16), PERIPH_A, 0); /* TF */
- if (flags & ATMEL_SSC_RF)
- select_peripheral(PB(17), PERIPH_A, 0); /* RF */
- if (flags & ATMEL_SSC_RK)
- select_peripheral(PB(18), PERIPH_A, 0); /* RK */
- break;
- default:
- return NULL;
- }
-
- platform_device_register(pdev);
- return pdev;
-}
-
-/* --------------------------------------------------------------------
- * USB Device Controller
- * -------------------------------------------------------------------- */
-static struct resource usba0_resource[] __initdata = {
- {
- .start = 0xff300000,
- .end = 0xff3fffff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = 0xfff03000,
- .end = 0xfff033ff,
- .flags = IORESOURCE_MEM,
- },
- IRQ(31),
-};
-static struct clk usba0_pclk = {
- .name = "pclk",
- .parent = &pbb_clk,
- .mode = pbb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .index = 12,
-};
-static struct clk usba0_hclk = {
- .name = "hclk",
- .parent = &hsb_clk,
- .mode = hsb_clk_mode,
- .get_rate = hsb_clk_get_rate,
- .index = 6,
-};
-
-struct platform_device *__init
-at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
-{
- struct platform_device *pdev;
-
- if (id != 0)
- return NULL;
-
- pdev = platform_device_alloc("atmel_usba_udc", 0);
- if (!pdev)
- return NULL;
-
- if (platform_device_add_resources(pdev, usba0_resource,
- ARRAY_SIZE(usba0_resource)))
- goto out_free_pdev;
-
- if (data) {
- if (platform_device_add_data(pdev, data, sizeof(*data)))
- goto out_free_pdev;
-
- if (data->vbus_pin != GPIO_PIN_NONE)
- at32_select_gpio(data->vbus_pin, 0);
- }
-
- usba0_pclk.dev = &pdev->dev;
- usba0_hclk.dev = &pdev->dev;
-
- platform_device_add(pdev);
-
- return pdev;
-
-out_free_pdev:
- platform_device_put(pdev);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * IDE / CompactFlash
- * -------------------------------------------------------------------- */
-static struct resource at32_smc_cs4_resource[] __initdata = {
- {
- .start = 0x04000000,
- .end = 0x07ffffff,
- .flags = IORESOURCE_MEM,
- },
- IRQ(~0UL), /* Magic IRQ will be overridden */
-};
-static struct resource at32_smc_cs5_resource[] __initdata = {
- {
- .start = 0x20000000,
- .end = 0x23ffffff,
- .flags = IORESOURCE_MEM,
- },
- IRQ(~0UL), /* Magic IRQ will be overridden */
-};
-
-static int __init at32_init_ide_or_cf(struct platform_device *pdev,
- unsigned int cs, unsigned int extint)
-{
- static unsigned int extint_pin_map[4] __initdata = {
- GPIO_PIN_PB(25),
- GPIO_PIN_PB(26),
- GPIO_PIN_PB(27),
- GPIO_PIN_PB(28),
- };
- static bool common_pins_initialized __initdata = false;
- unsigned int extint_pin;
- int ret;
-
- if (extint >= ARRAY_SIZE(extint_pin_map))
- return -EINVAL;
- extint_pin = extint_pin_map[extint];
-
- switch (cs) {
- case 4:
- ret = platform_device_add_resources(pdev,
- at32_smc_cs4_resource,
- ARRAY_SIZE(at32_smc_cs4_resource));
- if (ret)
- return ret;
-
- select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */
- set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
- break;
- case 5:
- ret = platform_device_add_resources(pdev,
- at32_smc_cs5_resource,
- ARRAY_SIZE(at32_smc_cs5_resource));
- if (ret)
- return ret;
-
- select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */
- set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
- break;
- default:
- return -EINVAL;
- }
-
- if (!common_pins_initialized) {
- select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */
- select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */
- select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */
- select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */
- common_pins_initialized = true;
- }
-
- at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
-
- pdev->resource[1].start = EIM_IRQ_BASE + extint;
- pdev->resource[1].end = pdev->resource[1].start;
-
- return 0;
-}
-
-struct platform_device *__init
-at32_add_device_ide(unsigned int id, unsigned int extint,
- struct ide_platform_data *data)
-{
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("at32_ide", id);
- if (!pdev)
- goto fail;
-
- if (platform_device_add_data(pdev, data,
- sizeof(struct ide_platform_data)))
- goto fail;
-
- if (at32_init_ide_or_cf(pdev, data->cs, extint))
- goto fail;
-
- platform_device_add(pdev);
- return pdev;
-
-fail:
- platform_device_put(pdev);
- return NULL;
-}
-
-struct platform_device *__init
-at32_add_device_cf(unsigned int id, unsigned int extint,
- struct cf_platform_data *data)
-{
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("at32_cf", id);
- if (!pdev)
- goto fail;
-
- if (platform_device_add_data(pdev, data,
- sizeof(struct cf_platform_data)))
- goto fail;
-
- if (at32_init_ide_or_cf(pdev, data->cs, extint))
- goto fail;
-
- if (data->detect_pin != GPIO_PIN_NONE)
- at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
- if (data->reset_pin != GPIO_PIN_NONE)
- at32_select_gpio(data->reset_pin, 0);
- if (data->vcc_pin != GPIO_PIN_NONE)
- at32_select_gpio(data->vcc_pin, 0);
- /* READY is used as extint, so we can't select it as gpio */
-
- platform_device_add(pdev);
- return pdev;
-
-fail:
- platform_device_put(pdev);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * AC97C
- * -------------------------------------------------------------------- */
-static struct resource atmel_ac97c0_resource[] __initdata = {
- PBMEM(0xfff02800),
- IRQ(29),
-};
-static struct clk atmel_ac97c0_pclk = {
- .name = "pclk",
- .parent = &pbb_clk,
- .mode = pbb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .index = 10,
-};
-
-struct platform_device *__init at32_add_device_ac97c(unsigned int id)
-{
- struct platform_device *pdev;
-
- if (id != 0)
- return NULL;
-
- pdev = platform_device_alloc("atmel_ac97c", id);
- if (!pdev)
- return NULL;
-
- if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
- ARRAY_SIZE(atmel_ac97c0_resource)))
- goto err_add_resources;
-
- select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
- select_peripheral(PB(21), PERIPH_B, 0); /* SDO */
- select_peripheral(PB(22), PERIPH_B, 0); /* SDI */
- select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
-
- atmel_ac97c0_pclk.dev = &pdev->dev;
-
- platform_device_add(pdev);
- return pdev;
-
-err_add_resources:
- platform_device_put(pdev);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * ABDAC
- * -------------------------------------------------------------------- */
-static struct resource abdac0_resource[] __initdata = {
- PBMEM(0xfff02000),
- IRQ(27),
-};
-static struct clk abdac0_pclk = {
- .name = "pclk",
- .parent = &pbb_clk,
- .mode = pbb_clk_mode,
- .get_rate = pbb_clk_get_rate,
- .index = 8,
-};
-static struct clk abdac0_sample_clk = {
- .name = "sample_clk",
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 6,
-};
-
-struct platform_device *__init at32_add_device_abdac(unsigned int id)
-{
- struct platform_device *pdev;
-
- if (id != 0)
- return NULL;
-
- pdev = platform_device_alloc("abdac", id);
- if (!pdev)
- return NULL;
-
- if (platform_device_add_resources(pdev, abdac0_resource,
- ARRAY_SIZE(abdac0_resource)))
- goto err_add_resources;
-
- select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */
- select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */
- select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */
- select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */
-
- abdac0_pclk.dev = &pdev->dev;
- abdac0_sample_clk.dev = &pdev->dev;
-
- platform_device_add(pdev);
- return pdev;
-
-err_add_resources:
- platform_device_put(pdev);
- return NULL;
-}
-
-/* --------------------------------------------------------------------
- * GCLK
- * -------------------------------------------------------------------- */
-static struct clk gclk0 = {
- .name = "gclk0",
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 0,
-};
-static struct clk gclk1 = {
- .name = "gclk1",
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 1,
-};
-static struct clk gclk2 = {
- .name = "gclk2",
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 2,
-};
-static struct clk gclk3 = {
- .name = "gclk3",
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 3,
-};
-static struct clk gclk4 = {
- .name = "gclk4",
- .mode = genclk_mode,
- .get_rate = genclk_get_rate,
- .set_rate = genclk_set_rate,
- .set_parent = genclk_set_parent,
- .index = 4,
-};
-
-struct clk *at32_clock_list[] = {
- &osc32k,
- &osc0,
- &osc1,
- &pll0,
- &pll1,
- &cpu_clk,
- &hsb_clk,
- &pba_clk,
- &pbb_clk,
- &at32_pm_pclk,
- &at32_intc0_pclk,
- &hmatrix_clk,
- &ebi_clk,
- &hramc_clk,
- &smc0_pclk,
- &smc0_mck,
- &pdc_hclk,
- &pdc_pclk,
- &dmaca0_hclk,
- &pico_clk,
- &pio0_mck,
- &pio1_mck,
- &pio2_mck,
- &pio3_mck,
- &pio4_mck,
- &at32_systc0_pclk,
- &atmel_usart0_usart,
- &atmel_usart1_usart,
- &atmel_usart2_usart,
- &atmel_usart3_usart,
- &macb0_hclk,
- &macb0_pclk,
- &macb1_hclk,
- &macb1_pclk,
- &atmel_spi0_spi_clk,
- &atmel_spi1_spi_clk,
- &atmel_twi0_pclk,
- &atmel_mci0_pclk,
- &atmel_lcdfb0_hck1,
- &atmel_lcdfb0_pixclk,
- &ssc0_pclk,
- &ssc1_pclk,
- &ssc2_pclk,
- &usba0_hclk,
- &usba0_pclk,
- &atmel_ac97c0_pclk,
- &abdac0_pclk,
- &abdac0_sample_clk,
- &gclk0,
- &gclk1,
- &gclk2,
- &gclk3,
- &gclk4,
-};
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
-
-void __init at32_portmux_init(void)
-{
- at32_init_pio(&pio0_device);
- at32_init_pio(&pio1_device);
- at32_init_pio(&pio2_device);
- at32_init_pio(&pio3_device);
- at32_init_pio(&pio4_device);
-}
-
-void __init at32_clock_init(void)
-{
- u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
- int i;
-
- if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
- main_clock = &pll0;
- cpu_clk.parent = &pll0;
- } else {
- main_clock = &osc0;
- cpu_clk.parent = &osc0;
- }
-
- if (pm_readl(PLL0) & PM_BIT(PLLOSC))
- pll0.parent = &osc1;
- if (pm_readl(PLL1) & PM_BIT(PLLOSC))
- pll1.parent = &osc1;
-
- genclk_init_parent(&gclk0);
- genclk_init_parent(&gclk1);
- genclk_init_parent(&gclk2);
- genclk_init_parent(&gclk3);
- genclk_init_parent(&gclk4);
- genclk_init_parent(&atmel_lcdfb0_pixclk);
- genclk_init_parent(&abdac0_sample_clk);
-
- /*
- * Turn on all clocks that have at least one user already, and
- * turn off everything else. We only do this for module
- * clocks, and even though it isn't particularly pretty to
- * check the address of the mode function, it should do the
- * trick...
- */
- for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
- struct clk *clk = at32_clock_list[i];
-
- if (clk->users == 0)
- continue;
-
- if (clk->mode == &cpu_clk_mode)
- cpu_mask |= 1 << clk->index;
- else if (clk->mode == &hsb_clk_mode)
- hsb_mask |= 1 << clk->index;
- else if (clk->mode == &pba_clk_mode)
- pba_mask |= 1 << clk->index;
- else if (clk->mode == &pbb_clk_mode)
- pbb_mask |= 1 << clk->index;
- }
-
- pm_writel(CPU_MASK, cpu_mask);
- pm_writel(HSB_MASK, hsb_mask);
- pm_writel(PBA_MASK, pba_mask);
- pm_writel(PBB_MASK, pbb_mask);
-}
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
new file mode 100644
index 0000000..06795d0
--- /dev/null
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -0,0 +1,1809 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/board.h>
+#include <asm/arch/portmux.h>
+
+#include <video/atmel_lcdc.h>
+
+#include "clock.h"
+#include "hmatrix.h"
+#include "pio.h"
+#include "pm.h"
+
+
+#define PBMEM(base) \
+ { \
+ .start = base, \
+ .end = base + 0x3ff, \
+ .flags = IORESOURCE_MEM, \
+ }
+#define IRQ(num) \
+ { \
+ .start = num, \
+ .end = num, \
+ .flags = IORESOURCE_IRQ, \
+ }
+#define NAMED_IRQ(num, _name) \
+ { \
+ .start = num, \
+ .end = num, \
+ .name = _name, \
+ .flags = IORESOURCE_IRQ, \
+ }
+
+/* REVISIT these assume *every* device supports DMA, but several
+ * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
+ */
+#define DEFINE_DEV(_name, _id) \
+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \
+static struct platform_device _name##_id##_device = { \
+ .name = #_name, \
+ .id = _id, \
+ .dev = { \
+ .dma_mask = &_name##_id##_dma_mask, \
+ .coherent_dma_mask = DMA_32BIT_MASK, \
+ }, \
+ .resource = _name##_id##_resource, \
+ .num_resources = ARRAY_SIZE(_name##_id##_resource), \
+}
+#define DEFINE_DEV_DATA(_name, _id) \
+static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \
+static struct platform_device _name##_id##_device = { \
+ .name = #_name, \
+ .id = _id, \
+ .dev = { \
+ .dma_mask = &_name##_id##_dma_mask, \
+ .platform_data = &_name##_id##_data, \
+ .coherent_dma_mask = DMA_32BIT_MASK, \
+ }, \
+ .resource = _name##_id##_resource, \
+ .num_resources = ARRAY_SIZE(_name##_id##_resource), \
+}
+
+#define select_peripheral(pin, periph, flags) \
+ at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+
+#define DEV_CLK(_name, devname, bus, _index) \
+static struct clk devname##_##_name = { \
+ .name = #_name, \
+ .dev = &devname##_device.dev, \
+ .parent = &bus##_clk, \
+ .mode = bus##_clk_mode, \
+ .get_rate = bus##_clk_get_rate, \
+ .index = _index, \
+}
+
+static DEFINE_SPINLOCK(pm_lock);
+
+unsigned long at32ap7000_osc_rates[3] = {
+ [0] = 32768,
+ /* FIXME: these are ATSTK1002-specific */
+ [1] = 20000000,
+ [2] = 12000000,
+};
+
+static unsigned long osc_get_rate(struct clk *clk)
+{
+ return at32ap7000_osc_rates[clk->index];
+}
+
+static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
+{
+ unsigned long div, mul, rate;
+
+ if (!(control & PM_BIT(PLLEN)))
+ return 0;
+
+ div = PM_BFEXT(PLLDIV, control) + 1;
+ mul = PM_BFEXT(PLLMUL, control) + 1;
+
+ rate = clk->parent->get_rate(clk->parent);
+ rate = (rate + div / 2) / div;
+ rate *= mul;
+
+ return rate;
+}
+
+static unsigned long pll0_get_rate(struct clk *clk)
+{
+ u32 control;
+
+ control = pm_readl(PLL0);
+
+ return pll_get_rate(clk, control);
+}
+
+static unsigned long pll1_get_rate(struct clk *clk)
+{
+ u32 control;
+
+ control = pm_readl(PLL1);
+
+ return pll_get_rate(clk, control);
+}
+
+/*
+ * The AT32AP7000 has five primary clock sources: One 32kHz
+ * oscillator, two crystal oscillators and two PLLs.
+ */
+static struct clk osc32k = {
+ .name = "osc32k",
+ .get_rate = osc_get_rate,
+ .users = 1,
+ .index = 0,
+};
+static struct clk osc0 = {
+ .name = "osc0",
+ .get_rate = osc_get_rate,
+ .users = 1,
+ .index = 1,
+};
+static struct clk osc1 = {
+ .name = "osc1",
+ .get_rate = osc_get_rate,
+ .index = 2,
+};
+static struct clk pll0 = {
+ .name = "pll0",
+ .get_rate = pll0_get_rate,
+ .parent = &osc0,
+};
+static struct clk pll1 = {
+ .name = "pll1",
+ .get_rate = pll1_get_rate,
+ .parent = &osc0,
+};
+
+/*
+ * The main clock can be either osc0 or pll0. The boot loader may
+ * have chosen one for us, so we don't really know which one until we
+ * have a look at the SM.
+ */
+static struct clk *main_clock;
+
+/*
+ * Synchronous clocks are generated from the main clock. The clocks
+ * must satisfy the constraint
+ * fCPU >= fHSB >= fPB
+ * i.e. each clock must not be faster than its parent.
+ */
+static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
+{
+ return main_clock->get_rate(main_clock) >> shift;
+};
+
+static void cpu_clk_mode(struct clk *clk, int enabled)
+{
+ unsigned long flags;
+ u32 mask;
+
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(CPU_MASK);
+ if (enabled)
+ mask |= 1 << clk->index;
+ else
+ mask &= ~(1 << clk->index);
+ pm_writel(CPU_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long cpu_clk_get_rate(struct clk *clk)
+{
+ unsigned long cksel, shift = 0;
+
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(CPUDIV))
+ shift = PM_BFEXT(CPUSEL, cksel) + 1;
+
+ return bus_clk_get_rate(clk, shift);
+}
+
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+ u32 control;
+ unsigned long parent_rate, child_div, actual_rate, div;
+
+ parent_rate = clk->parent->get_rate(clk->parent);
+ control = pm_readl(CKSEL);
+
+ if (control & PM_BIT(HSBDIV))
+ child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+ else
+ child_div = 1;
+
+ if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+ actual_rate = parent_rate;
+ control &= ~PM_BIT(CPUDIV);
+ } else {
+ unsigned int cpusel;
+ div = (parent_rate + rate / 2) / rate;
+ if (div > child_div)
+ div = child_div;
+ cpusel = (div > 1) ? (fls(div) - 2) : 0;
+ control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+ actual_rate = parent_rate / (1 << (cpusel + 1));
+ }
+
+ pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+ clk->name, rate, actual_rate);
+
+ if (apply)
+ pm_writel(CKSEL, control);
+
+ return actual_rate;
+}
+
+static void hsb_clk_mode(struct clk *clk, int enabled)
+{
+ unsigned long flags;
+ u32 mask;
+
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(HSB_MASK);
+ if (enabled)
+ mask |= 1 << clk->index;
+ else
+ mask &= ~(1 << clk->index);
+ pm_writel(HSB_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long hsb_clk_get_rate(struct clk *clk)
+{
+ unsigned long cksel, shift = 0;
+
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(HSBDIV))
+ shift = PM_BFEXT(HSBSEL, cksel) + 1;
+
+ return bus_clk_get_rate(clk, shift);
+}
+
+static void pba_clk_mode(struct clk *clk, int enabled)
+{
+ unsigned long flags;
+ u32 mask;
+
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(PBA_MASK);
+ if (enabled)
+ mask |= 1 << clk->index;
+ else
+ mask &= ~(1 << clk->index);
+ pm_writel(PBA_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long pba_clk_get_rate(struct clk *clk)
+{
+ unsigned long cksel, shift = 0;
+
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(PBADIV))
+ shift = PM_BFEXT(PBASEL, cksel) + 1;
+
+ return bus_clk_get_rate(clk, shift);
+}
+
+static void pbb_clk_mode(struct clk *clk, int enabled)
+{
+ unsigned long flags;
+ u32 mask;
+
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(PBB_MASK);
+ if (enabled)
+ mask |= 1 << clk->index;
+ else
+ mask &= ~(1 << clk->index);
+ pm_writel(PBB_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
+}
+
+static unsigned long pbb_clk_get_rate(struct clk *clk)
+{
+ unsigned long cksel, shift = 0;
+
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(PBBDIV))
+ shift = PM_BFEXT(PBBSEL, cksel) + 1;
+
+ return bus_clk_get_rate(clk, shift);
+}
+
+static struct clk cpu_clk = {
+ .name = "cpu",
+ .get_rate = cpu_clk_get_rate,
+ .set_rate = cpu_clk_set_rate,
+ .users = 1,
+};
+static struct clk hsb_clk = {
+ .name = "hsb",
+ .parent = &cpu_clk,
+ .get_rate = hsb_clk_get_rate,
+};
+static struct clk pba_clk = {
+ .name = "pba",
+ .parent = &hsb_clk,
+ .mode = hsb_clk_mode,
+ .get_rate = pba_clk_get_rate,
+ .index = 1,
+};
+static struct clk pbb_clk = {
+ .name = "pbb",
+ .parent = &hsb_clk,
+ .mode = hsb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .users = 1,
+ .index = 2,
+};
+
+/* --------------------------------------------------------------------
+ * Generic Clock operations
+ * -------------------------------------------------------------------- */
+
+static void genclk_mode(struct clk *clk, int enabled)
+{
+ u32 control;
+
+ control = pm_readl(GCCTRL(clk->index));
+ if (enabled)
+ control |= PM_BIT(CEN);
+ else
+ control &= ~PM_BIT(CEN);
+ pm_writel(GCCTRL(clk->index), control);
+}
+
+static unsigned long genclk_get_rate(struct clk *clk)
+{
+ u32 control;
+ unsigned long div = 1;
+
+ control = pm_readl(GCCTRL(clk->index));
+ if (control & PM_BIT(DIVEN))
+ div = 2 * (PM_BFEXT(DIV, control) + 1);
+
+ return clk->parent->get_rate(clk->parent) / div;
+}
+
+static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+ u32 control;
+ unsigned long parent_rate, actual_rate, div;
+
+ parent_rate = clk->parent->get_rate(clk->parent);
+ control = pm_readl(GCCTRL(clk->index));
+
+ if (rate > 3 * parent_rate / 4) {
+ actual_rate = parent_rate;
+ control &= ~PM_BIT(DIVEN);
+ } else {
+ div = (parent_rate + rate) / (2 * rate) - 1;
+ control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
+ actual_rate = parent_rate / (2 * (div + 1));
+ }
+
+ dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+ clk->name, rate, actual_rate);
+
+ if (apply)
+ pm_writel(GCCTRL(clk->index), control);
+
+ return actual_rate;
+}
+
+int genclk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 control;
+
+ dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+ clk->name, parent->name, clk->parent->name);
+
+ control = pm_readl(GCCTRL(clk->index));
+
+ if (parent == &osc1 || parent == &pll1)
+ control |= PM_BIT(OSCSEL);
+ else if (parent == &osc0 || parent == &pll0)
+ control &= ~PM_BIT(OSCSEL);
+ else
+ return -EINVAL;
+
+ if (parent == &pll0 || parent == &pll1)
+ control |= PM_BIT(PLLSEL);
+ else
+ control &= ~PM_BIT(PLLSEL);
+
+ pm_writel(GCCTRL(clk->index), control);
+ clk->parent = parent;
+
+ return 0;
+}
+
+static void __init genclk_init_parent(struct clk *clk)
+{
+ u32 control;
+ struct clk *parent;
+
+ BUG_ON(clk->index > 7);
+
+ control = pm_readl(GCCTRL(clk->index));
+ if (control & PM_BIT(OSCSEL))
+ parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
+ else
+ parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
+
+ clk->parent = parent;
+}
+
+/* --------------------------------------------------------------------
+ * System peripherals
+ * -------------------------------------------------------------------- */
+static struct resource at32_pm0_resource[] = {
+ {
+ .start = 0xfff00000,
+ .end = 0xfff0007f,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(20),
+};
+
+static struct resource at32ap700x_rtc0_resource[] = {
+ {
+ .start = 0xfff00080,
+ .end = 0xfff000af,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(21),
+};
+
+static struct resource at32_wdt0_resource[] = {
+ {
+ .start = 0xfff000b0,
+ .end = 0xfff000cf,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource at32_eic0_resource[] = {
+ {
+ .start = 0xfff00100,
+ .end = 0xfff0013f,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(19),
+};
+
+DEFINE_DEV(at32_pm, 0);
+DEFINE_DEV(at32ap700x_rtc, 0);
+DEFINE_DEV(at32_wdt, 0);
+DEFINE_DEV(at32_eic, 0);
+
+/*
+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+ * is always running.
+ */
+static struct clk at32_pm_pclk = {
+ .name = "pclk",
+ .dev = &at32_pm0_device.dev,
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .users = 1,
+ .index = 0,
+};
+
+static struct resource intc0_resource[] = {
+ PBMEM(0xfff00400),
+};
+struct platform_device at32_intc0_device = {
+ .name = "intc",
+ .id = 0,
+ .resource = intc0_resource,
+ .num_resources = ARRAY_SIZE(intc0_resource),
+};
+DEV_CLK(pclk, at32_intc0, pbb, 1);
+
+static struct clk ebi_clk = {
+ .name = "ebi",
+ .parent = &hsb_clk,
+ .mode = hsb_clk_mode,
+ .get_rate = hsb_clk_get_rate,
+ .users = 1,
+};
+static struct clk hramc_clk = {
+ .name = "hramc",
+ .parent = &hsb_clk,
+ .mode = hsb_clk_mode,
+ .get_rate = hsb_clk_get_rate,
+ .users = 1,
+ .index = 3,
+};
+
+static struct resource smc0_resource[] = {
+ PBMEM(0xfff03400),
+};
+DEFINE_DEV(smc, 0);
+DEV_CLK(pclk, smc0, pbb, 13);
+DEV_CLK(mck, smc0, hsb, 0);
+
+static struct platform_device pdc_device = {
+ .name = "pdc",
+ .id = 0,
+};
+DEV_CLK(hclk, pdc, hsb, 4);
+DEV_CLK(pclk, pdc, pba, 16);
+
+static struct clk pico_clk = {
+ .name = "pico",
+ .parent = &cpu_clk,
+ .mode = cpu_clk_mode,
+ .get_rate = cpu_clk_get_rate,
+ .users = 1,
+};
+
+static struct resource dmaca0_resource[] = {
+ {
+ .start = 0xff200000,
+ .end = 0xff20ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(2),
+};
+DEFINE_DEV(dmaca, 0);
+DEV_CLK(hclk, dmaca0, hsb, 10);
+
+/* --------------------------------------------------------------------
+ * HMATRIX
+ * -------------------------------------------------------------------- */
+
+static struct clk hmatrix_clk = {
+ .name = "hmatrix_clk",
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .index = 2,
+ .users = 1,
+};
+#define HMATRIX_BASE ((void __iomem *)0xfff00800)
+
+#define hmatrix_readl(reg) \
+ __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+#define hmatrix_writel(reg,value) \
+ __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+
+/*
+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
+ * External Bus Interface (EBI). This can be used to enable special
+ * features like CompactFlash support, NAND Flash support, etc. on
+ * certain chipselects.
+ */
+static inline void set_ebi_sfr_bits(u32 mask)
+{
+ u32 sfr;
+
+ clk_enable(&hmatrix_clk);
+ sfr = hmatrix_readl(SFR4);
+ sfr |= mask;
+ hmatrix_writel(SFR4, sfr);
+ clk_disable(&hmatrix_clk);
+}
+
+/* --------------------------------------------------------------------
+ * System Timer/Counter (TC)
+ * -------------------------------------------------------------------- */
+static struct resource at32_systc0_resource[] = {
+ PBMEM(0xfff00c00),
+ IRQ(22),
+};
+struct platform_device at32_systc0_device = {
+ .name = "systc",
+ .id = 0,
+ .resource = at32_systc0_resource,
+ .num_resources = ARRAY_SIZE(at32_systc0_resource),
+};
+DEV_CLK(pclk, at32_systc0, pbb, 3);
+
+/* --------------------------------------------------------------------
+ * PIO
+ * -------------------------------------------------------------------- */
+
+static struct resource pio0_resource[] = {
+ PBMEM(0xffe02800),
+ IRQ(13),
+};
+DEFINE_DEV(pio, 0);
+DEV_CLK(mck, pio0, pba, 10);
+
+static struct resource pio1_resource[] = {
+ PBMEM(0xffe02c00),
+ IRQ(14),
+};
+DEFINE_DEV(pio, 1);
+DEV_CLK(mck, pio1, pba, 11);
+
+static struct resource pio2_resource[] = {
+ PBMEM(0xffe03000),
+ IRQ(15),
+};
+DEFINE_DEV(pio, 2);
+DEV_CLK(mck, pio2, pba, 12);
+
+static struct resource pio3_resource[] = {
+ PBMEM(0xffe03400),
+ IRQ(16),
+};
+DEFINE_DEV(pio, 3);
+DEV_CLK(mck, pio3, pba, 13);
+
+static struct resource pio4_resource[] = {
+ PBMEM(0xffe03800),
+ IRQ(17),
+};
+DEFINE_DEV(pio, 4);
+DEV_CLK(mck, pio4, pba, 14);
+
+void __init at32_add_system_devices(void)
+{
+ platform_device_register(&at32_pm0_device);
+ platform_device_register(&at32_intc0_device);
+ platform_device_register(&at32ap700x_rtc0_device);
+ platform_device_register(&at32_wdt0_device);
+ platform_device_register(&at32_eic0_device);
+ platform_device_register(&smc0_device);
+ platform_device_register(&pdc_device);
+ platform_device_register(&dmaca0_device);
+
+ platform_device_register(&at32_systc0_device);
+
+ platform_device_register(&pio0_device);
+ platform_device_register(&pio1_device);
+ platform_device_register(&pio2_device);
+ platform_device_register(&pio3_device);
+ platform_device_register(&pio4_device);
+}
+
+/* --------------------------------------------------------------------
+ * USART
+ * -------------------------------------------------------------------- */
+
+static struct atmel_uart_data atmel_usart0_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart0_resource[] = {
+ PBMEM(0xffe00c00),
+ IRQ(6),
+};
+DEFINE_DEV_DATA(atmel_usart, 0);
+DEV_CLK(usart, atmel_usart0, pba, 3);
+
+static struct atmel_uart_data atmel_usart1_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart1_resource[] = {
+ PBMEM(0xffe01000),
+ IRQ(7),
+};
+DEFINE_DEV_DATA(atmel_usart, 1);
+DEV_CLK(usart, atmel_usart1, pba, 4);
+
+static struct atmel_uart_data atmel_usart2_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart2_resource[] = {
+ PBMEM(0xffe01400),
+ IRQ(8),
+};
+DEFINE_DEV_DATA(atmel_usart, 2);
+DEV_CLK(usart, atmel_usart2, pba, 5);
+
+static struct atmel_uart_data atmel_usart3_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart3_resource[] = {
+ PBMEM(0xffe01800),
+ IRQ(9),
+};
+DEFINE_DEV_DATA(atmel_usart, 3);
+DEV_CLK(usart, atmel_usart3, pba, 6);
+
+static inline void configure_usart0_pins(void)
+{
+ select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
+ select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
+}
+
+static inline void configure_usart1_pins(void)
+{
+ select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
+ select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
+}
+
+static inline void configure_usart2_pins(void)
+{
+ select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
+ select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
+}
+
+static inline void configure_usart3_pins(void)
+{
+ select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
+ select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
+}
+
+static struct platform_device *__initdata at32_usarts[4];
+
+void __init at32_map_usart(unsigned int hw_id, unsigned int line)
+{
+ struct platform_device *pdev;
+
+ switch (hw_id) {
+ case 0:
+ pdev = &atmel_usart0_device;
+ configure_usart0_pins();
+ break;
+ case 1:
+ pdev = &atmel_usart1_device;
+ configure_usart1_pins();
+ break;
+ case 2:
+ pdev = &atmel_usart2_device;
+ configure_usart2_pins();
+ break;
+ case 3:
+ pdev = &atmel_usart3_device;
+ configure_usart3_pins();
+ break;
+ default:
+ return;
+ }
+
+ if (PXSEG(pdev->resource[0].start) == P4SEG) {
+ /* Addresses in the P4 segment are permanently mapped 1:1 */
+ struct atmel_uart_data *data = pdev->dev.platform_data;
+ data->regs = (void __iomem *)pdev->resource[0].start;
+ }
+
+ pdev->id = line;
+ at32_usarts[line] = pdev;
+}
+
+struct platform_device *__init at32_add_device_usart(unsigned int id)
+{
+ platform_device_register(at32_usarts[id]);
+ return at32_usarts[id];
+}
+
+struct platform_device *atmel_default_console_device;
+
+void __init at32_setup_serial_console(unsigned int usart_id)
+{
+ atmel_default_console_device = at32_usarts[usart_id];
+}
+
+/* --------------------------------------------------------------------
+ * Ethernet
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_CPU_AT32AP7000
+static struct eth_platform_data macb0_data;
+static struct resource macb0_resource[] = {
+ PBMEM(0xfff01800),
+ IRQ(25),
+};
+DEFINE_DEV_DATA(macb, 0);
+DEV_CLK(hclk, macb0, hsb, 8);
+DEV_CLK(pclk, macb0, pbb, 6);
+
+static struct eth_platform_data macb1_data;
+static struct resource macb1_resource[] = {
+ PBMEM(0xfff01c00),
+ IRQ(26),
+};
+DEFINE_DEV_DATA(macb, 1);
+DEV_CLK(hclk, macb1, hsb, 9);
+DEV_CLK(pclk, macb1, pbb, 7);
+
+struct platform_device *__init
+at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
+{
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0:
+ pdev = &macb0_device;
+
+ select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
+ select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
+ select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
+ select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
+ select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
+ select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
+ select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
+ select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
+ select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
+ select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+
+ if (!data->is_rmii) {
+ select_peripheral(PC(0), PERIPH_A, 0); /* COL */
+ select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
+ select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
+ select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
+ select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
+ select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
+ select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
+ select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
+ select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
+ }
+ break;
+
+ case 1:
+ pdev = &macb1_device;
+
+ select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */
+ select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */
+ select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */
+ select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */
+ select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */
+ select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */
+ select_peripheral(PD(5), PERIPH_B, 0); /* RXER */
+ select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */
+ select_peripheral(PD(3), PERIPH_B, 0); /* MDC */
+ select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */
+
+ if (!data->is_rmii) {
+ select_peripheral(PC(19), PERIPH_B, 0); /* COL */
+ select_peripheral(PC(23), PERIPH_B, 0); /* CRS */
+ select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
+ select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
+ select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
+ select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
+ select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
+ select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
+ select_peripheral(PD(15), PERIPH_B, 0); /* SPD */
+ }
+ break;
+
+ default:
+ return NULL;
+ }
+
+ memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
+ platform_device_register(pdev);
+
+ return pdev;
+}
+#endif
+
+/* --------------------------------------------------------------------
+ * SPI
+ * -------------------------------------------------------------------- */
+static struct resource atmel_spi0_resource[] = {
+ PBMEM(0xffe00000),
+ IRQ(3),
+};
+DEFINE_DEV(atmel_spi, 0);
+DEV_CLK(spi_clk, atmel_spi0, pba, 0);
+
+static struct resource atmel_spi1_resource[] = {
+ PBMEM(0xffe00400),
+ IRQ(4),
+};
+DEFINE_DEV(atmel_spi, 1);
+DEV_CLK(spi_clk, atmel_spi1, pba, 1);
+
+static void __init
+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
+ unsigned int n, const u8 *pins)
+{
+ unsigned int pin, mode;
+
+ for (; n; n--, b++) {
+ b->bus_num = bus_num;
+ if (b->chip_select >= 4)
+ continue;
+ pin = (unsigned)b->controller_data;
+ if (!pin) {
+ pin = pins[b->chip_select];
+ b->controller_data = (void *)pin;
+ }
+ mode = AT32_GPIOF_OUTPUT;
+ if (!(b->mode & SPI_CS_HIGH))
+ mode |= AT32_GPIOF_HIGH;
+ at32_select_gpio(pin, mode);
+ }
+}
+
+struct platform_device *__init
+at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
+{
+ /*
+ * Manage the chipselects as GPIOs, normally using the same pins
+ * the SPI controller expects; but boards can use other pins.
+ */
+ static u8 __initdata spi0_pins[] =
+ { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
+ GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
+ static u8 __initdata spi1_pins[] =
+ { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
+ GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0:
+ pdev = &atmel_spi0_device;
+ select_peripheral(PA(0), PERIPH_A, 0); /* MISO */
+ select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
+ select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
+ at32_spi_setup_slaves(0, b, n, spi0_pins);
+ break;
+
+ case 1:
+ pdev = &atmel_spi1_device;
+ select_peripheral(PB(0), PERIPH_B, 0); /* MISO */
+ select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
+ select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
+ at32_spi_setup_slaves(1, b, n, spi1_pins);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ spi_register_board_info(b, n);
+ platform_device_register(pdev);
+ return pdev;
+}
+
+/* --------------------------------------------------------------------
+ * TWI
+ * -------------------------------------------------------------------- */
+static struct resource atmel_twi0_resource[] __initdata = {
+ PBMEM(0xffe00800),
+ IRQ(5),
+};
+static struct clk atmel_twi0_pclk = {
+ .name = "twi_pclk",
+ .parent = &pba_clk,
+ .mode = pba_clk_mode,
+ .get_rate = pba_clk_get_rate,
+ .index = 2,
+};
+
+struct platform_device *__init at32_add_device_twi(unsigned int id)
+{
+ struct platform_device *pdev;
+
+ if (id != 0)
+ return NULL;
+
+ pdev = platform_device_alloc("atmel_twi", id);
+ if (!pdev)
+ return NULL;
+
+ if (platform_device_add_resources(pdev, atmel_twi0_resource,
+ ARRAY_SIZE(atmel_twi0_resource)))
+ goto err_add_resources;
+
+ select_peripheral(PA(6), PERIPH_A, 0); /* SDA */
+ select_peripheral(PA(7), PERIPH_A, 0); /* SDL */
+
+ atmel_twi0_pclk.dev = &pdev->dev;
+
+ platform_device_add(pdev);
+ return pdev;
+
+err_add_resources:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * MMC
+ * -------------------------------------------------------------------- */
+static struct resource atmel_mci0_resource[] __initdata = {
+ PBMEM(0xfff02400),
+ IRQ(28),
+};
+static struct clk atmel_mci0_pclk = {
+ .name = "mci_clk",
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .index = 9,
+};
+
+struct platform_device *__init
+at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
+{
+ struct platform_device *pdev;
+
+ if (id != 0)
+ return NULL;
+
+ pdev = platform_device_alloc("atmel_mci", id);
+ if (!pdev)
+ goto fail;
+
+ if (platform_device_add_resources(pdev, atmel_mci0_resource,
+ ARRAY_SIZE(atmel_mci0_resource)))
+ goto fail;
+
+ if (data && platform_device_add_data(pdev, data,
+ sizeof(struct mci_platform_data)))
+ goto fail;
+
+ select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
+ select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
+ select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
+ select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
+ select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
+ select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+
+ if (data) {
+ if (data->detect_pin != GPIO_PIN_NONE)
+ at32_select_gpio(data->detect_pin, 0);
+ if (data->wp_pin != GPIO_PIN_NONE)
+ at32_select_gpio(data->wp_pin, 0);
+ }
+
+ atmel_mci0_pclk.dev = &pdev->dev;
+
+ platform_device_add(pdev);
+ return pdev;
+
+fail:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * LCDC
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
+static struct atmel_lcdfb_info atmel_lcdfb0_data;
+static struct resource atmel_lcdfb0_resource[] = {
+ {
+ .start = 0xff000000,
+ .end = 0xff000fff,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(1),
+ {
+ /* Placeholder for pre-allocated fb memory */
+ .start = 0x00000000,
+ .end = 0x00000000,
+ .flags = 0,
+ },
+};
+DEFINE_DEV_DATA(atmel_lcdfb, 0);
+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
+static struct clk atmel_lcdfb0_pixclk = {
+ .name = "lcdc_clk",
+ .dev = &atmel_lcdfb0_device.dev,
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 7,
+};
+
+struct platform_device *__init
+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+ unsigned long fbmem_start, unsigned long fbmem_len)
+{
+ struct platform_device *pdev;
+ struct atmel_lcdfb_info *info;
+ struct fb_monspecs *monspecs;
+ struct fb_videomode *modedb;
+ unsigned int modedb_size;
+
+ /*
+ * Do a deep copy of the fb data, monspecs and modedb. Make
+ * sure all allocations are done before setting up the
+ * portmux.
+ */
+ monspecs = kmemdup(data->default_monspecs,
+ sizeof(struct fb_monspecs), GFP_KERNEL);
+ if (!monspecs)
+ return NULL;
+
+ modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
+ modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
+ if (!modedb)
+ goto err_dup_modedb;
+ monspecs->modedb = modedb;
+
+ switch (id) {
+ case 0:
+ pdev = &atmel_lcdfb0_device;
+ select_peripheral(PC(19), PERIPH_A, 0); /* CC */
+ select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
+ select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
+ select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
+ select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
+ select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
+ select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
+ select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
+ select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
+ select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
+ select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
+ select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
+ select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
+ select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
+ select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
+ select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
+ select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
+ select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
+ select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
+ select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
+ select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
+ select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
+ select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
+ select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+ select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+ select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+ select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+ select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+ select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+ select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+ select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+
+ clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
+ clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
+ break;
+
+ default:
+ goto err_invalid_id;
+ }
+
+ if (fbmem_len) {
+ pdev->resource[2].start = fbmem_start;
+ pdev->resource[2].end = fbmem_start + fbmem_len - 1;
+ pdev->resource[2].flags = IORESOURCE_MEM;
+ }
+
+ info = pdev->dev.platform_data;
+ memcpy(info, data, sizeof(struct atmel_lcdfb_info));
+ info->default_monspecs = monspecs;
+
+ platform_device_register(pdev);
+ return pdev;
+
+err_invalid_id:
+ kfree(modedb);
+err_dup_modedb:
+ kfree(monspecs);
+ return NULL;
+}
+#endif
+
+/* --------------------------------------------------------------------
+ * PWM
+ * -------------------------------------------------------------------- */
+static struct resource atmel_pwm0_resource[] __initdata = {
+ PBMEM(0xfff01400),
+ IRQ(24),
+};
+static struct clk atmel_pwm0_mck = {
+ .name = "mck",
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .index = 5,
+};
+
+struct platform_device *__init at32_add_device_pwm(u32 mask)
+{
+ struct platform_device *pdev;
+
+ if (!mask)
+ return NULL;
+
+ pdev = platform_device_alloc("atmel_pwm", 0);
+ if (!pdev)
+ return NULL;
+
+ if (platform_device_add_resources(pdev, atmel_pwm0_resource,
+ ARRAY_SIZE(atmel_pwm0_resource)))
+ goto out_free_pdev;
+
+ if (platform_device_add_data(pdev, &mask, sizeof(mask)))
+ goto out_free_pdev;
+
+ if (mask & (1 << 0))
+ select_peripheral(PA(28), PERIPH_A, 0);
+ if (mask & (1 << 1))
+ select_peripheral(PA(29), PERIPH_A, 0);
+ if (mask & (1 << 2))
+ select_peripheral(PA(21), PERIPH_B, 0);
+ if (mask & (1 << 3))
+ select_peripheral(PA(22), PERIPH_B, 0);
+
+ atmel_pwm0_mck.dev = &pdev->dev;
+
+ platform_device_add(pdev);
+
+ return pdev;
+
+out_free_pdev:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * SSC
+ * -------------------------------------------------------------------- */
+static struct resource ssc0_resource[] = {
+ PBMEM(0xffe01c00),
+ IRQ(10),
+};
+DEFINE_DEV(ssc, 0);
+DEV_CLK(pclk, ssc0, pba, 7);
+
+static struct resource ssc1_resource[] = {
+ PBMEM(0xffe02000),
+ IRQ(11),
+};
+DEFINE_DEV(ssc, 1);
+DEV_CLK(pclk, ssc1, pba, 8);
+
+static struct resource ssc2_resource[] = {
+ PBMEM(0xffe02400),
+ IRQ(12),
+};
+DEFINE_DEV(ssc, 2);
+DEV_CLK(pclk, ssc2, pba, 9);
+
+struct platform_device *__init
+at32_add_device_ssc(unsigned int id, unsigned int flags)
+{
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0:
+ pdev = &ssc0_device;
+ if (flags & ATMEL_SSC_RF)
+ select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+ if (flags & ATMEL_SSC_RK)
+ select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+ if (flags & ATMEL_SSC_TK)
+ select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+ if (flags & ATMEL_SSC_TF)
+ select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+ if (flags & ATMEL_SSC_TD)
+ select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+ if (flags & ATMEL_SSC_RD)
+ select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+ break;
+ case 1:
+ pdev = &ssc1_device;
+ if (flags & ATMEL_SSC_RF)
+ select_peripheral(PA(0), PERIPH_B, 0); /* RF */
+ if (flags & ATMEL_SSC_RK)
+ select_peripheral(PA(1), PERIPH_B, 0); /* RK */
+ if (flags & ATMEL_SSC_TK)
+ select_peripheral(PA(2), PERIPH_B, 0); /* TK */
+ if (flags & ATMEL_SSC_TF)
+ select_peripheral(PA(3), PERIPH_B, 0); /* TF */
+ if (flags & ATMEL_SSC_TD)
+ select_peripheral(PA(4), PERIPH_B, 0); /* TD */
+ if (flags & ATMEL_SSC_RD)
+ select_peripheral(PA(5), PERIPH_B, 0); /* RD */
+ break;
+ case 2:
+ pdev = &ssc2_device;
+ if (flags & ATMEL_SSC_TD)
+ select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+ if (flags & ATMEL_SSC_RD)
+ select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+ if (flags & ATMEL_SSC_TK)
+ select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+ if (flags & ATMEL_SSC_TF)
+ select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+ if (flags & ATMEL_SSC_RF)
+ select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+ if (flags & ATMEL_SSC_RK)
+ select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+ break;
+ default:
+ return NULL;
+ }
+
+ platform_device_register(pdev);
+ return pdev;
+}
+
+/* --------------------------------------------------------------------
+ * USB Device Controller
+ * -------------------------------------------------------------------- */
+static struct resource usba0_resource[] __initdata = {
+ {
+ .start = 0xff300000,
+ .end = 0xff3fffff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 0xfff03000,
+ .end = 0xfff033ff,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(31),
+};
+static struct clk usba0_pclk = {
+ .name = "pclk",
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .index = 12,
+};
+static struct clk usba0_hclk = {
+ .name = "hclk",
+ .parent = &hsb_clk,
+ .mode = hsb_clk_mode,
+ .get_rate = hsb_clk_get_rate,
+ .index = 6,
+};
+
+struct platform_device *__init
+at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
+{
+ struct platform_device *pdev;
+
+ if (id != 0)
+ return NULL;
+
+ pdev = platform_device_alloc("atmel_usba_udc", 0);
+ if (!pdev)
+ return NULL;
+
+ if (platform_device_add_resources(pdev, usba0_resource,
+ ARRAY_SIZE(usba0_resource)))
+ goto out_free_pdev;
+
+ if (data) {
+ if (platform_device_add_data(pdev, data, sizeof(*data)))
+ goto out_free_pdev;
+
+ if (data->vbus_pin != GPIO_PIN_NONE)
+ at32_select_gpio(data->vbus_pin, 0);
+ }
+
+ usba0_pclk.dev = &pdev->dev;
+ usba0_hclk.dev = &pdev->dev;
+
+ platform_device_add(pdev);
+
+ return pdev;
+
+out_free_pdev:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * IDE / CompactFlash
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7001)
+static struct resource at32_smc_cs4_resource[] __initdata = {
+ {
+ .start = 0x04000000,
+ .end = 0x07ffffff,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(~0UL), /* Magic IRQ will be overridden */
+};
+static struct resource at32_smc_cs5_resource[] __initdata = {
+ {
+ .start = 0x20000000,
+ .end = 0x23ffffff,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(~0UL), /* Magic IRQ will be overridden */
+};
+
+static int __init at32_init_ide_or_cf(struct platform_device *pdev,
+ unsigned int cs, unsigned int extint)
+{
+ static unsigned int extint_pin_map[4] __initdata = {
+ GPIO_PIN_PB(25),
+ GPIO_PIN_PB(26),
+ GPIO_PIN_PB(27),
+ GPIO_PIN_PB(28),
+ };
+ static bool common_pins_initialized __initdata = false;
+ unsigned int extint_pin;
+ int ret;
+
+ if (extint >= ARRAY_SIZE(extint_pin_map))
+ return -EINVAL;
+ extint_pin = extint_pin_map[extint];
+
+ switch (cs) {
+ case 4:
+ ret = platform_device_add_resources(pdev,
+ at32_smc_cs4_resource,
+ ARRAY_SIZE(at32_smc_cs4_resource));
+ if (ret)
+ return ret;
+
+ select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */
+ set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
+ break;
+ case 5:
+ ret = platform_device_add_resources(pdev,
+ at32_smc_cs5_resource,
+ ARRAY_SIZE(at32_smc_cs5_resource));
+ if (ret)
+ return ret;
+
+ select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */
+ set_ebi_sfr_bits(HMATRIX_BIT(CS5A));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!common_pins_initialized) {
+ select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */
+ select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */
+ select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */
+ select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */
+ common_pins_initialized = true;
+ }
+
+ at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+
+ pdev->resource[1].start = EIM_IRQ_BASE + extint;
+ pdev->resource[1].end = pdev->resource[1].start;
+
+ return 0;
+}
+
+struct platform_device *__init
+at32_add_device_ide(unsigned int id, unsigned int extint,
+ struct ide_platform_data *data)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("at32_ide", id);
+ if (!pdev)
+ goto fail;
+
+ if (platform_device_add_data(pdev, data,
+ sizeof(struct ide_platform_data)))
+ goto fail;
+
+ if (at32_init_ide_or_cf(pdev, data->cs, extint))
+ goto fail;
+
+ platform_device_add(pdev);
+ return pdev;
+
+fail:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+struct platform_device *__init
+at32_add_device_cf(unsigned int id, unsigned int extint,
+ struct cf_platform_data *data)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("at32_cf", id);
+ if (!pdev)
+ goto fail;
+
+ if (platform_device_add_data(pdev, data,
+ sizeof(struct cf_platform_data)))
+ goto fail;
+
+ if (at32_init_ide_or_cf(pdev, data->cs, extint))
+ goto fail;
+
+ if (data->detect_pin != GPIO_PIN_NONE)
+ at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
+ if (data->reset_pin != GPIO_PIN_NONE)
+ at32_select_gpio(data->reset_pin, 0);
+ if (data->vcc_pin != GPIO_PIN_NONE)
+ at32_select_gpio(data->vcc_pin, 0);
+ /* READY is used as extint, so we can't select it as gpio */
+
+ platform_device_add(pdev);
+ return pdev;
+
+fail:
+ platform_device_put(pdev);
+ return NULL;
+}
+#endif
+
+/* --------------------------------------------------------------------
+ * AC97C
+ * -------------------------------------------------------------------- */
+static struct resource atmel_ac97c0_resource[] __initdata = {
+ PBMEM(0xfff02800),
+ IRQ(29),
+};
+static struct clk atmel_ac97c0_pclk = {
+ .name = "pclk",
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .index = 10,
+};
+
+struct platform_device *__init at32_add_device_ac97c(unsigned int id)
+{
+ struct platform_device *pdev;
+
+ if (id != 0)
+ return NULL;
+
+ pdev = platform_device_alloc("atmel_ac97c", id);
+ if (!pdev)
+ return NULL;
+
+ if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
+ ARRAY_SIZE(atmel_ac97c0_resource)))
+ goto err_add_resources;
+
+ select_peripheral(PB(20), PERIPH_B, 0); /* SYNC */
+ select_peripheral(PB(21), PERIPH_B, 0); /* SDO */
+ select_peripheral(PB(22), PERIPH_B, 0); /* SDI */
+ select_peripheral(PB(23), PERIPH_B, 0); /* SCLK */
+
+ atmel_ac97c0_pclk.dev = &pdev->dev;
+
+ platform_device_add(pdev);
+ return pdev;
+
+err_add_resources:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * ABDAC
+ * -------------------------------------------------------------------- */
+static struct resource abdac0_resource[] __initdata = {
+ PBMEM(0xfff02000),
+ IRQ(27),
+};
+static struct clk abdac0_pclk = {
+ .name = "pclk",
+ .parent = &pbb_clk,
+ .mode = pbb_clk_mode,
+ .get_rate = pbb_clk_get_rate,
+ .index = 8,
+};
+static struct clk abdac0_sample_clk = {
+ .name = "sample_clk",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 6,
+};
+
+struct platform_device *__init at32_add_device_abdac(unsigned int id)
+{
+ struct platform_device *pdev;
+
+ if (id != 0)
+ return NULL;
+
+ pdev = platform_device_alloc("abdac", id);
+ if (!pdev)
+ return NULL;
+
+ if (platform_device_add_resources(pdev, abdac0_resource,
+ ARRAY_SIZE(abdac0_resource)))
+ goto err_add_resources;
+
+ select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */
+ select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */
+ select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */
+ select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */
+
+ abdac0_pclk.dev = &pdev->dev;
+ abdac0_sample_clk.dev = &pdev->dev;
+
+ platform_device_add(pdev);
+ return pdev;
+
+err_add_resources:
+ platform_device_put(pdev);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------
+ * GCLK
+ * -------------------------------------------------------------------- */
+static struct clk gclk0 = {
+ .name = "gclk0",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 0,
+};
+static struct clk gclk1 = {
+ .name = "gclk1",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 1,
+};
+static struct clk gclk2 = {
+ .name = "gclk2",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 2,
+};
+static struct clk gclk3 = {
+ .name = "gclk3",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 3,
+};
+static struct clk gclk4 = {
+ .name = "gclk4",
+ .mode = genclk_mode,
+ .get_rate = genclk_get_rate,
+ .set_rate = genclk_set_rate,
+ .set_parent = genclk_set_parent,
+ .index = 4,
+};
+
+struct clk *at32_clock_list[] = {
+ &osc32k,
+ &osc0,
+ &osc1,
+ &pll0,
+ &pll1,
+ &cpu_clk,
+ &hsb_clk,
+ &pba_clk,
+ &pbb_clk,
+ &at32_pm_pclk,
+ &at32_intc0_pclk,
+ &hmatrix_clk,
+ &ebi_clk,
+ &hramc_clk,
+ &smc0_pclk,
+ &smc0_mck,
+ &pdc_hclk,
+ &pdc_pclk,
+ &dmaca0_hclk,
+ &pico_clk,
+ &pio0_mck,
+ &pio1_mck,
+ &pio2_mck,
+ &pio3_mck,
+ &pio4_mck,
+ &at32_systc0_pclk,
+ &atmel_usart0_usart,
+ &atmel_usart1_usart,
+ &atmel_usart2_usart,
+ &atmel_usart3_usart,
+ &atmel_pwm0_mck,
+#if defined(CONFIG_CPU_AT32AP7000)
+ &macb0_hclk,
+ &macb0_pclk,
+ &macb1_hclk,
+ &macb1_pclk,
+#endif
+ &atmel_spi0_spi_clk,
+ &atmel_spi1_spi_clk,
+ &atmel_twi0_pclk,
+ &atmel_mci0_pclk,
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
+ &atmel_lcdfb0_hck1,
+ &atmel_lcdfb0_pixclk,
+#endif
+ &ssc0_pclk,
+ &ssc1_pclk,
+ &ssc2_pclk,
+ &usba0_hclk,
+ &usba0_pclk,
+ &atmel_ac97c0_pclk,
+ &abdac0_pclk,
+ &abdac0_sample_clk,
+ &gclk0,
+ &gclk1,
+ &gclk2,
+ &gclk3,
+ &gclk4,
+};
+unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
+
+void __init at32_portmux_init(void)
+{
+ at32_init_pio(&pio0_device);
+ at32_init_pio(&pio1_device);
+ at32_init_pio(&pio2_device);
+ at32_init_pio(&pio3_device);
+ at32_init_pio(&pio4_device);
+}
+
+void __init at32_clock_init(void)
+{
+ u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
+ int i;
+
+ if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
+ main_clock = &pll0;
+ cpu_clk.parent = &pll0;
+ } else {
+ main_clock = &osc0;
+ cpu_clk.parent = &osc0;
+ }
+
+ if (pm_readl(PLL0) & PM_BIT(PLLOSC))
+ pll0.parent = &osc1;
+ if (pm_readl(PLL1) & PM_BIT(PLLOSC))
+ pll1.parent = &osc1;
+
+ genclk_init_parent(&gclk0);
+ genclk_init_parent(&gclk1);
+ genclk_init_parent(&gclk2);
+ genclk_init_parent(&gclk3);
+ genclk_init_parent(&gclk4);
+#if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
+ genclk_init_parent(&atmel_lcdfb0_pixclk);
+#endif
+ genclk_init_parent(&abdac0_sample_clk);
+
+ /*
+ * Turn on all clocks that have at least one user already, and
+ * turn off everything else. We only do this for module
+ * clocks, and even though it isn't particularly pretty to
+ * check the address of the mode function, it should do the
+ * trick...
+ */
+ for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
+ struct clk *clk = at32_clock_list[i];
+
+ if (clk->users == 0)
+ continue;
+
+ if (clk->mode == &cpu_clk_mode)
+ cpu_mask |= 1 << clk->index;
+ else if (clk->mode == &hsb_clk_mode)
+ hsb_mask |= 1 << clk->index;
+ else if (clk->mode == &pba_clk_mode)
+ pba_mask |= 1 << clk->index;
+ else if (clk->mode == &pbb_clk_mode)
+ pbb_mask |= 1 << clk->index;
+ }
+
+ pm_writel(CPU_MASK, cpu_mask);
+ pm_writel(HSB_MASK, hsb_mask);
+ pm_writel(PBA_MASK, pba_mask);
+ pm_writel(PBB_MASK, pbb_mask);
+}
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index f5bfd4c..c36a6d5 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -26,16 +26,10 @@
#define EIC_MODE 0x0014
#define EIC_EDGE 0x0018
#define EIC_LEVEL 0x001c
-#define EIC_TEST 0x0020
#define EIC_NMIC 0x0024
-/* Bitfields in TEST */
-#define EIC_TESTEN_OFFSET 31
-#define EIC_TESTEN_SIZE 1
-
/* Bitfields in NMIC */
-#define EIC_EN_OFFSET 0
-#define EIC_EN_SIZE 1
+#define EIC_NMIC_ENABLE (1 << 0)
/* Bit manipulation macros */
#define EIC_BIT(name) \
@@ -63,6 +57,9 @@ struct eic {
unsigned int first_irq;
};
+static struct eic *nmi_eic;
+static bool nmi_enabled;
+
static void eic_ack_irq(unsigned int irq)
{
struct eic *eic = get_irq_chip_data(irq);
@@ -133,8 +130,11 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
eic_writel(eic, EDGE, edge);
eic_writel(eic, LEVEL, level);
- if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
flow_type |= IRQ_LEVEL;
+ __set_irq_handler_unlocked(irq, handle_level_irq);
+ } else
+ __set_irq_handler_unlocked(irq, handle_edge_irq);
desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
desc->status |= flow_type;
}
@@ -154,9 +154,8 @@ static struct irq_chip eic_chip = {
static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
{
struct eic *eic = desc->handler_data;
- struct irq_desc *ext_desc;
unsigned long status, pending;
- unsigned int i, ext_irq;
+ unsigned int i;
status = eic_readl(eic, ISR);
pending = status & eic_readl(eic, IMR);
@@ -165,15 +164,28 @@ static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
i = fls(pending) - 1;
pending &= ~(1 << i);
- ext_irq = i + eic->first_irq;
- ext_desc = irq_desc + ext_irq;
- if (ext_desc->status & IRQ_LEVEL)
- handle_level_irq(ext_irq, ext_desc);
- else
- handle_edge_irq(ext_irq, ext_desc);
+ generic_handle_irq(i + eic->first_irq);
}
}
+int nmi_enable(void)
+{
+ nmi_enabled = true;
+
+ if (nmi_eic)
+ eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
+
+ return 0;
+}
+
+void nmi_disable(void)
+{
+ if (nmi_eic)
+ eic_writel(nmi_eic, NMIC, 0);
+
+ nmi_enabled = false;
+}
+
static int __init eic_probe(struct platform_device *pdev)
{
struct eic *eic;
@@ -214,14 +226,13 @@ static int __init eic_probe(struct platform_device *pdev)
pattern = eic_readl(eic, MODE);
nr_irqs = fls(pattern);
- /* Trigger on falling edge unless overridden by driver */
- eic_writel(eic, MODE, 0UL);
+ /* Trigger on low level unless overridden by driver */
eic_writel(eic, EDGE, 0UL);
+ eic_writel(eic, LEVEL, 0UL);
eic->chip = &eic_chip;
for (i = 0; i < nr_irqs; i++) {
- /* NOTE the handler we set here is ignored by the demux */
set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
handle_level_irq);
set_irq_chip_data(eic->first_irq + i, eic);
@@ -230,6 +241,16 @@ static int __init eic_probe(struct platform_device *pdev)
set_irq_chained_handler(int_irq, demux_eic_irq);
set_irq_data(int_irq, eic);
+ if (pdev->id == 0) {
+ nmi_eic = eic;
+ if (nmi_enabled)
+ /*
+ * Someone tried to enable NMI before we were
+ * ready. Do it now.
+ */
+ nmi_enable();
+ }
+
dev_info(&pdev->dev,
"External Interrupt Controller at 0x%p, IRQ %u\n",
eic->regs, int_irq);
diff --git a/arch/avr32/mach-at32ap/gpio-dev.c b/arch/avr32/mach-at32ap/gpio-dev.c
new file mode 100644
index 0000000..8cf6d11
--- /dev/null
+++ b/arch/avr32/mach-at32ap/gpio-dev.c
@@ -0,0 +1,573 @@
+/*
+ * GPIO /dev and configfs interface
+ *
+ * Copyright (C) 2006-2007 Atmel Corporation
+ *
+ * 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/configfs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/portmux.h>
+
+#define GPIO_DEV_MAX 8
+
+static struct class *gpio_dev_class;
+static dev_t gpio_devt;
+
+struct gpio_item {
+ spinlock_t lock;
+
+ int enabled;
+ int initialized;
+ int port;
+ u32 pin_mask;
+ u32 oe_mask;
+
+ /* Pin state last time we read it (for blocking reads) */
+ u32 pin_state;
+ int changed;
+
+ wait_queue_head_t change_wq;
+ struct fasync_struct *async_queue;
+
+ int id;
+ struct class_device *gpio_dev;
+ struct cdev char_dev;
+ struct config_item item;
+};
+
+struct gpio_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct gpio_item *, char *);
+ ssize_t (*store)(struct gpio_item *, const char *, size_t);
+};
+
+static irqreturn_t gpio_dev_interrupt(int irq, void *dev_id)
+{
+ struct gpio_item *gpio = dev_id;
+ u32 old_state, new_state;
+
+ old_state = gpio->pin_state;
+ new_state = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
+ gpio->pin_state = new_state;
+
+ if (new_state != old_state) {
+ gpio->changed = 1;
+ wake_up_interruptible(&gpio->change_wq);
+
+ if (gpio->async_queue)
+ kill_fasync(&gpio->async_queue, SIGIO, POLL_IN);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int gpio_dev_open(struct inode *inode, struct file *file)
+{
+ struct gpio_item *gpio = container_of(inode->i_cdev,
+ struct gpio_item,
+ char_dev);
+ unsigned int irq;
+ unsigned int i;
+ int ret;
+
+ nonseekable_open(inode, file);
+ config_item_get(&gpio->item);
+ file->private_data = gpio;
+
+ gpio->pin_state = at32_gpio_get_value_multiple(gpio->port,
+ gpio->pin_mask);
+ gpio->changed = 1;
+
+ for (i = 0; i < 32; i++) {
+ if (gpio->pin_mask & (1 << i)) {
+ irq = gpio_to_irq(32 * gpio->port + i);
+ ret = request_irq(irq, gpio_dev_interrupt, 0,
+ "gpio-dev", gpio);
+ if (ret)
+ goto err_irq;
+ }
+ }
+
+ return 0;
+
+err_irq:
+ while (i--) {
+ if (gpio->pin_mask & (1 << i)) {
+ irq = gpio_to_irq(32 * gpio->port + i);
+ free_irq(irq, gpio);
+ }
+ }
+
+ config_item_put(&gpio->item);
+
+ return ret;
+}
+
+static int gpio_dev_fasync(int fd, struct file *file, int mode)
+{
+ struct gpio_item *gpio = file->private_data;
+
+ return fasync_helper(fd, file, mode, &gpio->async_queue);
+}
+
+static int gpio_dev_release(struct inode *inode, struct file *file)
+{
+ struct gpio_item *gpio = file->private_data;
+ unsigned int irq;
+ unsigned int i;
+
+ gpio_dev_fasync(-1, file, 0);
+
+ for (i = 0; i < 32; i++) {
+ if (gpio->pin_mask & (1 << i)) {
+ irq = gpio_to_irq(32 * gpio->port + i);
+ free_irq(irq, gpio);
+ }
+ }
+
+ config_item_put(&gpio->item);
+
+ return 0;
+}
+
+static unsigned int gpio_dev_poll(struct file *file, poll_table *wait)
+{
+ struct gpio_item *gpio = file->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(file, &gpio->change_wq, wait);
+ if (gpio->changed)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static ssize_t gpio_dev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct gpio_item *gpio = file->private_data;
+ u32 value;
+
+ spin_lock_irq(&gpio->lock);
+ while (!gpio->changed) {
+ spin_unlock_irq(&gpio->lock);
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if (wait_event_interruptible(gpio->change_wq, gpio->changed))
+ return -ERESTARTSYS;
+
+ spin_lock_irq(&gpio->lock);
+ }
+
+ gpio->changed = 0;
+ value = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
+
+ spin_unlock_irq(&gpio->lock);
+
+ count = min(count, (size_t)4);
+ if (copy_to_user(buf, &value, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static ssize_t gpio_dev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct gpio_item *gpio = file->private_data;
+ u32 value = 0;
+ u32 mask = ~0UL;
+
+ count = min(count, (size_t)4);
+ if (copy_from_user(&value, buf, count))
+ return -EFAULT;
+
+ /* Assuming big endian */
+ mask <<= (4 - count) * 8;
+ mask &= gpio->pin_mask;
+
+ at32_gpio_set_value_multiple(gpio->port, value, mask);
+
+ return count;
+}
+
+static struct file_operations gpio_dev_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = gpio_dev_open,
+ .release = gpio_dev_release,
+ .fasync = gpio_dev_fasync,
+ .poll = gpio_dev_poll,
+ .read = gpio_dev_read,
+ .write = gpio_dev_write,
+};
+
+static struct gpio_item *to_gpio_item(struct config_item *item)
+{
+ return item ? container_of(item, struct gpio_item, item) : NULL;
+}
+
+static ssize_t gpio_show_gpio_id(struct gpio_item *gpio, char *page)
+{
+ return sprintf(page, "%d\n", gpio->port);
+}
+
+static ssize_t gpio_store_gpio_id(struct gpio_item *gpio,
+ const char *page, size_t count)
+{
+ unsigned long id;
+ char *p = (char *)page;
+ ssize_t ret = -EINVAL;
+
+ id = simple_strtoul(p, &p, 0);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ /* Switching PIO is not allowed when live... */
+ spin_lock(&gpio->lock);
+ if (!gpio->enabled) {
+ ret = -ENXIO;
+ if (at32_gpio_port_is_valid(id)) {
+ gpio->port = id;
+ ret = count;
+ }
+ }
+ spin_unlock(&gpio->lock);
+
+ return ret;
+}
+
+static ssize_t gpio_show_pin_mask(struct gpio_item *gpio, char *page)
+{
+ return sprintf(page, "0x%08x\n", gpio->pin_mask);
+}
+
+static ssize_t gpio_store_pin_mask(struct gpio_item *gpio,
+ const char *page, size_t count)
+{
+ u32 new_mask;
+ char *p = (char *)page;
+ ssize_t ret = -EINVAL;
+
+ new_mask = simple_strtoul(p, &p, 0);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ /* Can't update the pin mask while live. */
+ spin_lock(&gpio->lock);
+ if (!gpio->enabled) {
+ gpio->oe_mask &= new_mask;
+ gpio->pin_mask = new_mask;
+ ret = count;
+ }
+ spin_unlock(&gpio->lock);
+
+ return ret;
+}
+
+static ssize_t gpio_show_oe_mask(struct gpio_item *gpio, char *page)
+{
+ return sprintf(page, "0x%08x\n", gpio->oe_mask);
+}
+
+static ssize_t gpio_store_oe_mask(struct gpio_item *gpio,
+ const char *page, size_t count)
+{
+ u32 mask;
+ char *p = (char *)page;
+ ssize_t ret = -EINVAL;
+
+ mask = simple_strtoul(p, &p, 0);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ spin_lock(&gpio->lock);
+ if (!gpio->enabled) {
+ gpio->oe_mask = mask & gpio->pin_mask;
+ ret = count;
+ }
+ spin_unlock(&gpio->lock);
+
+ return ret;
+}
+
+static ssize_t gpio_show_enabled(struct gpio_item *gpio, char *page)
+{
+ return sprintf(page, "%d\n", gpio->enabled);
+}
+
+static ssize_t gpio_store_enabled(struct gpio_item *gpio,
+ const char *page, size_t count)
+{
+ char *p = (char *)page;
+ int enabled;
+ int ret;
+
+ enabled = simple_strtoul(p, &p, 0);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ /* make it a boolean value */
+ enabled = !!enabled;
+
+ if (gpio->enabled == enabled)
+ /* No change; do nothing. */
+ return count;
+
+ BUG_ON(gpio->id >= GPIO_DEV_MAX);
+
+ if (!enabled) {
+ class_device_unregister(gpio->gpio_dev);
+ cdev_del(&gpio->char_dev);
+ at32_deselect_pins(gpio->port, gpio->pin_mask);
+ gpio->initialized = 0;
+ } else {
+ if (gpio->port < 0 || !gpio->pin_mask)
+ return -ENODEV;
+ }
+
+ /* Disallow any updates to gpio_id or pin_mask */
+ spin_lock(&gpio->lock);
+ gpio->enabled = enabled;
+ spin_unlock(&gpio->lock);
+
+ if (!enabled)
+ return count;
+
+ /* Now, try to allocate the pins */
+ ret = at32_select_gpio_pins(gpio->port, gpio->pin_mask, gpio->oe_mask);
+ if (ret)
+ goto err_alloc_pins;
+
+ gpio->initialized = 1;
+
+ cdev_init(&gpio->char_dev, &gpio_dev_fops);
+ gpio->char_dev.owner = THIS_MODULE;
+ ret = cdev_add(&gpio->char_dev, MKDEV(MAJOR(gpio_devt), gpio->id), 1);
+ if (ret < 0)
+ goto err_cdev_add;
+ gpio->gpio_dev = class_device_create(gpio_dev_class, NULL,
+ MKDEV(MAJOR(gpio_devt), gpio->id),
+ NULL,
+ "gpio%d", gpio->id);
+ if (IS_ERR(gpio->gpio_dev)) {
+ printk(KERN_ERR "failed to create gpio%d\n", gpio->id);
+ ret = PTR_ERR(gpio->gpio_dev);
+ goto err_class_dev;
+ }
+
+ printk(KERN_INFO "created gpio%d (port%d/0x%08x) as (%d:%d)\n",
+ gpio->id, gpio->port, gpio->pin_mask,
+ MAJOR(gpio->gpio_dev->devt), MINOR(gpio->gpio_dev->devt));
+
+ return 0;
+
+err_class_dev:
+ cdev_del(&gpio->char_dev);
+err_cdev_add:
+ at32_deselect_pins(gpio->port, gpio->pin_mask);
+ gpio->initialized = 0;
+err_alloc_pins:
+ spin_lock(&gpio->lock);
+ gpio->enabled = 0;
+ spin_unlock(&gpio->lock);
+
+ return ret;
+}
+
+static struct gpio_attribute gpio_item_attr_gpio_id = {
+ .attr = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_id",
+ .ca_mode = S_IRUGO | S_IWUSR,
+ },
+ .show = gpio_show_gpio_id,
+ .store = gpio_store_gpio_id,
+};
+static struct gpio_attribute gpio_item_attr_pin_mask = {
+ .attr = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "pin_mask",
+ .ca_mode = S_IRUGO | S_IWUSR,
+ },
+ .show = gpio_show_pin_mask,
+ .store = gpio_store_pin_mask,
+};
+static struct gpio_attribute gpio_item_attr_oe_mask = {
+ .attr = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "oe_mask",
+ .ca_mode = S_IRUGO | S_IWUSR,
+ },
+ .show = gpio_show_oe_mask,
+ .store = gpio_store_oe_mask,
+};
+static struct gpio_attribute gpio_item_attr_enabled = {
+ .attr = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "enabled",
+ .ca_mode = S_IRUGO | S_IWUSR,
+ },
+ .show = gpio_show_enabled,
+ .store = gpio_store_enabled,
+};
+
+static struct configfs_attribute *gpio_item_attrs[] = {
+ &gpio_item_attr_gpio_id.attr,
+ &gpio_item_attr_pin_mask.attr,
+ &gpio_item_attr_oe_mask.attr,
+ &gpio_item_attr_enabled.attr,
+ NULL,
+};
+
+static ssize_t gpio_show_attr(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct gpio_item *gpio_item = to_gpio_item(item);
+ struct gpio_attribute *gpio_attr
+ = container_of(attr, struct gpio_attribute, attr);
+ ssize_t ret = 0;
+
+ if (gpio_attr->show)
+ ret = gpio_attr->show(gpio_item, page);
+ return ret;
+}
+
+static ssize_t gpio_store_attr(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct gpio_item *gpio_item = to_gpio_item(item);
+ struct gpio_attribute *gpio_attr
+ = container_of(attr, struct gpio_attribute, attr);
+ ssize_t ret = -EINVAL;
+
+ if (gpio_attr->store)
+ ret = gpio_attr->store(gpio_item, page, count);
+ return ret;
+}
+
+static void gpio_release(struct config_item *item)
+{
+ kfree(to_gpio_item(item));
+}
+
+static struct configfs_item_operations gpio_item_ops = {
+ .release = gpio_release,
+ .show_attribute = gpio_show_attr,
+ .store_attribute = gpio_store_attr,
+};
+
+static struct config_item_type gpio_item_type = {
+ .ct_item_ops = &gpio_item_ops,
+ .ct_attrs = gpio_item_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *gpio_make_item(struct config_group *group,
+ const char *name)
+{
+ static int next_id;
+ struct gpio_item *gpio;
+
+ if (next_id >= GPIO_DEV_MAX)
+ return NULL;
+
+ gpio = kzalloc(sizeof(struct gpio_item), GFP_KERNEL);
+ if (!gpio)
+ return NULL;
+
+ gpio->id = next_id++;
+ config_item_init_type_name(&gpio->item, name, &gpio_item_type);
+ spin_lock_init(&gpio->lock);
+ init_waitqueue_head(&gpio->change_wq);
+
+ return &gpio->item;
+}
+
+static void gpio_drop_item(struct config_group *group,
+ struct config_item *item)
+{
+ struct gpio_item *gpio = to_gpio_item(item);
+
+ spin_lock(&gpio->lock);
+ if (gpio->enabled) {
+ class_device_unregister(gpio->gpio_dev);
+ cdev_del(&gpio->char_dev);
+ }
+
+ if (gpio->initialized) {
+ at32_deselect_pins(gpio->port, gpio->pin_mask);
+ gpio->initialized = 0;
+ gpio->enabled = 0;
+ }
+ spin_unlock(&gpio->lock);
+}
+
+static struct configfs_group_operations gpio_group_ops = {
+ .make_item = gpio_make_item,
+ .drop_item = gpio_drop_item,
+};
+
+static struct config_item_type gpio_group_type = {
+ .ct_group_ops = &gpio_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem gpio_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "gpio",
+ .ci_type = &gpio_group_type,
+ },
+ },
+};
+
+static int __init gpio_dev_init(void)
+{
+ int err;
+
+ gpio_dev_class = class_create(THIS_MODULE, "gpio-dev");
+ if (IS_ERR(gpio_dev_class)) {
+ err = PTR_ERR(gpio_dev_class);
+ goto err_class_create;
+ }
+
+ err = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpio");
+ if (err < 0)
+ goto err_alloc_chrdev;
+
+ /* Configfs initialization */
+ config_group_init(&gpio_subsys.su_group);
+ mutex_init(&gpio_subsys.su_mutex);
+ err = configfs_register_subsystem(&gpio_subsys);
+ if (err)
+ goto err_register_subsys;
+
+ return 0;
+
+err_register_subsys:
+ unregister_chrdev_region(gpio_devt, GPIO_DEV_MAX);
+err_alloc_chrdev:
+ class_destroy(gpio_dev_class);
+err_class_create:
+ printk(KERN_WARNING "Failed to initialize gpio /dev interface\n");
+ return err;
+}
+late_initcall(gpio_dev_init);
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index d61a02d..c978c36 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -162,6 +162,82 @@ fail:
dump_stack();
}
+#ifdef CONFIG_GPIO_DEV
+
+/* Gang allocators and accessors; used by the GPIO /dev driver */
+int at32_gpio_port_is_valid(unsigned int port)
+{
+ return port < MAX_NR_PIO_DEVICES && pio_dev[port].regs != NULL;
+}
+
+int at32_select_gpio_pins(unsigned int port, u32 pins, u32 oe_mask)
+{
+ struct pio_device *pio;
+ u32 old, new;
+
+ pio = &pio_dev[port];
+ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs || (oe_mask & ~pins));
+
+ /* Try to allocate the pins */
+ do {
+ old = pio->pinmux_mask;
+ if (old & pins)
+ return -EBUSY;
+
+ new = old | pins;
+ } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
+
+ /* That went well, now configure the port */
+ pio_writel(pio, OER, oe_mask);
+ pio_writel(pio, PER, pins);
+
+ return 0;
+}
+
+void at32_deselect_pins(unsigned int port, u32 pins)
+{
+ struct pio_device *pio;
+ u32 old, new;
+
+ pio = &pio_dev[port];
+ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
+
+ /* Return to a "safe" mux configuration */
+ pio_writel(pio, PUER, pins);
+ pio_writel(pio, ODR, pins);
+
+ /* Deallocate the pins */
+ do {
+ old = pio->pinmux_mask;
+ new = old & ~pins;
+ } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
+}
+
+u32 at32_gpio_get_value_multiple(unsigned int port, u32 pins)
+{
+ struct pio_device *pio;
+
+ pio = &pio_dev[port];
+ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
+
+ return pio_readl(pio, PDSR) & pins;
+}
+
+void at32_gpio_set_value_multiple(unsigned int port, u32 value, u32 mask)
+{
+ struct pio_device *pio;
+
+ pio = &pio_dev[port];
+ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
+
+ /* No atomic updates for now... */
+ pio_writel(pio, CODR, ~value & mask);
+ pio_writel(pio, SODR, value & mask);
+}
+
+#endif /* CONFIG_GPIO_DEV */
+
+
/*--------------------------------------------------------------------------*/
/* GPIO API */
diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
index 177fea8..6d8c794 100644
--- a/arch/avr32/mm/dma-coherent.c
+++ b/arch/avr32/mm/dma-coherent.c
@@ -41,6 +41,13 @@ static struct page *__dma_alloc(struct device *dev, size_t size,
struct page *page, *free, *end;
int order;
+ /* Following is a work-around (a.k.a. hack) to prevent pages
+ * with __GFP_COMP being passed to split_page() which cannot
+ * handle them. The real problem is that this flag probably
+ * should be 0 on AVR32 as it is not supported on this
+ * platform--see CONFIG_HUGETLB_PAGE. */
+ gfp &= ~(__GFP_COMP);
+
size = PAGE_ALIGN(size);
order = get_order(size);
diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
index 5667201..b835257 100644
--- a/arch/avr32/mm/tlb.c
+++ b/arch/avr32/mm/tlb.c
@@ -348,7 +348,7 @@ static int tlb_show(struct seq_file *tlb, void *v)
return 0;
}
-static struct seq_operations tlb_ops = {
+static const struct seq_operations tlb_ops = {
.start = tlb_start,
.next = tlb_next,
.stop = tlb_stop,
diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
new file mode 100644
index 0000000..1fe81c3
--- /dev/null
+++ b/arch/avr32/oprofile/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+oprofile-y := $(addprefix ../../../drivers/oprofile/, \
+ oprof.o cpu_buffer.o buffer_sync.o \
+ event_buffer.o oprofile_files.o \
+ oprofilefs.o oprofile_stats.o \
+ timer_int.o)
+oprofile-y += op_model_avr32.o
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
new file mode 100644
index 0000000..e2f876b
--- /dev/null
+++ b/arch/avr32/oprofile/op_model_avr32.c
@@ -0,0 +1,235 @@
+/*
+ * AVR32 Performance Counter Driver
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * 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.
+ *
+ * Author: Ronny Pedersen
+ */
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include <asm/intc.h>
+#include <asm/sysreg.h>
+#include <asm/system.h>
+
+#define AVR32_PERFCTR_IRQ_GROUP 0
+#define AVR32_PERFCTR_IRQ_LINE 1
+
+enum { PCCNT, PCNT0, PCNT1, NR_counter };
+
+struct avr32_perf_counter {
+ unsigned long enabled;
+ unsigned long event;
+ unsigned long count;
+ unsigned long unit_mask;
+ unsigned long kernel;
+ unsigned long user;
+
+ u32 ie_mask;
+ u32 flag_mask;
+};
+
+static struct avr32_perf_counter counter[NR_counter] = {
+ {
+ .ie_mask = SYSREG_BIT(IEC),
+ .flag_mask = SYSREG_BIT(FC),
+ }, {
+ .ie_mask = SYSREG_BIT(IE0),
+ .flag_mask = SYSREG_BIT(F0),
+ }, {
+ .ie_mask = SYSREG_BIT(IE1),
+ .flag_mask = SYSREG_BIT(F1),
+ },
+};
+
+static void avr32_perf_counter_reset(void)
+{
+ /* Reset all counter and disable/clear all interrupts */
+ sysreg_write(PCCR, (SYSREG_BIT(PCCR_R)
+ | SYSREG_BIT(PCCR_C)
+ | SYSREG_BIT(FC)
+ | SYSREG_BIT(F0)
+ | SYSREG_BIT(F1)));
+}
+
+static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id)
+{
+ struct avr32_perf_counter *ctr = dev_id;
+ struct pt_regs *regs;
+ u32 pccr;
+
+ if (likely(!(intc_get_pending(AVR32_PERFCTR_IRQ_GROUP)
+ & (1 << AVR32_PERFCTR_IRQ_LINE))))
+ return IRQ_NONE;
+
+ regs = get_irq_regs();
+ pccr = sysreg_read(PCCR);
+
+ /* Clear the interrupt flags we're about to handle */
+ sysreg_write(PCCR, pccr);
+
+ /* PCCNT */
+ if (ctr->enabled && (pccr & ctr->flag_mask)) {
+ sysreg_write(PCCNT, -ctr->count);
+ oprofile_add_sample(regs, PCCNT);
+ }
+ ctr++;
+ /* PCNT0 */
+ if (ctr->enabled && (pccr & ctr->flag_mask)) {
+ sysreg_write(PCNT0, -ctr->count);
+ oprofile_add_sample(regs, PCNT0);
+ }
+ ctr++;
+ /* PCNT1 */
+ if (ctr->enabled && (pccr & ctr->flag_mask)) {
+ sysreg_write(PCNT1, -ctr->count);
+ oprofile_add_sample(regs, PCNT1);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int avr32_perf_counter_create_files(struct super_block *sb,
+ struct dentry *root)
+{
+ struct dentry *dir;
+ unsigned int i;
+ char filename[4];
+
+ for (i = 0; i < NR_counter; i++) {
+ snprintf(filename, sizeof(filename), "%u", i);
+ dir = oprofilefs_mkdir(sb, root, filename);
+
+ oprofilefs_create_ulong(sb, dir, "enabled",
+ &counter[i].enabled);
+ oprofilefs_create_ulong(sb, dir, "event",
+ &counter[i].event);
+ oprofilefs_create_ulong(sb, dir, "count",
+ &counter[i].count);
+
+ /* Dummy entries */
+ oprofilefs_create_ulong(sb, dir, "kernel",
+ &counter[i].kernel);
+ oprofilefs_create_ulong(sb, dir, "user",
+ &counter[i].user);
+ oprofilefs_create_ulong(sb, dir, "unit_mask",
+ &counter[i].unit_mask);
+ }
+
+ return 0;
+}
+
+static int avr32_perf_counter_setup(void)
+{
+ struct avr32_perf_counter *ctr;
+ u32 pccr;
+ int ret;
+ int i;
+
+ pr_debug("avr32_perf_counter_setup\n");
+
+ if (sysreg_read(PCCR) & SYSREG_BIT(PCCR_E)) {
+ printk(KERN_ERR
+ "oprofile: setup: perf counter already enabled\n");
+ return -EBUSY;
+ }
+
+ ret = request_irq(AVR32_PERFCTR_IRQ_GROUP,
+ avr32_perf_counter_interrupt, IRQF_SHARED,
+ "oprofile", counter);
+ if (ret)
+ return ret;
+
+ avr32_perf_counter_reset();
+
+ pccr = 0;
+ for (i = PCCNT; i < NR_counter; i++) {
+ ctr = &counter[i];
+ if (!ctr->enabled)
+ continue;
+
+ pr_debug("enabling counter %d...\n", i);
+
+ pccr |= ctr->ie_mask;
+
+ switch (i) {
+ case PCCNT:
+ /* PCCNT always counts cycles, so no events */
+ sysreg_write(PCCNT, -ctr->count);
+ break;
+ case PCNT0:
+ pccr |= SYSREG_BF(CONF0, ctr->event);
+ sysreg_write(PCNT0, -ctr->count);
+ break;
+ case PCNT1:
+ pccr |= SYSREG_BF(CONF1, ctr->event);
+ sysreg_write(PCNT1, -ctr->count);
+ break;
+ }
+ }
+
+ pr_debug("oprofile: writing 0x%x to PCCR...\n", pccr);
+
+ sysreg_write(PCCR, pccr);
+
+ return 0;
+}
+
+static void avr32_perf_counter_shutdown(void)
+{
+ pr_debug("avr32_perf_counter_shutdown\n");
+
+ avr32_perf_counter_reset();
+ free_irq(AVR32_PERFCTR_IRQ_GROUP, counter);
+}
+
+static int avr32_perf_counter_start(void)
+{
+ pr_debug("avr32_perf_counter_start\n");
+
+ sysreg_write(PCCR, sysreg_read(PCCR) | SYSREG_BIT(PCCR_E));
+
+ return 0;
+}
+
+static void avr32_perf_counter_stop(void)
+{
+ pr_debug("avr32_perf_counter_stop\n");
+
+ sysreg_write(PCCR, sysreg_read(PCCR) & ~SYSREG_BIT(PCCR_E));
+}
+
+static struct oprofile_operations avr32_perf_counter_ops __initdata = {
+ .create_files = avr32_perf_counter_create_files,
+ .setup = avr32_perf_counter_setup,
+ .shutdown = avr32_perf_counter_shutdown,
+ .start = avr32_perf_counter_start,
+ .stop = avr32_perf_counter_stop,
+ .cpu_type = "avr32",
+};
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+ if (!(current_cpu_data.features & AVR32_FEATURE_PCTR))
+ return -ENODEV;
+
+ memcpy(ops, &avr32_perf_counter_ops,
+ sizeof(struct oprofile_operations));
+
+ printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
+
+ return 0;
+}
+
+void oprofile_arch_exit(void)
+{
+
+}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c466c6c..0bb2052 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -88,6 +88,14 @@ config I2C_AT91
to support combined I2C messages. Use the i2c-gpio driver
unless your system can cope with those limitations.
+config I2C_ATMELTWI
+ tristate "Atmel Two-Wire Interface (TWI)"
+ depends on I2C && (ARCH_AT91 || PLATFORM_AT32AP)
+ help
+ Atmel on-chip TWI controller. Say Y if you have an AT32 or
+ AT91-based device and want to use its built-in TWI
+ functionality.
+
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
depends on SOC_AU1550 || SOC_AU1200
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 81d43c2..af3f350 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_I2C_ATMELTWI) += i2c-atmeltwi.o
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/busses/i2c-atmeltwi.c b/drivers/i2c/busses/i2c-atmeltwi.c
new file mode 100644
index 0000000..70c719a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-atmeltwi.c
@@ -0,0 +1,436 @@
+/*
+ * i2c Support for Atmel's Two-Wire Interface (TWI)
+ *
+ * Based on the work of Copyright (C) 2004 Rick Bronson
+ * Converted to 2.6 by Andrew Victor <andrew at sanpeople.com>
+ * Ported to AVR32 and heavily modified by Espen Krangnes
+ * <ekrangnes at atmel.com>
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * Borrowed heavily from the original work by:
+ * Copyright (C) 2000 Philip Edelbrock <phil at stimpy.netroedge.com>
+ *
+ * Partialy rewriten by Karel Hojdar <cmkaho at seznam.cz>
+ * bugs removed, interrupt routine markedly rewritten
+ *
+ * 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.
+ */
+#undef VERBOSE_DEBUG
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+
+#include "i2c-atmeltwi.h"
+
+static unsigned int baudrate = 100 * 1000;
+module_param(baudrate, uint, S_IRUGO);
+MODULE_PARM_DESC(baudrate, "The TWI baudrate");
+
+
+struct atmel_twi {
+ void __iomem *regs;
+ struct i2c_adapter adapter;
+ struct clk *pclk;
+ struct completion comp;
+ u32 mask;
+ u8 *buf;
+ u16 len;
+ u16 acks_left;
+ int status;
+ unsigned int irq;
+
+};
+#define to_atmel_twi(adap) container_of(adap, struct atmel_twi, adapter)
+
+/*
+ * (Re)Initialize the TWI hardware registers.
+ */
+static int twi_hwinit(struct atmel_twi *twi)
+{
+ unsigned long cdiv, ckdiv = 0;
+
+ /* REVISIT: wait till SCL is high before resetting; otherwise,
+ * some versions will wedge forever.
+ */
+
+ twi_writel(twi, IDR, ~0UL);
+ twi_writel(twi, CR, TWI_BIT(SWRST)); /*Reset peripheral*/
+ twi_readl(twi, SR);
+
+ cdiv = (clk_get_rate(twi->pclk) / (2 * baudrate)) - 4;
+
+ while (cdiv > 255) {
+ ckdiv++;
+ cdiv = cdiv >> 1;
+ }
+
+ /* REVISIT: there are various errata to consider re CDIV and CHDIV
+ * here, at least on at91 parts.
+ */
+
+ if (ckdiv > 7)
+ return -EINVAL;
+ else
+ twi_writel(twi, CWGR, TWI_BF(CKDIV, ckdiv)
+ | TWI_BF(CHDIV, cdiv)
+ | TWI_BF(CLDIV, cdiv));
+ return 0;
+}
+
+/*
+ * Waits for the i2c status register to set the specified bitmask
+ * Returns 0 if timed out ... ~100ms is much longer than the SMBus
+ * limit, but I2C has no limit at all.
+ */
+static int twi_complete(struct atmel_twi *twi, u32 mask)
+{
+ int timeout = msecs_to_jiffies(100);
+
+ mask |= TWI_BIT(TXCOMP);
+ twi->mask = mask | TWI_BIT(NACK) | TWI_BIT(OVRE);
+ init_completion(&twi->comp);
+
+ twi_writel(twi, IER, mask);
+
+ if (!wait_for_completion_timeout(&twi->comp, timeout)) {
+ /* RESET TWI interface */
+ twi_writel(twi, CR, TWI_BIT(SWRST));
+
+ /* Reinitialize TWI */
+ twi_hwinit(twi);
+
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ */
+static int twi_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+ struct atmel_twi *twi = to_atmel_twi(adap);
+ int i;
+
+ dev_dbg(&adap->dev, "twi_xfer: processing %d messages:\n", num);
+
+ twi->status = 0;
+ for (i = 0; i < num; i++, pmsg++) {
+ twi->len = pmsg->len;
+ twi->buf = pmsg->buf;
+ twi->acks_left = pmsg->len;
+ twi_writel(twi, MMR, TWI_BF(DADR, pmsg->addr) |
+ (pmsg->flags & I2C_M_RD ? TWI_BIT(MREAD) : 0));
+ twi_writel(twi, IADR, TWI_BF(IADR, pmsg->addr));
+
+ dev_dbg(&adap->dev,
+ "#%d: %s %d byte%s %s dev 0x%02x\n",
+ i,
+ pmsg->flags & I2C_M_RD ? "reading" : "writing",
+ pmsg->len,
+ pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+ /* enable */
+ twi_writel(twi, CR, TWI_BIT(MSEN));
+
+ if (pmsg->flags & I2C_M_RD) {
+ /* cleanup after previous RX overruns */
+ while (twi_readl(twi, SR) & TWI_BIT(RXRDY))
+ twi_readl(twi, RHR);
+
+ if (twi->len == 1)
+ twi_writel(twi, CR,
+ TWI_BIT(START) | TWI_BIT(STOP));
+ else
+ twi_writel(twi, CR, TWI_BIT(START));
+
+ if (twi_complete(twi, TWI_BIT(RXRDY)) == -ETIMEDOUT) {
+ dev_dbg(&adap->dev, "RX[%d] timeout. "
+ "Stopped with %d bytes left\n",
+ i, twi->acks_left);
+ return -ETIMEDOUT;
+ }
+ } else {
+ twi_writel(twi, THR, twi->buf[0]);
+ twi->acks_left--;
+ /* REVISIT: some chips don't start automagically:
+ * twi_writel(twi, CR, TWI_BIT(START));
+ */
+ if (twi_complete(twi, TWI_BIT(TXRDY)) == -ETIMEDOUT) {
+ dev_dbg(&adap->dev, "TX[%d] timeout. "
+ "Stopped with %d bytes left\n",
+ i, twi->acks_left);
+ return -ETIMEDOUT;
+ }
+ /* REVISIT: an erratum workaround may be needed here;
+ * see sam9261 "STOP not generated" (START either).
+ */
+ }
+
+ /* Disable TWI interface */
+ twi_writel(twi, CR, TWI_BIT(MSDIS));
+
+ if (twi->status)
+ return twi->status;
+
+ /* WARNING: This driver lies about properly supporting
+ * repeated start, or it would *ALWAYS* return here. It
+ * has issued a STOP. Continuing is a false claim -- that
+ * a second (or third, etc.) message is part of the same
+ * "combined" (no STOPs between parts) message.
+ */
+
+ } /* end cur msg */
+
+ return i;
+}
+
+
+static irqreturn_t twi_interrupt(int irq, void *dev_id)
+{
+ struct atmel_twi *twi = dev_id;
+ int status = twi_readl(twi, SR);
+
+ /* Save state for later debug prints */
+ int old_status = status;
+
+ if (twi->mask & status) {
+
+ status &= twi->mask;
+
+ if (status & TWI_BIT(RXRDY)) {
+ if ((status & TWI_BIT(OVRE)) && twi->acks_left) {
+ /* Note weakness in fault reporting model:
+ * we can't say "the first N of these data
+ * bytes are valid".
+ */
+ dev_err(&twi->adapter.dev,
+ "OVERRUN RX! %04x, lost %d\n",
+ old_status, twi->acks_left);
+ twi->acks_left = 0;
+ twi_writel(twi, CR, TWI_BIT(STOP));
+ twi->status = -EOVERFLOW;
+ } else if (twi->acks_left > 0) {
+ twi->buf[twi->len - twi->acks_left] =
+ twi_readl(twi, RHR);
+ twi->acks_left--;
+ }
+ if (status & TWI_BIT(TXCOMP))
+ goto done;
+ if (twi->acks_left == 1)
+ twi_writel(twi, CR, TWI_BIT(STOP));
+
+ } else if (status & (TWI_BIT(NACK) | TWI_BIT(TXCOMP))) {
+ goto done;
+
+ } else if (status & TWI_BIT(TXRDY)) {
+ if (twi->acks_left > 0) {
+ twi->acks_left--;
+ twi_writel(twi, THR,
+ twi->buf[twi->len - twi->acks_left]);
+ } else
+ twi_writel(twi, CR, TWI_BIT(STOP));
+ }
+
+ if (twi->acks_left == 0)
+ twi_writel(twi, IDR, ~TWI_BIT(TXCOMP));
+ }
+
+ /* enabling this message helps trigger overruns/underruns ... */
+ dev_vdbg(&twi->adapter.dev,
+ "ISR: SR 0x%04X, mask 0x%04X, acks %i\n",
+ old_status,
+ twi->acks_left ? twi->mask : TWI_BIT(TXCOMP),
+ twi->acks_left);
+
+ return IRQ_HANDLED;
+
+done:
+ /* Note weak fault reporting model: we can't report how many
+ * bytes we sent before the NAK, or let upper layers choose
+ * whether to continue. The I2C stack doesn't allow that...
+ */
+ if (status & TWI_BIT(NACK)) {
+ dev_dbg(&twi->adapter.dev, "NACK received! %d to go\n",
+ twi->acks_left);
+ twi->status = -EPIPE;
+
+ /* TX underrun morphs automagically into a premature STOP;
+ * we'll probably observe UVRE even when it's not documented.
+ */
+ } else if (twi->acks_left && (twi->mask & TWI_BIT(TXRDY))) {
+ dev_err(&twi->adapter.dev, "UNDERRUN TX! %04x, %d to go\n",
+ old_status, twi->acks_left);
+ twi->status = -ENOSR;
+ }
+
+ twi_writel(twi, IDR, ~0UL);
+ complete(&twi->comp);
+
+ dev_dbg(&twi->adapter.dev, "ISR: SR 0x%04X, acks %i --> %d\n",
+ old_status, twi->acks_left, twi->status);
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * Return list of supported functionality.
+ *
+ * NOTE: see warning above about repeated starts; this driver is falsely
+ * claiming to support "combined" transfers. The mid-message STOPs mean
+ * some slaves will never work with this driver. (Use i2c-gpio...)
+ */
+static u32 twi_func(struct i2c_adapter *adapter)
+{
+ return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL)
+ & ~I2C_FUNC_SMBUS_QUICK;
+}
+
+static struct i2c_algorithm twi_algorithm = {
+ .master_xfer = twi_xfer,
+ .functionality = twi_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __init twi_probe(struct platform_device *pdev)
+{
+ struct atmel_twi *twi;
+ struct resource *regs;
+ struct clk *pclk;
+ struct i2c_adapter *adapter;
+ int rc, irq;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+
+ pclk = clk_get(&pdev->dev, "twi_pclk");
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+ clk_enable(pclk);
+
+ rc = -ENOMEM;
+ twi = kzalloc(sizeof(struct atmel_twi), GFP_KERNEL);
+ if (!twi) {
+ dev_dbg(&pdev->dev, "can't allocate interface!\n");
+ goto err_alloc_twi;
+ }
+
+ twi->pclk = pclk;
+ twi->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!twi->regs)
+ goto err_ioremap;
+
+ irq = platform_get_irq(pdev, 0);
+ rc = request_irq(irq, twi_interrupt, 0, "twi", twi);
+ if (rc) {
+ dev_dbg(&pdev->dev, "can't bind irq!\n");
+ goto err_irq;
+ }
+ twi->irq = irq;
+
+ rc = twi_hwinit(twi);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set baudrate\n");
+ goto err_hw_init;
+ }
+
+ adapter = &twi->adapter;
+ sprintf(adapter->name, "TWI");
+ adapter->algo = &twi_algorithm;
+ adapter->class = I2C_CLASS_ALL;
+ adapter->nr = pdev->id;
+ adapter->dev.parent = &pdev->dev;
+
+ platform_set_drvdata(pdev, twi);
+
+ rc = i2c_add_numbered_adapter(adapter);
+ if (rc) {
+ dev_dbg(&pdev->dev, "Adapter %s registration failed\n",
+ adapter->name);
+ goto err_register;
+ }
+
+ dev_info(&pdev->dev,
+ "Atmel TWI/I2C adapter (baudrate %dk) at 0x%08lx.\n",
+ baudrate/1000, (unsigned long)regs->start);
+
+ return 0;
+
+
+err_register:
+ platform_set_drvdata(pdev, NULL);
+
+err_hw_init:
+ free_irq(irq, twi);
+
+err_irq:
+ iounmap(twi->regs);
+
+err_ioremap:
+ kfree(twi);
+
+err_alloc_twi:
+ clk_disable(pclk);
+ clk_put(pclk);
+
+ return rc;
+}
+
+static int __exit twi_remove(struct platform_device *pdev)
+{
+ struct atmel_twi *twi = platform_get_drvdata(pdev);
+ int res;
+
+ platform_set_drvdata(pdev, NULL);
+ res = i2c_del_adapter(&twi->adapter);
+ twi_writel(twi, CR, TWI_BIT(MSDIS));
+ iounmap(twi->regs);
+ clk_disable(twi->pclk);
+ clk_put(twi->pclk);
+ free_irq(twi->irq, twi);
+ kfree(twi);
+
+ return res;
+}
+
+static struct platform_driver twi_driver = {
+ .remove = __exit_p(twi_remove),
+ .driver = {
+ .name = "atmel_twi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init atmel_twi_init(void)
+{
+ return platform_driver_probe(&twi_driver, twi_probe);
+}
+
+static void __exit atmel_twi_exit(void)
+{
+ platform_driver_unregister(&twi_driver);
+}
+
+module_init(atmel_twi_init);
+module_exit(atmel_twi_exit);
+
+MODULE_AUTHOR("Espen Krangnes");
+MODULE_DESCRIPTION("I2C driver for Atmel TWI");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-atmeltwi.h b/drivers/i2c/busses/i2c-atmeltwi.h
new file mode 100644
index 0000000..1aca065
--- /dev/null
+++ b/drivers/i2c/busses/i2c-atmeltwi.h
@@ -0,0 +1,117 @@
+/*
+ * Register definitions for the Atmel Two-Wire Interface
+ */
+
+#ifndef __ATMELTWI_H__
+#define __ATMELTWI_H__
+
+/* TWI register offsets */
+#define TWI_CR 0x0000
+#define TWI_MMR 0x0004
+#define TWI_SMR 0x0008
+#define TWI_IADR 0x000c
+#define TWI_CWGR 0x0010
+#define TWI_SR 0x0020
+#define TWI_IER 0x0024
+#define TWI_IDR 0x0028
+#define TWI_IMR 0x002c
+#define TWI_RHR 0x0030
+#define TWI_THR 0x0034
+
+/* Bitfields in CR */
+#define TWI_START_OFFSET 0
+#define TWI_START_SIZE 1
+#define TWI_STOP_OFFSET 1
+#define TWI_STOP_SIZE 1
+#define TWI_MSEN_OFFSET 2
+#define TWI_MSEN_SIZE 1
+#define TWI_MSDIS_OFFSET 3
+#define TWI_MSDIS_SIZE 1
+#define TWI_SVEN_OFFSET 4
+#define TWI_SVEN_SIZE 1
+#define TWI_SVDIS_OFFSET 5
+#define TWI_SVDIS_SIZE 1
+#define TWI_SWRST_OFFSET 7
+#define TWI_SWRST_SIZE 1
+
+/* Bitfields in MMR */
+#define TWI_IADRSZ_OFFSET 8
+#define TWI_IADRSZ_SIZE 2
+#define TWI_MREAD_OFFSET 12
+#define TWI_MREAD_SIZE 1
+#define TWI_DADR_OFFSET 16
+#define TWI_DADR_SIZE 7
+
+/* Bitfields in SMR */
+#define TWI_SADR_OFFSET 16
+#define TWI_SADR_SIZE 7
+
+/* Bitfields in IADR */
+#define TWI_IADR_OFFSET 0
+#define TWI_IADR_SIZE 24
+
+/* Bitfields in CWGR */
+#define TWI_CLDIV_OFFSET 0
+#define TWI_CLDIV_SIZE 8
+#define TWI_CHDIV_OFFSET 8
+#define TWI_CHDIV_SIZE 8
+#define TWI_CKDIV_OFFSET 16
+#define TWI_CKDIV_SIZE 3
+
+/* Bitfields in SR */
+#define TWI_TXCOMP_OFFSET 0
+#define TWI_TXCOMP_SIZE 1
+#define TWI_RXRDY_OFFSET 1
+#define TWI_RXRDY_SIZE 1
+#define TWI_TXRDY_OFFSET 2
+#define TWI_TXRDY_SIZE 1
+#define TWI_SVDIR_OFFSET 3
+#define TWI_SVDIR_SIZE 1
+#define TWI_SVACC_OFFSET 4
+#define TWI_SVACC_SIZE 1
+#define TWI_GCACC_OFFSET 5
+#define TWI_GCACC_SIZE 1
+#define TWI_OVRE_OFFSET 6
+#define TWI_OVRE_SIZE 1
+#define TWI_UNRE_OFFSET 7
+#define TWI_UNRE_SIZE 1
+#define TWI_NACK_OFFSET 8
+#define TWI_NACK_SIZE 1
+#define TWI_ARBLST_OFFSET 9
+#define TWI_ARBLST_SIZE 1
+
+/* Bitfields in RHR */
+#define TWI_RXDATA_OFFSET 0
+#define TWI_RXDATA_SIZE 8
+
+/* Bitfields in THR */
+#define TWI_TXDATA_OFFSET 0
+#define TWI_TXDATA_SIZE 8
+
+/* Constants for IADRSZ */
+#define TWI_IADRSZ_NO_ADDR 0
+#define TWI_IADRSZ_ONE_BYTE 1
+#define TWI_IADRSZ_TWO_BYTES 2
+#define TWI_IADRSZ_THREE_BYTES 3
+
+/* Bit manipulation macros */
+#define TWI_BIT(name) \
+ (1 << TWI_##name##_OFFSET)
+#define TWI_BF(name, value) \
+ (((value) & ((1 << TWI_##name##_SIZE) - 1)) \
+ << TWI_##name##_OFFSET)
+#define TWI_BFEXT(name, value) \
+ (((value) >> TWI_##name##_OFFSET) \
+ & ((1 << TWI_##name##_SIZE) - 1))
+#define TWI_BFINS(name, value, old) \
+ (((old) & ~(((1 << TWI_##name##_SIZE) - 1) \
+ << TWI_##name##_OFFSET)) \
+ | TWI_BF(name, (value)))
+
+/* Register access macros */
+#define twi_readl(port, reg) \
+ __raw_readl((port)->regs + TWI_##reg)
+#define twi_writel(port, reg, value) \
+ __raw_writel((value), (port)->regs + TWI_##reg)
+
+#endif /* __ATMELTWI_H__ */
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ec568fa..4e1db3b 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -18,6 +18,13 @@ config LEDS_CLASS
comment "LED drivers"
+config LEDS_ATMEL_PWM
+ tristate "LED Support using Atmel PWM outputs"
+ depends on LEDS_CLASS && ATMEL_PWM
+ help
+ This option enables support for LEDs driven using outputs
+ of the dedicated PWM controller found on newer Atmel SOCs.
+
config LEDS_CORGI
tristate "LED Support for the Sharp SL-C7x0 series"
depends on LEDS_CLASS && PXA_SHARP_C7xx
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a60de1b..04bc850 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_CLASS) += led-class.o
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers
+obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o
obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o
diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c
new file mode 100644
index 0000000..187031c
--- /dev/null
+++ b/drivers/leds/leds-atmel-pwm.c
@@ -0,0 +1,155 @@
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/atmel_pwm.h>
+
+
+struct pwmled {
+ struct led_classdev cdev;
+ struct pwm_channel pwmc;
+ struct gpio_led *desc;
+ u32 mult;
+ u8 active_low;
+};
+
+
+/*
+ * For simplicity, we use "brightness" as if it were a linear function
+ * of PWM duty cycle. However, a logarithmic function of duty cycle is
+ * probably a better match for perceived brightness: two is half as bright
+ * as four, four is half as bright as eight, etc
+ */
+static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b)
+{
+ struct pwmled *led;
+
+ /* update the duty cycle for the *next* period */
+ led = container_of(cdev, struct pwmled, cdev);
+ pwm_channel_writel(&led->pwmc, PWM_CUPD, led->mult * (unsigned) b);
+}
+
+/*
+ * NOTE: we reuse the platform_data structure of GPIO leds,
+ * but repurpose its "gpio" number as a PWM channel number.
+ */
+static int __init pwmled_probe(struct platform_device *pdev)
+{
+ const struct gpio_led_platform_data *pdata;
+ struct pwmled *leds;
+ unsigned i;
+ int status;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata || pdata->num_leds < 1)
+ return -ENODEV;
+
+ leds = kcalloc(pdata->num_leds, sizeof(*leds), GFP_KERNEL);
+ if (!leds)
+ return -ENOMEM;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ struct pwmled *led = leds + i;
+ const struct gpio_led *dat = pdata->leds + i;
+ u32 tmp;
+
+ led->cdev.name = dat->name;
+ led->cdev.brightness = LED_OFF;
+ led->cdev.brightness_set = pwmled_brightness;
+ led->cdev.default_trigger = dat->default_trigger;
+
+ led->active_low = dat->active_low;
+
+ status = pwm_channel_alloc(dat->gpio, &led->pwmc);
+ if (status < 0)
+ goto err;
+
+ /*
+ * Prescale clock by 2^x, so PWM counts in low MHz.
+ * Start each cycle with the LED active, so increasing
+ * the duty cycle gives us more time on (== brighter).
+ */
+ tmp = 5;
+ if (!led->active_low)
+ tmp |= PWM_CPR_CPOL;
+ pwm_channel_writel(&led->pwmc, PWM_CMR, tmp);
+
+ /*
+ * Pick a period so PWM cycles at 100+ Hz; and a multiplier
+ * for scaling duty cycle: brightness * mult.
+ */
+ tmp = (led->pwmc.mck / (1 << 5)) / 100;
+ tmp /= 255;
+ led->mult = tmp;
+ pwm_channel_writel(&led->pwmc, PWM_CDTY,
+ led->cdev.brightness * 255);
+ pwm_channel_writel(&led->pwmc, PWM_CPRD,
+ LED_FULL * tmp);
+
+ pwm_channel_enable(&led->pwmc);
+
+ /* Hand it over to the LED framework */
+ status = led_classdev_register(&pdev->dev, &led->cdev);
+ if (status < 0) {
+ pwm_channel_free(&led->pwmc);
+ goto err;
+ }
+ }
+
+ platform_set_drvdata(pdev, leds);
+ return 0;
+
+err:
+ while (i-- > 0) {
+ led_classdev_unregister(&leds[i].cdev);
+ pwm_channel_free(&leds[i].pwmc);
+ }
+ kfree(leds);
+
+ return status;
+}
+
+static int __exit pwmled_remove(struct platform_device *pdev)
+{
+ const struct gpio_led_platform_data *pdata;
+ struct pwmled *leds;
+ unsigned i;
+
+ pdata = pdev->dev.platform_data;
+ leds = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ struct pwmled *led = leds + i;
+
+ led_classdev_unregister(&led->cdev);
+ pwm_channel_free(&led->pwmc);
+ }
+
+ kfree(leds);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver pwmled_driver = {
+ .driver = {
+ .name = "leds-atmel-pwm",
+ .owner = THIS_MODULE,
+ },
+ /* REVISIT add suspend() and resume() methods */
+ .remove = __exit_p(pwmled_remove),
+};
+
+static int __init modinit(void)
+{
+ return platform_driver_probe(&pwmled_driver, pwmled_probe);
+}
+module_init(modinit);
+
+static void __exit modexit(void)
+{
+ platform_driver_unregister(&pwmled_driver);
+}
+module_exit(modexit);
+
+MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b5e67c0..23a9231 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -13,6 +13,15 @@ menuconfig MISC_DEVICES
if MISC_DEVICES
+config ATMEL_PWM
+ tristate "Atmel AT32/AT91 PWM support"
+ depends on AVR32 || ARCH_AT91
+ help
+ This option enables device driver support for the PWM channels
+ on certain Atmel prcoessors. Pulse Width Modulation is used for
+ purposes including software controlled power-efficent backlights
+ on LCD displays, motor control, and waveform generation.
+
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
depends on X86 && PCI && INPUT && EXPERIMENTAL
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 87f2685..b4674c6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c
new file mode 100644
index 0000000..f8d3b9a
--- /dev/null
+++ b/drivers/misc/atmel_pwm.c
@@ -0,0 +1,409 @@
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/atmel_pwm.h>
+
+
+/*
+ * This is a simple driver for the PWM controller found in various newer
+ * Atmel SOCs, including the AVR32 series and the AT91sam9263.
+ *
+ * Chips with current Linux ports have only 4 PWM channels, out of max 32.
+ * AT32UC3A and AT32UC3B chips have 7 channels (but currently no Linux).
+ * Docs are inconsistent about the width of the channel counter registers;
+ * it's at least 16 bits, but several places say 20 bits.
+ */
+#define PWM_NCHAN 4 /* max 32 */
+
+struct pwm {
+ spinlock_t lock;
+ struct platform_device *pdev;
+ u32 mask;
+ int irq;
+ void __iomem *base;
+ struct clk *clk;
+ struct pwm_channel *channel[PWM_NCHAN];
+ void (*handler[PWM_NCHAN])(struct pwm_channel *);
+};
+
+
+/* global PWM controller registers */
+#define PWM_MR 0x00
+#define PWM_ENA 0x04
+#define PWM_DIS 0x08
+#define PWM_SR 0x0c
+#define PWM_IER 0x10
+#define PWM_IDR 0x14
+#define PWM_IMR 0x18
+#define PWM_ISR 0x1c
+
+static inline void pwm_writel(const struct pwm *p, unsigned offset, u32 val)
+{
+ __raw_writel(val, p->base + offset);
+}
+
+static inline u32 pwm_readl(const struct pwm *p, unsigned offset)
+{
+ return __raw_readl(p->base + offset);
+}
+
+static inline void __iomem *pwmc_regs(const struct pwm *p, int index)
+{
+ return p->base + 0x200 + index * 0x20;
+}
+
+static struct pwm *pwm;
+
+static void pwm_dumpregs(struct pwm_channel *ch, char *tag)
+{
+ struct device *dev = &pwm->pdev->dev;
+
+ dev_dbg(dev, "%s: mr %08x, sr %08x, imr %08x\n",
+ tag,
+ pwm_readl(pwm, PWM_MR),
+ pwm_readl(pwm, PWM_SR),
+ pwm_readl(pwm, PWM_IMR));
+ dev_dbg(dev,
+ "pwm ch%d - mr %08x, dty %u, prd %u, cnt %u\n",
+ ch->index,
+ pwm_channel_readl(ch, PWM_CMR),
+ pwm_channel_readl(ch, PWM_CDTY),
+ pwm_channel_readl(ch, PWM_CPRD),
+ pwm_channel_readl(ch, PWM_CCNT));
+}
+
+
+/**
+ * pwm_channel_alloc - allocate an unused PWM channel
+ * @index: identifies the channel
+ * @ch: structure to be initialized
+ *
+ * Drivers allocate PWM channels according to the board's wiring, and
+ * matching board-specific setup code. Returns zero or negative errno.
+ */
+int pwm_channel_alloc(int index, struct pwm_channel *ch)
+{
+ unsigned long flags;
+ int status = 0;
+
+ /* insist on PWM init, with this signal pinned out */
+ if (!pwm || !(pwm->mask & 1 << index))
+ return -ENODEV;
+
+ if (index < 0 || index >= PWM_NCHAN || !ch)
+ return -EINVAL;
+ memset(ch, 0, sizeof *ch);
+
+ spin_lock_irqsave(&pwm->lock, flags);
+ if (pwm->channel[index])
+ status = -EBUSY;
+ else {
+ clk_enable(pwm->clk);
+
+ ch->regs = pwmc_regs(pwm, index);
+ ch->index = index;
+
+ /* REVISIT: ap7000 seems to go 2x as fast as we expect!! */
+ ch->mck = clk_get_rate(pwm->clk);
+
+ pwm->channel[index] = ch;
+ pwm->handler[index] = NULL;
+
+ /* channel and irq are always disabled when we return */
+ pwm_writel(pwm, PWM_DIS, 1 << index);
+ pwm_writel(pwm, PWM_IDR, 1 << index);
+ }
+ spin_unlock_irqrestore(&pwm->lock, flags);
+ return status;
+}
+EXPORT_SYMBOL(pwm_channel_alloc);
+
+static int pwmcheck(struct pwm_channel *ch)
+{
+ int index;
+
+ if (!pwm)
+ return -ENODEV;
+ if (!ch)
+ return -EINVAL;
+ index = ch->index;
+ if (index < 0 || index >= PWM_NCHAN || pwm->channel[index] != ch)
+ return -EINVAL;
+
+ return index;
+}
+
+/**
+ * pwm_channel_free - release a previously allocated channel
+ * @ch: the channel being released
+ *
+ * The channel is completely shut down (counter and IRQ disabled),
+ * and made available for re-use. Returns zero, or negative errno.
+ */
+int pwm_channel_free(struct pwm_channel *ch)
+{
+ unsigned long flags;
+ int t;
+
+ spin_lock_irqsave(&pwm->lock, flags);
+ t = pwmcheck(ch);
+ if (t >= 0) {
+ pwm->channel[t] = NULL;
+ pwm->handler[t] = NULL;
+
+ /* channel and irq are always disabled when we return */
+ pwm_writel(pwm, PWM_DIS, 1 << t);
+ pwm_writel(pwm, PWM_IDR, 1 << t);
+
+ clk_disable(pwm->clk);
+ t = 0;
+ }
+ spin_unlock_irqrestore(&pwm->lock, flags);
+ return t;
+}
+EXPORT_SYMBOL(pwm_channel_free);
+
+int __pwm_channel_onoff(struct pwm_channel *ch, int enabled)
+{
+ unsigned long flags;
+ int t;
+
+ /* OMITTED FUNCTIONALITY: starting several channels in synch */
+
+ spin_lock_irqsave(&pwm->lock, flags);
+ t = pwmcheck(ch);
+ if (t >= 0) {
+ pwm_writel(pwm, enabled ? PWM_ENA : PWM_DIS, 1 << t);
+ t = 0;
+ pwm_dumpregs(ch, enabled ? "enable" : "disable");
+ }
+ spin_unlock_irqrestore(&pwm->lock, flags);
+
+ return t;
+}
+EXPORT_SYMBOL(__pwm_channel_onoff);
+
+/**
+ * pwm_clk_alloc - allocate and configure CLKA or CLKB
+ * @prescale: from 0..10, the power of two used to divide MCK
+ * @div: from 1..255, the linear divisor to use
+ *
+ * Returns PWM_CPR_CLKA, PWM_CPR_CLKB, or negative errno. The allocated
+ * clock will run with a period of (2^prescale * div) / MCK, or twice as
+ * long if center aligned PWM output is used. The clock must later be
+ * deconfigured using pwm_clk_free().
+ */
+int pwm_clk_alloc(unsigned prescale, unsigned div)
+{
+ unsigned long flags;
+ u32 mr;
+ u32 val = (prescale << 8) | div;
+ int ret = -EBUSY;
+
+ if (prescale >= 10 || div == 0 || div > 255)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pwm->lock, flags);
+ mr = pwm_readl(pwm, PWM_MR);
+ if ((mr & 0xffff) == 0) {
+ mr |= val;
+ ret = PWM_CPR_CLKA;
+ }
+ if ((mr & (0xffff << 16)) == 0) {
+ mr |= val << 16;
+ ret = PWM_CPR_CLKB;
+ }
+ if (ret > 0)
+ pwm_writel(pwm, PWM_MR, mr);
+ spin_unlock_irqrestore(&pwm->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(pwm_clk_alloc);
+
+/**
+ * pwm_clk_free - deconfigure and release CLKA or CLKB
+ *
+ * Reverses the effect of pwm_clk_alloc().
+ */
+void pwm_clk_free(unsigned clk)
+{
+ unsigned long flags;
+ u32 mr;
+
+ spin_lock_irqsave(&pwm->lock, flags);
+ mr = pwm_readl(pwm, PWM_MR);
+ if (clk == PWM_CPR_CLKA)
+ pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 0));
+ if (clk == PWM_CPR_CLKB)
+ pwm_writel(pwm, PWM_MR, mr & ~(0xffff << 16));
+ spin_unlock_irqrestore(&pwm->lock, flags);
+}
+EXPORT_SYMBOL(pwm_clk_free);
+
+/**
+ * pwm_channel_handler - manage channel's IRQ handler
+ * @ch: the channel
+ * @handler: the handler to use, possibly NULL
+ *
+ * If the handler is non-null, the handler will be called after every
+ * period of this PWM channel. If the handler is null, this channel
+ * won't generate an IRQ.
+ */
+int pwm_channel_handler(struct pwm_channel *ch,
+ void (*handler)(struct pwm_channel *ch))
+{
+ unsigned long flags;
+ int t;
+
+ spin_lock_irqsave(&pwm->lock, flags);
+ t = pwmcheck(ch);
+ if (t >= 0) {
+ pwm->handler[t] = handler;
+ pwm_writel(pwm, handler ? PWM_IER : PWM_IDR, 1 << t);
+ t = 0;
+ }
+ spin_unlock_irqrestore(&pwm->lock, flags);
+
+ return t;
+}
+EXPORT_SYMBOL(pwm_channel_handler);
+
+static irqreturn_t pwm_irq(int id, void *_pwm)
+{
+ struct pwm *p = _pwm;
+ irqreturn_t handled = IRQ_NONE;
+ u32 irqstat;
+ int index;
+
+ spin_lock(&p->lock);
+
+ /* ack irqs, then handle them */
+ irqstat = pwm_readl(pwm, PWM_ISR);
+
+ while (irqstat) {
+ struct pwm_channel *ch;
+ void (*handler)(struct pwm_channel *ch);
+
+ index = ffs(irqstat) - 1;
+ irqstat &= ~(1 << index);
+ ch = pwm->channel[index];
+ handler = pwm->handler[index];
+ if (handler && ch) {
+ spin_unlock(&p->lock);
+ handler(ch);
+ spin_lock(&p->lock);
+ handled = IRQ_HANDLED;
+ }
+ }
+
+ spin_unlock(&p->lock);
+ return handled;
+}
+
+static int __init pwm_probe(struct platform_device *pdev)
+{
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int irq = platform_get_irq(pdev, 0);
+ u32 *mp = pdev->dev.platform_data;
+ struct pwm *p;
+ int status = -EIO;
+
+ if (pwm)
+ return -EBUSY;
+ if (!r || irq < 0 || !mp || !*mp)
+ return -ENODEV;
+ if (*mp & ~((1<<PWM_NCHAN)-1)) {
+ dev_warn(&pdev->dev, "mask 0x%x ... more than %d channels\n",
+ *mp, PWM_NCHAN);
+ return -EINVAL;
+ }
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ spin_lock_init(&p->lock);
+ p->pdev = pdev;
+ p->mask = *mp;
+ p->irq = irq;
+ p->base = ioremap(r->start, r->end - r->start + 1);
+ if (!p->base)
+ goto fail;
+ p->clk = clk_get(&pdev->dev, "mck");
+ if (IS_ERR(p->clk)) {
+ status = PTR_ERR(p->clk);
+ p->clk = NULL;
+ goto fail;
+ }
+
+ status = request_irq(irq, pwm_irq, 0, pdev->name, p);
+ if (status < 0)
+ goto fail;
+
+ pwm = p;
+ platform_set_drvdata(pdev, p);
+
+ return 0;
+
+fail:
+ if (p->clk)
+ clk_put(p->clk);
+ if (p->base)
+ iounmap(p->base);
+
+ kfree(p);
+ return status;
+}
+
+static int __exit pwm_remove(struct platform_device *pdev)
+{
+ struct pwm *p = platform_get_drvdata(pdev);
+
+ if (p != pwm)
+ return -EINVAL;
+
+ clk_enable(pwm->clk);
+ pwm_writel(pwm, PWM_DIS, (1 << PWM_NCHAN) - 1);
+ pwm_writel(pwm, PWM_IDR, (1 << PWM_NCHAN) - 1);
+ clk_disable(pwm->clk);
+
+ pwm = NULL;
+
+ free_irq(p->irq, p);
+ clk_put(p->clk);
+ iounmap(p->base);
+ kfree(p);
+
+ return 0;
+}
+
+static struct platform_driver atmel_pwm_driver = {
+ .driver = {
+ .name = "atmel_pwm",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(pwm_remove),
+
+ /* NOTE: PWM can keep running in AVR32 "idle" and "frozen" states;
+ * and all AT91sam9263 states, albeit at reduced clock rate if
+ * MCK becomes the slow clock (i.e. what Linux labels STR).
+ */
+};
+
+static int __init pwm_init(void)
+{
+ return platform_driver_probe(&atmel_pwm_driver, pwm_probe);
+}
+module_init(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+ platform_driver_unregister(&atmel_pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5fef678..4970b53 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -91,6 +91,16 @@ config MMC_AT91
If unsure, say N.
+config MMC_ATMELMCI
+ tristate "Atmel Multimedia Card Interface support"
+ depends on AVR32 && MMC
+ help
+ This selects the Atmel Multimedia Card Interface. If you have
+ a AT91 (ARM) or AT32 (AVR32) platform with a Multimedia Card
+ slot, say Y or M here.
+
+ If unsure, say N.
+
config MMC_IMX
tristate "Motorola i.MX Multimedia Card Interface support"
depends on ARCH_IMX
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 3877c87..e80ea72 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
+obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
new file mode 100644
index 0000000..0b5ec58
--- /dev/null
+++ b/drivers/mmc/host/atmel-mci.c
@@ -0,0 +1,1176 @@
+/*
+ * Atmel MultiMedia Card Interface driver
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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/blkdev.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/dma-controller.h>
+#include <asm/io.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+#include "atmel-mci.h"
+
+#define DRIVER_NAME "atmel_mci"
+
+#define MCI_DATA_ERROR_FLAGS (MCI_BIT(DCRCE) | MCI_BIT(DTOE) | \
+ MCI_BIT(OVRE) | MCI_BIT(UNRE))
+
+enum {
+ EVENT_CMD_COMPLETE = 0,
+ EVENT_DATA_COMPLETE,
+ EVENT_DATA_ERROR,
+ EVENT_STOP_SENT,
+ EVENT_STOP_COMPLETE,
+ EVENT_DMA_COMPLETE,
+ EVENT_DMA_ERROR,
+ EVENT_CARD_DETECT,
+};
+
+struct atmel_mci_dma {
+ struct dma_request_sg req;
+ unsigned short rx_periph_id;
+ unsigned short tx_periph_id;
+};
+
+struct atmel_mci {
+ struct mmc_host *mmc;
+ void __iomem *regs;
+ struct atmel_mci_dma dma;
+
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ u32 cmd_status;
+ u32 data_status;
+ u32 stop_status;
+ u32 stop_cmdr;
+
+ struct tasklet_struct tasklet;
+ unsigned long pending_events;
+ unsigned long completed_events;
+
+ int present;
+ int detect_pin;
+ int wp_pin;
+
+ unsigned long bus_hz;
+ unsigned long mapbase;
+ struct clk *mck;
+ struct platform_device *pdev;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_regs;
+ struct dentry *debugfs_req;
+ struct dentry *debugfs_pending_events;
+ struct dentry *debugfs_completed_events;
+#endif
+};
+
+/* Those printks take an awful lot of time... */
+#ifndef DEBUG
+static unsigned int fmax = 15000000U;
+#else
+static unsigned int fmax = 1000000U;
+#endif
+module_param(fmax, uint, 0444);
+MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
+
+/* Test bit macros for completed events */
+#define mci_cmd_is_complete(host) \
+ test_bit(EVENT_CMD_COMPLETE, &host->completed_events)
+#define mci_data_is_complete(host) \
+ test_bit(EVENT_DATA_COMPLETE, &host->completed_events)
+#define mci_data_error_is_complete(host) \
+ test_bit(EVENT_DATA_ERROR, &host->completed_events)
+#define mci_stop_sent_is_complete(host) \
+ test_bit(EVENT_STOP_SENT, &host->completed_events)
+#define mci_stop_is_complete(host) \
+ test_bit(EVENT_STOP_COMPLETE, &host->completed_events)
+#define mci_dma_is_complete(host) \
+ test_bit(EVENT_DMA_COMPLETE, &host->completed_events)
+#define mci_dma_error_is_complete(host) \
+ test_bit(EVENT_DMA_ERROR, &host->completed_events)
+#define mci_card_detect_is_complete(host) \
+ test_bit(EVENT_CARD_DETECT, &host->completed_events)
+
+/* Test and clear bit macros for pending events */
+#define mci_clear_cmd_is_pending(host) \
+ test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
+#define mci_clear_data_is_pending(host) \
+ test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
+#define mci_clear_data_error_is_pending(host) \
+ test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)
+#define mci_clear_stop_sent_is_pending(host) \
+ test_and_clear_bit(EVENT_STOP_SENT, &host->pending_events)
+#define mci_clear_stop_is_pending(host) \
+ test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
+#define mci_clear_dma_error_is_pending(host) \
+ test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)
+#define mci_clear_card_detect_is_pending(host) \
+ test_and_clear_bit(EVENT_CARD_DETECT, &host->pending_events)
+
+/* Test and set bit macros for completed events */
+#define mci_set_cmd_is_completed(host) \
+ test_and_set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
+#define mci_set_data_is_completed(host) \
+ test_and_set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
+#define mci_set_data_error_is_completed(host) \
+ test_and_set_bit(EVENT_DATA_ERROR, &host->completed_events)
+#define mci_set_stop_sent_is_completed(host) \
+ test_and_set_bit(EVENT_STOP_SENT, &host->completed_events)
+#define mci_set_stop_is_completed(host) \
+ test_and_set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
+#define mci_set_dma_error_is_completed(host) \
+ test_and_set_bit(EVENT_DMA_ERROR, &host->completed_events)
+#define mci_set_card_detect_is_completed(host) \
+ test_and_set_bit(EVENT_CARD_DETECT, &host->completed_events)
+
+/* Set bit macros for completed events */
+#define mci_set_cmd_complete(host) \
+ set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
+#define mci_set_data_complete(host) \
+ set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
+#define mci_set_data_error_complete(host) \
+ set_bit(EVENT_DATA_ERROR, &host->completed_events)
+#define mci_set_stop_sent_complete(host) \
+ set_bit(EVENT_STOP_SENT, &host->completed_events)
+#define mci_set_stop_complete(host) \
+ set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
+#define mci_set_dma_complete(host) \
+ set_bit(EVENT_DMA_COMPLETE, &host->completed_events)
+#define mci_set_dma_error_complete(host) \
+ set_bit(EVENT_DMA_ERROR, &host->completed_events)
+#define mci_set_card_detect_complete(host) \
+ set_bit(EVENT_CARD_DETECT, &host->completed_events)
+
+/* Set bit macros for pending events */
+#define mci_set_cmd_pending(host) \
+ set_bit(EVENT_CMD_COMPLETE, &host->pending_events)
+#define mci_set_data_pending(host) \
+ set_bit(EVENT_DATA_COMPLETE, &host->pending_events)
+#define mci_set_data_error_pending(host) \
+ set_bit(EVENT_DATA_ERROR, &host->pending_events)
+#define mci_set_stop_sent_pending(host) \
+ set_bit(EVENT_STOP_SENT, &host->pending_events)
+#define mci_set_stop_pending(host) \
+ set_bit(EVENT_STOP_COMPLETE, &host->pending_events)
+#define mci_set_dma_error_pending(host) \
+ set_bit(EVENT_DMA_ERROR, &host->pending_events)
+#define mci_set_card_detect_pending(host) \
+ set_bit(EVENT_CARD_DETECT, &host->pending_events)
+
+/* Clear bit macros for pending events */
+#define mci_clear_cmd_pending(host) \
+ clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
+#define mci_clear_data_pending(host) \
+ clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
+#define mci_clear_data_error_pending(host) \
+ clear_bit(EVENT_DATA_ERROR, &host->pending_events)
+#define mci_clear_stop_sent_pending(host) \
+ clear_bit(EVENT_STOP_SENT, &host->pending_events)
+#define mci_clear_stop_pending(host) \
+ clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
+#define mci_clear_dma_error_pending(host) \
+ clear_bit(EVENT_DMA_ERROR, &host->pending_events)
+#define mci_clear_card_detect_pending(host) \
+ clear_bit(EVENT_CARD_DETECT, &host->pending_events)
+
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+#define DBG_REQ_BUF_SIZE (4096 - sizeof(unsigned int))
+
+struct req_dbg_data {
+ unsigned int nbytes;
+ char str[DBG_REQ_BUF_SIZE];
+};
+
+static int req_dbg_open(struct inode *inode, struct file *file)
+{
+ struct atmel_mci *host;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd, *stop;
+ struct mmc_data *data;
+ struct req_dbg_data *priv;
+ char *str;
+ unsigned long n = 0;
+
+ priv = kzalloc(DBG_REQ_BUF_SIZE, GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ str = priv->str;
+
+ mutex_lock(&inode->i_mutex);
+ host = inode->i_private;
+
+ spin_lock_irq(&host->mmc->lock);
+ mrq = host->mrq;
+ if (mrq) {
+ cmd = mrq->cmd;
+ data = mrq->data;
+ stop = mrq->stop;
+ n = snprintf(str, DBG_REQ_BUF_SIZE,
+ "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
+ cmd->opcode, cmd->arg, cmd->flags,
+ cmd->resp[0], cmd->resp[1], cmd->resp[2],
+ cmd->resp[3], cmd->error);
+ if (n < DBG_REQ_BUF_SIZE && data)
+ n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
+ "DATA %u * %u (%u) %x (err %u)\n",
+ data->blocks, data->blksz,
+ data->bytes_xfered, data->flags,
+ data->error);
+ if (n < DBG_REQ_BUF_SIZE && stop)
+ n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
+ "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
+ stop->opcode, stop->arg, stop->flags,
+ stop->resp[0], stop->resp[1],
+ stop->resp[2], stop->resp[3],
+ stop->error);
+ }
+ spin_unlock_irq(&host->mmc->lock);
+ mutex_unlock(&inode->i_mutex);
+
+ priv->nbytes = min(n, DBG_REQ_BUF_SIZE);
+ file->private_data = priv;
+
+ return 0;
+}
+
+static ssize_t req_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct req_dbg_data *priv = file->private_data;
+
+ return simple_read_from_buffer(buf, nbytes, ppos,
+ priv->str, priv->nbytes);
+}
+
+static int req_dbg_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations req_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = req_dbg_open,
+ .llseek = no_llseek,
+ .read = req_dbg_read,
+ .release = req_dbg_release,
+};
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+ struct atmel_mci *host;
+ unsigned int i;
+ u32 *data;
+ int ret = -ENOMEM;
+
+ mutex_lock(&inode->i_mutex);
+ host = inode->i_private;
+ data = kmalloc(inode->i_size, GFP_KERNEL);
+ if (!data)
+ goto out;
+
+ spin_lock_irq(&host->mmc->lock);
+ for (i = 0; i < inode->i_size / 4; i++)
+ data[i] = __raw_readl(host->regs + i * 4);
+ spin_unlock_irq(&host->mmc->lock);
+
+ file->private_data = data;
+ ret = 0;
+
+out:
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ mutex_lock(&inode->i_mutex);
+ ret = simple_read_from_buffer(buf, nbytes, ppos,
+ file->private_data,
+ file->f_dentry->d_inode->i_size);
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations regs_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = regs_dbg_open,
+ .llseek = generic_file_llseek,
+ .read = regs_dbg_read,
+ .release = regs_dbg_release,
+};
+
+static void atmci_init_debugfs(struct atmel_mci *host)
+{
+ struct mmc_host *mmc;
+ struct dentry *root, *regs;
+ struct resource *res;
+
+ mmc = host->mmc;
+ root = debugfs_create_dir(mmc_hostname(mmc), NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+ host->debugfs_root = root;
+
+ regs = debugfs_create_file("regs", 0400, root, host, &regs_dbg_fops);
+ if (!regs)
+ goto err_regs;
+
+ res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
+ regs->d_inode->i_size = res->end - res->start + 1;
+ host->debugfs_regs = regs;
+
+ host->debugfs_req = debugfs_create_file("req", 0400, root,
+ host, &req_dbg_fops);
+ if (!host->debugfs_req)
+ goto err_req;
+
+ host->debugfs_pending_events
+ = debugfs_create_u32("pending_events", 0400, root,
+ (u32 *)&host->pending_events);
+ if (!host->debugfs_pending_events)
+ goto err_pending_events;
+
+ host->debugfs_completed_events
+ = debugfs_create_u32("completed_events", 0400, root,
+ (u32 *)&host->completed_events);
+ if (!host->debugfs_completed_events)
+ goto err_completed_events;
+
+ return;
+
+err_completed_events:
+ debugfs_remove(host->debugfs_pending_events);
+err_pending_events:
+ debugfs_remove(host->debugfs_req);
+err_req:
+ debugfs_remove(host->debugfs_regs);
+err_regs:
+ debugfs_remove(host->debugfs_root);
+err_root:
+ host->debugfs_root = NULL;
+ dev_err(&host->pdev->dev,
+ "failed to initialize debugfs for %s\n",
+ mmc_hostname(mmc));
+}
+
+static void atmci_cleanup_debugfs(struct atmel_mci *host)
+{
+ if (host->debugfs_root) {
+ debugfs_remove(host->debugfs_completed_events);
+ debugfs_remove(host->debugfs_pending_events);
+ debugfs_remove(host->debugfs_req);
+ debugfs_remove(host->debugfs_regs);
+ debugfs_remove(host->debugfs_root);
+ host->debugfs_root = NULL;
+ }
+}
+#else
+static inline void atmci_init_debugfs(struct atmel_mci *host)
+{
+
+}
+
+static inline void atmci_cleanup_debugfs(struct atmel_mci *host)
+{
+
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static inline unsigned int ns_to_clocks(struct atmel_mci *host,
+ unsigned int ns)
+{
+ return (ns * (host->bus_hz / 1000000) + 999) / 1000;
+}
+
+static void atmci_set_timeout(struct atmel_mci *host,
+ struct mmc_data *data)
+{
+ static unsigned dtomul_to_shift[] = {
+ 0, 4, 7, 8, 10, 12, 16, 20
+ };
+ unsigned timeout;
+ unsigned dtocyc, dtomul;
+
+ timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks;
+
+ for (dtomul = 0; dtomul < 8; dtomul++) {
+ unsigned shift = dtomul_to_shift[dtomul];
+ dtocyc = (timeout + (1 << shift) - 1) >> shift;
+ if (dtocyc < 15)
+ break;
+ }
+
+ if (dtomul >= 8) {
+ dtomul = 7;
+ dtocyc = 15;
+ }
+
+ dev_dbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
+ dtocyc << dtomul_to_shift[dtomul]);
+ mci_writel(host, DTOR, (MCI_BF(DTOMUL, dtomul)
+ | MCI_BF(DTOCYC, dtocyc)));
+}
+
+/*
+ * Return mask with command flags to be enabled for this command.
+ */
+static u32 atmci_prepare_command(struct mmc_host *mmc,
+ struct mmc_command *cmd)
+{
+ u32 cmdr;
+
+ cmd->error = 0;
+
+ cmdr = MCI_BF(CMDNB, cmd->opcode);
+
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136)
+ cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_136_BIT);
+ else
+ cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_48_BIT);
+ }
+
+ /*
+ * This should really be MAXLAT_5 for CMD2 and ACMD41, but
+ * it's too difficult to determine whether this is an ACMD or
+ * not. Better make it 64.
+ */
+ cmdr |= MCI_BIT(MAXLAT);
+
+ if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
+ cmdr |= MCI_BIT(OPDCMD);
+
+ dev_dbg(&mmc->class_dev,
+ "cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n",
+ cmd->opcode, cmd->arg, cmd->flags, (unsigned long)cmdr);
+
+ return cmdr;
+}
+
+static void atmci_start_command(struct atmel_mci *host,
+ struct mmc_command *cmd,
+ u32 cmd_flags)
+{
+ WARN_ON(host->cmd);
+ host->cmd = cmd;
+
+ mci_writel(host, ARGR, cmd->arg);
+ mci_writel(host, CMDR, cmd_flags);
+
+ if (cmd->data)
+ dma_start_request(host->dma.req.req.dmac,
+ host->dma.req.req.channel);
+}
+
+/*
+ * Returns a mask of flags to be set in the command register when the
+ * command to start the transfer is to be sent.
+ */
+static u32 atmci_prepare_data(struct mmc_host *mmc, struct mmc_data *data)
+{
+ struct atmel_mci *host = mmc_priv(mmc);
+ u32 cmd_flags;
+
+ WARN_ON(host->data);
+ host->data = data;
+
+ atmci_set_timeout(host, data);
+ mci_writel(host, BLKR, (MCI_BF(BCNT, data->blocks)
+ | MCI_BF(BLKLEN, data->blksz)));
+ host->dma.req.block_size = data->blksz;
+ host->dma.req.nr_blocks = data->blocks;
+
+ cmd_flags = MCI_BF(TRCMD, MCI_TRCMD_START_TRANS);
+ if (data->flags & MMC_DATA_STREAM)
+ cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
+ else if (data->blocks > 1)
+ cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
+ else
+ cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_BLOCK);
+
+ if (data->flags & MMC_DATA_READ) {
+ cmd_flags |= MCI_BIT(TRDIR);
+ host->dma.req.nr_sg
+ = dma_map_sg(&host->pdev->dev, data->sg,
+ data->sg_len, DMA_FROM_DEVICE);
+ host->dma.req.periph_id = host->dma.rx_periph_id;
+ host->dma.req.direction = DMA_DIR_PERIPH_TO_MEM;
+ host->dma.req.data_reg = host->mapbase + MCI_RDR;
+ } else {
+ host->dma.req.nr_sg
+ = dma_map_sg(&host->pdev->dev, data->sg,
+ data->sg_len, DMA_TO_DEVICE);
+ host->dma.req.periph_id = host->dma.tx_periph_id;
+ host->dma.req.direction = DMA_DIR_MEM_TO_PERIPH;
+ host->dma.req.data_reg = host->mapbase + MCI_TDR;
+ }
+ host->dma.req.sg = data->sg;
+
+ dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req);
+
+ return cmd_flags;
+}
+
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct atmel_mci *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+ u32 iflags;
+ u32 cmdflags = 0;
+
+ iflags = mci_readl(host, IMR);
+ if (iflags)
+ dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
+ mci_readl(host, IMR));
+
+ WARN_ON(host->mrq != NULL);
+ host->mrq = mrq;
+ host->pending_events = 0;
+ host->completed_events = 0;
+
+ iflags = MCI_BIT(CMDRDY);
+ cmdflags = atmci_prepare_command(mmc, mrq->cmd);
+
+ if (mrq->stop) {
+ WARN_ON(!data);
+
+ host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
+ host->stop_cmdr |= MCI_BF(TRCMD, MCI_TRCMD_STOP_TRANS);
+ if (!(data->flags & MMC_DATA_WRITE))
+ host->stop_cmdr |= MCI_BIT(TRDIR);
+ if (data->flags & MMC_DATA_STREAM)
+ host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
+ else
+ host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
+ }
+ if (data) {
+ cmdflags |= atmci_prepare_data(mmc, data);
+ iflags |= MCI_DATA_ERROR_FLAGS;
+ }
+
+ atmci_start_command(host, mrq->cmd, cmdflags);
+ mci_writel(host, IER, iflags);
+}
+
+static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct atmel_mci *host = mmc_priv(mmc);
+ u32 mr;
+
+ if (ios->clock) {
+ u32 clkdiv;
+
+ /* Set clock rate */
+ clkdiv = host->bus_hz / (2 * ios->clock) - 1;
+ if (clkdiv > 255) {
+ dev_warn(&mmc->class_dev,
+ "clock %u too slow; using %lu\n",
+ ios->clock, host->bus_hz / (2 * 256));
+ clkdiv = 255;
+ }
+
+ mr = mci_readl(host, MR);
+ mr = MCI_BFINS(CLKDIV, clkdiv, mr)
+ | MCI_BIT(WRPROOF) | MCI_BIT(RDPROOF);
+ mci_writel(host, MR, mr);
+
+ /* Enable the MCI controller */
+ mci_writel(host, CR, MCI_BIT(MCIEN));
+ } else {
+ /* Disable the MCI controller */
+ mci_writel(host, CR, MCI_BIT(MCIDIS));
+ }
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ mci_writel(host, SDCR, 0);
+ break;
+ case MMC_BUS_WIDTH_4:
+ mci_writel(host, SDCR, MCI_BIT(SDCBUS));
+ break;
+ }
+
+ switch (ios->power_mode) {
+ case MMC_POWER_ON:
+ /* Send init sequence (74 clock cycles) */
+ mci_writel(host, IDR, ~0UL);
+ mci_writel(host, CMDR, MCI_BF(SPCMD, MCI_SPCMD_INIT_CMD));
+ while (!(mci_readl(host, SR) & MCI_BIT(CMDRDY)))
+ cpu_relax();
+ break;
+ default:
+ /*
+ * TODO: None of the currently available AVR32-based
+ * boards allow MMC power to be turned off. Implement
+ * power control when this can be tested properly.
+ */
+ break;
+ }
+}
+
+static int atmci_get_ro(struct mmc_host *mmc)
+{
+ int read_only = 0;
+ struct atmel_mci *host = mmc_priv(mmc);
+
+ if (host->wp_pin >= 0) {
+ read_only = gpio_get_value(host->wp_pin);
+ dev_dbg(&mmc->class_dev, "card is %s\n",
+ read_only ? "read-only" : "read-write");
+ } else {
+ dev_dbg(&mmc->class_dev,
+ "no pin for checking read-only switch."
+ " Assuming write-enable.\n");
+ }
+
+ return read_only;
+}
+
+static struct mmc_host_ops atmci_ops = {
+ .request = atmci_request,
+ .set_ios = atmci_set_ios,
+ .get_ro = atmci_get_ro,
+};
+
+static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct atmel_mci *host = mmc_priv(mmc);
+
+ WARN_ON(host->cmd || host->data);
+ host->mrq = NULL;
+
+ mmc_request_done(mmc, mrq);
+}
+
+static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data,
+ u32 flags)
+{
+ struct atmel_mci *host = mmc_priv(mmc);
+
+ atmci_start_command(host, data->stop, host->stop_cmdr | flags);
+ mci_writel(host, IER, MCI_BIT(CMDRDY));
+}
+
+static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data)
+{
+ host->data = NULL;
+ dma_unmap_sg(&host->pdev->dev, data->sg, host->dma.req.nr_sg,
+ ((data->flags & MMC_DATA_WRITE)
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+
+ /*
+ * Data might complete before command for very short transfers
+ * (like READ_SCR)
+ */
+ if (mci_cmd_is_complete(host)
+ && (!data->stop || mci_stop_is_complete(host)))
+ atmci_request_end(host->mmc, data->mrq);
+}
+
+static void atmci_command_complete(struct atmel_mci *host,
+ struct mmc_command *cmd, u32 status)
+{
+ if (status & MCI_BIT(RTOE))
+ cmd->error = -ETIMEDOUT;
+ else if ((cmd->flags & MMC_RSP_CRC)
+ && (status & MCI_BIT(RCRCE)))
+ cmd->error = -EILSEQ;
+ else if (status & (MCI_BIT(RINDE) | MCI_BIT(RDIRE) | MCI_BIT(RENDE)))
+ cmd->error = -EIO;
+
+ if (cmd->error) {
+ dev_dbg(&host->mmc->class_dev,
+ "command error: op=0x%x status=0x%08x\n",
+ cmd->opcode, status);
+
+ if (cmd->data) {
+ dma_stop_request(host->dma.req.req.dmac,
+ host->dma.req.req.channel);
+ mci_writel(host, IDR, MCI_BIT(NOTBUSY)
+ | MCI_DATA_ERROR_FLAGS);
+ host->data = NULL;
+ }
+ }
+}
+
+static void atmci_tasklet_func(unsigned long priv)
+{
+ struct mmc_host *mmc = (struct mmc_host *)priv;
+ struct atmel_mci *host = mmc_priv(mmc);
+ struct mmc_request *mrq = host->mrq;
+ struct mmc_data *data = host->data;
+
+ dev_vdbg(&mmc->class_dev,
+ "tasklet: pending/completed/mask %lx/%lx/%x\n",
+ host->pending_events, host->completed_events,
+ mci_readl(host, IMR));
+
+ if (mci_clear_cmd_is_pending(host)) {
+ mci_set_cmd_complete(host);
+ atmci_command_complete(host, mrq->cmd, host->cmd_status);
+ if (!host->data || mci_data_is_complete(host)
+ || mci_data_error_is_complete(host))
+ atmci_request_end(mmc, mrq);
+ }
+ if (mci_clear_stop_is_pending(host)) {
+ mci_set_stop_complete(host);
+ atmci_command_complete(host, mrq->stop, host->stop_status);
+ if (mci_data_is_complete(host)
+ || mci_data_error_is_complete(host))
+ atmci_request_end(mmc, mrq);
+ }
+ if (mci_clear_dma_error_is_pending(host)) {
+ mci_set_dma_error_complete(host);
+ mci_clear_data_pending(host);
+
+ /* DMA controller got bus error => invalid address */
+ data->error = -EIO;
+
+ dev_dbg(&mmc->class_dev, "dma error after %u bytes xfered\n",
+ host->data->bytes_xfered);
+
+ if (data->stop
+ && !mci_set_stop_sent_is_completed(host))
+ /* TODO: Check if card is still present */
+ send_stop_cmd(host->mmc, data, 0);
+
+ atmci_data_complete(host, data);
+ }
+ if (mci_clear_data_error_is_pending(host)) {
+ u32 status = host->data_status;
+
+ mci_set_data_error_complete(host);
+ mci_clear_data_pending(host);
+
+ dma_stop_request(host->dma.req.req.dmac,
+ host->dma.req.req.channel);
+
+ if (status & MCI_BIT(DCRCE)) {
+ dev_dbg(&mmc->class_dev, "data CRC error\n");
+ data->error = -EILSEQ;
+ } else if (status & MCI_BIT(DTOE)) {
+ dev_dbg(&mmc->class_dev, "data timeout error\n");
+ data->error = -ETIMEDOUT;
+ } else {
+ dev_dbg(&mmc->class_dev, "data FIFO error\n");
+ data->error = -EIO;
+ }
+ dev_dbg(&mmc->class_dev, "bytes xfered: %u\n",
+ data->bytes_xfered);
+
+ if (data->stop
+ && !mci_set_stop_sent_is_completed(host))
+ /* TODO: Check if card is still present */
+ send_stop_cmd(host->mmc, data, 0);
+
+ atmci_data_complete(host, data);
+ }
+ if (mci_clear_data_is_pending(host)) {
+ mci_set_data_complete(host);
+ data->bytes_xfered = data->blocks * data->blksz;
+ atmci_data_complete(host, data);
+ }
+ if (mci_clear_card_detect_is_pending(host)) {
+ /* Reset controller if card is gone */
+ if (!host->present) {
+ mci_writel(host, CR, MCI_BIT(SWRST));
+ mci_writel(host, IDR, ~0UL);
+ mci_writel(host, CR, MCI_BIT(MCIEN));
+ }
+
+ /* Clean up queue if present */
+ if (mrq) {
+ if (!mci_cmd_is_complete(host))
+ mrq->cmd->error = -ETIMEDOUT;
+ if (mrq->data && !mci_data_is_complete(host)
+ && !mci_data_error_is_complete(host)) {
+ dma_stop_request(host->dma.req.req.dmac,
+ host->dma.req.req.channel);
+ host->data->error = -ETIMEDOUT;
+ atmci_data_complete(host, data);
+ }
+ if (mrq->stop && !mci_stop_is_complete(host))
+ mrq->stop->error = -ETIMEDOUT;
+
+ host->cmd = NULL;
+ atmci_request_end(mmc, mrq);
+ }
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+ }
+}
+
+static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+{
+ struct atmel_mci *host = mmc_priv(mmc);
+ struct mmc_command *cmd = host->cmd;
+
+ /*
+ * Read the response now so that we're free to send a new
+ * command immediately.
+ */
+ cmd->resp[0] = mci_readl(host, RSPR);
+ cmd->resp[1] = mci_readl(host, RSPR);
+ cmd->resp[2] = mci_readl(host, RSPR);
+ cmd->resp[3] = mci_readl(host, RSPR);
+
+ mci_writel(host, IDR, MCI_BIT(CMDRDY));
+ host->cmd = NULL;
+
+ if (mci_stop_sent_is_complete(host)) {
+ host->stop_status = status;
+ mci_set_stop_pending(host);
+ } else {
+ if (host->mrq->stop && mci_dma_is_complete(host)
+ && !mci_set_stop_sent_is_completed(host))
+ send_stop_cmd(host->mmc, host->data, 0);
+ host->cmd_status = status;
+ mci_set_cmd_pending(host);
+ }
+
+ tasklet_schedule(&host->tasklet);
+}
+
+static void atmci_xfer_complete(struct dma_request *_req)
+{
+ struct dma_request_sg *req = to_dma_request_sg(_req);
+ struct atmel_mci_dma *dma;
+ struct atmel_mci *host;
+ struct mmc_data *data;
+
+ dma = container_of(req, struct atmel_mci_dma, req);
+ host = container_of(dma, struct atmel_mci, dma);
+ data = host->data;
+
+ /*
+ * This callback may be called before we see the CMDRDY
+ * interrupt under heavy irq load (possibly caused by other
+ * drivers) or when interrupts are disabled for a long time.
+ */
+ mci_set_dma_complete(host);
+ if (data->stop && mci_cmd_is_complete(host)
+ && !mci_set_stop_sent_is_completed(host))
+ send_stop_cmd(host->mmc, data, 0);
+
+ /*
+ * Regardless of what the documentation says, we have to wait
+ * for NOTBUSY even after block read operations.
+ *
+ * When the DMA transfer is complete, the controller may still
+ * be reading the CRC from the card, i.e. the data transfer is
+ * still in progress and we haven't seen all the potential
+ * error bits yet.
+ */
+ mci_writel(host, IER, MCI_BIT(NOTBUSY));
+}
+
+static void atmci_dma_error(struct dma_request *_req)
+{
+ struct dma_request_sg *req = to_dma_request_sg(_req);
+ struct atmel_mci_dma *dma;
+ struct atmel_mci *host;
+
+ dma = container_of(req, struct atmel_mci_dma, req);
+ host = container_of(dma, struct atmel_mci, dma);
+
+ mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
+ | MCI_DATA_ERROR_FLAGS));
+
+ mci_set_dma_error_pending(host);
+ tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+{
+ struct mmc_host *mmc = dev_id;
+ struct atmel_mci *host = mmc_priv(mmc);
+ u32 status, mask, pending;
+
+ spin_lock(&mmc->lock);
+
+ status = mci_readl(host, SR);
+ mask = mci_readl(host, IMR);
+ pending = status & mask;
+
+ do {
+ if (pending & MCI_DATA_ERROR_FLAGS) {
+ mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
+ | MCI_DATA_ERROR_FLAGS));
+ host->data_status = status;
+ mci_set_data_error_pending(host);
+ tasklet_schedule(&host->tasklet);
+ break;
+ }
+ if (pending & MCI_BIT(CMDRDY))
+ atmci_cmd_interrupt(mmc, status);
+ if (pending & MCI_BIT(NOTBUSY)) {
+ mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
+ | MCI_DATA_ERROR_FLAGS));
+ mci_set_data_pending(host);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ status = mci_readl(host, SR);
+ mask = mci_readl(host, IMR);
+ pending = status & mask;
+ } while (pending);
+
+ spin_unlock(&mmc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t atmci_detect_change(int irq, void *dev_id)
+{
+ struct mmc_host *mmc = dev_id;
+ struct atmel_mci *host = mmc_priv(mmc);
+
+ int present = !gpio_get_value(irq_to_gpio(irq));
+
+ if (present != host->present) {
+ dev_dbg(&mmc->class_dev, "card %s\n",
+ present ? "inserted" : "removed");
+ host->present = present;
+ mci_set_card_detect_pending(host);
+ tasklet_schedule(&host->tasklet);
+ }
+ return IRQ_HANDLED;
+}
+
+static int __devinit atmci_probe(struct platform_device *pdev)
+{
+ struct mci_platform_data *board;
+ struct atmel_mci *host;
+ struct mmc_host *mmc;
+ struct resource *regs;
+ int irq;
+ int ret;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ board = pdev->dev.platform_data;
+
+ mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ host = mmc_priv(mmc);
+ host->pdev = pdev;
+ host->mmc = mmc;
+ if (board) {
+ host->detect_pin = board->detect_pin;
+ host->wp_pin = board->wp_pin;
+ } else {
+ host->detect_pin = -1;
+ host->detect_pin = -1;
+ }
+
+ host->mck = clk_get(&pdev->dev, "mci_clk");
+ if (IS_ERR(host->mck)) {
+ ret = PTR_ERR(host->mck);
+ goto out_free_host;
+ }
+ clk_enable(host->mck);
+
+ ret = -ENOMEM;
+ host->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!host->regs)
+ goto out_disable_clk;
+
+ host->bus_hz = clk_get_rate(host->mck);
+ host->mapbase = regs->start;
+
+ mmc->ops = &atmci_ops;
+ mmc->f_min = (host->bus_hz + 511) / 512;
+ mmc->f_max = min((unsigned int)(host->bus_hz / 2), fmax);
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
+
+ ret = request_irq(irq, atmci_interrupt, 0, "mmci", mmc);
+ if (ret)
+ goto out_unmap;
+
+ /* Assume card is present if we don't have a detect pin */
+ host->present = 1;
+ if (host->detect_pin >= 0) {
+ if (gpio_request(host->detect_pin, "mmc_detect")) {
+ dev_dbg(&mmc->class_dev, "no detect pin available\n");
+ host->detect_pin = -1;
+ } else {
+ host->present = !gpio_get_value(host->detect_pin);
+ }
+ }
+ if (host->wp_pin >= 0) {
+ if (gpio_request(host->wp_pin, "mmc_wp")) {
+ dev_dbg(&mmc->class_dev, "no WP pin available\n");
+ host->wp_pin = -1;
+ }
+ }
+
+ /* TODO: Get this information from platform data */
+ ret = -ENOMEM;
+ host->dma.req.req.dmac = find_dma_controller(0);
+ if (!host->dma.req.req.dmac) {
+ dev_dbg(&mmc->class_dev, "no DMA controller available\n");
+ goto out_free_irq;
+ }
+ ret = dma_alloc_channel(host->dma.req.req.dmac);
+ if (ret < 0) {
+ dev_dbg(&mmc->class_dev, "unable to allocate DMA channel\n");
+ goto out_free_irq;
+ }
+ host->dma.req.req.channel = ret;
+ host->dma.req.width = DMA_WIDTH_32BIT;
+ host->dma.req.req.xfer_complete = atmci_xfer_complete;
+ host->dma.req.req.block_complete = NULL; // atmci_block_complete;
+ host->dma.req.req.error = atmci_dma_error;
+ host->dma.rx_periph_id = 0;
+ host->dma.tx_periph_id = 1;
+
+ mci_writel(host, CR, MCI_BIT(SWRST));
+ mci_writel(host, IDR, ~0UL);
+
+ platform_set_drvdata(pdev, host);
+
+ mmc_add_host(mmc);
+
+ if (host->detect_pin >= 0) {
+ ret = request_irq(gpio_to_irq(host->detect_pin),
+ atmci_detect_change,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ DRIVER_NAME, mmc);
+ if (ret) {
+ dev_dbg(&mmc->class_dev,
+ "could not request IRQ %d for detect pin\n",
+ gpio_to_irq(host->detect_pin));
+ gpio_free(host->detect_pin);
+ host->detect_pin = -1;
+ }
+ }
+
+ dev_info(&mmc->class_dev, "Atmel MCI controller at 0x%08lx irq %d\n",
+ host->mapbase, irq);
+
+ atmci_init_debugfs(host);
+
+ return 0;
+
+out_free_irq:
+ if (host->detect_pin >= 0)
+ gpio_free(host->detect_pin);
+ if (host->wp_pin >= 0)
+ gpio_free(host->wp_pin);
+ free_irq(irq, mmc);
+out_unmap:
+ iounmap(host->regs);
+out_disable_clk:
+ clk_disable(host->mck);
+ clk_put(host->mck);
+out_free_host:
+ mmc_free_host(mmc);
+ return ret;
+}
+
+static int __devexit atmci_remove(struct platform_device *pdev)
+{
+ struct atmel_mci *host = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (host) {
+ atmci_cleanup_debugfs(host);
+
+ if (host->detect_pin >= 0) {
+ free_irq(gpio_to_irq(host->detect_pin), host->mmc);
+ cancel_delayed_work(&host->mmc->detect);
+ gpio_free(host->detect_pin);
+ }
+
+ mmc_remove_host(host->mmc);
+
+ mci_writel(host, IDR, ~0UL);
+ mci_writel(host, CR, MCI_BIT(MCIDIS));
+ mci_readl(host, SR);
+
+ dma_release_channel(host->dma.req.req.dmac,
+ host->dma.req.req.channel);
+
+ if (host->wp_pin >= 0)
+ gpio_free(host->wp_pin);
+
+ free_irq(platform_get_irq(pdev, 0), host->mmc);
+ iounmap(host->regs);
+
+ clk_disable(host->mck);
+ clk_put(host->mck);
+
+ mmc_free_host(host->mmc);
+ }
+ return 0;
+}
+
+static struct platform_driver atmci_driver = {
+ .probe = atmci_probe,
+ .remove = __devexit_p(atmci_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init atmci_init(void)
+{
+ return platform_driver_register(&atmci_driver);
+}
+
+static void __exit atmci_exit(void)
+{
+ platform_driver_unregister(&atmci_driver);
+}
+
+module_init(atmci_init);
+module_exit(atmci_exit);
+
+MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/atmel-mci.h b/drivers/mmc/host/atmel-mci.h
new file mode 100644
index 0000000..60d15c4
--- /dev/null
+++ b/drivers/mmc/host/atmel-mci.h
@@ -0,0 +1,192 @@
+/*
+ * Atmel MultiMedia Card Interface driver
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __DRIVERS_MMC_ATMEL_MCI_H__
+#define __DRIVERS_MMC_ATMEL_MCI_H__
+
+/* MCI register offsets */
+#define MCI_CR 0x0000
+#define MCI_MR 0x0004
+#define MCI_DTOR 0x0008
+#define MCI_SDCR 0x000c
+#define MCI_ARGR 0x0010
+#define MCI_CMDR 0x0014
+#define MCI_BLKR 0x0018
+#define MCI_RSPR 0x0020
+#define MCI_RSPR1 0x0024
+#define MCI_RSPR2 0x0028
+#define MCI_RSPR3 0x002c
+#define MCI_RDR 0x0030
+#define MCI_TDR 0x0034
+#define MCI_SR 0x0040
+#define MCI_IER 0x0044
+#define MCI_IDR 0x0048
+#define MCI_IMR 0x004c
+
+/* Bitfields in CR */
+#define MCI_MCIEN_OFFSET 0
+#define MCI_MCIEN_SIZE 1
+#define MCI_MCIDIS_OFFSET 1
+#define MCI_MCIDIS_SIZE 1
+#define MCI_PWSEN_OFFSET 2
+#define MCI_PWSEN_SIZE 1
+#define MCI_PWSDIS_OFFSET 3
+#define MCI_PWSDIS_SIZE 1
+#define MCI_SWRST_OFFSET 7
+#define MCI_SWRST_SIZE 1
+
+/* Bitfields in MR */
+#define MCI_CLKDIV_OFFSET 0
+#define MCI_CLKDIV_SIZE 8
+#define MCI_PWSDIV_OFFSET 8
+#define MCI_PWSDIV_SIZE 3
+#define MCI_RDPROOF_OFFSET 11
+#define MCI_RDPROOF_SIZE 1
+#define MCI_WRPROOF_OFFSET 12
+#define MCI_WRPROOF_SIZE 1
+#define MCI_DMAPADV_OFFSET 14
+#define MCI_DMAPADV_SIZE 1
+#define MCI_BLKLEN_OFFSET 16
+#define MCI_BLKLEN_SIZE 16
+
+/* Bitfields in DTOR */
+#define MCI_DTOCYC_OFFSET 0
+#define MCI_DTOCYC_SIZE 4
+#define MCI_DTOMUL_OFFSET 4
+#define MCI_DTOMUL_SIZE 3
+
+/* Bitfields in SDCR */
+#define MCI_SDCSEL_OFFSET 0
+#define MCI_SDCSEL_SIZE 4
+#define MCI_SDCBUS_OFFSET 7
+#define MCI_SDCBUS_SIZE 1
+
+/* Bitfields in ARGR */
+#define MCI_ARG_OFFSET 0
+#define MCI_ARG_SIZE 32
+
+/* Bitfields in CMDR */
+#define MCI_CMDNB_OFFSET 0
+#define MCI_CMDNB_SIZE 6
+#define MCI_RSPTYP_OFFSET 6
+#define MCI_RSPTYP_SIZE 2
+#define MCI_SPCMD_OFFSET 8
+#define MCI_SPCMD_SIZE 3
+#define MCI_OPDCMD_OFFSET 11
+#define MCI_OPDCMD_SIZE 1
+#define MCI_MAXLAT_OFFSET 12
+#define MCI_MAXLAT_SIZE 1
+#define MCI_TRCMD_OFFSET 16
+#define MCI_TRCMD_SIZE 2
+#define MCI_TRDIR_OFFSET 18
+#define MCI_TRDIR_SIZE 1
+#define MCI_TRTYP_OFFSET 19
+#define MCI_TRTYP_SIZE 2
+
+/* Bitfields in BLKR */
+#define MCI_BCNT_OFFSET 0
+#define MCI_BCNT_SIZE 16
+
+/* Bitfields in RSPRn */
+#define MCI_RSP_OFFSET 0
+#define MCI_RSP_SIZE 32
+
+/* Bitfields in SR/IER/IDR/IMR */
+#define MCI_CMDRDY_OFFSET 0
+#define MCI_CMDRDY_SIZE 1
+#define MCI_RXRDY_OFFSET 1
+#define MCI_RXRDY_SIZE 1
+#define MCI_TXRDY_OFFSET 2
+#define MCI_TXRDY_SIZE 1
+#define MCI_BLKE_OFFSET 3
+#define MCI_BLKE_SIZE 1
+#define MCI_DTIP_OFFSET 4
+#define MCI_DTIP_SIZE 1
+#define MCI_NOTBUSY_OFFSET 5
+#define MCI_NOTBUSY_SIZE 1
+#define MCI_ENDRX_OFFSET 6
+#define MCI_ENDRX_SIZE 1
+#define MCI_ENDTX_OFFSET 7
+#define MCI_ENDTX_SIZE 1
+#define MCI_RXBUFF_OFFSET 14
+#define MCI_RXBUFF_SIZE 1
+#define MCI_TXBUFE_OFFSET 15
+#define MCI_TXBUFE_SIZE 1
+#define MCI_RINDE_OFFSET 16
+#define MCI_RINDE_SIZE 1
+#define MCI_RDIRE_OFFSET 17
+#define MCI_RDIRE_SIZE 1
+#define MCI_RCRCE_OFFSET 18
+#define MCI_RCRCE_SIZE 1
+#define MCI_RENDE_OFFSET 19
+#define MCI_RENDE_SIZE 1
+#define MCI_RTOE_OFFSET 20
+#define MCI_RTOE_SIZE 1
+#define MCI_DCRCE_OFFSET 21
+#define MCI_DCRCE_SIZE 1
+#define MCI_DTOE_OFFSET 22
+#define MCI_DTOE_SIZE 1
+#define MCI_OVRE_OFFSET 30
+#define MCI_OVRE_SIZE 1
+#define MCI_UNRE_OFFSET 31
+#define MCI_UNRE_SIZE 1
+
+/* Constants for DTOMUL */
+#define MCI_DTOMUL_1_CYCLE 0
+#define MCI_DTOMUL_16_CYCLES 1
+#define MCI_DTOMUL_128_CYCLES 2
+#define MCI_DTOMUL_256_CYCLES 3
+#define MCI_DTOMUL_1024_CYCLES 4
+#define MCI_DTOMUL_4096_CYCLES 5
+#define MCI_DTOMUL_65536_CYCLES 6
+#define MCI_DTOMUL_1048576_CYCLES 7
+
+/* Constants for RSPTYP */
+#define MCI_RSPTYP_NO_RESP 0
+#define MCI_RSPTYP_48_BIT 1
+#define MCI_RSPTYP_136_BIT 2
+
+/* Constants for SPCMD */
+#define MCI_SPCMD_NO_SPEC_CMD 0
+#define MCI_SPCMD_INIT_CMD 1
+#define MCI_SPCMD_SYNC_CMD 2
+#define MCI_SPCMD_INT_CMD 4
+#define MCI_SPCMD_INT_RESP 5
+
+/* Constants for TRCMD */
+#define MCI_TRCMD_NO_TRANS 0
+#define MCI_TRCMD_START_TRANS 1
+#define MCI_TRCMD_STOP_TRANS 2
+
+/* Constants for TRTYP */
+#define MCI_TRTYP_BLOCK 0
+#define MCI_TRTYP_MULTI_BLOCK 1
+#define MCI_TRTYP_STREAM 2
+
+/* Bit manipulation macros */
+#define MCI_BIT(name) \
+ (1 << MCI_##name##_OFFSET)
+#define MCI_BF(name,value) \
+ (((value) & ((1 << MCI_##name##_SIZE) - 1)) \
+ << MCI_##name##_OFFSET)
+#define MCI_BFEXT(name,value) \
+ (((value) >> MCI_##name##_OFFSET) \
+ & ((1 << MCI_##name##_SIZE) - 1))
+#define MCI_BFINS(name,value,old) \
+ (((old) & ~(((1 << MCI_##name##_SIZE) - 1) \
+ << MCI_##name##_OFFSET)) \
+ | MCI_BF(name,value))
+
+/* Register access macros */
+#define mci_readl(port,reg) \
+ __raw_readl((port)->regs + MCI_##reg)
+#define mci_writel(port,reg,value) \
+ __raw_writel((value), (port)->regs + MCI_##reg)
+
+#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 1707f98..d2ec6eb 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -50,6 +50,7 @@
#define I82802AC 0x00ac
#define MANUFACTURER_ST 0x0020
#define M50LPW080 0x002F
+#define AT49BV640D 0x02de
static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -157,6 +158,47 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
}
#endif
+/* Atmel chips don't use the same PRI format as Intel chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+ struct cfi_pri_atmel atmel_pri;
+ uint32_t features = 0;
+
+ /* Reverse byteswapping */
+ extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
+ extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
+ extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
+
+ memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+ memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+ printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
+
+ if (atmel_pri.Features & 0x01) /* chip erase supported */
+ features |= (1<<0);
+ if (atmel_pri.Features & 0x02) /* erase suspend supported */
+ features |= (1<<1);
+ if (atmel_pri.Features & 0x04) /* program suspend supported */
+ features |= (1<<2);
+ if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
+ features |= (1<<9);
+ if (atmel_pri.Features & 0x20) /* page mode read supported */
+ features |= (1<<7);
+ if (atmel_pri.Features & 0x40) /* queued erase supported */
+ features |= (1<<4);
+ if (atmel_pri.Features & 0x80) /* Protection bits supported */
+ features |= (1<<6);
+
+ extp->FeatureSupport = features;
+
+ /* burst write mode not supported */
+ cfi->cfiq->BufWriteTimeoutTyp = 0;
+ cfi->cfiq->BufWriteTimeoutMax = 0;
+}
+
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
@@ -234,6 +276,7 @@ static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
}
static struct cfi_fixup cfi_fixup_table[] = {
+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
#endif
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 389acc6..571226e 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -185,6 +185,10 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
extp->TopBottom = 2;
else
extp->TopBottom = 3;
+
+ /* burst write mode not supported */
+ cfi->cfiq->BufWriteTimeoutTyp = 0;
+ cfi->cfiq->BufWriteTimeoutMax = 0;
}
static void fixup_use_secsi(struct mtd_info *mtd, void *param)
@@ -217,6 +221,7 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
}
static struct cfi_fixup cfi_fixup_table[] = {
+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
#ifdef AMD_BOOTLOC_BUG
{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
#endif
@@ -229,7 +234,6 @@ static struct cfi_fixup cfi_fixup_table[] = {
#if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
#endif
- { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
{ 0, 0, NULL, NULL }
};
static struct cfi_fixup jedec_fixup_table[] = {
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 519b4ff..847f983 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -276,6 +276,13 @@ config ELECTRA_CF
Say Y here to support the CompactFlash controller on the
PA Semi Electra eval board.
+config AT32_CF
+ tristate "AT32AP CompactFlash Controller"
+ depends on PCMCIA && AVR32 && PLATFORM_AT32AP
+ help
+ Say Y here to support the CompactFlash controller on AT32 chips.
+ Or choose M to compile the driver as a module named "at32_cf".
+
config PCCARD_NONSTATIC
tristate
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 6f6478b..3526fd8 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o
obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
+obj-$(CONFIG_AT32_CF) += at32_cf.o
sa11xx_core-y += soc_common.o sa11xx_base.o
pxa2xx_core-y += soc_common.o pxa2xx_base.o
diff --git a/drivers/pcmcia/at32_cf.c b/drivers/pcmcia/at32_cf.c
new file mode 100644
index 0000000..010bdfd
--- /dev/null
+++ b/drivers/pcmcia/at32_cf.c
@@ -0,0 +1,533 @@
+/*
+ * Driver for AVR32 Static Memory Controller: CompactFlash support
+ *
+ * Copyright (C) 2006 Atmel Norway
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/board.h>
+
+#include <asm/arch/smc.h>
+
+struct at32_cf_socket {
+ struct pcmcia_socket socket;
+ int detect_pin;
+ int reset_pin;
+ int vcc_pin;
+ int ready_pin;
+ struct resource res_attr;
+ struct resource res_mem;
+ struct resource res_io;
+ struct smc_config smc;
+ unsigned int irq;
+ unsigned int cf_cs;
+ socket_state_t state;
+ unsigned present:1;
+};
+#define to_at32_cf(sock) container_of(sock, struct at32_cf_socket, socket)
+
+/*
+ * We have the following memory layout relative to the base address:
+ *
+ * Alt IDE Mode: 00e0 0000 -> 00ff ffff
+ * True IDE Mode: 00c0 0000 -> 00df ffff
+ * I/O memory: 0080 0000 -> 00bf ffff
+ * Common memory: 0040 0000 -> 007f ffff
+ * Attribute memory: 0000 0000 -> 003f ffff
+ */
+#define CF_ATTR_OFFSET 0x00000000
+#define CF_MEM_OFFSET 0x00400000
+#define CF_IO_OFFSET 0x00800000
+#define CF_RES_SIZE 4096
+
+#ifdef DEBUG
+
+static int pc_debug;
+module_param(pc_debug, int, 0644);
+
+static void at32_cf_debug(struct at32_cf_socket *cf, const char *func,
+ int level, const char *fmt, ...)
+{
+ va_list args;
+
+ if (pc_debug > level) {
+ printk(KERN_DEBUG "at32_cf/%u: %s: ", cf->cf_cs, func);
+ va_start(args, fmt);
+ vprintk(fmt, args);
+ va_end(args);
+ }
+}
+
+#define debug(cf, lvl, fmt, arg...) \
+ at32_cf_debug(cf, __func__, lvl, fmt, ##arg)
+
+#else
+#define debug(cf, lvl, fmt, arg...) do { } while (0)
+#endif
+
+static inline int at32_cf_present(struct at32_cf_socket *cf)
+{
+ int present = 1;
+
+ /* If we don't have a detect pin, assume the card is present */
+ if (cf->detect_pin >= 0)
+ present = !gpio_get_value(cf->detect_pin);
+
+ return present;
+}
+
+static irqreturn_t at32_cf_irq(int irq, void *dev_id)
+{
+ struct at32_cf_socket *cf = dev_id;
+ unsigned int present;
+
+ present = at32_cf_present(cf);
+ if (present != cf->present) {
+ cf->present = present;
+ debug(cf, 3, "card %s\n", present ? "present" : "gone");
+ pcmcia_parse_events(&cf->socket, SS_DETECT);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int at32_cf_get_status(struct pcmcia_socket *sock, u_int *value)
+{
+ struct at32_cf_socket *cf;
+ u_int status = 0;
+
+ cf = container_of(sock, struct at32_cf_socket, socket);
+
+ if (at32_cf_present(cf)) {
+ /* NOTE: gpio on AP7xxx is 3.3V */
+ status = SS_DETECT | SS_3VCARD;
+ if (cf->ready_pin < 0 || gpio_get_value(cf->ready_pin))
+ status |= SS_READY;
+ if (cf->vcc_pin < 0 || gpio_get_value(cf->vcc_pin))
+ status |= SS_POWERON;
+ }
+
+ *value = status;
+ return 0;
+}
+
+static int at32_cf_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+ struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
+
+ debug(cf, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
+ (state->csc_mask==0)?"<NONE> ":"",
+ (state->csc_mask&SS_DETECT)?"DETECT ":"",
+ (state->csc_mask&SS_READY)?"READY ":"",
+ (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
+ (state->csc_mask&SS_BATWARN)?"BATWARN ":"",
+ (state->csc_mask&SS_STSCHG)?"STSCHG ":"",
+ (state->flags==0)?"<NONE> ":"",
+ (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
+ (state->flags&SS_IOCARD)?"IOCARD ":"",
+ (state->flags&SS_RESET)?"RESET ":"",
+ (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
+ (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+ state->Vcc, state->Vpp, state->io_irq);
+
+ /*
+ * TODO: Allow boards to override this in case they have level
+ * converters.
+ */
+ switch (state->Vcc) {
+ case 0:
+ if (cf->vcc_pin >= 0)
+ gpio_set_value(cf->vcc_pin, 0);
+ break;
+ case 33:
+ if (cf->vcc_pin >= 0)
+ gpio_set_value(cf->vcc_pin, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (cf->reset_pin >= 0)
+ gpio_set_value(cf->reset_pin, state->flags & SS_RESET);
+
+ cf->state = *state;
+
+ return 0;
+}
+
+static int at32_cf_socket_init(struct pcmcia_socket *sock)
+{
+ debug(to_at32_cf(sock), 2, "called\n");
+
+ return 0;
+}
+
+static int at32_cf_suspend(struct pcmcia_socket *sock)
+{
+ debug(to_at32_cf(sock), 2, "called\n");
+
+ at32_cf_set_socket(sock, &dead_socket);
+
+ return 0;
+}
+
+static int at32_cf_set_io_map(struct pcmcia_socket *sock,
+ struct pccard_io_map *map)
+{
+ struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
+ int retval;
+
+ debug(cf, 2, "map %u speed %u start 0x%08x stop 0x%08x\n",
+ map->map, map->speed, map->start, map->stop);
+ debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
+ (map->flags == 0) ? "<NONE>":"",
+ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
+ (map->flags & MAP_16BIT) ? "16BIT " : "",
+ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
+ (map->flags & MAP_0WS) ? "0WS " : "",
+ (map->flags & MAP_WRPROT) ? "WRPROT " : "",
+ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
+ (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
+
+ map->flags &= MAP_ACTIVE | MAP_16BIT | MAP_USE_WAIT;
+
+ if (map->flags & MAP_16BIT)
+ cf->smc.bus_width = 2;
+ else
+ cf->smc.bus_width = 1;
+
+ if (map->flags & MAP_USE_WAIT)
+ cf->smc.nwait_mode = 3;
+ else
+ cf->smc.nwait_mode = 0;
+
+ retval = smc_set_configuration(cf->cf_cs, &cf->smc);
+ if (retval) {
+ printk(KERN_ERR "at32_cf: could not set up SMC for I/O\n");
+ return retval;
+ }
+
+ map->start = cf->socket.io_offset;
+ map->stop = map->start + CF_RES_SIZE - 1;
+
+ return 0;
+}
+
+static int
+at32_cf_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
+{
+ struct at32_cf_socket *cf;
+ struct resource *res;
+ int retval;
+
+ cf = container_of(sock, struct at32_cf_socket, socket);
+
+ debug(cf, 2, "map %u speed %u card_start %08x\n",
+ map->map, map->speed, map->card_start);
+ debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
+ (map->flags==0)?"<NONE>":"",
+ (map->flags&MAP_ACTIVE)?"ACTIVE ":"",
+ (map->flags&MAP_16BIT)?"16BIT ":"",
+ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
+ (map->flags&MAP_0WS)?"0WS ":"",
+ (map->flags&MAP_WRPROT)?"WRPROT ":"",
+ (map->flags&MAP_ATTRIB)?"ATTRIB ":"",
+ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
+
+ if (map->card_start)
+ return -EINVAL;
+
+ map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT | MAP_USE_WAIT;
+
+ if (map->flags & MAP_ATTRIB) {
+ res = &cf->res_attr;
+
+ /* Linksys WCF12 seems to use WAIT when reading CIS */
+ map->flags |= MAP_USE_WAIT;
+ } else {
+ res = &cf->res_mem;
+ }
+
+ if (map->flags & MAP_USE_WAIT)
+ cf->smc.nwait_mode = 3;
+ else
+ cf->smc.nwait_mode = 0;
+
+ retval = smc_set_configuration(cf->cf_cs, &cf->smc);
+ if (retval) {
+ printk(KERN_ERR "at32_cf: could not set up SMC for mem\n");
+ return retval;
+ }
+
+ map->static_start = res->start;
+
+ return 0;
+}
+
+static struct pccard_operations at32_cf_ops = {
+ .init = at32_cf_socket_init,
+ .suspend = at32_cf_suspend,
+ .get_status = at32_cf_get_status,
+ .set_socket = at32_cf_set_socket,
+ .set_io_map = at32_cf_set_io_map,
+ .set_mem_map = at32_cf_set_mem_map,
+};
+
+static int __init request_pin(struct platform_device *pdev,
+ unsigned int pin, const char *name)
+{
+ if (gpio_request(pin, name)) {
+ dev_warn(&pdev->dev, "failed to request %s pin\n", name);
+ return -1;
+ }
+
+ return pin;
+}
+
+static struct smc_timing at32_cf_timing __initdata = {
+ .ncs_read_setup = 30,
+ .nrd_setup = 100,
+ .ncs_write_setup = 30,
+ .nwe_setup = 100,
+
+ .ncs_read_pulse = 360,
+ .nrd_pulse = 290,
+ .ncs_write_pulse = 360,
+ .nwe_pulse = 290,
+
+ .read_cycle = 420,
+ .write_cycle = 420,
+};
+
+static int __init at32_cf_probe(struct platform_device *pdev)
+{
+ struct at32_cf_socket *cf;
+ struct cf_platform_data *board = pdev->dev.platform_data;
+ struct resource *res_skt;
+ int irq;
+ int ret;
+
+ dev_dbg(&pdev->dev, "probe");
+
+ if (!board)
+ return -ENXIO;
+
+ res_skt = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_skt)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ cf = kzalloc(sizeof(struct at32_cf_socket), GFP_KERNEL);
+ if (!cf)
+ return -ENOMEM;
+
+ cf->detect_pin = -1;
+ cf->reset_pin = -1;
+ cf->vcc_pin = -1;
+ cf->ready_pin = -1;
+ cf->cf_cs = board->cs;
+
+ if (board->detect_pin != GPIO_PIN_NONE)
+ cf->detect_pin = request_pin(pdev, board->detect_pin,
+ "cf_detect");
+ if (board->reset_pin != GPIO_PIN_NONE)
+ cf->reset_pin = request_pin(pdev, board->reset_pin,
+ "cf_reset");
+ if (board->vcc_pin != GPIO_PIN_NONE)
+ cf->vcc_pin = request_pin(pdev, board->vcc_pin,
+ "cf_vcc");
+ if (board->ready_pin != GPIO_PIN_NONE)
+ /* READY is also used for irq through EIM */
+ cf->ready_pin = board->ready_pin;
+
+ debug(cf, 2, "pins: detect=%d reset=%d vcc=%d\n",
+ cf->detect_pin, cf->reset_pin, cf->vcc_pin);
+
+ cf->socket.pci_irq = irq;
+ cf->socket.ops = &at32_cf_ops;
+ cf->socket.resource_ops = &pccard_static_ops;
+ cf->socket.dev.parent = &pdev->dev;
+ cf->socket.owner = THIS_MODULE;
+ cf->socket.features =
+ SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ cf->socket.map_size = CF_RES_SIZE;
+
+ cf->res_attr.start = res_skt->start + CF_ATTR_OFFSET;
+ cf->res_attr.end = cf->res_attr.start + CF_RES_SIZE - 1;
+ cf->res_attr.name = "attribute";
+ cf->res_attr.flags = IORESOURCE_MEM;
+ ret = request_resource(res_skt, &cf->res_attr);
+ if (ret)
+ goto err_request_res_attr;
+
+ cf->res_mem.start = res_skt->start + CF_MEM_OFFSET;
+ cf->res_mem.end = cf->res_mem.start + CF_RES_SIZE - 1;
+ cf->res_mem.name = "memory";
+ cf->res_mem.flags = IORESOURCE_MEM;
+ ret = request_resource(res_skt, &cf->res_mem);
+ if (ret)
+ goto err_request_res_mem;
+
+ cf->res_io.start = res_skt->start + CF_IO_OFFSET;
+ cf->res_io.end = cf->res_io.start + CF_RES_SIZE - 1;
+ cf->res_io.name = "io";
+ cf->res_io.flags = IORESOURCE_MEM;
+ ret = request_resource(res_skt, &cf->res_io);
+ if (ret)
+ goto err_request_res_io;
+
+ cf->socket.io_offset = cf->res_io.start;
+
+ if (cf->detect_pin >= 0) {
+ ret = request_irq(gpio_to_irq(cf->detect_pin), at32_cf_irq,
+ IRQF_SHARED, "cf_detect", cf);
+ if (ret) {
+ debug(cf, 1,
+ "failed to request cf_detect interrupt\n");
+ goto err_detect_irq;
+ }
+ }
+
+ cf->present = at32_cf_present(cf);
+
+ /* Setup SMC timings */
+ smc_set_timing(&cf->smc, &at32_cf_timing);
+
+ cf->smc.bus_width = 2;
+ cf->smc.nrd_controlled = 1;
+ cf->smc.nwe_controlled = 1;
+ cf->smc.nwait_mode = 0;
+ cf->smc.byte_write = 0;
+ cf->smc.tdf_cycles = 8;
+ cf->smc.tdf_mode = 0;
+
+ ret = smc_set_configuration(cf->cf_cs, &cf->smc);
+ if (ret) {
+ debug(cf, 1, "failed to configure SMC\n", ret);
+ goto err_smc;
+ }
+
+ ret = pcmcia_register_socket(&cf->socket);
+ if (ret) {
+ debug(cf, 1, "failed to register socket: %d\n", ret);
+ goto err_register_socket;
+ }
+
+ if (cf->reset_pin >= 0)
+ gpio_direction_output(cf->reset_pin, 0);
+
+ platform_set_drvdata(pdev, cf);
+
+ dev_info(&pdev->dev, "Atmel SMC CF interface at 0x%08lx\n",
+ (unsigned long)res_skt->start);
+
+ return 0;
+
+err_register_socket:
+err_smc:
+ if (cf->detect_pin >= 0)
+ free_irq(gpio_to_irq(cf->detect_pin), cf);
+err_detect_irq:
+ release_resource(&cf->res_io);
+err_request_res_io:
+ release_resource(&cf->res_mem);
+err_request_res_mem:
+ release_resource(&cf->res_attr);
+err_request_res_attr:
+ if (cf->vcc_pin >= 0)
+ gpio_free(cf->vcc_pin);
+ if (cf->reset_pin >= 0)
+ gpio_free(cf->reset_pin);
+ if (cf->detect_pin >= 0)
+ gpio_free(cf->detect_pin);
+ kfree(cf);
+
+ return ret;
+}
+
+static int __exit at32_cf_remove(struct platform_device *pdev)
+{
+ struct at32_cf_socket *cf = platform_get_drvdata(pdev);
+
+ pcmcia_unregister_socket(&cf->socket);
+ if (cf->detect_pin >= 0) {
+ free_irq(gpio_to_irq(cf->detect_pin), cf);
+ gpio_free(cf->detect_pin);
+ }
+ if (cf->vcc_pin >= 0)
+ gpio_free(cf->vcc_pin);
+ if (cf->reset_pin >= 0)
+ gpio_free(cf->reset_pin);
+
+ release_resource(&cf->res_io);
+ release_resource(&cf->res_mem);
+ release_resource(&cf->res_attr);
+ kfree(cf);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver at32_cf_driver = {
+ .remove = __exit_p(at32_cf_remove),
+ .driver = {
+ .name = "at32_cf",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at32_cf_init(void)
+{
+ int ret;
+
+ ret = platform_driver_probe(&at32_cf_driver, at32_cf_probe);
+ if (ret)
+ printk(KERN_ERR "at32_cf: probe failed: %d\n", ret);
+ return ret;
+}
+
+static void __exit at32_cf_exit(void)
+{
+ platform_driver_unregister(&at32_cf_driver);
+}
+
+module_init(at32_cf_init);
+module_exit(at32_cf_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for SMC PCMCIA interface");
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index d7e1996..67bfbb0 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -380,6 +380,21 @@ config SERIAL_ATMEL_CONSOLE
console is the device which receives all kernel messages and
warnings and which allows logins in single user mode).
+config SERIAL_ATMEL_PDC
+ bool "Support DMA transfers on AT91 / AT32 serial port"
+ depends on SERIAL_ATMEL
+ default y
+ help
+ Say Y here if you wish to use the PDC to do DMA transfers to
+ and from the Atmel AT91 / AT32 serial port. In order to
+ actually use DMA transfers, make sure that the use_dma_tx
+ and use_dma_rx members in the atmel_uart_data struct is set
+ appropriately for each port.
+
+ Note that break and error handling currently doesn't work
+ properly when DMA is enabled. Make sure that ports where
+ this matters don't use DMA.
+
config SERIAL_ATMEL_TTYAT
bool "Install as device ttyATn instead of ttySn"
depends on SERIAL_ATMEL=y
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 111da57..477950f 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -7,6 +7,8 @@
* Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
+ * DMA support added by Chip Coldwell.
+ *
* 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
@@ -33,6 +35,7 @@
#include <linux/sysrq.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <linux/atmel_pdc.h>
#include <asm/io.h>
@@ -47,6 +50,10 @@
#include "atmel_serial.h"
+#define PDC_BUFFER_SIZE 512
+/* Revisit: We should calculate this based on the actual port settings */
+#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */
+
#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
@@ -74,6 +81,7 @@
#define ATMEL_ISR_PASS_LIMIT 256
+/* UART registers. CR is write-only, hence no GET macro */
#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR)
#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR)
#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR)
@@ -87,8 +95,6 @@
#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
-// #define UART_GET_CR(port) __raw_readl((port)->membase + ATMEL_US_CR) // is write-only
-
/* PDC registers */
#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR)
@@ -101,12 +107,24 @@
#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
-//#define UART_PUT_TNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR)
-//#define UART_PUT_TNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR)
static int (*atmel_open_hook)(struct uart_port *);
static void (*atmel_close_hook)(struct uart_port *);
+struct atmel_dma_buffer {
+ unsigned char *buf;
+ dma_addr_t dma_addr;
+ unsigned int dma_size;
+ unsigned int ofs;
+};
+
+struct atmel_uart_char {
+ u16 status;
+ u16 ch;
+};
+
+#define ATMEL_SERIAL_RINGSIZE 1024
+
/*
* We wrap our port structure around the generic uart_port.
*/
@@ -115,6 +133,19 @@ struct atmel_uart_port {
struct clk *clk; /* uart clock */
unsigned short suspended; /* is port suspended? */
int break_active; /* break being received */
+
+ short use_dma_rx; /* enable PDC receiver */
+ short pdc_rx_idx; /* current PDC RX buffer */
+ struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */
+
+ short use_dma_tx; /* enable PDC transmitter */
+ struct atmel_dma_buffer pdc_tx; /* PDC transmitter */
+
+ struct tasklet_struct tasklet;
+ unsigned int irq_status;
+ unsigned int irq_status_prev;
+
+ struct circ_buf rx_ring;
};
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -123,6 +154,38 @@ static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
static struct console atmel_console;
#endif
+static inline struct atmel_uart_port *
+to_atmel_uart_port(struct uart_port *uart)
+{
+ return container_of(uart, struct atmel_uart_port, uart);
+}
+
+#ifdef CONFIG_SERIAL_ATMEL_PDC
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->use_dma_rx;
+}
+
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->use_dma_tx;
+}
+#else
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+ return false;
+}
+
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+ return false;
+}
+#endif
+
/*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/
@@ -142,8 +205,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
#ifdef CONFIG_ARCH_AT91RM9200
if (cpu_is_at91rm9200()) {
/*
- * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
- * We need to drive the pin manually.
+ * AT91RM9200 Errata #39: RTS0 is not internally connected
+ * to PA21. We need to drive the pin manually.
*/
if (port->mapbase == AT91RM9200_BASE_US0) {
if (mctrl & TIOCM_RTS)
@@ -204,7 +267,12 @@ static u_int atmel_get_mctrl(struct uart_port *port)
*/
static void atmel_stop_tx(struct uart_port *port)
{
- UART_PUT_IDR(port, ATMEL_US_TXRDY);
+ if (atmel_use_dma_tx(port)) {
+ /* disable PDC transmit */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+ UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+ } else
+ UART_PUT_IDR(port, ATMEL_US_TXRDY);
}
/*
@@ -212,7 +280,17 @@ static void atmel_stop_tx(struct uart_port *port)
*/
static void atmel_start_tx(struct uart_port *port)
{
- UART_PUT_IER(port, ATMEL_US_TXRDY);
+ if (atmel_use_dma_tx(port)) {
+ if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
+ /* The transmitter is already running. Yes, we
+ really need this.*/
+ return;
+
+ UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+ /* re-enable PDC transmit */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+ } else
+ UART_PUT_IER(port, ATMEL_US_TXRDY);
}
/*
@@ -220,7 +298,12 @@ static void atmel_start_tx(struct uart_port *port)
*/
static void atmel_stop_rx(struct uart_port *port)
{
- UART_PUT_IDR(port, ATMEL_US_RXRDY);
+ if (atmel_use_dma_rx(port)) {
+ /* disable PDC receive */
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
+ UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+ } else
+ UART_PUT_IDR(port, ATMEL_US_RXRDY);
}
/*
@@ -228,7 +311,8 @@ static void atmel_stop_rx(struct uart_port *port)
*/
static void atmel_enable_ms(struct uart_port *port)
{
- UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+ UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
+ | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
}
/*
@@ -243,22 +327,63 @@ static void atmel_break_ctl(struct uart_port *port, int break_state)
}
/*
+ * Stores the incoming character in the ring buffer
+ */
+static void
+atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
+ unsigned int ch)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct circ_buf *ring = &atmel_port->rx_ring;
+ struct atmel_uart_char *c;
+
+ if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
+ /* Buffer overflow, ignore char */
+ return;
+
+ c = &((struct atmel_uart_char *)ring->buf)[ring->head];
+ c->status = status;
+ c->ch = ch;
+
+ /* Make sure the character is stored before we update head. */
+ smp_wmb();
+
+ ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+}
+
+/*
+ * Deal with parity, framing and overrun errors.
+ */
+static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
+{
+ /* clear error */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
+ if (status & ATMEL_US_RXBRK) {
+ /* ignore side-effect */
+ status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+ port->icount.brk++;
+ }
+ if (status & ATMEL_US_PARE)
+ port->icount.parity++;
+ if (status & ATMEL_US_FRAME)
+ port->icount.frame++;
+ if (status & ATMEL_US_OVRE)
+ port->icount.overrun++;
+}
+
+/*
* Characters received (called from interrupt handler)
*/
static void atmel_rx_chars(struct uart_port *port)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
- struct tty_struct *tty = port->info->tty;
- unsigned int status, ch, flg;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int status, ch;
status = UART_GET_CSR(port);
while (status & ATMEL_US_RXRDY) {
ch = UART_GET_CHAR(port);
- port->icount.rx++;
-
- flg = TTY_NORMAL;
-
/*
* note that the error handling code is
* out of the main execution path
@@ -266,15 +391,14 @@ static void atmel_rx_chars(struct uart_port *port)
if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
| ATMEL_US_OVRE | ATMEL_US_RXBRK)
|| atmel_port->break_active)) {
- UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */
+
+ /* clear error */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
if (status & ATMEL_US_RXBRK
&& !atmel_port->break_active) {
- status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */
- port->icount.brk++;
atmel_port->break_active = 1;
UART_PUT_IER(port, ATMEL_US_RXBRK);
- if (uart_handle_break(port))
- goto ignore_char;
} else {
/*
* This is either the end-of-break
@@ -287,52 +411,30 @@ static void atmel_rx_chars(struct uart_port *port)
status &= ~ATMEL_US_RXBRK;
atmel_port->break_active = 0;
}
- if (status & ATMEL_US_PARE)
- port->icount.parity++;
- if (status & ATMEL_US_FRAME)
- port->icount.frame++;
- if (status & ATMEL_US_OVRE)
- port->icount.overrun++;
-
- status &= port->read_status_mask;
-
- if (status & ATMEL_US_RXBRK)
- flg = TTY_BREAK;
- else if (status & ATMEL_US_PARE)
- flg = TTY_PARITY;
- else if (status & ATMEL_US_FRAME)
- flg = TTY_FRAME;
}
- if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
-
- uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg);
-
- ignore_char:
+ atmel_buffer_rx_char(port, status, ch);
status = UART_GET_CSR(port);
}
- tty_flip_buffer_push(tty);
+ tasklet_schedule(&atmel_port->tasklet);
}
/*
- * Transmit characters (called from interrupt handler)
+ * Transmit characters (called from tasklet with TXRDY interrupt
+ * disabled)
*/
static void atmel_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
- if (port->x_char) {
+ if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
- return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- atmel_stop_tx(port);
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
- }
while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
@@ -345,8 +447,88 @@ static void atmel_tx_chars(struct uart_port *port)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
- atmel_stop_tx(port);
+ if (!uart_circ_empty(xmit))
+ UART_PUT_IER(port, ATMEL_US_TXRDY);
+}
+
+/*
+ * receive interrupt handler.
+ */
+static void
+atmel_handle_receive(struct uart_port *port, unsigned int pending)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ if (atmel_use_dma_rx(port)) {
+ /*
+ * PDC receive. Just schedule the tasklet and let it
+ * figure out the details.
+ *
+ * TODO: We're not handling error flags correctly at
+ * the moment.
+ */
+ if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
+ UART_PUT_IDR(port, (ATMEL_US_ENDRX
+ | ATMEL_US_TIMEOUT));
+ tasklet_schedule(&atmel_port->tasklet);
+ }
+
+ if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
+ ATMEL_US_FRAME | ATMEL_US_PARE))
+ atmel_pdc_rxerr(port, pending);
+ }
+
+ /* Interrupt receive */
+ if (pending & ATMEL_US_RXRDY)
+ atmel_rx_chars(port);
+ else if (pending & ATMEL_US_RXBRK) {
+ /*
+ * End of break detected. If it came along with a
+ * character, atmel_rx_chars will handle it.
+ */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA);
+ UART_PUT_IDR(port, ATMEL_US_RXBRK);
+ atmel_port->break_active = 0;
+ }
+}
+
+/*
+ * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
+ */
+static void
+atmel_handle_transmit(struct uart_port *port, unsigned int pending)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ if (atmel_use_dma_tx(port)) {
+ /* PDC transmit */
+ if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) {
+ UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+ tasklet_schedule(&atmel_port->tasklet);
+ }
+ } else {
+ /* Interrupt transmit */
+ if (pending & ATMEL_US_TXRDY) {
+ UART_PUT_IDR(port, ATMEL_US_TXRDY);
+ tasklet_schedule(&atmel_port->tasklet);
+ }
+ }
+}
+
+/*
+ * status flags interrupt handler.
+ */
+static void
+atmel_handle_status(struct uart_port *port, unsigned int pending,
+ unsigned int status)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
+ | ATMEL_US_CTSIC)) {
+ atmel_port->irq_status = status;
+ tasklet_schedule(&atmel_port->tasklet);
+ }
}
/*
@@ -355,47 +537,255 @@ static void atmel_tx_chars(struct uart_port *port)
static irqreturn_t atmel_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
unsigned int status, pending, pass_counter = 0;
- status = UART_GET_CSR(port);
- pending = status & UART_GET_IMR(port);
- while (pending) {
- /* Interrupt receive */
- if (pending & ATMEL_US_RXRDY)
- atmel_rx_chars(port);
- else if (pending & ATMEL_US_RXBRK) {
+ do {
+ status = UART_GET_CSR(port);
+ pending = status & UART_GET_IMR(port);
+ if (!pending)
+ break;
+
+ atmel_handle_receive(port, pending);
+ atmel_handle_status(port, pending, status);
+ atmel_handle_transmit(port, pending);
+ } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
+ */
+static void atmel_tx_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct circ_buf *xmit = &port->info->xmit;
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+ int count;
+
+ xmit->tail += pdc->ofs;
+ xmit->tail &= UART_XMIT_SIZE - 1;
+
+ port->icount.tx += pdc->ofs;
+ pdc->ofs = 0;
+
+ if (!uart_circ_empty(xmit)) {
+ /* more to transmit - setup next transfer */
+
+ /* disable PDC transmit */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+ dma_sync_single_for_device(port->dev,
+ pdc->dma_addr,
+ pdc->dma_size,
+ DMA_TO_DEVICE);
+
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ pdc->ofs = count;
+
+ UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
+ UART_PUT_TCR(port, count);
+ /* re-enable PDC transmit and interrupts */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+ UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+ } else {
+ /* nothing left to transmit - disable the transmitter */
+
+ /* disable PDC transmit */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static void atmel_rx_from_ring(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct circ_buf *ring = &atmel_port->rx_ring;
+ unsigned int flg;
+ unsigned int status;
+
+ while (ring->head != ring->tail) {
+ struct atmel_uart_char c;
+
+ /* Make sure c is loaded after head. */
+ smp_rmb();
+
+ c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
+
+ ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+
+ port->icount.rx++;
+ status = c.status;
+ flg = TTY_NORMAL;
+
+ /*
+ * note that the error handling code is
+ * out of the main execution path
+ */
+ if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+ | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+ if (status & ATMEL_US_RXBRK) {
+ /* ignore side-effect */
+ status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ }
+ if (status & ATMEL_US_PARE)
+ port->icount.parity++;
+ if (status & ATMEL_US_FRAME)
+ port->icount.frame++;
+ if (status & ATMEL_US_OVRE)
+ port->icount.overrun++;
+
+ status &= port->read_status_mask;
+
+ if (status & ATMEL_US_RXBRK)
+ flg = TTY_BREAK;
+ else if (status & ATMEL_US_PARE)
+ flg = TTY_PARITY;
+ else if (status & ATMEL_US_FRAME)
+ flg = TTY_FRAME;
+ }
+
+
+ if (uart_handle_sysrq_char(port, c.ch))
+ continue;
+
+ uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
+ }
+
+ /*
+ * Drop the lock here since it might end up calling
+ * uart_start(), which takes the lock.
+ */
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(port->info->tty);
+ spin_lock(&port->lock);
+}
+
+static void atmel_rx_from_dma(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct tty_struct *tty = port->info->tty;
+ struct atmel_dma_buffer *pdc;
+ int rx_idx = atmel_port->pdc_rx_idx;
+ unsigned int head;
+ unsigned int tail;
+ unsigned int count;
+
+ do {
+ /* Reset the UART timeout early so that we don't miss one */
+ UART_PUT_CR(port, ATMEL_US_STTTO);
+
+ pdc = &atmel_port->pdc_rx[rx_idx];
+ head = UART_GET_RPR(port) - pdc->dma_addr;
+ tail = pdc->ofs;
+
+ /* If the PDC has switched buffers, RPR won't contain
+ * any address within the current buffer. Since head
+ * is unsigned, we just need a one-way comparison to
+ * find out.
+ *
+ * In this case, we just need to consume the entire
+ * buffer and resubmit it for DMA. This will clear the
+ * ENDRX bit as well, so that we can safely re-enable
+ * all interrupts below.
+ */
+ head = min(head, pdc->dma_size);
+
+ if (likely(head != tail)) {
+ dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
+ pdc->dma_size, DMA_FROM_DEVICE);
+
/*
- * End of break detected. If it came along
- * with a character, atmel_rx_chars will
- * handle it.
+ * head will only wrap around when we recycle
+ * the DMA buffer, and when that happens, we
+ * explicitly set tail to 0. So head will
+ * always be greater than tail.
*/
- UART_PUT_CR(port, ATMEL_US_RSTSTA);
- UART_PUT_IDR(port, ATMEL_US_RXBRK);
- atmel_port->break_active = 0;
+ count = head - tail;
+
+ tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
+
+ dma_sync_single_for_device(port->dev, pdc->dma_addr,
+ pdc->dma_size, DMA_FROM_DEVICE);
+
+ port->icount.rx += count;
+ pdc->ofs = head;
}
- // TODO: All reads to CSR will clear these interrupts!
- if (pending & ATMEL_US_RIIC) port->icount.rng++;
- if (pending & ATMEL_US_DSRIC) port->icount.dsr++;
- if (pending & ATMEL_US_DCDIC)
+ /*
+ * If the current buffer is full, we need to check if
+ * the next one contains any additional data.
+ */
+ if (head >= pdc->dma_size) {
+ pdc->ofs = 0;
+ UART_PUT_RNPR(port, pdc->dma_addr);
+ UART_PUT_RNCR(port, pdc->dma_size);
+
+ rx_idx = !rx_idx;
+ atmel_port->pdc_rx_idx = rx_idx;
+ }
+ } while (head >= pdc->dma_size);
+
+ /*
+ * Drop the lock here since it might end up calling
+ * uart_start(), which takes the lock.
+ */
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tty);
+ spin_lock(&port->lock);
+
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+}
+
+/*
+ * tasklet handling tty stuff outside the interrupt handler.
+ */
+static void atmel_tasklet_func(unsigned long data)
+{
+ struct uart_port *port = (struct uart_port *)data;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int status;
+ unsigned int status_change;
+
+ /* The interrupt handler does not take the lock */
+ spin_lock(&port->lock);
+
+ if (atmel_use_dma_tx(port))
+ atmel_tx_dma(port);
+ else
+ atmel_tx_chars(port);
+
+ status = atmel_port->irq_status;
+ status_change = status ^ atmel_port->irq_status_prev;
+
+ if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
+ | ATMEL_US_DCD | ATMEL_US_CTS)) {
+ /* TODO: All reads to CSR will clear these interrupts! */
+ if (status_change & ATMEL_US_RI)
+ port->icount.rng++;
+ if (status_change & ATMEL_US_DSR)
+ port->icount.dsr++;
+ if (status_change & ATMEL_US_DCD)
uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
- if (pending & ATMEL_US_CTSIC)
+ if (status_change & ATMEL_US_CTS)
uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
- if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC))
- wake_up_interruptible(&port->info->delta_msr_wait);
- /* Interrupt transmit */
- if (pending & ATMEL_US_TXRDY)
- atmel_tx_chars(port);
+ wake_up_interruptible(&port->info->delta_msr_wait);
- if (pass_counter++ > ATMEL_ISR_PASS_LIMIT)
- break;
-
- status = UART_GET_CSR(port);
- pending = status & UART_GET_IMR(port);
+ atmel_port->irq_status_prev = status;
}
- return IRQ_HANDLED;
+
+ if (atmel_use_dma_rx(port))
+ atmel_rx_from_dma(port);
+ else
+ atmel_rx_from_ring(port);
+
+ spin_unlock(&port->lock);
}
/*
@@ -403,6 +793,8 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
*/
static int atmel_startup(struct uart_port *port)
{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct tty_struct *tty = port->info->tty;
int retval;
/*
@@ -415,13 +807,64 @@ static int atmel_startup(struct uart_port *port)
/*
* Allocate the IRQ
*/
- retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port);
+ retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+ tty ? tty->name : "atmel_serial", port);
if (retval) {
printk("atmel_serial: atmel_startup - Can't get irq\n");
return retval;
}
/*
+ * Initialize DMA (if necessary)
+ */
+ if (atmel_use_dma_rx(port)) {
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+ pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+ if (pdc->buf == NULL) {
+ if (i != 0) {
+ dma_unmap_single(port->dev,
+ atmel_port->pdc_rx[0].dma_addr,
+ PDC_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ kfree(atmel_port->pdc_rx[0].buf);
+ }
+ free_irq(port->irq, port);
+ return -ENOMEM;
+ }
+ pdc->dma_addr = dma_map_single(port->dev,
+ pdc->buf,
+ PDC_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ pdc->dma_size = PDC_BUFFER_SIZE;
+ pdc->ofs = 0;
+ }
+
+ atmel_port->pdc_rx_idx = 0;
+
+ UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+ UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+ UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+ UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+ }
+ if (atmel_use_dma_tx(port)) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+ struct circ_buf *xmit = &port->info->xmit;
+
+ pdc->buf = xmit->buf;
+ pdc->dma_addr = dma_map_single(port->dev,
+ pdc->buf,
+ UART_XMIT_SIZE,
+ DMA_TO_DEVICE);
+ pdc->dma_size = UART_XMIT_SIZE;
+ pdc->ofs = 0;
+ }
+
+ /*
* If there is a specific "open" function (to register
* control line interrupts)
*/
@@ -437,9 +880,21 @@ static int atmel_startup(struct uart_port *port)
* Finally, enable the serial port
*/
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
- UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */
+ /* enable xmit & rcvr */
+ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
- UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */
+ if (atmel_use_dma_rx(port)) {
+ /* set UART timeout */
+ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+ UART_PUT_CR(port, ATMEL_US_STTTO);
+
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+ /* enable PDC controller */
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+ } else {
+ /* enable receive only */
+ UART_PUT_IER(port, ATMEL_US_RXRDY);
+ }
return 0;
}
@@ -449,6 +904,38 @@ static int atmel_startup(struct uart_port *port)
*/
static void atmel_shutdown(struct uart_port *port)
{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ /*
+ * Ensure everything is stopped.
+ */
+ atmel_stop_rx(port);
+ atmel_stop_tx(port);
+
+ /*
+ * Shut-down the DMA.
+ */
+ if (atmel_use_dma_rx(port)) {
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+ dma_unmap_single(port->dev,
+ pdc->dma_addr,
+ pdc->dma_size,
+ DMA_FROM_DEVICE);
+ kfree(pdc->buf);
+ }
+ }
+ if (atmel_use_dma_tx(port)) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+ dma_unmap_single(port->dev,
+ pdc->dma_addr,
+ pdc->dma_size,
+ DMA_TO_DEVICE);
+ }
+
/*
* Disable all interrupts, port and break condition.
*/
@@ -471,45 +958,48 @@ static void atmel_shutdown(struct uart_port *port)
/*
* Power / Clock management.
*/
-static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+static void atmel_serial_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
switch (state) {
- case 0:
- /*
- * Enable the peripheral clock for this serial port.
- * This is called on uart_open() or a resume event.
- */
- clk_enable(atmel_port->clk);
- break;
- case 3:
- /*
- * Disable the peripheral clock for this serial port.
- * This is called on uart_close() or a suspend event.
- */
- clk_disable(atmel_port->clk);
- break;
- default:
- printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+ case 0:
+ /*
+ * Enable the peripheral clock for this serial port.
+ * This is called on uart_open() or a resume event.
+ */
+ clk_enable(atmel_port->clk);
+ break;
+ case 3:
+ /*
+ * Disable the peripheral clock for this serial port.
+ * This is called on uart_close() or a suspend event.
+ */
+ clk_disable(atmel_port->clk);
+ break;
+ default:
+ printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
}
}
/*
* Change the port parameters
*/
-static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old)
+static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned long flags;
unsigned int mode, imr, quot, baud;
/* Get current mode register */
- mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+ mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
+ | ATMEL_US_NBSTOP | ATMEL_US_PAR);
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
quot = uart_get_divisor(port, baud);
- if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */
+ if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */
quot /= 8;
mode |= ATMEL_US_USCLKS_MCK_DIV8;
}
@@ -536,18 +1026,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios,
/* parity */
if (termios->c_cflag & PARENB) {
- if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
+ /* Mark or Space parity */
+ if (termios->c_cflag & CMSPAR) {
if (termios->c_cflag & PARODD)
mode |= ATMEL_US_PAR_MARK;
else
mode |= ATMEL_US_PAR_SPACE;
- }
- else if (termios->c_cflag & PARODD)
+ } else if (termios->c_cflag & PARODD)
mode |= ATMEL_US_PAR_ODD;
else
mode |= ATMEL_US_PAR_EVEN;
- }
- else
+ } else
mode |= ATMEL_US_PAR_NONE;
spin_lock_irqsave(&port->lock, flags);
@@ -558,6 +1047,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios,
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= ATMEL_US_RXBRK;
+ if (atmel_use_dma_rx(port))
+ /* need to enable error interrupts */
+ UART_PUT_IER(port, port->read_status_mask);
+
/*
* Characters to ignore
*/
@@ -573,16 +1066,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios,
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ATMEL_US_OVRE;
}
-
- // TODO: Ignore all characters if CREAD is set.
+ /* TODO: Ignore all characters if CREAD is set.*/
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
- /* disable interrupts and drain transmitter */
- imr = UART_GET_IMR(port); /* get interrupt mask */
- UART_PUT_IDR(port, -1); /* disable all interrupts */
- while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); }
+ /* save/disable interrupts and drain transmitter */
+ imr = UART_GET_IMR(port);
+ UART_PUT_IDR(port, -1);
+ while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+ cpu_relax();
/* disable receiver and transmitter */
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
@@ -708,7 +1201,8 @@ static struct uart_ops atmel_pops = {
/*
* Configure the port from the platform device resource info.
*/
-static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev)
+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+ struct platform_device *pdev)
{
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *data = pdev->dev.platform_data;
@@ -723,6 +1217,11 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct
port->mapbase = pdev->resource[0].start;
port->irq = pdev->resource[1].start;
+ tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
+ (unsigned long)port);
+
+ memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
+
if (data->regs)
/* Already mapped by setup code */
port->membase = data->regs;
@@ -731,11 +1230,17 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct
port->membase = NULL;
}
- if (!atmel_port->clk) { /* for console, the clock could already be configured */
+ /* for console, the clock could already be configured */
+ if (!atmel_port->clk) {
atmel_port->clk = clk_get(&pdev->dev, "usart");
clk_enable(atmel_port->clk);
port->uartclk = clk_get_rate(atmel_port->clk);
}
+
+ atmel_port->use_dma_rx = data->use_dma_rx;
+ atmel_port->use_dma_tx = data->use_dma_tx;
+ if (atmel_use_dma_tx(port))
+ port->fifosize = PDC_BUFFER_SIZE;
}
/*
@@ -755,12 +1260,11 @@ void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
atmel_pops.set_wake = fns->set_wake;
}
-
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
static void atmel_console_putchar(struct uart_port *port, int ch)
{
while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
- barrier();
+ cpu_relax();
UART_PUT_CHAR(port, ch);
}
@@ -773,38 +1277,40 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
unsigned int status, imr;
/*
- * First, save IMR and then disable interrupts
+ * First, save IMR and then disable interrupts
*/
- imr = UART_GET_IMR(port); /* get interrupt mask */
+ imr = UART_GET_IMR(port);
UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
uart_console_write(port, s, count, atmel_console_putchar);
/*
- * Finally, wait for transmitter to become empty
- * and restore IMR
+ * Finally, wait for transmitter to become empty
+ * and restore IMR
*/
do {
status = UART_GET_CSR(port);
} while (!(status & ATMEL_US_TXRDY));
- UART_PUT_IER(port, imr); /* set interrupts back the way they were */
+ /* set interrupts back the way they were */
+ UART_PUT_IER(port, imr);
}
/*
- * If the port was already initialised (eg, by a boot loader), try to determine
- * the current setup.
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
*/
-static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+static void __init atmel_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
{
unsigned int mr, quot;
-// TODO: CR is a write-only register
-// unsigned int cr;
-//
-// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN);
-// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) {
-// /* ok, the port was enabled */
-// }
+ /*
+ * If the baud rate generator isn't running, the port wasn't
+ * initialized by the boot loader.
+ */
+ quot = UART_GET_BRGR(port);
+ if (!quot)
+ return;
mr = UART_GET_MR(port) & ATMEL_US_CHRL;
if (mr == ATMEL_US_CHRL_8)
@@ -824,7 +1330,6 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud,
* lower than one of those, as it would make us fall through
* to a much lower baud rate than we really want.
*/
- quot = UART_GET_BRGR(port);
*baud = port->uartclk / (16 * (quot - 1));
}
@@ -836,10 +1341,12 @@ static int __init atmel_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
- if (port->membase == 0) /* Port not initialized yet - delay setup */
+ if (port->membase == NULL) {
+ /* Port not initialized yet - delay setup */
return -ENODEV;
+ }
- UART_PUT_IDR(port, -1); /* disable interrupts */
+ UART_PUT_IDR(port, -1);
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
@@ -871,13 +1378,16 @@ static struct console atmel_console = {
static int __init atmel_console_init(void)
{
if (atmel_default_console_device) {
- add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL);
- atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device);
+ add_preferred_console(ATMEL_DEVICENAME,
+ atmel_default_console_device->id, NULL);
+ atmel_init_port(&atmel_ports[atmel_default_console_device->id],
+ atmel_default_console_device);
register_console(&atmel_console);
}
return 0;
}
+
console_initcall(atmel_console_init);
/*
@@ -885,34 +1395,48 @@ console_initcall(atmel_console_init);
*/
static int __init atmel_late_console_init(void)
{
- if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED))
+ if (atmel_default_console_device
+ && !(atmel_console.flags & CON_ENABLED))
register_console(&atmel_console);
return 0;
}
+
core_initcall(atmel_late_console_init);
+static inline bool atmel_is_console_port(struct uart_port *port)
+{
+ return port->cons && port->cons->index == port->line;
+}
+
#else
#define ATMEL_CONSOLE_DEVICE NULL
+
+static inline bool atmel_is_console_port(struct uart_port *port)
+{
+ return false;
+}
#endif
static struct uart_driver atmel_uart = {
- .owner = THIS_MODULE,
- .driver_name = "atmel_serial",
- .dev_name = ATMEL_DEVICENAME,
- .major = SERIAL_ATMEL_MAJOR,
- .minor = MINOR_START,
- .nr = ATMEL_MAX_UART,
- .cons = ATMEL_CONSOLE_DEVICE,
+ .owner = THIS_MODULE,
+ .driver_name = "atmel_serial",
+ .dev_name = ATMEL_DEVICENAME,
+ .major = SERIAL_ATMEL_MAJOR,
+ .minor = MINOR_START,
+ .nr = ATMEL_MAX_UART,
+ .cons = ATMEL_CONSOLE_DEVICE,
};
#ifdef CONFIG_PM
-static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state)
+static int atmel_serial_suspend(struct platform_device *pdev,
+ pm_message_t state)
{
struct uart_port *port = platform_get_drvdata(pdev);
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
+ if (device_may_wakeup(&pdev->dev)
+ && !at91_suspend_entering_slow_clock())
enable_irq_wake(port->irq);
else {
uart_suspend_port(&atmel_uart, port);
@@ -925,13 +1449,12 @@ static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state
static int atmel_serial_resume(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
if (atmel_port->suspended) {
uart_resume_port(&atmel_uart, port);
atmel_port->suspended = 0;
- }
- else
+ } else
disable_irq_wake(port->irq);
return 0;
@@ -944,15 +1467,40 @@ static int atmel_serial_resume(struct platform_device *pdev)
static int __devinit atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
+ void *data;
int ret;
+ BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE));
+
port = &atmel_ports[pdev->id];
atmel_init_port(port, pdev);
+ if (!atmel_use_dma_rx(&port->uart)) {
+ ret = -ENOMEM;
+ data = kmalloc(sizeof(struct atmel_uart_char)
+ * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
+ if (!data)
+ goto err_alloc_ring;
+ port->rx_ring.buf = data;
+ }
+
ret = uart_add_one_port(&atmel_uart, &port->uart);
- if (!ret) {
- device_init_wakeup(&pdev->dev, 1);
- platform_set_drvdata(pdev, port);
+ if (ret)
+ goto err_add_port;
+
+ device_init_wakeup(&pdev->dev, 1);
+ platform_set_drvdata(pdev, port);
+
+ return 0;
+
+err_add_port:
+ kfree(port->rx_ring.buf);
+ port->rx_ring.buf = NULL;
+err_alloc_ring:
+ if (!atmel_is_console_port(&port->uart)) {
+ clk_disable(port->clk);
+ clk_put(port->clk);
+ port->clk = NULL;
}
return ret;
@@ -961,19 +1509,21 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
static int __devexit atmel_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int ret = 0;
- clk_disable(atmel_port->clk);
- clk_put(atmel_port->clk);
-
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
- if (port) {
- ret = uart_remove_one_port(&atmel_uart, port);
- kfree(port);
- }
+ ret = uart_remove_one_port(&atmel_uart, port);
+
+ tasklet_kill(&atmel_port->tasklet);
+ kfree(atmel_port->rx_ring.buf);
+
+ /* "port" is allocated statically, so we shouldn't free it */
+
+ clk_disable(atmel_port->clk);
+ clk_put(atmel_port->clk);
return ret;
}
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index ff10808..293b7ca 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -51,7 +51,9 @@ struct atmel_spi {
u8 stopping;
struct list_head queue;
struct spi_transfer *current_transfer;
- unsigned long remaining_bytes;
+ unsigned long current_remaining_bytes;
+ struct spi_transfer *next_transfer;
+ unsigned long next_remaining_bytes;
void *buffer;
dma_addr_t buffer_dma;
@@ -121,6 +123,48 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
gpio_set_value(gpio, !active);
}
+static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+ struct spi_transfer *xfer)
+{
+ return msg->transfers.prev == &xfer->transfer_list;
+}
+
+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+{
+ return xfer->delay_usecs == 0 && !xfer->cs_change;
+}
+
+static void atmel_spi_next_xfer_data(struct spi_master *master,
+ struct spi_transfer *xfer,
+ dma_addr_t *tx_dma,
+ dma_addr_t *rx_dma,
+ u32 *plen)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ u32 len = *plen;
+
+ /* use scratch buffer only when rx or tx data is unspecified */
+ if (xfer->rx_buf)
+ *rx_dma = xfer->rx_dma + xfer->len - len;
+ else {
+ *rx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ }
+ if (xfer->tx_buf)
+ *tx_dma = xfer->tx_dma + xfer->len - len;
+ else {
+ *tx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ memset(as->buffer, 0, len);
+ dma_sync_single_for_device(&as->pdev->dev,
+ as->buffer_dma, len, DMA_TO_DEVICE);
+ }
+
+ *plen = len;
+}
+
/*
* Submit next transfer for DMA.
* lock is held, spi irq is blocked
@@ -130,53 +174,78 @@ static void atmel_spi_next_xfer(struct spi_master *master,
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_transfer *xfer;
- u32 len;
+ u32 len, remaining, total;
dma_addr_t tx_dma, rx_dma;
- xfer = as->current_transfer;
- if (!xfer || as->remaining_bytes == 0) {
- if (xfer)
- xfer = list_entry(xfer->transfer_list.next,
- struct spi_transfer, transfer_list);
- else
- xfer = list_entry(msg->transfers.next,
- struct spi_transfer, transfer_list);
- as->remaining_bytes = xfer->len;
- as->current_transfer = xfer;
- }
+ if (!as->current_transfer)
+ xfer = list_entry(msg->transfers.next,
+ struct spi_transfer, transfer_list);
+ else if (!as->next_transfer)
+ xfer = list_entry(as->current_transfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ else
+ xfer = NULL;
- len = as->remaining_bytes;
+ if (xfer) {
+ len = xfer->len;
+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ remaining = xfer->len - len;
- tx_dma = xfer->tx_dma + xfer->len - len;
- rx_dma = xfer->rx_dma + xfer->len - len;
+ spi_writel(as, RPR, rx_dma);
+ spi_writel(as, TPR, tx_dma);
- /* use scratch buffer only when rx or tx data is unspecified */
- if (!xfer->rx_buf) {
- rx_dma = as->buffer_dma;
- if (len > BUFFER_SIZE)
- len = BUFFER_SIZE;
- }
- if (!xfer->tx_buf) {
- tx_dma = as->buffer_dma;
- if (len > BUFFER_SIZE)
- len = BUFFER_SIZE;
- memset(as->buffer, 0, len);
- dma_sync_single_for_device(&as->pdev->dev,
- as->buffer_dma, len, DMA_TO_DEVICE);
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+ spi_writel(as, RCR, len);
+ spi_writel(as, TCR, len);
+
+ dev_dbg(&msg->spi->dev,
+ " start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ } else {
+ xfer = as->next_transfer;
+ remaining = as->next_remaining_bytes;
}
- spi_writel(as, RPR, rx_dma);
- spi_writel(as, TPR, tx_dma);
+ as->current_transfer = xfer;
+ as->current_remaining_bytes = remaining;
- as->remaining_bytes -= len;
- if (msg->spi->bits_per_word > 8)
- len >>= 1;
+ if (remaining > 0)
+ len = remaining;
+ else if (!atmel_spi_xfer_is_last(msg, xfer)
+ && atmel_spi_xfer_can_be_chained(xfer)) {
+ xfer = list_entry(xfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ len = xfer->len;
+ } else
+ xfer = NULL;
- /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
- * mechanism might help avoid the IRQ latency between transfers
- * (and improve the nCS0 errata handling on at91rm9200 chips)
- *
- * We're also waiting for ENDRX before we start the next
+ as->next_transfer = xfer;
+
+ if (xfer) {
+ total = len;
+ atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ as->next_remaining_bytes = total - len;
+
+ spi_writel(as, RNPR, rx_dma);
+ spi_writel(as, TNPR, tx_dma);
+
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+ spi_writel(as, RNCR, len);
+ spi_writel(as, TNCR, len);
+
+ dev_dbg(&msg->spi->dev,
+ " next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ } else {
+ spi_writel(as, RNCR, 0);
+ spi_writel(as, TNCR, 0);
+ }
+
+ /* REVISIT: We're waiting for ENDRX before we start the next
* transfer because we need to handle some difficult timing
* issues otherwise. If we wait for ENDTX in one transfer and
* then starts waiting for ENDRX in the next, it's difficult
@@ -186,17 +255,7 @@ static void atmel_spi_next_xfer(struct spi_master *master,
*
* It should be doable, though. Just not now...
*/
- spi_writel(as, TNCR, 0);
- spi_writel(as, RNCR, 0);
spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
-
- dev_dbg(&msg->spi->dev,
- " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
- xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
-
- spi_writel(as, RCR, len);
- spi_writel(as, TCR, len);
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
@@ -294,6 +353,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
spin_lock(&as->lock);
as->current_transfer = NULL;
+ as->next_transfer = NULL;
/* continue if needed */
if (list_empty(&as->queue) || as->stopping)
@@ -377,7 +437,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
spi_writel(as, IDR, pending);
- if (as->remaining_bytes == 0) {
+ if (as->current_remaining_bytes == 0) {
msg->actual_length += xfer->len;
if (!msg->is_dma_mapped)
@@ -387,7 +447,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
- if (msg->transfers.prev == &xfer->transfer_list) {
+ if (atmel_spi_xfer_is_last(msg, xfer)) {
/* report completed message */
atmel_spi_msg_done(master, as, msg, 0,
xfer->cs_change);
@@ -490,9 +550,14 @@ static int atmel_spi_setup(struct spi_device *spi)
if (!(spi->mode & SPI_CPHA))
csr |= SPI_BIT(NCPHA);
- /* TODO: DLYBS and DLYBCT */
- csr |= SPI_BF(DLYBS, 10);
- csr |= SPI_BF(DLYBCT, 10);
+ /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
+ *
+ * DLYBCT would add delays between words, slowing down transfers.
+ * It could potentially be useful to cope with DMA bottlenecks, but
+ * in those cases it's probably best to just use a lower bitrate.
+ */
+ csr |= SPI_BF(DLYBS, 0);
+ csr |= SPI_BF(DLYBCT, 0);
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned int)spi->controller_data;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 7c30cc8..5e99671 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -16,6 +16,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/backlight.h>
#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
@@ -37,7 +38,9 @@
#endif
#if defined(CONFIG_ARCH_AT91)
-#define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT
+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+ | FBINFO_PARTIAL_PAN_OK \
+ | FBINFO_HWACCEL_YPAN)
static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
struct fb_var_screeninfo *var)
@@ -69,12 +72,113 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
}
#endif
+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+/* some bl->props field just changed */
+static int atmel_bl_update_status(struct backlight_device *bl)
+{
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+ int power = sinfo->bl_power;
+ int brightness = bl->props.brightness;
+
+ /* REVISIT there may be a meaningful difference between
+ * fb_blank and power ... there seem to be some cases
+ * this doesn't handle correctly.
+ */
+ if (bl->props.fb_blank != sinfo->bl_power)
+ power = bl->props.fb_blank;
+ else if (bl->props.power != sinfo->bl_power)
+ power = bl->props.power;
+
+ if (brightness < 0 && power == FB_BLANK_UNBLANK)
+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ else if (power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+ brightness ? contrast_ctr : 0);
+
+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+ return 0;
+}
+
+static int atmel_bl_get_brightness(struct backlight_device *bl)
+{
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+}
+
+static struct backlight_ops atmel_lcdc_bl_ops = {
+ .update_status = atmel_bl_update_status,
+ .get_brightness = atmel_bl_get_brightness,
+};
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ struct backlight_device *bl;
+
+ sinfo->bl_power = FB_BLANK_UNBLANK;
+
+ if (sinfo->backlight)
+ return;
+
+ bl = backlight_device_register("backlight", &sinfo->pdev->dev,
+ sinfo, &atmel_lcdc_bl_ops);
+ if (IS_ERR(sinfo->backlight)) {
+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+ return;
+ }
+ sinfo->backlight = bl;
+
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.max_brightness = 0xff;
+ bl->props.brightness = atmel_bl_get_brightness(bl);
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->backlight)
+ backlight_device_unregister(sinfo->backlight);
+}
+
+#else
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+}
+
+#endif
+
+static void init_contrast(struct atmel_lcdfb_info *sinfo)
+{
+ /* have some default contrast/backlight settings */
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+
+ if (sinfo->lcdcon_is_backlight)
+ init_backlight(sinfo);
+}
+
static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
- .ypanstep = 0,
+ .ypanstep = 1,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
@@ -148,6 +252,8 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
return -ENOMEM;
}
+ memset(info->screen_base, 0, info->fix.smem_len);
+
return 0;
}
@@ -203,6 +309,26 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->transp.offset = var->transp.length = 0;
var->xoffset = var->yoffset = 0;
+ /* Saturate vertical and horizontal timings at maximum values */
+ var->vsync_len = min_t(u32, var->vsync_len,
+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+ var->upper_margin = min_t(u32, var->upper_margin,
+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+ var->lower_margin = min_t(u32, var->lower_margin,
+ ATMEL_LCDC_VFP);
+ var->right_margin = min_t(u32, var->right_margin,
+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+ var->hsync_len = min_t(u32, var->hsync_len,
+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+ var->left_margin = min_t(u32, var->left_margin,
+ ATMEL_LCDC_HBP + 1);
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+ var->right_margin = max_t(u32, var->right_margin, 1);
+ var->hsync_len = max_t(u32, var->hsync_len, 1);
+ var->left_margin = max_t(u32, var->left_margin, 1);
+
switch (var->bits_per_pixel) {
case 1:
case 2:
@@ -370,10 +496,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Disable all interrupts */
lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
- /* Set contrast */
- value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
/* ...wait for DMA engine to become idle... */
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
msleep(10);
@@ -516,7 +638,6 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
struct fb_info *info = sinfo->info;
int ret = 0;
- memset_io(info->screen_base, 0, info->fix.smem_len);
info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
dev_info(info->device,
@@ -577,6 +698,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
sinfo->default_monspecs = pdata_sinfo->default_monspecs;
sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
sinfo->guard_time = pdata_sinfo->guard_time;
+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
} else {
dev_err(dev, "cannot get default configuration\n");
goto free_info;
@@ -645,6 +767,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
if (!info->screen_base)
goto release_intmem;
+
+ /*
+ * Don't clear the framebuffer -- someone may have set
+ * up a splash image.
+ */
} else {
/* alocate memory buffer */
ret = atmel_lcdfb_alloc_video_memory(sinfo);
@@ -670,6 +797,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
goto release_mem;
}
+ /* Initialize PWM for contrast or backlight ("off") */
+ init_contrast(sinfo);
+
/* interrupt */
ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
if (ret) {
@@ -721,6 +851,7 @@ free_cmap:
unregister_irqs:
free_irq(sinfo->irq_base, info);
unmap_mmio:
+ exit_backlight(sinfo);
iounmap(sinfo->mmio);
release_mem:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
@@ -755,6 +886,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
if (!sinfo)
return 0;
+ exit_backlight(sinfo);
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(0);
unregister_framebuffer(info);
@@ -781,6 +913,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),
+
+// FIXME need suspend, resume
+
.driver = {
.name = "atmel_lcdfb",
.owner = THIS_MODULE,
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 9609a6c..924e255 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
+config BACKLIGHT_ATMEL_LCDC
+ bool "Atmel LCDC Contrast-as-Backlight control"
+ depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+ default y if MACH_SAM9261EK || MACH_SAM9263EK
+ help
+ This provides a backlight control internal to the Atmel LCDC
+ driver. If the LCD "contrast control" on your board is wired
+ so it controls the backlight brightness, select this option to
+ export this as a PWM-based backlight control.
+
+ If in doubt, it's safe to enable this option; it doesn't kick
+ in unless the board's description says it's wired that way.
+
config BACKLIGHT_CORGI
tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index b87ed37..2b53d1f 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -6,7 +6,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EMBEDDED || !X86
- depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN
+ depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32
default y
help
Saying Y here will allow you to use Linux in text mode through a
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 52dff40..fbd6112 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG
config AT32AP700X_WDT
tristate "AT32AP700x watchdog"
- depends on CPU_AT32AP7000
+ depends on CPU_AT32AP700X
help
Watchdog timer embedded into AT32AP700x devices. This will reboot
your system when the timeout is reached.
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
deleted file mode 100644
index 3914d7b..0000000
--- a/include/asm-avr32/arch-at32ap/at32ap7000.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Pin definitions for AT32AP7000.
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * 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.
- */
-#ifndef __ASM_ARCH_AT32AP7000_H__
-#define __ASM_ARCH_AT32AP7000_H__
-
-#define GPIO_PERIPH_A 0
-#define GPIO_PERIPH_B 1
-
-#define NR_GPIO_CONTROLLERS 4
-
-/*
- * Pin numbers identifying specific GPIO pins on the chip. They can
- * also be converted to IRQ numbers by passing them through
- * gpio_to_irq().
- */
-#define GPIO_PIOA_BASE (0)
-#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
-#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
-#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
-#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32)
-
-#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
-#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
-#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
-#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
-#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N))
-
-#endif /* __ASM_ARCH_AT32AP7000_H__ */
diff --git a/include/asm-avr32/arch-at32ap/at32ap700x.h b/include/asm-avr32/arch-at32ap/at32ap700x.h
new file mode 100644
index 0000000..99684d6
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/at32ap700x.h
@@ -0,0 +1,35 @@
+/*
+ * Pin definitions for AT32AP7000.
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __ASM_ARCH_AT32AP700X_H__
+#define __ASM_ARCH_AT32AP700X_H__
+
+#define GPIO_PERIPH_A 0
+#define GPIO_PERIPH_B 1
+
+#define NR_GPIO_CONTROLLERS 4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be converted to IRQ numbers by passing them through
+ * gpio_to_irq().
+ */
+#define GPIO_PIOA_BASE (0)
+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
+#define GPIO_PIOE_BASE (GPIO_PIOD_BASE + 32)
+
+#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
+#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
+#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
+#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
+#define GPIO_PIN_PE(N) (GPIO_PIOE_BASE + (N))
+
+#endif /* __ASM_ARCH_AT32AP700X_H__ */
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index d6993a6..8816b66 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -51,6 +51,9 @@ struct platform_device *
at32_add_device_ide(unsigned int id, unsigned int extint,
struct ide_platform_data *data);
+/* mask says which PWM channels to mux */
+struct platform_device *at32_add_device_pwm(u32 mask);
+
/* depending on what's hooked up, not all SSC pins will be used */
#define ATMEL_SSC_TK 0x01
#define ATMEL_SSC_TF 0x02
@@ -66,7 +69,13 @@ struct platform_device *
at32_add_device_ssc(unsigned int id, unsigned int flags);
struct platform_device *at32_add_device_twi(unsigned int id);
-struct platform_device *at32_add_device_mci(unsigned int id);
+
+struct mci_platform_data {
+ int detect_pin;
+ int wp_pin;
+};
+struct platform_device *
+at32_add_device_mci(unsigned int id, struct mci_platform_data *data);
struct platform_device *at32_add_device_ac97c(unsigned int id);
struct platform_device *at32_add_device_abdac(unsigned int id);
diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
index a762f42..0dc2026 100644
--- a/include/asm-avr32/arch-at32ap/cpu.h
+++ b/include/asm-avr32/arch-at32ap/cpu.h
@@ -14,7 +14,7 @@
* Only AT32AP7000 is defined for now. We can identify the specific
* chip at runtime, but I'm not sure if it's really worth it.
*/
-#ifdef CONFIG_CPU_AT32AP7000
+#ifdef CONFIG_CPU_AT32AP700X
# define cpu_is_at32ap7000() (1)
#else
# define cpu_is_at32ap7000() (0)
diff --git a/include/asm-avr32/arch-at32ap/io.h b/include/asm-avr32/arch-at32ap/io.h
index ee59e40..4ec6abc 100644
--- a/include/asm-avr32/arch-at32ap/io.h
+++ b/include/asm-avr32/arch-at32ap/io.h
@@ -4,7 +4,7 @@
/* For "bizarre" halfword swapping */
#include <linux/byteorder/swabb.h>
-#if defined(CONFIG_AP7000_32_BIT_SMC)
+#if defined(CONFIG_AP700X_32_BIT_SMC)
# define __swizzle_addr_b(addr) (addr ^ 3UL)
# define __swizzle_addr_w(addr) (addr ^ 2UL)
# define __swizzle_addr_l(addr) (addr)
@@ -14,7 +14,7 @@
# define __mem_ioswabb(a, x) (x)
# define __mem_ioswabw(a, x) swab16(x)
# define __mem_ioswabl(a, x) swab32(x)
-#elif defined(CONFIG_AP7000_16_BIT_SMC)
+#elif defined(CONFIG_AP700X_16_BIT_SMC)
# define __swizzle_addr_b(addr) (addr ^ 1UL)
# define __swizzle_addr_w(addr) (addr)
# define __swizzle_addr_l(addr) (addr)
diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h
index b1abe6b..135e034 100644
--- a/include/asm-avr32/arch-at32ap/portmux.h
+++ b/include/asm-avr32/arch-at32ap/portmux.h
@@ -26,4 +26,16 @@ void at32_select_periph(unsigned int pin, unsigned int periph,
void at32_select_gpio(unsigned int pin, unsigned long flags);
void at32_reserve_pin(unsigned int pin);
+#ifdef CONFIG_GPIO_DEV
+
+/* Gang allocators and accessors; used by the GPIO /dev driver */
+int at32_gpio_port_is_valid(unsigned int port);
+int at32_select_gpio_pins(unsigned int port, u32 pins, u32 oe_mask);
+void at32_deselect_pins(unsigned int port, u32 pins);
+
+u32 at32_gpio_get_value_multiple(unsigned int port, u32 pins);
+void at32_gpio_set_value_multiple(unsigned int port, u32 value, u32 mask);
+
+#endif /* CONFIG_GPIO_DEV */
+
#endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/include/asm-avr32/dma-controller.h b/include/asm-avr32/dma-controller.h
new file mode 100644
index 0000000..56a4965
--- /dev/null
+++ b/include/asm-avr32/dma-controller.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __ASM_AVR32_DMA_CONTROLLER_H
+#define __ASM_AVR32_DMA_CONTROLLER_H
+
+#include <linux/device.h>
+
+#define DMA_DIR_MEM_TO_MEM 0x0000
+#define DMA_DIR_MEM_TO_PERIPH 0x0001
+#define DMA_DIR_PERIPH_TO_MEM 0x0002
+#define DMA_DIR_PERIPH_TO_PERIPH 0x0003
+
+#define DMA_WIDTH_8BIT 0
+#define DMA_WIDTH_16BIT 1
+#define DMA_WIDTH_32BIT 2
+
+struct dma_request {
+ struct dma_controller *dmac;
+ struct list_head list;
+
+ unsigned short channel;
+
+ void (*xfer_complete)(struct dma_request *req);
+ void (*block_complete)(struct dma_request *req);
+ void (*error)(struct dma_request *req);
+};
+
+struct dma_request_sg {
+ struct dma_request req;
+
+ int nr_sg;
+ struct scatterlist *sg;
+ unsigned long block_size;
+ unsigned int nr_blocks;
+
+ dma_addr_t data_reg;
+ unsigned short periph_id;
+
+ unsigned char direction;
+ unsigned char width;
+};
+#define to_dma_request_sg(_req) \
+ container_of(_req, struct dma_request_sg, req)
+
+struct dma_request_cyclic {
+ struct dma_request req;
+
+ int periods;
+ unsigned long buffer_size;
+
+ dma_addr_t buffer_start;
+ dma_addr_t data_reg;
+
+ unsigned short periph_id;
+ unsigned char direction;
+ unsigned char width;
+
+ void *dev_id;
+};
+#define to_dma_request_cyclic(_req) \
+ container_of(_req, struct dma_request_cyclic, req)
+
+struct dma_request_memcpy {
+ struct dma_request req;
+
+ dma_addr_t src_addr;
+ unsigned int src_width;
+ unsigned int src_stride;
+
+ dma_addr_t dst_addr;
+ unsigned int dst_width;
+ unsigned int dst_stride;
+
+ size_t length;
+
+ unsigned short src_reverse:1;
+ unsigned short dst_reverse:1;
+};
+#define to_dma_request_memcpy(_req) \
+ container_of(_req, struct dma_request_memcpy, req)
+
+struct dma_controller {
+ struct list_head list;
+ int id;
+ struct device *dev;
+
+ int (*alloc_channel)(struct dma_controller *dmac);
+ void (*release_channel)(struct dma_controller *dmac,
+ int channel);
+ int (*prepare_request_sg)(struct dma_controller *dmac,
+ struct dma_request_sg *req);
+ int (*prepare_request_cyclic)(struct dma_controller *dmac,
+ struct dma_request_cyclic *req);
+ int (*prepare_request_memcpy)(struct dma_controller *dmac,
+ struct dma_request_memcpy *req);
+ int (*start_request)(struct dma_controller *dmac,
+ unsigned int channel);
+ int (*stop_request)(struct dma_controller *dmac,
+ unsigned int channel);
+ dma_addr_t (*get_current_pos)(struct dma_controller *dmac,
+ unsigned int channel);
+};
+
+static inline int
+dma_alloc_channel(struct dma_controller *dmac)
+{
+ return dmac->alloc_channel(dmac);
+}
+
+static inline void
+dma_release_channel(struct dma_controller *dmac, int chan)
+{
+ dmac->release_channel(dmac, chan);
+}
+
+static inline int
+dma_prepare_request_sg(struct dma_controller *dmac,
+ struct dma_request_sg *req)
+{
+ return dmac->prepare_request_sg(dmac, req);
+}
+
+static inline int
+dma_prepare_request_cyclic(struct dma_controller *dmac,
+ struct dma_request_cyclic *req)
+{
+ return dmac->prepare_request_cyclic(dmac, req);
+}
+
+static inline int
+dma_prepare_request_memcpy(struct dma_controller *dmac,
+ struct dma_request_memcpy *req)
+{
+ return dmac->prepare_request_memcpy(dmac, req);
+}
+
+static inline int
+dma_start_request(struct dma_controller *dmac,
+ unsigned int channel)
+{
+ return dmac->start_request(dmac, channel);
+}
+
+static inline int
+dma_stop_request(struct dma_controller *dmac,
+ unsigned int channel)
+{
+ return dmac->stop_request(dmac, channel);
+}
+
+static inline dma_addr_t
+dma_get_current_pos(struct dma_controller *dmac,
+ unsigned int channel)
+{
+ return dmac->get_current_pos(dmac, channel);
+}
+
+extern int register_dma_controller(struct dma_controller *dmac);
+extern struct dma_controller *find_dma_controller(int id);
+
+#endif /* __ASM_AVR32_DMA_CONTROLLER_H */
diff --git a/include/asm-avr32/irq.h b/include/asm-avr32/irq.h
index 83e6549..9315724 100644
--- a/include/asm-avr32/irq.h
+++ b/include/asm-avr32/irq.h
@@ -11,4 +11,9 @@
#define irq_canonicalize(i) (i)
+#ifndef __ASSEMBLER__
+int nmi_enable(void);
+void nmi_disable(void);
+#endif
+
#endif /* __ASM_AVR32_IOCTLS_H */
diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
index fd7e990..ca4f954 100644
--- a/include/asm-avr32/kdebug.h
+++ b/include/asm-avr32/kdebug.h
@@ -5,6 +5,7 @@
enum die_val {
DIE_BREAKPOINT,
DIE_SSTEP,
+ DIE_NMI,
};
#endif /* __ASM_AVR32_KDEBUG_H */
diff --git a/include/asm-avr32/ocd.h b/include/asm-avr32/ocd.h
index 996405e..6bef094 100644
--- a/include/asm-avr32/ocd.h
+++ b/include/asm-avr32/ocd.h
@@ -533,6 +533,11 @@ static inline void __ocd_write(unsigned int reg, unsigned long value)
#define ocd_read(reg) __ocd_read(OCD_##reg)
#define ocd_write(reg, value) __ocd_write(OCD_##reg, value)
+struct task_struct;
+
+void ocd_enable(struct task_struct *child);
+void ocd_disable(struct task_struct *child);
+
#endif /* !__ASSEMBLER__ */
#endif /* __ASM_AVR32_OCD_H */
diff --git a/include/asm-avr32/processor.h b/include/asm-avr32/processor.h
index a52576b..4212551 100644
--- a/include/asm-avr32/processor.h
+++ b/include/asm-avr32/processor.h
@@ -57,11 +57,25 @@ struct avr32_cpuinfo {
unsigned short cpu_revision;
enum tlb_config tlb_config;
unsigned long features;
+ u32 device_id;
struct cache_info icache;
struct cache_info dcache;
};
+static inline unsigned int avr32_get_manufacturer_id(struct avr32_cpuinfo *cpu)
+{
+ return (cpu->device_id >> 1) & 0x7f;
+}
+static inline unsigned int avr32_get_product_number(struct avr32_cpuinfo *cpu)
+{
+ return (cpu->device_id >> 12) & 0xffff;
+}
+static inline unsigned int avr32_get_chip_revision(struct avr32_cpuinfo *cpu)
+{
+ return (cpu->device_id >> 28) & 0x0f;
+}
+
extern struct avr32_cpuinfo boot_cpu_data;
#ifdef CONFIG_SMP
diff --git a/include/asm-avr32/ptrace.h b/include/asm-avr32/ptrace.h
index 8c5dba5..9e2d44f 100644
--- a/include/asm-avr32/ptrace.h
+++ b/include/asm-avr32/ptrace.h
@@ -121,7 +121,15 @@ struct pt_regs {
};
#ifdef __KERNEL__
-# define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
+
+#include <asm/ocd.h>
+
+#define arch_ptrace_attach(child) ocd_enable(child)
+
+#define user_mode(regs) (((regs)->sr & MODE_MASK) == MODE_USER)
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+
extern void show_regs (struct pt_regs *);
static __inline__ int valid_user_regs(struct pt_regs *regs)
@@ -141,9 +149,6 @@ static __inline__ int valid_user_regs(struct pt_regs *regs)
return 0;
}
-#define instruction_pointer(regs) ((regs)->pc)
-
-#define profile_pc(regs) instruction_pointer(regs)
#endif /* __KERNEL__ */
diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
index 184b574..07049f6 100644
--- a/include/asm-avr32/thread_info.h
+++ b/include/asm-avr32/thread_info.h
@@ -88,6 +88,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_MEMDIE 6
#define TIF_RESTORE_SIGMASK 7 /* restore signal mask in do_signal */
#define TIF_CPU_GOING_TO_SLEEP 8 /* CPU is entering sleep 0 mode */
+#define TIF_DEBUG 30 /* debugging enabled */
#define TIF_USERSPACE 31 /* true if FS sets userspace */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
diff --git a/include/linux/atmel_pwm.h b/include/linux/atmel_pwm.h
new file mode 100644
index 0000000..ea04abb
--- /dev/null
+++ b/include/linux/atmel_pwm.h
@@ -0,0 +1,70 @@
+#ifndef __LINUX_ATMEL_PWM_H
+#define __LINUX_ATMEL_PWM_H
+
+/**
+ * struct pwm_channel - driver handle to a PWM channel
+ * @regs: base of this channel's registers
+ * @index: number of this channel (0..31)
+ * @mck: base clock rate, which can be prescaled and maybe subdivided
+ *
+ * Drivers initialize a pwm_channel structure using pwm_channel_alloc().
+ * Then they configure its clock rate (derived from MCK), alignment,
+ * polarity, and duty cycle by writing directly to the channel registers,
+ * before enabling the channel by calling pwm_channel_enable().
+ *
+ * After emitting a PWM signal for the desired length of time, drivers
+ * may then pwm_channel_disable() or pwm_channel_free(). Both of these
+ * disable the channel, but when it's freed the IRQ is deconfigured and
+ * the channel must later be re-allocated and reconfigured.
+ *
+ * Note that if the period or duty cycle need to be changed while the
+ * PWM channel is operating, drivers must use the PWM_CUPD double buffer
+ * mechanism, either polling until they change or getting implicitly
+ * notified through a once-per-period interrupt handler.
+ */
+struct pwm_channel {
+ void __iomem *regs;
+ unsigned index;
+ unsigned long mck;
+};
+
+extern int pwm_channel_alloc(int index, struct pwm_channel *ch);
+extern int pwm_channel_free(struct pwm_channel *ch);
+
+extern int pwm_clk_alloc(unsigned prescale, unsigned div);
+extern void pwm_clk_free(unsigned clk);
+
+extern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled);
+
+#define pwm_channel_enable(ch) __pwm_channel_onoff((ch), 1)
+#define pwm_channel_disable(ch) __pwm_channel_onoff((ch), 0)
+
+/* periodic interrupts, mostly for CUPD changes to period or cycle */
+extern int pwm_channel_handler(struct pwm_channel *ch,
+ void (*handler)(struct pwm_channel *ch));
+
+/* per-channel registers (banked at pwm_channel->regs) */
+#define PWM_CMR 0x00 /* mode register */
+#define PWM_CPR_CPD (1 << 10) /* set: CUPD modifies period */
+#define PWM_CPR_CPOL (1 << 9) /* set: idle high */
+#define PWM_CPR_CALG (1 << 8) /* set: center align */
+#define PWM_CPR_CPRE (0xf << 0) /* mask: rate is mck/(2^pre) */
+#define PWM_CPR_CLKA (0xb << 0) /* rate CLKA */
+#define PWM_CPR_CLKB (0xc << 0) /* rate CLKB */
+#define PWM_CDTY 0x04 /* duty cycle (max of CPRD) */
+#define PWM_CPRD 0x08 /* period (count up from zero) */
+#define PWM_CCNT 0x0c /* counter (20 bits?) */
+#define PWM_CUPD 0x10 /* update CPRD (or CDTY) next period */
+
+static inline void
+pwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val)
+{
+ __raw_writel(val, pwmc->regs + offset);
+}
+
+static inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset)
+{
+ return __raw_readl(pwmc->regs + offset);
+}
+
+#endif /* __LINUX_ATMEL_PWM_H */
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
index 4eea637..336c20d 100644
--- a/include/video/atmel_lcdc.h
+++ b/include/video/atmel_lcdc.h
@@ -22,7 +22,7 @@
#ifndef __ATMEL_LCDC_H__
#define __ATMEL_LCDC_H__
- /* LCD Controller info data structure */
+ /* LCD Controller info data structure, stored in device platform_data */
struct atmel_lcdfb_info {
spinlock_t lock;
struct fb_info *info;
@@ -33,7 +33,14 @@ struct atmel_lcdfb_info {
struct platform_device *pdev;
struct clk *bus_clk;
struct clk *lcdc_clk;
- unsigned int default_bpp;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+ struct backlight_device *backlight;
+ u8 bl_power;
+#endif
+ bool lcdcon_is_backlight;
+
+ u8 default_bpp;
unsigned int default_lcdcon2;
unsigned int default_dmacon;
void (*atmel_lcdfb_power_control)(int on);
@@ -115,20 +122,20 @@ struct atmel_lcdfb_info {
#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31)
#define ATMEL_LCDC_TIM1 0x0808
-#define ATMEL_LCDC_VFP (0xff << 0)
+#define ATMEL_LCDC_VFP (0xffU << 0)
#define ATMEL_LCDC_VBP_OFFSET 8
-#define ATMEL_LCDC_VBP (0xff << ATMEL_LCDC_VBP_OFFSET)
+#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET)
#define ATMEL_LCDC_VPW_OFFSET 16
-#define ATMEL_LCDC_VPW (0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET)
#define ATMEL_LCDC_VHDLY_OFFSET 24
-#define ATMEL_LCDC_VHDLY (0xf << ATMEL_LCDC_VHDLY_OFFSET)
+#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET)
#define ATMEL_LCDC_TIM2 0x080c
-#define ATMEL_LCDC_HBP (0xff << 0)
+#define ATMEL_LCDC_HBP (0xffU << 0)
#define ATMEL_LCDC_HPW_OFFSET 8
-#define ATMEL_LCDC_HPW (0x3f << ATMEL_LCDC_HPW_OFFSET)
+#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET)
#define ATMEL_LCDC_HFP_OFFSET 21
-#define ATMEL_LCDC_HFP (0x7ff << ATMEL_LCDC_HFP_OFFSET)
+#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
#define ATMEL_LCDC_LCDFRMCFG 0x0810
#define ATMEL_LCDC_LINEVAL (0x7ff << 0)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index c25db86..c719bb9 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -470,6 +470,8 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
lock_kernel();
if (request == PTRACE_TRACEME) {
ret = ptrace_traceme();
+ if (!ret)
+ arch_ptrace_attach(current);
goto out;
}
diff --git a/sound/Kconfig b/sound/Kconfig
index b2a2db4..29a9979 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -63,6 +63,8 @@ source "sound/aoa/Kconfig"
source "sound/arm/Kconfig"
+source "sound/avr32/Kconfig"
+
if SPI
source "sound/spi/Kconfig"
endif
diff --git a/sound/Makefile b/sound/Makefile
index c76d707..a52b236 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
- sparc/ spi/ parisc/ pcmcia/ mips/ soc/
+ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ avr32/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff --git a/sound/avr32/Kconfig b/sound/avr32/Kconfig
new file mode 100644
index 0000000..17d1d91
--- /dev/null
+++ b/sound/avr32/Kconfig
@@ -0,0 +1,11 @@
+menu "AVR32 devices"
+ depends on SND != n && AVR32
+
+config SND_ATMEL_AC97
+ tristate "Atmel AC97 Controller Driver"
+ select SND_PCM
+ select SND_AC97_CODEC
+ help
+ ALSA sound driver for the Atmel AC97 controller.
+
+endmenu
diff --git a/sound/avr32/Makefile b/sound/avr32/Makefile
new file mode 100644
index 0000000..5d87d0e
--- /dev/null
+++ b/sound/avr32/Makefile
@@ -0,0 +1,3 @@
+snd-atmel-ac97-objs := ac97c.o
+
+obj-$(CONFIG_SND_ATMEL_AC97) += snd-atmel-ac97.o
diff --git a/sound/avr32/ac97c.c b/sound/avr32/ac97c.c
new file mode 100644
index 0000000..0ec0b1c
--- /dev/null
+++ b/sound/avr32/ac97c.c
@@ -0,0 +1,914 @@
+/*
+ * Driver for the Atmel AC97 controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/memalloc.h>
+
+#include <asm/dma-controller.h>
+
+#include "ac97c.h"
+
+/* Serialize access to opened */
+static DEFINE_MUTEX(opened_mutex);
+
+struct atmel_ac97_dma_info {
+ struct dma_request_cyclic req_tx;
+ struct dma_request_cyclic req_rx;
+ unsigned short rx_periph_id;
+ unsigned short tx_periph_id;
+};
+
+struct atmel_ac97 {
+ /* Serialize access to opened */
+ spinlock_t lock;
+ void __iomem *regs;
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_ac97 *ac97;
+ struct snd_ac97_bus *ac97_bus;
+ int opened;
+ int period;
+ u64 cur_format;
+ unsigned int cur_rate;
+ struct clk *mck;
+ struct platform_device *pdev;
+ struct atmel_ac97_dma_info dma;
+};
+
+#define get_chip(card) ((struct atmel_ac97 *)(card)->private_data)
+
+#define ac97c_writel(chip, reg, val) \
+ __raw_writel((val), (chip)->regs + AC97C_##reg)
+#define ac97c_readl(chip, reg) \
+ __raw_readl((chip)->regs + AC97C_##reg)
+
+/*
+ * PCM part
+ */
+static struct snd_pcm_hardware snd_atmel_ac97_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED
+ | SNDRV_PCM_INFO_MMAP
+ | SNDRV_PCM_INFO_MMAP_VALID
+ | SNDRV_PCM_INFO_BLOCK_TRANSFER
+ | SNDRV_PCM_INFO_JOINT_DUPLEX),
+ .formats = (SNDRV_PCM_FMTBIT_S16_BE
+ | SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_CONTINUOUS),
+ .rate_min = 4000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 6,
+ .buffer_bytes_max = 64*1024,
+ .period_bytes_min = 512,
+ .period_bytes_max = 4095,
+ .periods_min = 8,
+ .periods_max = 1024,
+};
+
+static struct snd_pcm_hardware snd_atmel_ac97_capture_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED
+ | SNDRV_PCM_INFO_MMAP
+ | SNDRV_PCM_INFO_MMAP_VALID
+ | SNDRV_PCM_INFO_BLOCK_TRANSFER
+ | SNDRV_PCM_INFO_JOINT_DUPLEX),
+ .formats = (SNDRV_PCM_FMTBIT_S16_BE
+ | SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_CONTINUOUS),
+ .rate_min = 4000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 64*1024,
+ .period_bytes_min = 512,
+ .period_bytes_max = 4095,
+ .periods_min = 8,
+ .periods_max = 1024,
+};
+
+/*
+ * PCM functions
+ */
+static int
+snd_atmel_ac97_playback_open(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ mutex_lock(&opened_mutex);
+ chip->opened++;
+ runtime->hw = snd_atmel_ac97_playback_hw;
+ if (chip->cur_rate) {
+ runtime->hw.rate_min = chip->cur_rate;
+ runtime->hw.rate_max = chip->cur_rate;
+ }
+ if (chip->cur_format)
+ runtime->hw.formats = (1ULL << chip->cur_format);
+ mutex_unlock(&opened_mutex);
+ chip->playback_substream = substream;
+ chip->period = 0;
+ return 0;
+}
+
+static int
+snd_atmel_ac97_capture_open(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ mutex_lock(&opened_mutex);
+ chip->opened++;
+ runtime->hw = snd_atmel_ac97_capture_hw;
+ if (chip->cur_rate) {
+ runtime->hw.rate_min = chip->cur_rate;
+ runtime->hw.rate_max = chip->cur_rate;
+ }
+ if (chip->cur_format)
+ runtime->hw.formats = (1ULL << chip->cur_format);
+ mutex_unlock(&opened_mutex);
+ chip->capture_substream = substream;
+ chip->period = 0;
+ return 0;
+}
+
+static int snd_atmel_ac97_playback_close(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ mutex_lock(&opened_mutex);
+ chip->opened--;
+ if (!chip->opened) {
+ chip->cur_rate = 0;
+ chip->cur_format = 0;
+ }
+ mutex_unlock(&opened_mutex);
+ return 0;
+}
+
+static int snd_atmel_ac97_capture_close(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ mutex_lock(&opened_mutex);
+ chip->opened--;
+ if (!chip->opened) {
+ chip->cur_rate = 0;
+ chip->cur_format = 0;
+ }
+ mutex_unlock(&opened_mutex);
+ return 0;
+}
+
+static int
+snd_atmel_ac97_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ int err;
+
+ err = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ return err;
+
+ /* Set restrictions to params */
+ mutex_lock(&opened_mutex);
+ chip->cur_rate = params_rate(hw_params);
+ chip->cur_format = params_format(hw_params);
+ mutex_unlock(&opened_mutex);
+
+ return 0;
+}
+
+static int
+snd_atmel_ac97_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ int err;
+
+ err = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ return err;
+
+ /* Set restrictions to params */
+ mutex_lock(&opened_mutex);
+ chip->cur_rate = params_rate(hw_params);
+ chip->cur_format = params_format(hw_params);
+ mutex_unlock(&opened_mutex);
+
+ return 0;
+}
+
+static int snd_atmel_ac97_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_atmel_ac97_capture_hw_free(struct snd_pcm_substream *substream)
+{
+
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_atmel_ac97_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ struct platform_device *pdev = chip->pdev;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int block_size = frames_to_bytes(runtime, runtime->period_size);
+ unsigned long word = 0;
+ unsigned long buffer_size = 0;
+
+ dma_sync_single_for_device(&pdev->dev, runtime->dma_addr,
+ block_size * 2, DMA_TO_DEVICE);
+
+ /* Assign slots to channels */
+ switch (substream->runtime->channels) {
+ case 1:
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+ break;
+ case 2:
+ /* Assign Left and Right slot to Channel A */
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+ | AC97C_CH_ASSIGN(PCM_RIGHT, A);
+ break;
+ default:
+ /* TODO: support more than two channels */
+ return -EINVAL;
+ break;
+ }
+ ac97c_writel(chip, OCA, word);
+
+ /* Configure sample format and size */
+ word = AC97C_CMR_PDCEN | AC97C_CMR_SIZE_16;
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word |= AC97C_CMR_CEM_LITTLE;
+ break;
+ case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
+ default:
+ word &= ~AC97C_CMR_CEM_LITTLE;
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, word);
+
+ /* Set variable rate if needed */
+ if (runtime->rate != 48000) {
+ word = ac97c_readl(chip, MR);
+ word |= AC97C_MR_VRA;
+ ac97c_writel(chip, MR, word);
+ } else {
+ /* Clear Variable Rate Bit */
+ word = ac97c_readl(chip, MR);
+ word &= ~AC97C_MR_VRA;
+ ac97c_writel(chip, MR, word);
+ }
+
+ /* Set rate */
+ snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+
+ buffer_size = frames_to_bytes(runtime, runtime->period_size) *
+ runtime->periods;
+
+ chip->dma.req_tx.buffer_size = buffer_size;
+ chip->dma.req_tx.periods = runtime->periods;
+
+ BUG_ON(chip->dma.req_tx.buffer_size !=
+ (chip->dma.req_tx.periods *
+ frames_to_bytes(runtime, runtime->period_size)));
+
+ chip->dma.req_tx.buffer_start = runtime->dma_addr;
+ chip->dma.req_tx.data_reg = (dma_addr_t)(chip->regs + AC97C_CATHR + 2);
+ chip->dma.req_tx.periph_id = chip->dma.tx_periph_id;
+ chip->dma.req_tx.direction = DMA_DIR_MEM_TO_PERIPH;
+ chip->dma.req_tx.width = DMA_WIDTH_16BIT;
+ chip->dma.req_tx.dev_id = chip;
+
+ return 0;
+}
+
+static int snd_atmel_ac97_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ struct platform_device *pdev = chip->pdev;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int block_size = frames_to_bytes(runtime, runtime->period_size);
+ unsigned long word = 0;
+ unsigned long buffer_size = 0;
+
+ dma_sync_single_for_device(&pdev->dev, runtime->dma_addr,
+ block_size * 2, DMA_FROM_DEVICE);
+
+ /* Assign slots to channels */
+ switch (substream->runtime->channels) {
+ case 1:
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+ break;
+ case 2:
+ /* Assign Left and Right slot to Channel A */
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+ | AC97C_CH_ASSIGN(PCM_RIGHT, A);
+ break;
+ default:
+ /* TODO: support more than two channels */
+ return -EINVAL;
+ break;
+ }
+ ac97c_writel(chip, ICA, word);
+
+ /* Configure sample format and size */
+ word = AC97C_CMR_PDCEN | AC97C_CMR_SIZE_16;
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word |= AC97C_CMR_CEM_LITTLE;
+ break;
+ case SNDRV_PCM_FORMAT_S16_BE:
+ default:
+ word &= ~(AC97C_CMR_CEM_LITTLE);
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, word);
+
+ /* Set variable rate if needed */
+ if (runtime->rate != 48000) {
+ word = ac97c_readl(chip, MR);
+ word |= AC97C_MR_VRA;
+ ac97c_writel(chip, MR, word);
+ } else {
+ /* Clear Variable Rate Bit */
+ word = ac97c_readl(chip, MR);
+ word &= ~(AC97C_MR_VRA);
+ ac97c_writel(chip, MR, word);
+ }
+
+ /* Set rate */
+ snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
+
+ buffer_size = frames_to_bytes(runtime, runtime->period_size) *
+ runtime->periods;
+
+ chip->dma.req_rx.buffer_size = buffer_size;
+ chip->dma.req_rx.periods = runtime->periods;
+
+ BUG_ON(chip->dma.req_rx.buffer_size !=
+ (chip->dma.req_rx.periods *
+ frames_to_bytes(runtime, runtime->period_size)));
+
+ chip->dma.req_rx.buffer_start = runtime->dma_addr;
+ chip->dma.req_rx.data_reg = (dma_addr_t)(chip->regs + AC97C_CARHR + 2);
+ chip->dma.req_rx.periph_id = chip->dma.rx_periph_id;
+ chip->dma.req_rx.direction = DMA_DIR_PERIPH_TO_MEM;
+ chip->dma.req_rx.width = DMA_WIDTH_16BIT;
+ chip->dma.req_rx.dev_id = chip;
+
+ return 0;
+}
+
+ static int
+snd_atmel_ac97_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ unsigned long camr;
+ int flags, err = 0;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ camr = ac97c_readl(chip, CAMR);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = dma_prepare_request_cyclic(chip->dma.req_tx.req.dmac,
+ &chip->dma.req_tx);
+ dma_start_request(chip->dma.req_tx.req.dmac,
+ chip->dma.req_tx.req.channel);
+ camr |= AC97C_CMR_CENA;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ err = dma_stop_request(chip->dma.req_tx.req.dmac,
+ chip->dma.req_tx.req.channel);
+ if (chip->opened <= 1)
+ camr &= ~AC97C_CMR_CENA;
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, camr);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+ return err;
+}
+
+ static int
+snd_atmel_ac97_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ unsigned long camr;
+ int flags, err = 0;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ camr = ac97c_readl(chip, CAMR);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = dma_prepare_request_cyclic(chip->dma.req_rx.req.dmac,
+ &chip->dma.req_rx);
+ dma_start_request(chip->dma.req_rx.req.dmac,
+ chip->dma.req_rx.req.channel);
+ camr |= AC97C_CMR_CENA;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ err = dma_stop_request(chip->dma.req_rx.req.dmac,
+ chip->dma.req_rx.req.channel);
+ mutex_lock(&opened_mutex);
+ if (chip->opened <= 1)
+ camr &= ~AC97C_CMR_CENA;
+ mutex_unlock(&opened_mutex);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, camr);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+ return err;
+}
+
+ static snd_pcm_uframes_t
+snd_atmel_ac97_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t pos;
+ unsigned long bytes;
+
+ bytes = (dma_get_current_pos
+ (chip->dma.req_tx.req.dmac,
+ chip->dma.req_tx.req.channel) - runtime->dma_addr);
+ pos = bytes_to_frames(runtime, bytes);
+ if (pos >= runtime->buffer_size)
+ pos -= runtime->buffer_size;
+
+ return pos;
+}
+
+ static snd_pcm_uframes_t
+snd_atmel_ac97_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97 *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t pos;
+ unsigned long bytes;
+
+ bytes = (dma_get_current_pos
+ (chip->dma.req_rx.req.dmac,
+ chip->dma.req_rx.req.channel)
+ - runtime->dma_addr);
+ pos = bytes_to_frames(runtime, bytes);
+ if (pos >= runtime->buffer_size)
+ pos -= runtime->buffer_size;
+
+
+ return pos;
+}
+
+static struct snd_pcm_ops atmel_ac97_playback_ops = {
+ .open = snd_atmel_ac97_playback_open,
+ .close = snd_atmel_ac97_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_atmel_ac97_playback_hw_params,
+ .hw_free = snd_atmel_ac97_playback_hw_free,
+ .prepare = snd_atmel_ac97_playback_prepare,
+ .trigger = snd_atmel_ac97_playback_trigger,
+ .pointer = snd_atmel_ac97_playback_pointer,
+};
+
+static struct snd_pcm_ops atmel_ac97_capture_ops = {
+ .open = snd_atmel_ac97_capture_open,
+ .close = snd_atmel_ac97_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_atmel_ac97_capture_hw_params,
+ .hw_free = snd_atmel_ac97_capture_hw_free,
+ .prepare = snd_atmel_ac97_capture_prepare,
+ .trigger = snd_atmel_ac97_capture_trigger,
+ .pointer = snd_atmel_ac97_capture_pointer,
+};
+
+static struct ac97_pcm atmel_ac97_pcm_defs[] __devinitdata = {
+ /* Playback */
+ {
+ .exclusive = 1,
+ .r = { {
+ .slots = ((1 << AC97_SLOT_PCM_LEFT)
+ | (1 << AC97_SLOT_PCM_RIGHT)
+ | (1 << AC97_SLOT_PCM_CENTER)
+ | (1 << AC97_SLOT_PCM_SLEFT)
+ | (1 << AC97_SLOT_PCM_SRIGHT)
+ | (1 << AC97_SLOT_LFE)),
+ } }
+ },
+ /* PCM in */
+ {
+ .stream = 1,
+ .exclusive = 1,
+ .r = { {
+ .slots = ((1 << AC97_SLOT_PCM_LEFT)
+ | (1 << AC97_SLOT_PCM_RIGHT)),
+ } }
+ },
+ /* Mic in */
+ {
+ .stream = 1,
+ .exclusive = 1,
+ .r = { {
+ .slots = (1<<AC97_SLOT_MIC),
+ } }
+ },
+};
+
+static int __devinit snd_atmel_ac97_pcm_new(struct atmel_ac97 *chip)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_ac97_pcm_assign(chip->ac97_bus,
+ ARRAY_SIZE(atmel_ac97_pcm_defs),
+ atmel_ac97_pcm_defs);
+ if (err)
+ return err;
+
+ err = snd_pcm_new(chip->card, "Atmel-AC97", 0, 1, 1, &pcm);
+ if (err)
+ return err;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &atmel_ac97_playback_ops);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &atmel_ac97_capture_ops);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ &chip->pdev->dev,
+ 128 * 1024, 128 * 1024);
+
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "Atmel-AC97");
+ chip->pcm = pcm;
+
+ return 0;
+}
+
+/*
+ * Mixer part.
+ */
+static int snd_atmel_ac97_mixer_new(struct atmel_ac97 *chip)
+{
+ int err;
+ struct snd_ac97_template template;
+
+ memset(&template, 0, sizeof(template));
+ template.private_data = chip;
+ err = snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
+
+ return err;
+}
+
+static void atmel_ac97_error(struct dma_request *_req)
+{
+ struct dma_request_cyclic *req = to_dma_request_cyclic(_req);
+ struct atmel_ac97 *chip = req->dev_id;
+
+ dev_dbg(&chip->pdev->dev, "DMA Controller error, channel %d\n",
+ req->req.channel);
+}
+
+static void atmel_ac97_block_complete(struct dma_request *_req)
+{
+ struct dma_request_cyclic *req = to_dma_request_cyclic(_req);
+ struct atmel_ac97 *chip = req->dev_id;
+ if (req->periph_id == chip->dma.tx_periph_id)
+ snd_pcm_period_elapsed(chip->playback_substream);
+ else
+ snd_pcm_period_elapsed(chip->capture_substream);
+}
+
+/*
+ * Codec part.
+ */
+static void snd_atmel_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ struct atmel_ac97 *chip = get_chip(ac97);
+ unsigned long word;
+ int timeout = 40;
+
+ word = (reg & 0x7f) << 16 | val;
+
+ do {
+ if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
+ ac97c_writel(chip, COTHR, word);
+ return;
+ }
+ udelay(1);
+ } while (--timeout);
+
+ dev_dbg(&chip->pdev->dev, "codec write timeout\n");
+}
+
+static unsigned short snd_atmel_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct atmel_ac97 *chip = get_chip(ac97);
+ unsigned long word;
+ int timeout = 40;
+ int write = 10;
+
+ word = (0x80 | (reg & 0x7f)) << 16;
+
+ if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
+ ac97c_readl(chip, CORHR);
+
+retry_write:
+ timeout = 40;
+
+ do {
+ if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
+ ac97c_writel(chip, COTHR, word);
+ goto read_reg;
+ }
+ mdelay(10);
+ } while (--timeout);
+
+ if (!--write)
+ goto timed_out;
+ goto retry_write;
+
+read_reg:
+ do {
+ if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
+ unsigned short val = ac97c_readl(chip, CORHR);
+ return val;
+ }
+ mdelay(10);
+ } while (--timeout);
+
+ if (!--write)
+ goto timed_out;
+ goto retry_write;
+
+timed_out:
+ dev_dbg(&chip->pdev->dev, "codec read timeout\n");
+ return 0xffff;
+}
+
+static void snd_atmel_ac97_reset(struct atmel_ac97 *chip)
+{
+ ac97c_writel(chip, MR, AC97C_MR_WRST);
+ mdelay(1);
+ ac97c_writel(chip, MR, AC97C_MR_ENA);
+}
+
+static void snd_atmel_ac97_destroy(struct snd_card *card)
+{
+ struct atmel_ac97 *chip = get_chip(card);
+
+ if (chip->regs)
+ iounmap(chip->regs);
+
+ if (chip->mck) {
+ clk_disable(chip->mck);
+ clk_put(chip->mck);
+ }
+
+ if (chip->dma.req_tx.req.dmac) {
+ dma_release_channel(chip->dma.req_tx.req.dmac,
+ chip->dma.req_tx.req.channel);
+ }
+ if (chip->dma.req_rx.req.dmac) {
+ dma_release_channel(chip->dma.req_rx.req.dmac,
+ chip->dma.req_rx.req.channel);
+ }
+}
+
+static int __devinit snd_atmel_ac97_create(struct snd_card *card,
+ struct platform_device *pdev)
+{
+ static struct snd_ac97_bus_ops ops = {
+ .write = snd_atmel_ac97_write,
+ .read = snd_atmel_ac97_read,
+ };
+ struct atmel_ac97 *chip = get_chip(card);
+ struct resource *regs;
+ struct clk *mck;
+ int err;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+
+ mck = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(mck))
+ return PTR_ERR(mck);
+ clk_enable(mck);
+ chip->mck = mck;
+
+ card->private_free = snd_atmel_ac97_destroy;
+
+ spin_lock_init(&chip->lock);
+ chip->card = card;
+ chip->pdev = pdev;
+
+ chip->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!chip->regs)
+ return -ENOMEM;
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
+
+ return err;
+}
+
+static int __devinit snd_atmel_ac97_probe(struct platform_device *pdev)
+{
+ static int dev;
+ struct snd_card *card;
+ struct atmel_ac97 *chip;
+ int err;
+ int ch;
+
+ mutex_init(&opened_mutex);
+
+ err = -ENOMEM;
+ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct atmel_ac97));
+ if (!card)
+ goto out;
+ chip = get_chip(card);
+
+ err = snd_atmel_ac97_create(card, pdev);
+ if (err)
+ goto out_free_card;
+
+ snd_atmel_ac97_reset(chip);
+
+ err = snd_atmel_ac97_mixer_new(chip);
+ if (err)
+ goto out_free_card;
+
+ err = snd_atmel_ac97_pcm_new(chip);
+ if (err)
+ goto out_free_card;
+
+ /* TODO: Get this information from the platform device */
+ chip->dma.req_tx.req.dmac = find_dma_controller(0);
+ if (!chip->dma.req_tx.req.dmac) {
+ dev_dbg(&chip->pdev->dev, "DMA controller for TX missing\n");
+ err = -ENODEV;
+ goto out_free_card;
+ }
+ chip->dma.req_rx.req.dmac = find_dma_controller(0);
+ if (!chip->dma.req_rx.req.dmac) {
+ dev_dbg(&chip->pdev->dev, "DMA controller for RX missing\n");
+ err = -ENODEV;
+ goto out_free_card;
+ }
+
+ chip->dma.rx_periph_id = 3;
+ chip->dma.tx_periph_id = 4;
+
+ ch = dma_alloc_channel(chip->dma.req_tx.req.dmac);
+ if (ch < 0) {
+ dev_dbg(&chip->pdev->dev,
+ "could not allocate TX DMA channel\n");
+ err = ch;
+ goto out_free_card;
+ }
+ chip->dma.req_tx.req.channel = ch;
+ chip->dma.req_tx.width = DMA_WIDTH_16BIT;
+ chip->dma.req_tx.req.block_complete = atmel_ac97_block_complete;
+ chip->dma.req_tx.req.error = atmel_ac97_error;
+
+ ch = dma_alloc_channel(chip->dma.req_rx.req.dmac);
+ if (ch < 0) {
+ dev_dbg(&chip->pdev->dev,
+ "could not allocate RX DMA channel\n");
+ err = ch;
+ goto out_free_card;
+ }
+ chip->dma.req_rx.req.channel = ch;
+ chip->dma.req_rx.width = DMA_WIDTH_16BIT;
+ chip->dma.req_rx.req.block_complete = atmel_ac97_block_complete;
+ chip->dma.req_rx.req.error = atmel_ac97_error;
+
+ strcpy(card->driver, "atmel_ac97c");
+ strcpy(card->shortname, "atmel_ac97c");
+ sprintf(card->longname, "Atmel AVR32 AC97 controller");
+
+ err = snd_card_register(card);
+ if (err)
+ goto out_free_card;
+
+ platform_set_drvdata(pdev, card);
+ dev++;
+
+ dev_info(&pdev->dev, "Atmel AVR32 AC97 controller at 0x%p\n",
+ chip->regs);
+
+ return 0;
+
+out_free_card:
+ snd_card_free(card);
+out:
+ return err;
+}
+
+#ifdef CONFIG_PM
+ static int
+snd_atmel_ac97_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_ac97 *chip = card->private_data;
+
+ clk_disable(chip->mck);
+
+ return 0;
+}
+
+static int snd_atmel_ac97_resume(struct platform_device *pdev)
+{
+ struct snd_card *card = dev_get_drvdata(pdev);
+ struct atmel_ac97 *chip = card->private_data;
+
+ clk_enable(chip->mck);
+
+ return 0;
+}
+#else
+#define snd_atmel_ac97_suspend NULL
+#define snd_atmel_ac97_resume NULL
+#endif
+
+static int __devexit snd_atmel_ac97_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ snd_card_free(card);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver atmel_ac97_driver = {
+ .remove = __devexit_p(snd_atmel_ac97_remove),
+ .driver = {
+ .name = "atmel_ac97c",
+ },
+ .suspend = snd_atmel_ac97_suspend,
+ .resume = snd_atmel_ac97_resume,
+};
+
+static int __init atmel_ac97_init(void)
+{
+ return platform_driver_probe(&atmel_ac97_driver,
+ snd_atmel_ac97_probe);
+}
+module_init(atmel_ac97_init);
+
+static void __exit atmel_ac97_exit(void)
+{
+ platform_driver_unregister(&atmel_ac97_driver);
+}
+module_exit(atmel_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel AC97 Controller");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
diff --git a/sound/avr32/ac97c.h b/sound/avr32/ac97c.h
new file mode 100644
index 0000000..96246e7
--- /dev/null
+++ b/sound/avr32/ac97c.h
@@ -0,0 +1,71 @@
+/*
+ * Register definitions for the Atmel AC97 Controller.
+ *
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __SOUND_AVR32_AC97C_H
+#define __SOUND_AVR32_AC97C_H
+
+#define AC97C_MR 0x08
+#define AC97C_ICA 0x10
+#define AC97C_OCA 0x14
+#define AC97C_CARHR 0x20
+#define AC97C_CATHR 0x24
+#define AC97C_CASR 0x28
+#define AC97C_CAMR 0x2c
+#define AC97C_CBRHR 0x30
+#define AC97C_CBTHR 0x34
+#define AC97C_CBSR 0x38
+#define AC97C_CBMR 0x3c
+#define AC97C_CORHR 0x40
+#define AC97C_COTHR 0x44
+#define AC97C_COSR 0x48
+#define AC97C_COMR 0x4c
+#define AC97C_SR 0x50
+#define AC97C_IER 0x54
+#define AC97C_IDR 0x58
+#define AC97C_IMR 0x5c
+#define AC97C_VERSION 0xfc
+
+#define AC97C_CATPR PDC_TPR
+#define AC97C_CATCR PDC_TCR
+#define AC97C_CATNPR PDC_TNPR
+#define AC97C_CATNCR PDC_TNCR
+#define AC97C_CARPR PDC_RPR
+#define AC97C_CARCR PDC_RCR
+#define AC97C_CARNPR PDC_RNPR
+#define AC97C_CARNCR PDC_RNCR
+#define AC97C_PTCR PDC_PTCR
+
+#define AC97C_MR_ENA (1 << 0)
+#define AC97C_MR_WRST (1 << 1)
+#define AC97C_MR_VRA (1 << 2)
+
+#define AC97C_CSR_TXRDY (1 << 0)
+#define AC97C_CSR_UNRUN (1 << 2)
+#define AC97C_CSR_RXRDY (1 << 4)
+#define AC97C_CSR_ENDTX (1 << 10)
+#define AC97C_CSR_ENDRX (1 << 14)
+
+#define AC97C_CMR_SIZE_20 (0 << 16)
+#define AC97C_CMR_SIZE_18 (1 << 16)
+#define AC97C_CMR_SIZE_16 (2 << 16)
+#define AC97C_CMR_SIZE_10 (3 << 16)
+#define AC97C_CMR_CEM_LITTLE (1 << 18)
+#define AC97C_CMR_CEM_BIG (0 << 18)
+#define AC97C_CMR_CENA (1 << 21)
+#define AC97C_CMR_PDCEN (1 << 22)
+
+#define AC97C_SR_CAEVT (1 << 3)
+
+#define AC97C_CH_ASSIGN(slot, channel) \
+ (AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
+#define AC97C_CHANNEL_NONE 0x0
+#define AC97C_CHANNEL_A 0x1
+#define AC97C_CHANNEL_B 0x2
+
+#endif /* __SOUND_AVR32_AC97C_H */
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 857008b..db69a17 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -654,3 +654,7 @@ config SOUND_SH_DAC_AUDIO_CHANNEL
int "DAC channel"
default "1"
depends on SOUND_SH_DAC_AUDIO
+
+config SOUND_AT32_ABDAC
+ tristate "Atmel AT32 Audio Bitstream DAC (ABDAC) support"
+ depends on SOUND_PRIME && AVR32
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index f883c4b..a41853b 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
# Please leave it as is, cause the link order is significant !
+obj-$(CONFIG_SOUND_AT32_ABDAC) += at32_abdac.o
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
obj-$(CONFIG_SOUND_HAL2) += hal2.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
diff --git a/sound/oss/at32_abdac.c b/sound/oss/at32_abdac.c
new file mode 100644
index 0000000..cb997d7
--- /dev/null
+++ b/sound/oss/at32_abdac.c
@@ -0,0 +1,722 @@
+/*
+ * OSS Sound Driver for the Atmel AT32 on-chip DAC.
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+
+#include <asm/byteorder.h>
+#include <asm/dma-controller.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/* We want to use the "bizarre" swap-bytes-in-each-halfword macro */
+#include <linux/byteorder/swabb.h>
+
+#include "at32_abdac.h"
+
+#define DMA_BUFFER_SIZE 32768
+#define DMA_PERIOD_SHIFT 10
+#define DMA_PERIOD_SIZE (1 << DMA_PERIOD_SHIFT)
+#define DMA_WRITE_THRESHOLD DMA_PERIOD_SIZE
+
+struct sound_settings {
+ unsigned int format;
+ unsigned int channels;
+ unsigned int sample_rate;
+ /* log2(bytes per sample) */
+ unsigned int input_order;
+};
+
+struct at32_dac {
+ spinlock_t lock;
+ void __iomem *regs;
+
+ /* head and tail refer to number of words */
+ struct {
+ u32 *buf;
+ int head;
+ int tail;
+ } dma;
+
+ struct semaphore sem;
+ wait_queue_head_t write_wait;
+
+ /*
+ * Read at most ucount bytes from ubuf, translate to 2-channel
+ * signed 16-bit big endian format and write to the DMA buffer
+ * as long as there is room left. Return the number of bytes
+ * successfully copied from ubuf, or -EFAULT if the first
+ * sample from ubuf couldn't be read. This function is not
+ * called unless there is room for at least one sample (4
+ * bytes) in the DMA buffer.
+ */
+ ssize_t (*trans)(struct at32_dac *dac, const char __user *ubuf,
+ size_t ucount);
+
+ struct sound_settings dsp_settings;
+ struct dma_request_cyclic req;
+
+ struct clk *mck;
+ struct clk *sample_clk;
+ struct platform_device *pdev;
+ int busy;
+ int playing;
+ int dev_dsp;
+};
+static struct at32_dac *the_dac;
+
+static inline unsigned int abdac_get_head(struct at32_dac *dac)
+{
+ return dac->dma.head & ((DMA_BUFFER_SIZE / 4) - 1);
+}
+
+static inline unsigned int abdac_get_tail(struct at32_dac *dac)
+{
+ return dac->dma.tail & ((DMA_BUFFER_SIZE / 4) - 1);
+}
+
+static inline unsigned int abdac_dma_space(struct at32_dac *dac)
+{
+ unsigned int space;
+
+ space = ((dac->dma.tail - dac->dma.head - 1)
+ & ((DMA_BUFFER_SIZE / 4) - 1));
+ return space;
+}
+
+static void abdac_update_dma_tail(struct at32_dac *dac)
+{
+ dma_addr_t dma_addr;
+ unsigned int new_tail;
+
+ if (dac->playing) {
+ dma_addr = dma_get_current_pos(dac->req.req.dmac,
+ dac->req.req.channel);
+ new_tail = (dma_addr - dac->req.buffer_start) / 4;
+ if (new_tail >= dac->dma.head
+ && (dac->dma.tail < dac->dma.head
+ || dac->dma.tail > new_tail))
+ dev_notice(&dac->pdev->dev, "DMA underrun detected!\n");
+ dac->dma.tail = new_tail;
+ dev_dbg(&dac->pdev->dev, "update tail: 0x%x - 0x%x = %u\n",
+ dma_addr, dac->req.buffer_start, dac->dma.tail);
+ }
+}
+
+static int abdac_start(struct at32_dac *dac)
+{
+ int ret;
+
+ if (dac->playing)
+ return 0;
+
+ memset(dac->dma.buf, 0, DMA_BUFFER_SIZE);
+
+ clk_enable(dac->sample_clk);
+
+ ret = dma_prepare_request_cyclic(dac->req.req.dmac, &dac->req);
+ if (ret)
+ goto out_stop_clock;
+
+ dev_dbg(&dac->pdev->dev, "starting DMA...\n");
+ ret = dma_start_request(dac->req.req.dmac, dac->req.req.channel);
+ if (ret)
+ goto out_stop_request;
+
+ dac_writel(dac, CTRL, DAC_BIT(EN));
+ dac->playing = 1;
+
+ return 0;
+
+out_stop_request:
+ dma_stop_request(dac->req.req.dmac,
+ dac->req.req.channel);
+out_stop_clock:
+ clk_disable(dac->sample_clk);
+ return ret;
+}
+
+static int abdac_stop(struct at32_dac *dac)
+{
+ if (dac->playing) {
+ dma_stop_request(dac->req.req.dmac, dac->req.req.channel);
+ dac_writel(dac, DATA, 0);
+ dac_writel(dac, CTRL, 0);
+ dac->playing = 0;
+ clk_disable(dac->sample_clk);
+ }
+
+ return 0;
+}
+
+static int abdac_dma_prepare(struct at32_dac *dac)
+{
+ dac->dma.buf = dma_alloc_coherent(&dac->pdev->dev, DMA_BUFFER_SIZE,
+ &dac->req.buffer_start, GFP_KERNEL);
+ if (!dac->dma.buf)
+ return -ENOMEM;
+
+ dac->dma.head = dac->dma.tail = 0;
+ dac->req.periods = DMA_BUFFER_SIZE / DMA_PERIOD_SIZE;
+ dac->req.buffer_size = DMA_BUFFER_SIZE;
+
+ return 0;
+}
+
+static void abdac_dma_cleanup(struct at32_dac *dac)
+{
+ if (dac->dma.buf)
+ dma_free_coherent(&dac->pdev->dev, DMA_BUFFER_SIZE,
+ dac->dma.buf, dac->req.buffer_start);
+ dac->dma.buf = NULL;
+}
+
+static void abdac_dma_block_complete(struct dma_request *req)
+{
+ struct dma_request_cyclic *creq = to_dma_request_cyclic(req);
+ struct at32_dac *dac = container_of(creq, struct at32_dac, req);
+
+ wake_up(&dac->write_wait);
+}
+
+static void abdac_dma_error(struct dma_request *req)
+{
+ struct dma_request_cyclic *creq = to_dma_request_cyclic(req);
+ struct at32_dac *dac = container_of(creq, struct at32_dac, req);
+
+ dev_err(&dac->pdev->dev, "DMA error\n");
+}
+
+static irqreturn_t abdac_interrupt(int irq, void *dev_id)
+{
+ struct at32_dac *dac = dev_id;
+ u32 status;
+
+ status = dac_readl(dac, INT_STATUS);
+ if (status & DAC_BIT(UNDERRUN)) {
+ dev_err(&dac->pdev->dev, "Underrun detected!\n");
+ dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN));
+ } else {
+ dev_err(&dac->pdev->dev, "Spurious interrupt (status=0x%x)\n",
+ status);
+ dac_writel(dac, INT_CLR, status);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t trans_s16be(struct at32_dac *dac, const char __user *ubuf,
+ size_t ucount)
+{
+ ssize_t ret;
+
+ if (dac->dsp_settings.channels == 2) {
+ const u32 __user *up = (const u32 __user *)ubuf;
+ u32 sample;
+
+ for (ret = 0; ret < (ssize_t)(ucount - 3); ret += 4) {
+ if (!abdac_dma_space(dac))
+ break;
+
+ if (unlikely(__get_user(sample, up++))) {
+ if (ret == 0)
+ ret = -EFAULT;
+ break;
+ }
+ dac->dma.buf[abdac_get_head(dac)] = sample;
+ dac->dma.head++;
+ }
+ } else {
+ const u16 __user *up = (const u16 __user *)ubuf;
+ u16 sample;
+
+ for (ret = 0; ret < (ssize_t)(ucount - 1); ret += 2) {
+ if (!abdac_dma_space(dac))
+ break;
+
+ if (unlikely(__get_user(sample, up++))) {
+ if (ret == 0)
+ ret = -EFAULT;
+ break;
+ }
+ dac->dma.buf[abdac_get_head(dac)]
+ = (sample << 16) | sample;
+ dac->dma.head++;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t trans_s16le(struct at32_dac *dac, const char __user *ubuf,
+ size_t ucount)
+{
+ ssize_t ret;
+
+ if (dac->dsp_settings.channels == 2) {
+ const u32 __user *up = (const u32 __user *)ubuf;
+ u32 sample;
+
+ for (ret = 0; ret < (ssize_t)(ucount - 3); ret += 4) {
+ if (!abdac_dma_space(dac))
+ break;
+
+ if (unlikely(__get_user(sample, up++))) {
+ if (ret == 0)
+ ret = -EFAULT;
+ break;
+ }
+ /* Swap bytes in each halfword */
+ dac->dma.buf[abdac_get_head(dac)] = swahb32(sample);
+ dac->dma.head++;
+ }
+ } else {
+ const u16 __user *up = (const u16 __user *)ubuf;
+ u16 sample;
+
+ for (ret = 0; ret < (ssize_t)(ucount - 1); ret += 2) {
+ if (!abdac_dma_space(dac))
+ break;
+
+ if (unlikely(__get_user(sample, up++))) {
+ if (ret == 0)
+ ret = -EFAULT;
+ break;
+ }
+ sample = swab16(sample);
+ dac->dma.buf[abdac_get_head(dac)]
+ = (sample << 16) | sample;
+ dac->dma.head++;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t abdac_dma_translate_from_user(struct at32_dac *dac,
+ const char __user *buffer,
+ size_t count)
+{
+ /* At least one buffer must be available at this point */
+ dev_dbg(&dac->pdev->dev, "copying %zu bytes from user...\n", count);
+
+ return dac->trans(dac, buffer, count);
+}
+
+static int abdac_set_format(struct at32_dac *dac, int format)
+{
+ unsigned int order;
+
+ switch (format) {
+ case AFMT_S16_BE:
+ order = 1;
+ dac->trans = trans_s16be;
+ break;
+ case AFMT_S16_LE:
+ order = 1;
+ dac->trans = trans_s16le;
+ break;
+ default:
+ dev_dbg(&dac->pdev->dev, "unsupported format: %d\n", format);
+ return -EINVAL;
+ }
+
+ if (dac->dsp_settings.channels == 2)
+ order++;
+
+ dac->dsp_settings.input_order = order;
+ dac->dsp_settings.format = format;
+ return 0;
+}
+
+static int abdac_set_sample_rate(struct at32_dac *dac, unsigned long rate)
+{
+ unsigned long new_rate;
+ int ret;
+
+ ret = clk_set_rate(dac->sample_clk, 256 * rate);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: mplayer seems to have a problem with this */
+#if 0
+ new_rate = clk_get_rate(dac->sample_clk);
+ dac->dsp_settings.sample_rate = new_rate / 256;
+#else
+ dac->dsp_settings.sample_rate = rate;
+#endif
+
+ return 0;
+}
+
+static ssize_t abdac_dsp_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct at32_dac *dac = file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned int avail;
+ ssize_t copied;
+ ssize_t ret;
+
+ /* Avoid address space checking in the translation functions */
+ if (!access_ok(buffer, count, VERIFY_READ))
+ return -EFAULT;
+
+ down(&dac->sem);
+
+ if (!dac->dma.buf) {
+ ret = abdac_dma_prepare(dac);
+ if (ret)
+ goto out;
+ }
+
+ add_wait_queue(&dac->write_wait, &wait);
+ ret = 0;
+ while (count > 0) {
+ do {
+ abdac_update_dma_tail(dac);
+ avail = abdac_dma_space(dac);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (avail >= DMA_WRITE_THRESHOLD)
+ break;
+
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ pr_debug("Going to wait (avail = %u, count = %zu)\n",
+ avail, count);
+
+ up(&dac->sem);
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ goto out_nosem;
+ }
+ down(&dac->sem);
+ } while (1);
+
+ copied = abdac_dma_translate_from_user(dac, buffer, count);
+ if (copied < 0) {
+ if (!ret)
+ ret = -EFAULT;
+ goto out;
+ }
+
+ abdac_start(dac);
+
+ count -= copied;
+ ret += copied;
+ }
+
+out:
+ up(&dac->sem);
+out_nosem:
+ remove_wait_queue(&dac->write_wait, &wait);
+ set_current_state(TASK_RUNNING);
+ return ret;
+}
+
+static int abdac_dsp_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct at32_dac *dac = file->private_data;
+ int __user *up = (int __user *)arg;
+ struct audio_buf_info abinfo;
+ int val, ret;
+
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, up);
+
+ case SNDCTL_DSP_SPEED:
+ if (get_user(val, up))
+ return -EFAULT;
+ if (val >= 0) {
+ abdac_stop(dac);
+ ret = abdac_set_sample_rate(dac, val);
+ if (ret)
+ return ret;
+ }
+ return put_user(dac->dsp_settings.sample_rate, up);
+
+ case SNDCTL_DSP_STEREO:
+ if (get_user(val, up))
+ return -EFAULT;
+ abdac_stop(dac);
+ if (val && dac->dsp_settings.channels == 1)
+ dac->dsp_settings.input_order++;
+ else if (!val && dac->dsp_settings.channels != 1)
+ dac->dsp_settings.input_order--;
+ dac->dsp_settings.channels = val ? 2 : 1;
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, up))
+ return -EFAULT;
+
+ if (val) {
+ if (val < 0 || val > 2)
+ return -EINVAL;
+
+ abdac_stop(dac);
+ dac->dsp_settings.input_order
+ += val - dac->dsp_settings.channels;
+ dac->dsp_settings.channels = val;
+ }
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS:
+ return put_user(AFMT_S16_BE | AFMT_S16_BE, up);
+
+ case SNDCTL_DSP_SETFMT:
+ if (get_user(val, up))
+ return -EFAULT;
+
+ if (val == AFMT_QUERY) {
+ val = dac->dsp_settings.format;
+ } else {
+ ret = abdac_set_format(dac, val);
+ if (ret)
+ return ret;
+ }
+ return put_user(val, up);
+
+ case SNDCTL_DSP_GETOSPACE:
+ abdac_update_dma_tail(dac);
+ abinfo.fragsize = ((1 << dac->dsp_settings.input_order)
+ * (DMA_PERIOD_SIZE / 4));
+ abinfo.bytes = (abdac_dma_space(dac)
+ << dac->dsp_settings.input_order);
+ abinfo.fragstotal = ((DMA_BUFFER_SIZE * 4)
+ >> (DMA_PERIOD_SHIFT
+ + dac->dsp_settings.input_order));
+ abinfo.fragments = ((abinfo.bytes
+ >> dac->dsp_settings.input_order)
+ / (DMA_PERIOD_SIZE / 4));
+ pr_debug("fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
+ abinfo.fragments, abinfo.fragstotal, abinfo.fragsize,
+ abinfo.bytes);
+ return copy_to_user(up, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ default:
+ dev_dbg(&dac->pdev->dev, "Unimplemented ioctl cmd: 0x%x\n", cmd);
+ return -EINVAL;
+ }
+}
+
+static int abdac_dsp_open(struct inode *inode, struct file *file)
+{
+ struct at32_dac *dac = the_dac;
+ int ret;
+
+ if (file->f_mode & FMODE_READ)
+ return -ENXIO;
+
+ down(&dac->sem);
+ ret = -EBUSY;
+ if (dac->busy)
+ goto out;
+
+ dac->dma.head = dac->dma.tail = 0;
+
+ /* FIXME: What are the correct defaults? */
+ dac->dsp_settings.channels = 2;
+ abdac_set_format(dac, AFMT_S16_BE);
+ ret = abdac_set_sample_rate(dac, 8000);
+ if (ret)
+ goto out;
+
+ file->private_data = dac;
+ dac->busy = 1;
+
+ ret = 0;
+
+out:
+ up(&dac->sem);
+ return ret;
+}
+
+static int abdac_dsp_release(struct inode *inode, struct file *file)
+{
+ struct at32_dac *dac = file->private_data;
+
+ down(&dac->sem);
+
+ abdac_stop(dac);
+ abdac_dma_cleanup(dac);
+ dac->busy = 0;
+
+ up(&dac->sem);
+
+ return 0;
+}
+
+static struct file_operations abdac_dsp_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = abdac_dsp_write,
+ .ioctl = abdac_dsp_ioctl,
+ .open = abdac_dsp_open,
+ .release = abdac_dsp_release,
+};
+
+static int __init abdac_probe(struct platform_device *pdev)
+{
+ struct at32_dac *dac;
+ struct resource *regs;
+ struct clk *mck;
+ struct clk *sample_clk;
+ int irq;
+ int ret;
+
+ if (the_dac)
+ return -EBUSY;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ mck = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(mck))
+ return PTR_ERR(mck);
+ sample_clk = clk_get(&pdev->dev, "sample_clk");
+ if (IS_ERR(sample_clk)) {
+ ret = PTR_ERR(sample_clk);
+ goto out_put_mck;
+ }
+ clk_enable(mck);
+
+ ret = -ENOMEM;
+ dac = kzalloc(sizeof(struct at32_dac), GFP_KERNEL);
+ if (!dac)
+ goto out_disable_clk;
+
+ spin_lock_init(&dac->lock);
+ init_MUTEX(&dac->sem);
+ init_waitqueue_head(&dac->write_wait);
+ dac->pdev = pdev;
+ dac->mck = mck;
+ dac->sample_clk = sample_clk;
+
+ dac->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!dac->regs)
+ goto out_free_dac;
+
+ ret = request_irq(irq, abdac_interrupt, 0, "dac", dac);
+ if (ret)
+ goto out_unmap_regs;
+
+ /* FIXME */
+ dac->req.req.dmac = find_dma_controller(0);
+ if (!dac->req.req.dmac)
+ goto out_free_irq;
+
+ ret = dma_alloc_channel(dac->req.req.dmac);
+ if (ret < 0)
+ goto out_free_irq;
+
+ dac->req.req.channel = ret;
+ dac->req.req.block_complete = abdac_dma_block_complete;
+ dac->req.req.error = abdac_dma_error;
+ dac->req.data_reg = regs->start + DAC_DATA;
+ dac->req.periph_id = 2; /* FIXME */
+ dac->req.direction = DMA_DIR_MEM_TO_PERIPH;
+ dac->req.width = DMA_WIDTH_32BIT;
+
+ /* Make sure the DAC is silent and disabled */
+ dac_writel(dac, DATA, 0);
+ dac_writel(dac, CTRL, 0);
+
+ ret = register_sound_dsp(&abdac_dsp_fops, -1);
+ if (ret < 0)
+ goto out_free_dma;
+ dac->dev_dsp = ret;
+
+ /* TODO: Register mixer */
+
+ the_dac = dac;
+ platform_set_drvdata(pdev, dac);
+
+ return 0;
+
+out_free_dma:
+ dma_release_channel(dac->req.req.dmac, dac->req.req.channel);
+out_free_irq:
+ free_irq(irq, dac);
+out_unmap_regs:
+ iounmap(dac->regs);
+out_free_dac:
+ kfree(dac);
+out_disable_clk:
+ clk_disable(mck);
+ clk_put(sample_clk);
+out_put_mck:
+ clk_put(mck);
+ return ret;
+}
+
+static int __exit abdac_remove(struct platform_device *pdev)
+{
+ struct at32_dac *dac;
+
+ dac = platform_get_drvdata(pdev);
+ if (dac) {
+ unregister_sound_dsp(dac->dev_dsp);
+ dma_release_channel(dac->req.req.dmac, dac->req.req.channel);
+ free_irq(platform_get_irq(pdev, 0), dac);
+ iounmap(dac->regs);
+ clk_disable(dac->mck);
+ clk_put(dac->sample_clk);
+ clk_put(dac->mck);
+ kfree(dac);
+ platform_set_drvdata(pdev, NULL);
+ the_dac = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver abdac_driver = {
+ .remove = __exit_p(abdac_remove),
+ .driver = {
+ .name = "abdac",
+ },
+};
+
+static int __init abdac_init(void)
+{
+ return platform_driver_probe(&abdac_driver, abdac_probe);
+}
+module_init(abdac_init);
+
+static void __exit abdac_exit(void)
+{
+ platform_driver_unregister(&abdac_driver);
+}
+module_exit(abdac_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Sound Driver for the Atmel AT32 ABDAC");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/at32_abdac.h b/sound/oss/at32_abdac.h
new file mode 100644
index 0000000..3c88e25
--- /dev/null
+++ b/sound/oss/at32_abdac.h
@@ -0,0 +1,59 @@
+/*
+ * Register definitions for the Atmel AT32 on-chip DAC.
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __SOUND_OSS_AT32_ABDAC_H__
+#define __SOUND_OSS_AT32_ABDAC_H__
+
+/* DAC register offsets */
+#define DAC_DATA 0x0000
+#define DAC_CTRL 0x0008
+#define DAC_INT_MASK 0x000c
+#define DAC_INT_EN 0x0010
+#define DAC_INT_DIS 0x0014
+#define DAC_INT_CLR 0x0018
+#define DAC_INT_STATUS 0x001c
+#define DAC_PDC_DATA 0x0020
+
+/* Bitfields in CTRL */
+#define DAC_SWAP_OFFSET 30
+#define DAC_SWAP_SIZE 1
+#define DAC_EN_OFFSET 31
+#define DAC_EN_SIZE 1
+
+/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */
+#define DAC_UNDERRUN_OFFSET 28
+#define DAC_UNDERRUN_SIZE 1
+#define DAC_TX_READY_OFFSET 29
+#define DAC_TX_READY_SIZE 1
+#define DAC_TX_BUFFER_EMPTY_OFFSET 30
+#define DAC_TX_BUFFER_EMPTY_SIZE 1
+#define DAC_CHANNEL_TX_END_OFFSET 31
+#define DAC_CHANNEL_TX_END_SIZE 1
+
+/* Bit manipulation macros */
+#define DAC_BIT(name) \
+ (1 << DAC_##name##_OFFSET)
+#define DAC_BF(name, value) \
+ (((value) & ((1 << DAC_##name##_SIZE) - 1)) \
+ << DAC_##name##_OFFSET)
+#define DAC_BFEXT(name, value) \
+ (((value) >> DAC_##name##_OFFSET) \
+ & ((1 << DAC_##name##_SIZE) - 1))
+#define DAC_BFINS(name, value, old) \
+ (((old) & ~(((1 << DAC_##name##_SIZE) - 1) \
+ << DAC_##name##_OFFSET)) \
+ | DAC_BF(name,value))
+
+/* Register access macros */
+#define dac_readl(port, reg) \
+ __raw_readl((port)->regs + DAC_##reg)
+#define dac_writel(port, reg, value) \
+ __raw_writel((value), (port)->regs + DAC_##reg)
+
+#endif /* __SOUND_OSS_AT32_ABDAC_H__ */