--- a/Documentation/serial/driver +++ b/Documentation/serial/driver @@ -186,6 +186,17 @@ Locking: port_sem taken. Interrupts: caller dependent. + flush_buffer(port) + Flush any write buffers, reset any DMA state and stop any + ongoing DMA transfers. + + This will be called whenever the port->info->xmit circular + buffer is cleared. + + Locking: port->lock taken. + Interrupts: locally disabled. + This call must not sleep + set_termios(port,termios,oldtermios) Change the port parameters, including word length, parity, stop bits. Update read_status_mask and ignore_status_mask to indicate --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -47,6 +47,9 @@ config GENERIC_TIME def_bool y +config GENERIC_CLOCKEVENTS + def_bool y + config RWSEM_XCHGADD_ALGORITHM def_bool n @@ -70,6 +73,8 @@ menu "System Type and features" +source "kernel/time/Kconfig" + config SUBARCH_AVR32B bool config MMU @@ -83,6 +88,7 @@ select MMU select PERFORMANCE_COUNTERS select HAVE_GPIO_LIB + select GENERIC_ALLOCATOR # # CPU types @@ -117,6 +123,9 @@ 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" @@ -142,6 +151,9 @@ source "kernel/Kconfig.preempt" +config QUICKLIST + def_bool y + config HAVE_ARCH_BOOTMEM_NODE def_bool n @@ -180,6 +192,10 @@ 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" @@ -196,6 +212,11 @@ menu "Power management options" +config ARCH_SUSPEND_POSSIBLE + def_bool y + +source "kernel/power/Kconfig" + menu "CPU Frequency scaling" source "drivers/cpufreq/Kconfig" --- a/arch/avr32/Makefile +++ b/arch/avr32/Makefile @@ -32,6 +32,7 @@ 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 --- /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. --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -25,6 +25,13 @@ #include <asm/arch/init.h> #include <asm/arch/portmux.h> +/* Oscillator frequencies. These are board-specific */ +unsigned long at32_board_osc_rates[3] = { + [0] = 32768, /* 32.768 kHz on RTC osc */ + [1] = 20000000, /* 20 MHz on osc0 */ + [2] = 12000000, /* 12 MHz on osc1 */ +}; + /* Initialized by bootloader-specific startup code. */ struct tag *bootloader_tags __initdata; @@ -37,11 +44,16 @@ static struct spi_board_info spi0_board_info[] __initdata = { { .modalias = "mtd_dataflash", - .max_speed_hz = 10000000, + .max_speed_hz = 8000000, .chip_select = 0, }, }; +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 +136,7 @@ } }; +#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 +152,7 @@ .platform_data = &i2c_gpio_data, }, }; +#endif static int __init atngw100_init(void) { @@ -157,6 +171,7 @@ set_hw_addr(at32_add_device_eth(1, ð_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 +180,15 @@ } 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, NULL, 0); +#endif return 0; } --- a/arch/avr32/boards/atstk1000/Kconfig +++ b/arch/avr32/boards/atstk1000/Kconfig @@ -18,6 +18,10 @@ bool "ATSTK1004" select CPU_AT32AP7002 +config BOARD_ATSTK1006 + bool "ATSTK1006" + select CPU_AT32AP7000 + endchoice @@ -102,4 +106,60 @@ 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. + +config BOARD_ATSTK100X_ENABLE_PSIF + bool "Enable PSIF peripheral (PS/2 support)" + default n + help + Select this if you want to use the PSIF peripheral to hook up PS/2 + devices to your STK1000. This will require a hardware modification to + work correctly, since PS/2 devices require 5 volt power and signals, + while the STK1000 only provides 3.3 volt. + + Say N if you have not modified the hardware to boost the voltage, say + Y if you have level convertion hardware or a PS/2 device capable of + operating on 3.3 volt. + endif # stk 1000 --- a/arch/avr32/boards/atstk1000/Makefile +++ b/arch/avr32/boards/atstk1000/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_BOARD_ATSTK1002) += atstk1002.o obj-$(CONFIG_BOARD_ATSTK1003) += atstk1003.o obj-$(CONFIG_BOARD_ATSTK1004) += atstk1004.o +obj-$(CONFIG_BOARD_ATSTK1006) += atstk1002.o --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -1,7 +1,7 @@ /* - * ATSTK1002 daughterboard-specific init code + * ATSTK1002/ATSTK1006 daughterboard-specific init code * - * Copyright (C) 2005-2006 Atmel Corporation + * 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 @@ -28,6 +28,80 @@ #include "atstk1000.h" +/* Oscillator frequencies. These are board specific */ +unsigned long at32_board_osc_rates[3] = { + [0] = 32768, /* 32.768 kHz on RTC osc */ + [1] = 20000000, /* 20 MHz on osc0 */ + [2] = 12000000, /* 12 MHz on osc1 */ +}; + +/* + * The ATSTK1006 daughterboard is very similar to the ATSTK1002. Both + * have the AT32AP7000 chip on board; the difference is that the + * STK1006 has 128 MB SDRAM (the STK1002 uses the 8 MB SDRAM chip on + * the STK1000 motherboard) and 256 MB NAND flash (the STK1002 has + * none.) + * + * The RAM difference is handled by the boot loader, so the only + * difference we end up handling here is the NAND flash. + */ +#ifdef CONFIG_BOARD_ATSTK1006 +#include <linux/mtd/partitions.h> +#include <asm/arch/smc.h> + +static struct smc_timing nand_timing __initdata = { + .ncs_read_setup = 0, + .nrd_setup = 10, + .ncs_write_setup = 0, + .nwe_setup = 10, + + .ncs_read_pulse = 30, + .nrd_pulse = 15, + .ncs_write_pulse = 30, + .nwe_pulse = 15, + + .read_cycle = 30, + .write_cycle = 30, + + .ncs_read_recover = 0, + .nrd_recover = 15, + .ncs_write_recover = 0, + /* WE# high -> RE# low min 60 ns */ + .nwe_recover = 50, +}; + +static struct smc_config nand_config __initdata = { + .bus_width = 1, + .nrd_controlled = 1, + .nwe_controlled = 1, + .nwait_mode = 0, + .byte_write = 0, + .tdf_cycles = 2, + .tdf_mode = 0, +}; + +static struct mtd_partition nand_partitions[] = { + { + .name = "main", + .offset = 0x00000000, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct mtd_partition *nand_part_info(int size, int *num_partitions) +{ + *num_partitions = ARRAY_SIZE(nand_partitions); + return nand_partitions; +} + +static struct atmel_nand_data atstk1006_nand_data __initdata = { + .cle = 21, + .ale = 22, + .rdy_pin = GPIO_PIN_PB(30), + .enable_pin = GPIO_PIN_PB(29), + .partition_info = nand_part_info, +}; +#endif struct eth_addr { u8 addr[6]; @@ -83,6 +157,19 @@ } }; #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 @@ -212,6 +299,12 @@ at32_add_system_devices(); +#ifdef CONFIG_BOARD_ATSTK1006 + smc_set_timing(&nand_config, &nand_timing); + smc_set_configuration(3, &nand_config); + at32_add_device_nand(0, &atstk1006_nand_data); +#endif + #ifdef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM at32_add_device_usart(1); #else @@ -228,16 +321,30 @@ #ifdef CONFIG_BOARD_ATSTK100X_SPI1 at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); #endif + at32_add_device_twi(0, NULL, 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, ð_data[1])); #else at32_add_device_lcdc(0, &atstk1000_lcdc_data, - fbmem_start, fbmem_size); + fbmem_start, fbmem_size, 0); #endif at32_add_device_usba(0, NULL); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97 + at32_add_device_ac97c(0, NULL); +#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); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF + at32_add_device_psif(0); + at32_add_device_psif(1); +#endif atstk1000_setup_j2_leds(); atstk1002_setup_extdac(); --- a/arch/avr32/boards/atstk1000/atstk1003.c +++ b/arch/avr32/boards/atstk1000/atstk1003.c @@ -27,6 +27,13 @@ #include "atstk1000.h" +/* Oscillator frequencies. These are board specific */ +unsigned long at32_board_osc_rates[3] = { + [0] = 32768, /* 32.768 kHz on RTC osc */ + [1] = 20000000, /* 20 MHz on osc0 */ + [2] = 12000000, /* 12 MHz on osc1 */ +}; + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC static struct at73c213_board_info at73c213_data = { .ssc_id = 0, @@ -59,6 +66,19 @@ } }; #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) { @@ -147,12 +167,22 @@ 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); + at32_add_device_mci(0, NULL); #endif at32_add_device_usba(0, NULL); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97 + at32_add_device_ac97c(0, NULL); +#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); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF + at32_add_device_psif(0); + at32_add_device_psif(1); +#endif atstk1000_setup_j2_leds(); atstk1003_setup_extdac(); --- a/arch/avr32/boards/atstk1000/atstk1004.c +++ b/arch/avr32/boards/atstk1000/atstk1004.c @@ -29,6 +29,13 @@ #include "atstk1000.h" +/* Oscillator frequencies. These are board specific */ +unsigned long at32_board_osc_rates[3] = { + [0] = 32768, /* 32.768 kHz on RTC osc */ + [1] = 20000000, /* 20 MHz on osc0 */ + [2] = 12000000, /* 12 MHz on osc1 */ +}; + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC static struct at73c213_board_info at73c213_data = { .ssc_id = 0, @@ -130,14 +137,23 @@ 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); + at32_add_device_mci(0, NULL); #endif at32_add_device_lcdc(0, &atstk1000_lcdc_data, - fbmem_start, fbmem_size); + fbmem_start, fbmem_size, 0); at32_add_device_usba(0, NULL); +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_AC97 + at32_add_device_ac97c(0, NULL); +#else + at32_add_device_abdac(0); +#endif #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM at32_add_device_ssc(0, ATMEL_SSC_TX); #endif +#ifdef CONFIG_BOARD_ATSTK100X_ENABLE_PSIF + at32_add_device_psif(0); + at32_add_device_psif(1); +#endif atstk1000_setup_j2_leds(); atstk1004_setup_extdac(); --- a/arch/avr32/configs/atngw100_defconfig +++ b/arch/avr32/configs/atngw100_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc7 -# Wed Jan 9 23:20:41 2008 +# Linux kernel version: 2.6.25.4 +# Wed Jun 11 15:23:36 2008 # CONFIG_AVR32=y CONFIG_GENERIC_GPIO=y @@ -13,10 +13,10 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=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 @@ -37,17 +37,15 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y # 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=y -CONFIG_FAIR_USER_SCHED=y -# CONFIG_FAIR_CGROUP_SCHED is not set +# CONFIG_GROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -61,11 +59,13 @@ CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +# CONFIG_COMPAT_BRK is not set # CONFIG_BASE_FULL is not set 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 @@ -73,6 +73,14 @@ # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set @@ -101,10 +109,15 @@ CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y # # System Type and features # +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y @@ -113,6 +126,7 @@ 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 # @@ -121,6 +135,7 @@ # 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 @@ -146,16 +161,26 @@ 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_SCHED_HRTICK is not set CONFIG_CMDLINE="" # # Power management options # +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y # # CPU Frequency scaling @@ -164,9 +189,9 @@ 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_PERFORMANCE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set @@ -202,6 +227,7 @@ CONFIG_XFRM_USER=y # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set CONFIG_NET_KEY=y # CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y @@ -260,82 +286,33 @@ # CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set -CONFIG_BRIDGE_NETFILTER=y +# CONFIG_NETFILTER_ADVANCED is not set # # Core Netfilter Configuration # -# CONFIG_NETFILTER_NETLINK is not set -CONFIG_NF_CONNTRACK_ENABLED=m +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_LOG=m CONFIG_NF_CONNTRACK=m -CONFIG_NF_CT_ACCT=y -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 CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m CONFIG_NETFILTER_XTABLES=y -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set -# CONFIG_NETFILTER_XT_TARGET_DSCP is not set 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 -# CONFIG_NETFILTER_XT_MATCH_DSCP is not set -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -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 -# CONFIG_NETFILTER_XT_MATCH_SCTP is not set 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 # # IP: Netfilter Configuration # CONFIG_NF_CONNTRACK_IPV4=m CONFIG_NF_CONNTRACK_PROC_COMPAT=y -# CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_LOG=m @@ -343,54 +320,25 @@ CONFIG_NF_NAT=m CONFIG_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_NF_NAT_PROTO_GRE=m CONFIG_NF_NAT_FTP=m CONFIG_NF_NAT_IRC=m -CONFIG_NF_NAT_TFTP=m -CONFIG_NF_NAT_AMANDA=m -CONFIG_NF_NAT_PPTP=m -CONFIG_NF_NAT_H323=m +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_H323 is not set CONFIG_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m # -# IPv6: Netfilter Configuration (EXPERIMENTAL) +# IPv6: Netfilter Configuration # CONFIG_NF_CONNTRACK_IPV6=m -CONFIG_IP6_NF_QUEUE=m CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_OWNER=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_EUI64=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_TARGET_LOG=m 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 @@ -407,7 +355,6 @@ # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_SCHED is not set -CONFIG_NET_CLS_ROUTE=y # # Network testing @@ -415,6 +362,7 @@ # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -531,11 +479,18 @@ CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set -# CONFIG_MISC_DEVICES is not set -# CONFIG_IDE is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ATMEL_PWM is not set +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HAVE_IDE is not set # # SCSI device support @@ -568,11 +523,13 @@ # CONFIG_SMSC_PHY is not set # CONFIG_BROADCOM_PHY is not set # CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set # CONFIG_FIXED_PHY is not set # CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y # CONFIG_MII is not set CONFIG_MACB=y +# CONFIG_ENC28J60 is not set # CONFIG_IBM_NEW_EMAC_ZMII is not set # CONFIG_IBM_NEW_EMAC_RGMII is not set # CONFIG_IBM_NEW_EMAC_TAH is not set @@ -599,7 +556,6 @@ # 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 @@ -633,6 +589,7 @@ # 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 @@ -640,8 +597,6 @@ # 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 @@ -659,6 +614,7 @@ # # 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 @@ -669,13 +625,12 @@ # # 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_PCF8575 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -702,9 +657,27 @@ # CONFIG_SPI_AT25 is not set CONFIG_SPI_SPIDEV=m # CONFIG_SPI_TLE62X0 is not set +CONFIG_HAVE_GPIO_LIB=y + +# +# GPIO Support +# +# CONFIG_DEBUG_GPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -757,10 +730,6 @@ # # 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 @@ -787,21 +756,24 @@ # CONFIG_USB_FILE_STORAGE_TEST is not set CONFIG_USB_G_SERIAL=m # CONFIG_USB_MIDI_GADGET is not set -CONFIG_MMC=m +# CONFIG_USB_G_PRINTER 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=m +CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_SDIO_UART is not set # # MMC/SD Host Controller Drivers # +CONFIG_MMC_ATMELMCI=y CONFIG_MMC_SPI=m +# CONFIG_MEMSTICK is not set CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -844,19 +816,22 @@ # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_PCF8583 is not set # CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set # # SPI RTC drivers # -# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set # # Platform RTC drivers # +# CONFIG_RTC_DRV_DS1511 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_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set @@ -874,25 +849,23 @@ # # 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=m +CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=m +CONFIG_JBD=y # 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_DNOTIFY 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 @@ -923,7 +896,7 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set -CONFIG_CONFIGFS_FS=m +CONFIG_CONFIGFS_FS=y # # Miscellaneous filesystems @@ -948,8 +921,10 @@ # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y @@ -1030,11 +1005,6 @@ # 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 @@ -1053,6 +1023,7 @@ # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set # CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1069,9 +1040,10 @@ # 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_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_SAMPLES is not set @@ -1084,7 +1056,9 @@ # CONFIG_SECURITY_FILE_CAPABILITIES is not set CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_SEQIV is not set CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=y @@ -1103,6 +1077,9 @@ CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_LRW is not set # CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_FCRYPT is not set @@ -1117,12 +1094,14 @@ # CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 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 -# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_LZO is not set CONFIG_CRYPTO_HW=y # @@ -1137,10 +1116,7 @@ # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m +CONFIG_GENERIC_ALLOCATOR=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc7 -# Wed Jan 9 23:07:43 2008 +# Linux kernel version: 2.6.25.4 +# Wed Jun 11 15:29:18 2008 # CONFIG_AVR32=y CONFIG_GENERIC_GPIO=y @@ -13,10 +13,10 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=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 @@ -36,15 +36,15 @@ CONFIG_POSIX_MQUEUE=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_GROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -58,11 +58,13 @@ CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +# CONFIG_COMPAT_BRK is not set # CONFIG_BASE_FULL is not set 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 @@ -70,6 +72,14 @@ # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set @@ -98,10 +108,15 @@ CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y # # System Type and features # +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y @@ -113,12 +128,16 @@ CONFIG_BOARD_ATSTK1002=y # CONFIG_BOARD_ATSTK1003 is not set # CONFIG_BOARD_ATSTK1004 is not set +# CONFIG_BOARD_ATSTK1006 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_BOARD_ATSTK100X_ENABLE_PSIF is not set CONFIG_LOADER_U_BOOT=y # @@ -127,6 +146,7 @@ # 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 @@ -152,16 +172,26 @@ 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_SCHED_HRTICK is not set CONFIG_CMDLINE="" # # Power management options # +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y # # CPU Frequency scaling @@ -170,9 +200,9 @@ 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_PERFORMANCE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set @@ -208,6 +238,7 @@ CONFIG_XFRM_USER=m # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set CONFIG_NET_KEY=m # CONFIG_NET_KEY_MIGRATE is not set CONFIG_INET=y @@ -279,6 +310,7 @@ # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -395,13 +427,18 @@ CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set CONFIG_MISC_DEVICES=y +CONFIG_ATMEL_PWM=m +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 # CONFIG_EEPROM_93CX6 is not set CONFIG_ATMEL_SSC=m -# CONFIG_IDE is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HAVE_IDE is not set # # SCSI device support @@ -444,6 +481,7 @@ # CONFIG_SCSI_LOWLEVEL is not set CONFIG_ATA=m # CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_MV is not set CONFIG_PATA_AT32=m # CONFIG_PATA_PLATFORM is not set # CONFIG_MD is not set @@ -469,11 +507,13 @@ # CONFIG_SMSC_PHY is not set # CONFIG_BROADCOM_PHY is not set # CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set # CONFIG_FIXED_PHY is not set # CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y # CONFIG_MII is not set CONFIG_MACB=y +# CONFIG_ENC28J60 is not set # CONFIG_IBM_NEW_EMAC_ZMII is not set # CONFIG_IBM_NEW_EMAC_RGMII is not set # CONFIG_IBM_NEW_EMAC_TAH is not set @@ -500,7 +540,6 @@ # 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 @@ -568,6 +607,7 @@ # 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 @@ -575,8 +615,6 @@ # 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 @@ -594,6 +632,7 @@ # # 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 @@ -604,13 +643,12 @@ # # 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_PCF8575 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -637,9 +675,27 @@ # CONFIG_SPI_AT25 is not set CONFIG_SPI_SPIDEV=m # CONFIG_SPI_TLE62X0 is not set +CONFIG_HAVE_GPIO_LIB=y + +# +# GPIO Support +# +# CONFIG_DEBUG_GPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -732,12 +788,18 @@ # # 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 @@ -753,9 +815,14 @@ # # +# ALSA SoC audio for Freescale SOCs +# + +# # 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 @@ -765,10 +832,6 @@ # # 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 @@ -796,27 +859,31 @@ # CONFIG_USB_FILE_STORAGE_TEST is not set CONFIG_USB_G_SERIAL=m # CONFIG_USB_MIDI_GADGET is not set -CONFIG_MMC=m +# CONFIG_USB_G_PRINTER 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=m +CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_SDIO_UART is not set # # MMC/SD Host Controller Drivers # +CONFIG_MMC_ATMELMCI=y CONFIG_MMC_SPI=m +# CONFIG_MEMSTICK is not set CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=m # # LED drivers # +CONFIG_LEDS_ATMEL_PWM=m CONFIG_LEDS_GPIO=m # @@ -853,19 +920,22 @@ # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_PCF8583 is not set # CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set # # SPI RTC drivers # -# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set # # Platform RTC drivers # +# CONFIG_RTC_DRV_DS1511 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_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set @@ -883,13 +953,13 @@ # # 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=m +CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=m +CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set @@ -897,12 +967,10 @@ # CONFIG_XFS_FS is not set # CONFIG_GFS2_FS is not set # CONFIG_OCFS2_FS is not set -CONFIG_MINIX_FS=m -# CONFIG_ROMFS_FS is not set +# CONFIG_DNOTIFY 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 @@ -933,7 +1001,7 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set -# CONFIG_CONFIGFS_FS is not set +CONFIG_CONFIGFS_FS=y # # Miscellaneous filesystems @@ -957,8 +1025,10 @@ # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set +CONFIG_MINIX_FS=m # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y @@ -1028,11 +1098,6 @@ # 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 @@ -1051,6 +1116,7 @@ # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set # CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1067,9 +1133,10 @@ # 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_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_SAMPLES is not set @@ -1082,7 +1149,9 @@ # CONFIG_SECURITY_FILE_CAPABILITIES is not set CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_AEAD=m CONFIG_CRYPTO_BLKCIPHER=m +# CONFIG_CRYPTO_SEQIV is not set CONFIG_CRYPTO_HASH=m CONFIG_CRYPTO_MANAGER=m CONFIG_CRYPTO_HMAC=m @@ -1101,6 +1170,9 @@ # CONFIG_CRYPTO_PCBC is not set # CONFIG_CRYPTO_LRW is not set # CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_DES=m # CONFIG_CRYPTO_FCRYPT is not set @@ -1115,12 +1187,14 @@ # CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 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_AUTHENC=m +# CONFIG_CRYPTO_LZO is not set # CONFIG_CRYPTO_HW is not set # @@ -1135,6 +1209,7 @@ # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_GENERIC_ALLOCATOR=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y --- a/arch/avr32/configs/atstk1003_defconfig +++ b/arch/avr32/configs/atstk1003_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc7 -# Wed Jan 9 22:54:34 2008 +# Linux kernel version: 2.6.25.4 +# Wed Jun 11 15:33:36 2008 # CONFIG_AVR32=y CONFIG_GENERIC_GPIO=y @@ -13,10 +13,10 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=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 @@ -39,17 +39,15 @@ 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_GROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -63,11 +61,13 @@ CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +# CONFIG_COMPAT_BRK is not set # CONFIG_BASE_FULL is not set 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 @@ -75,6 +75,14 @@ # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set @@ -103,10 +111,15 @@ CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y # # System Type and features # +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y @@ -118,12 +131,16 @@ # CONFIG_BOARD_ATSTK1002 is not set CONFIG_BOARD_ATSTK1003=y # CONFIG_BOARD_ATSTK1004 is not set +# CONFIG_BOARD_ATSTK1006 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_BOARD_ATSTK100X_ENABLE_PSIF is not set CONFIG_LOADER_U_BOOT=y # @@ -132,6 +149,7 @@ # 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 @@ -157,16 +175,26 @@ 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_SCHED_HRTICK is not set CONFIG_CMDLINE="" # # Power management options # +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y # # CPU Frequency scaling @@ -175,9 +203,9 @@ 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_PERFORMANCE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set @@ -260,6 +288,7 @@ # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -376,13 +405,18 @@ CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set CONFIG_MISC_DEVICES=y +CONFIG_ATMEL_PWM=m +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 # CONFIG_EEPROM_93CX6 is not set CONFIG_ATMEL_SSC=m -# CONFIG_IDE is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HAVE_IDE is not set # # SCSI device support @@ -427,6 +461,7 @@ # CONFIG_SCSI_DEBUG is not set CONFIG_ATA=m # CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_MV is not set CONFIG_PATA_AT32=m # CONFIG_PATA_PLATFORM is not set # CONFIG_MD is not set @@ -460,7 +495,6 @@ # 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 @@ -528,6 +562,7 @@ # 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 @@ -535,8 +570,6 @@ # 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 @@ -554,6 +587,7 @@ # # 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 @@ -564,13 +598,12 @@ # # 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_PCF8575 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -597,9 +630,27 @@ # CONFIG_SPI_AT25 is not set CONFIG_SPI_SPIDEV=m # CONFIG_SPI_TLE62X0 is not set +CONFIG_HAVE_GPIO_LIB=y + +# +# GPIO Support +# +# CONFIG_DEBUG_GPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -665,12 +716,18 @@ # # 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 @@ -686,9 +743,14 @@ # # +# ALSA SoC audio for Freescale SOCs +# + +# # 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 @@ -698,10 +760,6 @@ # # 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 @@ -729,27 +787,31 @@ # CONFIG_USB_FILE_STORAGE_TEST is not set CONFIG_USB_G_SERIAL=m # CONFIG_USB_MIDI_GADGET is not set -CONFIG_MMC=m +# CONFIG_USB_G_PRINTER 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=m +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_MEMSTICK is not set CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y # # LED drivers # +CONFIG_LEDS_ATMEL_PWM=m CONFIG_LEDS_GPIO=y # @@ -786,19 +848,22 @@ # CONFIG_RTC_DRV_PCF8563 is not set # CONFIG_RTC_DRV_PCF8583 is not set # CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_S35390A is not set # # SPI RTC drivers # -# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set # # Platform RTC drivers # +# CONFIG_RTC_DRV_DS1511 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_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set @@ -816,13 +881,13 @@ # # 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=m +CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set # CONFIG_EXT4DEV_FS is not set -CONFIG_JBD=m +CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set @@ -830,12 +895,10 @@ # 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_DNOTIFY 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 @@ -866,7 +929,7 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set -CONFIG_CONFIGFS_FS=m +CONFIG_CONFIGFS_FS=y # # Miscellaneous filesystems @@ -891,8 +954,10 @@ # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set # CONFIG_NETWORK_FILESYSTEMS is not set @@ -943,11 +1008,6 @@ # 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 @@ -965,6 +1025,7 @@ CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set +# CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -981,9 +1042,10 @@ # 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_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_SAMPLES is not set @@ -1009,6 +1071,7 @@ CONFIG_AUDIT_GENERIC=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_GENERIC_ALLOCATOR=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y --- a/arch/avr32/configs/atstk1004_defconfig +++ b/arch/avr32/configs/atstk1004_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc7 -# Wed Jan 9 23:04:20 2008 +# Linux kernel version: 2.6.25.4 +# Wed Jun 11 15:37:49 2008 # CONFIG_AVR32=y CONFIG_GENERIC_GPIO=y @@ -13,10 +13,10 @@ CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=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 @@ -34,15 +34,15 @@ # 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_GROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set # CONFIG_BLK_DEV_INITRD is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y @@ -54,24 +54,37 @@ CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +# CONFIG_COMPAT_BRK is not set # CONFIG_BASE_FULL is not set # CONFIG_FUTEX is not set # CONFIG_EPOLL is not set # CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD 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_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_KPROBES=y +# CONFIG_HAVE_KRETPROBES is not set +# CONFIG_PROC_PAGE_MONITOR is not set # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=1 # CONFIG_MODULES is not set # CONFIG_BLOCK is not set +CONFIG_CLASSIC_RCU=y # # System Type and features # +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_SUBARCH_AVR32B=y CONFIG_MMU=y CONFIG_PERFORMANCE_COUNTERS=y @@ -83,10 +96,14 @@ # CONFIG_BOARD_ATSTK1002 is not set # CONFIG_BOARD_ATSTK1003 is not set CONFIG_BOARD_ATSTK1004=y +# CONFIG_BOARD_ATSTK1006 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_EXTDAC=y +# CONFIG_BOARD_ATSTK100X_ENABLE_AC97 is not set +# CONFIG_BOARD_ATSTK1000_CF_HACKS is not set +# CONFIG_BOARD_ATSTK100X_ENABLE_PSIF is not set CONFIG_LOADER_U_BOOT=y # @@ -95,6 +112,7 @@ # 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 @@ -120,34 +138,26 @@ 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 # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set CONFIG_CMDLINE="" # # Power management options # +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_PM is not set # # 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 +# CONFIG_CPU_FREQ is not set # # Bus options @@ -222,6 +232,7 @@ # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -321,6 +332,7 @@ # CONFIG_MTD_UBI is not set # CONFIG_PARPORT is not set # CONFIG_MISC_DEVICES is not set +# CONFIG_HAVE_IDE is not set # # SCSI device support @@ -358,6 +370,7 @@ # 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 @@ -365,8 +378,6 @@ # 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 @@ -389,9 +400,24 @@ # CONFIG_SPI_AT25 is not set # CONFIG_SPI_SPIDEV is not set # CONFIG_SPI_TLE62X0 is not set +CONFIG_HAVE_GPIO_LIB=y + +# +# GPIO Support +# + +# +# I2C GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set +# CONFIG_THERMAL is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -471,10 +497,6 @@ # # 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 @@ -499,7 +521,9 @@ # CONFIG_USB_FILE_STORAGE is not set # CONFIG_USB_G_SERIAL is not set # CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set # CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y @@ -519,15 +543,17 @@ # # SPI RTC drivers # -# CONFIG_RTC_DRV_RS5C348 is not set # CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set # # Platform RTC drivers # +# CONFIG_RTC_DRV_DS1511 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_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set @@ -545,9 +571,9 @@ # # File systems # +# CONFIG_DNOTIFY is not set # 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 @@ -580,7 +606,6 @@ # CONFIG_NETWORK_FILESYSTEMS is not set # CONFIG_NLS is not set # CONFIG_DLM is not set -# CONFIG_INSTRUMENTATION is not set # # Kernel hacking @@ -616,6 +641,7 @@ # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_GENERIC_ALLOCATOR=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y --- /dev/null +++ b/arch/avr32/configs/atstk1006_defconfig @@ -0,0 +1,1235 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.25.4 +# Wed Jun 11 15:40:45 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_GENERIC_CLOCKEVENTS=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_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 is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +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_COMPAT_BRK is not set +# CONFIG_BASE_FULL is not set +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=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +# CONFIG_HAVE_KRETPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +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" +CONFIG_CLASSIC_RCU=y + +# +# System Type and features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +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=y +# CONFIG_BOARD_ATNGW100 is not set +# CONFIG_BOARD_ATSTK1002 is not set +# CONFIG_BOARD_ATSTK1003 is not set +# CONFIG_BOARD_ATSTK1004 is not set +CONFIG_BOARD_ATSTK1006=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_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_BOARD_ATSTK100X_ENABLE_PSIF 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_SCHED_HRTICK is not set +CONFIG_CMDLINE="" + +# +# Power management options +# +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y + +# +# 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 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# 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_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS 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 +CONFIG_IP_FIB_HASH=y +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=m +CONFIG_NET_IPGRE=m +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES 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=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=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=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 +# 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_CAN 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=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_NAND_ATMEL_ECC_HW=y +# CONFIG_MTD_NAND_ATMEL_ECC_SOFT is not set +# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG 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_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +CONFIG_ATMEL_PWM=m +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_TCB_CLKSRC=y +CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0 +# CONFIG_EEPROM_93CX6 is not set +CONFIG_ATMEL_SSC=m +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HAVE_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 is not set +CONFIG_ATA=m +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_MV 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=m +# 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_REALTEK_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +CONFIG_MACB=y +# CONFIG_ENC28J60 is not set +# 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 + +# +# 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_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=m +# 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_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_DS1682 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 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_HAVE_GPIO_LIB=y + +# +# GPIO Support +# +# CONFIG_DEBUG_GPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL 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=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 +# + +# +# ALSA SoC audio for Freescale SOCs +# + +# +# 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' +# +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_USB_G_PRINTER 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=y +# CONFIG_SDIO_UART is not set + +# +# MMC/SD Host Controller Drivers +# +CONFIG_MMC_ATMELMCI=y +CONFIG_MMC_SPI=m +# CONFIG_MEMSTICK is not set +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 + +# +# 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 +# CONFIG_RTC_DRV_S35390A is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 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_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP 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_DNOTIFY is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA 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 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_MINIX_FS=m +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +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_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS 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 + +# +# 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_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_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_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_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=y +CONFIG_CRYPTO_ALGAPI=m +CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_BLKCIPHER=m +# CONFIG_CRYPTO_SEQIV is not set +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_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM 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_SALSA20 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=m +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_HW 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_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y --- /dev/null +++ b/arch/avr32/drivers/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DW_DMAC) += dw-dmac.o --- /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"); --- /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__ */ --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile @@ -9,6 +9,7 @@ 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 --- a/arch/avr32/kernel/avr32_ksyms.c +++ b/arch/avr32/kernel/avr32_ksyms.c @@ -29,7 +29,9 @@ */ EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); + EXPORT_SYMBOL(clear_page); +EXPORT_SYMBOL(copy_page); /* * Userspace access stuff. @@ -41,6 +43,8 @@ EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(strnlen_user); + EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); --- /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); --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -74,50 +74,41 @@ .align 2 bral do_dtlb_modified - /* - * r0 : PGD/PT/PTE - * r1 : Offending address - * r2 : Scratch register - * r3 : Cause (5, 12 or 13) - */ #define tlbmiss_save pushm r0-r3 #define tlbmiss_restore popm r0-r3 - .section .tlbx.ex.text,"ax",@progbits + .org 0x50 .global itlb_miss itlb_miss: tlbmiss_save rjmp tlb_miss_common - .section .tlbr.ex.text,"ax",@progbits + .org 0x60 dtlb_miss_read: tlbmiss_save rjmp tlb_miss_common - .section .tlbw.ex.text,"ax",@progbits + .org 0x70 dtlb_miss_write: tlbmiss_save .global tlb_miss_common + .align 2 tlb_miss_common: mfsr r0, SYSREG_TLBEAR mfsr r1, SYSREG_PTBR - /* Is it the vmalloc space? */ - bld r0, 31 - brcs handle_vmalloc_miss - - /* First level lookup */ + /* + * First level lookup: The PGD contains virtual pointers to + * the second-level page tables, but they may be NULL if not + * present. + */ pgtbl_lookup: lsr r2, r0, PGDIR_SHIFT ld.w r3, r1[r2 << 2] bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT - bld r3, _PAGE_BIT_PRESENT - brcc page_table_not_present - - /* Translate to virtual address in P1. */ - andl r3, 0xf000 - sbr r3, 31 + cp.w r3, 0 + breq page_table_not_present /* Second level lookup */ ld.w r2, r3[r1 << 2] @@ -148,16 +139,55 @@ tlbmiss_restore rete -handle_vmalloc_miss: - /* Simply do the lookup in init's page table */ + /* The slow path of the TLB miss handler */ + .align 2 +page_table_not_present: + /* Do we need to synchronize with swapper_pg_dir? */ + bld r0, 31 + brcs sync_with_swapper_pg_dir + +page_not_present: + tlbmiss_restore + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_page_fault + rjmp ret_from_exception + + .align 2 +sync_with_swapper_pg_dir: + /* + * If swapper_pg_dir contains a non-NULL second-level page + * table pointer, copy it into the current PGD. If not, we + * must handle it as a full-blown page fault. + * + * Jumping back to pgtbl_lookup causes an unnecessary lookup, + * but it is guaranteed to be a cache hit, it won't happen + * very often, and we absolutely do not want to sacrifice any + * performance in the fast path in order to improve this. + */ mov r1, lo(swapper_pg_dir) orh r1, hi(swapper_pg_dir) + ld.w r3, r1[r2 << 2] + cp.w r3, 0 + breq page_not_present + mfsr r1, SYSREG_PTBR + st.w r1[r2 << 2], r3 rjmp pgtbl_lookup + /* + * We currently have two bytes left at this point until we + * crash into the system call handler... + * + * Don't worry, the assembler will let us know. + */ + /* --- System Call --- */ - .section .scall.text,"ax",@progbits + .org 0x100 system_call: #ifdef CONFIG_PREEMPT mask_interrupts @@ -266,18 +296,6 @@ brcc syscall_exit_cont rjmp enter_monitor_mode - /* The slow path of the TLB miss handler */ -page_table_not_present: -page_not_present: - tlbmiss_restore - sub sp, 4 - stmts --sp, r0-lr - rcall save_full_context_ex - mfsr r12, SYSREG_ECR - mov r11, sp - rcall do_page_fault - rjmp ret_from_exception - /* This function expects to find offending PC in SYSREG_RAR_EX */ .type save_full_context_ex, @function .align 2 @@ -741,26 +759,6 @@ .section .irq.text,"ax",@progbits -.global cpu_idle_sleep -cpu_idle_sleep: - mask_interrupts - get_thread_info r8 - ld.w r9, r8[TI_flags] - bld r9, TIF_NEED_RESCHED - brcs cpu_idle_enable_int_and_exit - sbr r9, TIF_CPU_GOING_TO_SLEEP - st.w r8[TI_flags], r9 - unmask_interrupts - sleep 0 -cpu_idle_skip_sleep: - mask_interrupts - ld.w r9, r8[TI_flags] - cbr r9, TIF_CPU_GOING_TO_SLEEP - st.w r8[TI_flags], r9 -cpu_idle_enable_int_and_exit: - unmask_interrupts - retal r12 - .global irq_level0 .global irq_level1 .global irq_level2 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -18,11 +18,11 @@ #include <asm/sysreg.h> #include <asm/ocd.h> +#include <asm/arch/pm.h> + void (*pm_power_off)(void) = NULL; EXPORT_SYMBOL(pm_power_off); -extern void cpu_idle_sleep(void); - /* * This file handles the architecture-dependent parts of process handling.. */ @@ -54,6 +54,8 @@ void machine_power_off(void) { + if (pm_power_off) + pm_power_off(); } void machine_restart(char *cmd) --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -274,6 +274,8 @@ printk(KERN_WARNING "Failed to allocate framebuffer memory\n"); fbmem_size = 0; + } else { + memset(__va(fbmem_start), 0, fbmem_size); } } --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -93,6 +93,9 @@ if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) + goto badframe; + pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n", regs->pc, regs->lr, regs->sp); --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -1,233 +1,147 @@ /* * Copyright (C) 2004-2007 Atmel Corporation * - * Based on MIPS implementation arch/mips/kernel/time.c - * Copyright 2001 MontaVista Software Inc. - * * 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/clocksource.h> -#include <linux/time.h> -#include <linux/module.h> +#include <linux/clockchips.h> +#include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/profile.h> -#include <linux/sysdev.h> -#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/time.h> -#include <asm/div64.h> #include <asm/sysreg.h> -#include <asm/io.h> -#include <asm/sections.h> -/* how many counter cycles in a jiffy? */ -static u32 cycles_per_jiffy; +#include <asm/arch/pm.h> -/* the count value for the next timer interrupt */ -static u32 expirelo; -cycle_t __weak read_cycle_count(void) +static cycle_t read_cycle_count(void) { return (cycle_t)sysreg_read(COUNT); } -struct clocksource __weak clocksource_avr32 = { - .name = "avr32", - .rating = 350, +/* + * The architectural cycle count registers are a fine clocksource unless + * the system idle loop use sleep states like "idle": the CPU cycles + * measured by COUNT (and COMPARE) don't happen during sleep states. + * Their duration also changes if cpufreq changes the CPU clock rate. + * So we rate the clocksource using COUNT as very low quality. + */ +static struct clocksource counter = { + .name = "avr32_counter", + .rating = 50, .read = read_cycle_count, .mask = CLOCKSOURCE_MASK(32), .shift = 16, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -irqreturn_t __weak timer_interrupt(int irq, void *dev_id); - -struct irqaction timer_irqaction = { - .handler = timer_interrupt, - .flags = IRQF_DISABLED, - .name = "timer", -}; - -/* - * By default we provide the null RTC ops - */ -static unsigned long null_rtc_get_time(void) -{ - return mktime(2007, 1, 1, 0, 0, 0); -} - -static int null_rtc_set_time(unsigned long sec) +static irqreturn_t timer_interrupt(int irq, void *dev_id) { - return 0; -} - -static unsigned long (*rtc_get_time)(void) = null_rtc_get_time; -static int (*rtc_set_time)(unsigned long) = null_rtc_set_time; + struct clock_event_device *evdev = dev_id; -static void avr32_timer_ack(void) -{ - u32 count; - - /* Ack this timer interrupt and set the next one */ - expirelo += cycles_per_jiffy; - /* setting COMPARE to 0 stops the COUNT-COMPARE */ - if (expirelo == 0) { - sysreg_write(COMPARE, expirelo + 1); - } else { - sysreg_write(COMPARE, expirelo); - } + /* + * Disable the interrupt until the clockevent subsystem + * reprograms it. + */ + sysreg_write(COMPARE, 0); - /* Check to see if we have missed any timer interrupts */ - count = sysreg_read(COUNT); - if ((count - expirelo) < 0x7fffffff) { - expirelo = count + cycles_per_jiffy; - sysreg_write(COMPARE, expirelo); - } + evdev->event_handler(evdev); + return IRQ_HANDLED; } -int __weak avr32_hpt_init(void) -{ - int ret; - unsigned long mult, shift, count_hz; - - count_hz = clk_get_rate(boot_cpu_data.clk); - shift = clocksource_avr32.shift; - mult = clocksource_hz2mult(count_hz, shift); - clocksource_avr32.mult = mult; - - { - u64 tmp; - - tmp = TICK_NSEC; - tmp <<= shift; - tmp += mult / 2; - do_div(tmp, mult); - - cycles_per_jiffy = tmp; - } +static struct irqaction timer_irqaction = { + .handler = timer_interrupt, + .flags = IRQF_TIMER | IRQF_DISABLED, + .name = "avr32_comparator", +}; - ret = setup_irq(0, &timer_irqaction); - if (ret) { - pr_debug("timer: could not request IRQ 0: %d\n", ret); - return -ENODEV; - } +static int comparator_next_event(unsigned long delta, + struct clock_event_device *evdev) +{ + unsigned long flags; - printk(KERN_INFO "timer: AT32AP COUNT-COMPARE at irq 0, " - "%lu.%03lu MHz\n", - ((count_hz + 500) / 1000) / 1000, - ((count_hz + 500) / 1000) % 1000); + raw_local_irq_save(flags); - return 0; -} + /* The time to read COUNT then update COMPARE must be less + * than the min_delta_ns value for this clockevent source. + */ + sysreg_write(COMPARE, (sysreg_read(COUNT) + delta) ? : 1); -/* - * Taken from MIPS c0_hpt_timer_init(). - * - * The reason COUNT is written twice is probably to make sure we don't get any - * timer interrupts while we are messing with the counter. - */ -int __weak avr32_hpt_start(void) -{ - u32 count = sysreg_read(COUNT); - expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy; - sysreg_write(COUNT, expirelo - cycles_per_jiffy); - sysreg_write(COMPARE, expirelo); - sysreg_write(COUNT, count); + raw_local_irq_restore(flags); return 0; } -/* - * local_timer_interrupt() does profiling and process accounting on a - * per-CPU basis. - * - * In UP mode, it is invoked from the (global) timer_interrupt. - */ -void local_timer_interrupt(int irq, void *dev_id) +static void comparator_mode(enum clock_event_mode mode, + struct clock_event_device *evdev) { - if (current->pid) - profile_tick(CPU_PROFILING); - update_process_times(user_mode(get_irq_regs())); + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + pr_debug("%s: start\n", evdev->name); + /* FALLTHROUGH */ + case CLOCK_EVT_MODE_RESUME: + cpu_disable_idle_sleep(); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + sysreg_write(COMPARE, 0); + pr_debug("%s: stop\n", evdev->name); + cpu_enable_idle_sleep(); + break; + default: + BUG(); + } } -irqreturn_t __weak timer_interrupt(int irq, void *dev_id) -{ - /* ack timer interrupt and try to set next interrupt */ - avr32_timer_ack(); - - /* - * Call the generic timer interrupt handler - */ - write_seqlock(&xtime_lock); - do_timer(1); - write_sequnlock(&xtime_lock); - - /* - * In UP mode, we call local_timer_interrupt() to do profiling - * and process accounting. - * - * SMP is not supported yet. - */ - local_timer_interrupt(irq, dev_id); - - return IRQ_HANDLED; -} +static struct clock_event_device comparator = { + .name = "avr32_comparator", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 16, + .rating = 50, + .cpumask = CPU_MASK_CPU0, + .set_next_event = comparator_next_event, + .set_mode = comparator_mode, +}; void __init time_init(void) { + unsigned long counter_hz; int ret; - /* - * Make sure we don't get any COMPARE interrupts before we can - * handle them. - */ - sysreg_write(COMPARE, 0); - - xtime.tv_sec = rtc_get_time(); + xtime.tv_sec = mktime(2007, 1, 1, 0, 0, 0); xtime.tv_nsec = 0; set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - ret = avr32_hpt_init(); - if (ret) { - pr_debug("timer: failed setup: %d\n", ret); - return; - } + /* figure rate for counter */ + counter_hz = clk_get_rate(boot_cpu_data.clk); + counter.mult = clocksource_hz2mult(counter_hz, counter.shift); - ret = clocksource_register(&clocksource_avr32); + ret = clocksource_register(&counter); if (ret) pr_debug("timer: could not register clocksource: %d\n", ret); - ret = avr32_hpt_start(); - if (ret) { - pr_debug("timer: failed starting: %d\n", ret); - return; - } -} + /* setup COMPARE clockevent */ + comparator.mult = div_sc(counter_hz, NSEC_PER_SEC, comparator.shift); + comparator.max_delta_ns = clockevent_delta2ns((u32)~0, &comparator); + comparator.min_delta_ns = clockevent_delta2ns(50, &comparator) + 1; -static struct sysdev_class timer_class = { - .name = "timer", -}; + sysreg_write(COMPARE, 0); + timer_irqaction.dev_id = &comparator; -static struct sys_device timer_device = { - .id = 0, - .cls = &timer_class, -}; + ret = setup_irq(0, &timer_irqaction); + if (ret) + pr_debug("timer: could not request IRQ 0: %d\n", ret); + else { + clockevents_register_device(&comparator); -static int __init init_timer_sysfs(void) -{ - int err = sysdev_class_register(&timer_class); - if (!err) - err = sysdev_register(&timer_device); - return err; + pr_info("%s: irq 0, %lu.%03lu MHz\n", comparator.name, + ((counter_hz + 500) / 1000) / 1000, + ((counter_hz + 500) / 1000) % 1000); + } } - -device_initcall(init_timer_sysfs); --- a/arch/avr32/kernel/vmlinux.lds.S +++ b/arch/avr32/kernel/vmlinux.lds.S @@ -68,14 +68,6 @@ _evba = .; _text = .; *(.ex.text) - . = 0x50; - *(.tlbx.ex.text) - . = 0x60; - *(.tlbr.ex.text) - . = 0x70; - *(.tlbw.ex.text) - . = 0x100; - *(.scall.text) *(.irq.text) KPROBES_TEXT TEXT_TEXT @@ -107,6 +99,10 @@ */ *(.data.init_task) + /* Then, the page-aligned data */ + . = ALIGN(PAGE_SIZE); + *(.data.page_aligned) + /* Then, the cacheline aligned data */ . = ALIGN(L1_CACHE_BYTES); *(.data.cacheline_aligned) --- a/arch/avr32/lib/io-readsb.S +++ b/arch/avr32/lib/io-readsb.S @@ -41,7 +41,7 @@ 2: sub r10, -4 reteq r12 -3: ld.uh r8, r12[0] +3: ld.ub r8, r12[0] sub r10, 1 st.b r11++, r8 brne 3b --- a/arch/avr32/mach-at32ap/Kconfig +++ b/arch/avr32/mach-at32ap/Kconfig @@ -26,6 +26,13 @@ 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 --- a/arch/avr32/mach-at32ap/Makefile +++ b/arch/avr32/mach-at32ap/Makefile @@ -1,4 +1,9 @@ -obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o -obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o -obj-$(CONFIG_CPU_AT32AP700X) += time-tc.o +obj-y += pdc.o clock.o intc.o extint.o pio.o hsmc.o +obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o +obj-$(CONFIG_GPIO_DEV) += gpio-dev.o +obj-$(CONFIG_PM) += pm.o + +ifeq ($(CONFIG_PM_DEBUG),y) +CFLAGS_pm.o += -DDEBUG +endif --- a/arch/avr32/mach-at32ap/at32ap.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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/err.h> -#include <linux/init.h> -#include <linux/platform_device.h> - -#include <asm/arch/init.h> - -void __init setup_platform(void) -{ - at32_clock_init(); - at32_portmux_init(); -} - -static int __init pdc_probe(struct platform_device *pdev) -{ - struct clk *pclk, *hclk; - - pclk = clk_get(&pdev->dev, "pclk"); - if (IS_ERR(pclk)) { - dev_err(&pdev->dev, "no pclk defined\n"); - return PTR_ERR(pclk); - } - hclk = clk_get(&pdev->dev, "hclk"); - if (IS_ERR(hclk)) { - dev_err(&pdev->dev, "no hclk defined\n"); - clk_put(pclk); - return PTR_ERR(hclk); - } - - clk_enable(pclk); - clk_enable(hclk); - - dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n"); - return 0; -} - -static struct platform_driver pdc_driver = { - .probe = pdc_probe, - .driver = { - .name = "pdc", - }, -}; - -static int __init pdc_init(void) -{ - return platform_driver_register(&pdc_driver); -} -arch_initcall(pdc_init); --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -6,11 +6,13 @@ * published by the Free Software Foundation. */ #include <linux/clk.h> +#include <linux/delay.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 <linux/usb/atmel_usba_udc.h> #include <asm/io.h> #include <asm/irq.h> @@ -18,6 +20,7 @@ #include <asm/arch/at32ap700x.h> #include <asm/arch/board.h> #include <asm/arch/portmux.h> +#include <asm/arch/sram.h> #include <video/atmel_lcdc.h> @@ -91,25 +94,18 @@ static DEFINE_SPINLOCK(pm_lock); -unsigned long at32ap7000_osc_rates[3] = { - [0] = 32768, - /* FIXME: these are ATSTK1002-specific */ - [1] = 20000000, - [2] = 12000000, -}; +static struct clk osc0; +static struct clk osc1; static unsigned long osc_get_rate(struct clk *clk) { - return at32ap7000_osc_rates[clk->index]; + return at32_board_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; @@ -120,6 +116,71 @@ return rate; } +static long pll_set_rate(struct clk *clk, unsigned long rate, + u32 *pll_ctrl) +{ + unsigned long mul; + unsigned long mul_best_fit = 0; + unsigned long div; + unsigned long div_min; + unsigned long div_max; + unsigned long div_best_fit = 0; + unsigned long base; + unsigned long pll_in; + unsigned long actual = 0; + unsigned long rate_error; + unsigned long rate_error_prev = ~0UL; + u32 ctrl; + + /* Rate must be between 80 MHz and 200 Mhz. */ + if (rate < 80000000UL || rate > 200000000UL) + return -EINVAL; + + ctrl = PM_BF(PLLOPT, 4); + base = clk->parent->get_rate(clk->parent); + + /* PLL input frequency must be between 6 MHz and 32 MHz. */ + div_min = DIV_ROUND_UP(base, 32000000UL); + div_max = base / 6000000UL; + + if (div_max < div_min) + return -EINVAL; + + for (div = div_min; div <= div_max; div++) { + pll_in = (base + div / 2) / div; + mul = (rate + pll_in / 2) / pll_in; + + if (mul == 0) + continue; + + actual = pll_in * mul; + rate_error = abs(actual - rate); + + if (rate_error < rate_error_prev) { + mul_best_fit = mul; + div_best_fit = div; + rate_error_prev = rate_error; + } + + if (rate_error == 0) + break; + } + + if (div_best_fit == 0) + return -EINVAL; + + ctrl |= PM_BF(PLLMUL, mul_best_fit - 1); + ctrl |= PM_BF(PLLDIV, div_best_fit - 1); + ctrl |= PM_BF(PLLCOUNT, 16); + + if (clk->parent == &osc1) + ctrl |= PM_BIT(PLLOSC); + + *pll_ctrl = ctrl; + + return actual; +} + static unsigned long pll0_get_rate(struct clk *clk) { u32 control; @@ -129,6 +190,41 @@ return pll_get_rate(clk, control); } +static void pll1_mode(struct clk *clk, int enabled) +{ + unsigned long timeout; + u32 status; + u32 ctrl; + + ctrl = pm_readl(PLL1); + + if (enabled) { + if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) { + pr_debug("clk %s: failed to enable, rate not set\n", + clk->name); + return; + } + + ctrl |= PM_BIT(PLLEN); + pm_writel(PLL1, ctrl); + + /* Wait for PLL lock. */ + for (timeout = 10000; timeout; timeout--) { + status = pm_readl(ISR); + if (status & PM_BIT(LOCK1)) + break; + udelay(10); + } + + if (!(status & PM_BIT(LOCK1))) + printk(KERN_ERR "clk %s: timeout waiting for lock\n", + clk->name); + } else { + ctrl &= ~PM_BIT(PLLEN); + pm_writel(PLL1, ctrl); + } +} + static unsigned long pll1_get_rate(struct clk *clk) { u32 control; @@ -138,6 +234,49 @@ return pll_get_rate(clk, control); } +static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply) +{ + u32 ctrl = 0; + unsigned long actual_rate; + + actual_rate = pll_set_rate(clk, rate, &ctrl); + + if (apply) { + if (actual_rate != rate) + return -EINVAL; + if (clk->users > 0) + return -EBUSY; + pr_debug(KERN_INFO "clk %s: new rate %lu (actual rate %lu)\n", + clk->name, rate, actual_rate); + pm_writel(PLL1, ctrl); + } + + return actual_rate; +} + +static int pll1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 ctrl; + + if (clk->users > 0) + return -EBUSY; + + ctrl = pm_readl(PLL1); + WARN_ON(ctrl & PM_BIT(PLLEN)); + + if (parent == &osc0) + ctrl &= ~PM_BIT(PLLOSC); + else if (parent == &osc1) + ctrl |= PM_BIT(PLLOSC); + else + return -EINVAL; + + pm_writel(PLL1, ctrl); + clk->parent = parent; + + return 0; +} + /* * The AT32AP7000 has five primary clock sources: One 32kHz * oscillator, two crystal oscillators and two PLLs. @@ -166,7 +305,10 @@ }; static struct clk pll1 = { .name = "pll1", + .mode = pll1_mode, .get_rate = pll1_get_rate, + .set_rate = pll1_set_rate, + .set_parent = pll1_set_parent, .parent = &osc0, }; @@ -534,6 +676,14 @@ .users = 1, .index = 3, }; +static struct clk sdramc_clk = { + .name = "sdramc_clk", + .parent = &pbb_clk, + .mode = pbb_clk_mode, + .get_rate = pbb_clk_get_rate, + .users = 1, + .index = 14, +}; static struct resource smc0_resource[] = { PBMEM(0xfff03400), @@ -605,19 +755,32 @@ } /* -------------------------------------------------------------------- - * System Timer/Counter (TC) + * Timer/Counter (TC) * -------------------------------------------------------------------- */ -static struct resource at32_systc0_resource[] = { + +static struct resource at32_tcb0_resource[] = { PBMEM(0xfff00c00), IRQ(22), }; -struct platform_device at32_systc0_device = { - .name = "systc", +static struct platform_device at32_tcb0_device = { + .name = "atmel_tcb", .id = 0, - .resource = at32_systc0_resource, - .num_resources = ARRAY_SIZE(at32_systc0_resource), + .resource = at32_tcb0_resource, + .num_resources = ARRAY_SIZE(at32_tcb0_resource), +}; +DEV_CLK(t0_clk, at32_tcb0, pbb, 3); + +static struct resource at32_tcb1_resource[] = { + PBMEM(0xfff01000), + IRQ(23), +}; +static struct platform_device at32_tcb1_device = { + .name = "atmel_tcb", + .id = 1, + .resource = at32_tcb1_resource, + .num_resources = ARRAY_SIZE(at32_tcb1_resource), }; -DEV_CLK(pclk, at32_systc0, pbb, 3); +DEV_CLK(t0_clk, at32_tcb1, pbb, 4); /* -------------------------------------------------------------------- * PIO @@ -669,7 +832,8 @@ platform_device_register(&pdc_device); platform_device_register(&dmaca0_device); - platform_device_register(&at32_systc0_device); + platform_device_register(&at32_tcb0_device); + platform_device_register(&at32_tcb1_device); platform_device_register(&pio0_device); platform_device_register(&pio1_device); @@ -679,6 +843,81 @@ } /* -------------------------------------------------------------------- + * PSIF + * -------------------------------------------------------------------- */ +static struct resource atmel_psif0_resource[] __initdata = { + { + .start = 0xffe03c00, + .end = 0xffe03cff, + .flags = IORESOURCE_MEM, + }, + IRQ(18), +}; +static struct clk atmel_psif0_pclk = { + .name = "pclk", + .parent = &pba_clk, + .mode = pba_clk_mode, + .get_rate = pba_clk_get_rate, + .index = 15, +}; + +static struct resource atmel_psif1_resource[] __initdata = { + { + .start = 0xffe03d00, + .end = 0xffe03dff, + .flags = IORESOURCE_MEM, + }, + IRQ(18), +}; +static struct clk atmel_psif1_pclk = { + .name = "pclk", + .parent = &pba_clk, + .mode = pba_clk_mode, + .get_rate = pba_clk_get_rate, + .index = 15, +}; + +struct platform_device *__init at32_add_device_psif(unsigned int id) +{ + struct platform_device *pdev; + + if (!(id == 0 || id == 1)) + return NULL; + + pdev = platform_device_alloc("atmel_psif", id); + if (!pdev) + return NULL; + + switch (id) { + case 0: + if (platform_device_add_resources(pdev, atmel_psif0_resource, + ARRAY_SIZE(atmel_psif0_resource))) + goto err_add_resources; + atmel_psif0_pclk.dev = &pdev->dev; + select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */ + select_peripheral(PA(9), PERIPH_A, 0); /* DATA */ + break; + case 1: + if (platform_device_add_resources(pdev, atmel_psif1_resource, + ARRAY_SIZE(atmel_psif1_resource))) + goto err_add_resources; + atmel_psif1_pclk.dev = &pdev->dev; + select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */ + select_peripheral(PB(12), PERIPH_A, 0); /* DATA */ + break; + default: + return NULL; + } + + platform_device_add(pdev); + return pdev; + +err_add_resources: + platform_device_put(pdev); + return NULL; +} + +/* -------------------------------------------------------------------- * USART * -------------------------------------------------------------------- */ @@ -951,7 +1190,8 @@ switch (id) { case 0: pdev = &atmel_spi0_device; - select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ + /* pullup MISO so a level is always defined */ + select_peripheral(PA(0), PERIPH_A, AT32_GPIOF_PULLUP); 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); @@ -959,7 +1199,8 @@ case 1: pdev = &atmel_spi1_device; - select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ + /* pullup MISO so a level is always defined */ + select_peripheral(PB(0), PERIPH_B, AT32_GPIOF_PULLUP); 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); @@ -989,7 +1230,9 @@ .index = 2, }; -struct platform_device *__init at32_add_device_twi(unsigned int id) +struct platform_device *__init at32_add_device_twi(unsigned int id, + struct i2c_board_info *b, + unsigned int n) { struct platform_device *pdev; @@ -1009,6 +1252,9 @@ atmel_twi0_pclk.dev = &pdev->dev; + if (b) + i2c_register_board_info(id, b, n); + platform_device_add(pdev); return pdev; @@ -1032,7 +1278,8 @@ .index = 9, }; -struct platform_device *__init at32_add_device_mci(unsigned int id) +struct platform_device *__init +at32_add_device_mci(unsigned int id, struct mci_platform_data *data) { struct platform_device *pdev; @@ -1041,11 +1288,15 @@ pdev = platform_device_alloc("atmel_mci", id); if (!pdev) - return NULL; + goto fail; if (platform_device_add_resources(pdev, atmel_mci0_resource, ARRAY_SIZE(atmel_mci0_resource))) - goto err_add_resources; + 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 */ @@ -1054,12 +1305,19 @@ 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; -err_add_resources: +fail: platform_device_put(pdev); return NULL; } @@ -1097,7 +1355,8 @@ struct platform_device *__init at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, - unsigned long fbmem_start, unsigned long fbmem_len) + unsigned long fbmem_start, unsigned long fbmem_len, + unsigned int pin_config) { struct platform_device *pdev; struct atmel_lcdfb_info *info; @@ -1124,37 +1383,77 @@ 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 */ + + switch (pin_config) { + case 0: + 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 */ + break; + case 1: + select_peripheral(PE(0), PERIPH_B, 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(PE(1), PERIPH_B, 0); /* DVAL */ + select_peripheral(PE(2), PERIPH_B, 0); /* MODE */ + select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ + select_peripheral(PE(3), PERIPH_B, 0); /* DATA0 */ + select_peripheral(PE(4), PERIPH_B, 0); /* DATA1 */ + select_peripheral(PE(5), PERIPH_B, 0); /* DATA2 */ + select_peripheral(PE(6), PERIPH_B, 0); /* DATA3 */ + select_peripheral(PE(7), PERIPH_B, 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(PE(8), PERIPH_B, 0); /* DATA8 */ + select_peripheral(PE(9), PERIPH_B, 0); /* DATA9 */ + select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */ + select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */ + select_peripheral(PE(12), PERIPH_B, 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(PE(13), PERIPH_B, 0); /* DATA16 */ + select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */ + select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */ + select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */ + select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */ + select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */ + select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ + select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ + break; + default: + goto err_invalid_id; + } clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); @@ -1351,9 +1650,39 @@ .index = 6, }; +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ + [idx] = { \ + .name = nam, \ + .index = idx, \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .can_dma = dma, \ + .can_isoc = isoc, \ + } + +static struct usba_ep_data at32_usba_ep[] __initdata = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1", 1, 512, 2, 1, 1), + EP("ep2", 2, 512, 2, 1, 1), + EP("ep3-int", 3, 64, 3, 1, 0), + EP("ep4-int", 4, 64, 3, 1, 0), + EP("ep5", 5, 1024, 3, 1, 1), + EP("ep6", 6, 1024, 3, 1, 1), +}; + +#undef EP + struct platform_device *__init at32_add_device_usba(unsigned int id, struct usba_platform_data *data) { + /* + * pdata doesn't have room for any endpoints, so we need to + * append room for the ones we need right after it. + */ + struct { + struct usba_platform_data pdata; + struct usba_ep_data ep[7]; + } usba_data; struct platform_device *pdev; if (id != 0) @@ -1367,13 +1696,20 @@ 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) + usba_data.pdata.vbus_pin = data->vbus_pin; + else + usba_data.pdata.vbus_pin = -EINVAL; - if (data->vbus_pin != GPIO_PIN_NONE) - at32_select_gpio(data->vbus_pin, 0); - } + data = &usba_data.pdata; + data->num_ep = ARRAY_SIZE(at32_usba_ep); + memcpy(data->ep, at32_usba_ep, sizeof(at32_usba_ep)); + + if (platform_device_add_data(pdev, data, sizeof(usba_data))) + goto out_free_pdev; + + if (data->vbus_pin >= 0) + at32_select_gpio(data->vbus_pin, 0); usba0_pclk.dev = &pdev->dev; usba0_hclk.dev = &pdev->dev; @@ -1526,6 +1862,58 @@ #endif /* -------------------------------------------------------------------- + * NAND Flash / SmartMedia + * -------------------------------------------------------------------- */ +static struct resource smc_cs3_resource[] __initdata = { + { + .start = 0x0c000000, + .end = 0x0fffffff, + .flags = IORESOURCE_MEM, + }, { + .start = 0xfff03c00, + .end = 0xfff03fff, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device *__init +at32_add_device_nand(unsigned int id, struct atmel_nand_data *data) +{ + struct platform_device *pdev; + + if (id != 0 || !data) + return NULL; + + pdev = platform_device_alloc("atmel_nand", id); + if (!pdev) + goto fail; + + if (platform_device_add_resources(pdev, smc_cs3_resource, + ARRAY_SIZE(smc_cs3_resource))) + goto fail; + + if (platform_device_add_data(pdev, data, + sizeof(struct atmel_nand_data))) + goto fail; + + set_ebi_sfr_bits(HMATRIX_BIT(CS3A)); + if (data->enable_pin) + at32_select_gpio(data->enable_pin, + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + if (data->rdy_pin) + at32_select_gpio(data->rdy_pin, 0); + if (data->det_pin) + at32_select_gpio(data->det_pin, 0); + + platform_device_add(pdev); + return pdev; + +fail: + platform_device_put(pdev); + return NULL; +} + +/* -------------------------------------------------------------------- * AC97C * -------------------------------------------------------------------- */ static struct resource atmel_ac97c0_resource[] __initdata = { @@ -1540,9 +1928,11 @@ .index = 10, }; -struct platform_device *__init at32_add_device_ac97c(unsigned int id) +struct platform_device *__init +at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data) { struct platform_device *pdev; + struct ac97c_platform_data _data; if (id != 0) return NULL; @@ -1553,19 +1943,37 @@ if (platform_device_add_resources(pdev, atmel_ac97c0_resource, ARRAY_SIZE(atmel_ac97c0_resource))) - goto err_add_resources; + goto fail; - 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 */ + if (!data) { + data = &_data; + memset(data, 0, sizeof(struct ac97c_platform_data)); + data->reset_pin = GPIO_PIN_NONE; + } + + data->dma_rx_periph_id = 3; + data->dma_tx_periph_id = 4; + data->dma_controller_id = 0; + + if (platform_device_add_data(pdev, data, + sizeof(struct ac97c_platform_data))) + goto fail; + + select_peripheral(PB(20), PERIPH_B, 0); /* SDO */ + select_peripheral(PB(21), PERIPH_B, 0); /* SYNC */ + select_peripheral(PB(22), PERIPH_B, 0); /* SCLK */ + select_peripheral(PB(23), PERIPH_B, 0); /* SDI */ + + /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */ + if (data->reset_pin != GPIO_PIN_NONE) + at32_select_gpio(data->reset_pin, 0); atmel_ac97c0_pclk.dev = &pdev->dev; platform_device_add(pdev); return pdev; -err_add_resources: +fail: platform_device_put(pdev); return NULL; } @@ -1683,6 +2091,7 @@ &hmatrix_clk, &ebi_clk, &hramc_clk, + &sdramc_clk, &smc0_pclk, &smc0_mck, &pdc_hclk, @@ -1694,7 +2103,10 @@ &pio2_mck, &pio3_mck, &pio4_mck, - &at32_systc0_pclk, + &at32_tcb0_t0_clk, + &at32_tcb1_t0_clk, + &atmel_psif0_pclk, + &atmel_psif1_pclk, &atmel_usart0_usart, &atmel_usart1_usart, &atmel_usart2_usart, @@ -1730,16 +2142,7 @@ }; 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) +void __init setup_platform(void) { u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; int i; @@ -1794,4 +2197,36 @@ pm_writel(HSB_MASK, hsb_mask); pm_writel(PBA_MASK, pba_mask); pm_writel(PBB_MASK, pbb_mask); + + /* Initialize the port muxes */ + 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); +} + +struct gen_pool *sram_pool; + +static int __init sram_init(void) +{ + struct gen_pool *pool; + + /* 1KiB granularity */ + pool = gen_pool_create(10, -1); + if (!pool) + goto fail; + + if (gen_pool_add(pool, 0x24000000, 0x8000, -1)) + goto err_pool_add; + + sram_pool = pool; + return 0; + +err_pool_add: + gen_pool_destroy(pool); +fail: + pr_err("Failed to create SRAM pool\n"); + return -ENOMEM; } +core_initcall(sram_init); --- a/arch/avr32/mach-at32ap/cpufreq.c +++ b/arch/avr32/mach-at32ap/cpufreq.c @@ -108,5 +108,4 @@ { return cpufreq_register_driver(&at32_driver); } - -arch_initcall(at32_cpufreq_init); +late_initcall(at32_cpufreq_init); --- /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); --- a/arch/avr32/mach-at32ap/hsmc.c +++ b/arch/avr32/mach-at32ap/hsmc.c @@ -278,4 +278,4 @@ { return platform_driver_register(&hsmc_driver); } -arch_initcall(hsmc_init); +core_initcall(hsmc_init); --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Atmel Corporation + * Copyright (C) 2006, 2008 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 @@ -12,15 +12,20 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/sysdev.h> -#include <asm/intc.h> #include <asm/io.h> #include "intc.h" struct intc { - void __iomem *regs; - struct irq_chip chip; + void __iomem *regs; + struct irq_chip chip; + struct sys_device sysdev; +#ifdef CONFIG_PM + unsigned long suspend_ipr; + unsigned long saved_ipr[64]; +#endif }; extern struct platform_device at32_intc0_device; @@ -137,6 +142,74 @@ panic("Interrupt controller initialization failed!\n"); } +#ifdef CONFIG_PM +void intc_set_suspend_handler(unsigned long offset) +{ + intc0.suspend_ipr = offset; +} + +static int intc_suspend(struct sys_device *sdev, pm_message_t state) +{ + struct intc *intc = container_of(sdev, struct intc, sysdev); + int i; + + if (unlikely(!irqs_disabled())) { + pr_err("intc_suspend: called with interrupts enabled\n"); + return -EINVAL; + } + + if (unlikely(!intc->suspend_ipr)) { + pr_err("intc_suspend: suspend_ipr not initialized\n"); + return -EINVAL; + } + + for (i = 0; i < 64; i++) { + intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i); + intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr); + } + + return 0; +} + +static int intc_resume(struct sys_device *sdev) +{ + struct intc *intc = container_of(sdev, struct intc, sysdev); + int i; + + WARN_ON(!irqs_disabled()); + + for (i = 0; i < 64; i++) + intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]); + + return 0; +} +#else +#define intc_suspend NULL +#define intc_resume NULL +#endif + +static struct sysdev_class intc_class = { + .name = "intc", + .suspend = intc_suspend, + .resume = intc_resume, +}; + +static int __init intc_init_sysdev(void) +{ + int ret; + + ret = sysdev_class_register(&intc_class); + if (ret) + return ret; + + intc0.sysdev.id = 0; + intc0.sysdev.cls = &intc_class; + ret = sysdev_register(&intc0.sysdev); + + return ret; +} +device_initcall(intc_init_sysdev); + unsigned long intc_get_pending(unsigned int group) { return intc_readl(&intc0, INTREQ0 + 4 * group); --- /dev/null +++ b/arch/avr32/mach-at32ap/pdc.c @@ -0,0 +1,48 @@ +/* + * 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/err.h> +#include <linux/init.h> +#include <linux/platform_device.h> + +static int __init pdc_probe(struct platform_device *pdev) +{ + struct clk *pclk, *hclk; + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) { + dev_err(&pdev->dev, "no pclk defined\n"); + return PTR_ERR(pclk); + } + hclk = clk_get(&pdev->dev, "hclk"); + if (IS_ERR(hclk)) { + dev_err(&pdev->dev, "no hclk defined\n"); + clk_put(pclk); + return PTR_ERR(hclk); + } + + clk_enable(pclk); + clk_enable(hclk); + + dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n"); + return 0; +} + +static struct platform_driver pdc_driver = { + .probe = pdc_probe, + .driver = { + .name = "pdc", + }, +}; + +static int __init pdc_init(void) +{ + return platform_driver_register(&pdc_driver); +} +arch_initcall(pdc_init); --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -157,6 +157,82 @@ 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 */ @@ -318,6 +394,8 @@ const char *label; label = gpiochip_is_requested(chip, i); + if (!label && (imr & mask)) + label = "[irq]"; if (!label) continue; --- a/arch/avr32/mach-at32ap/pio.h +++ b/arch/avr32/mach-at32ap/pio.h @@ -57,7 +57,7 @@ /* Bitfields in IFDR */ -/* Bitfields in ISFR */ +/* Bitfields in IFSR */ /* Bitfields in SODR */ --- /dev/null +++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S @@ -0,0 +1,174 @@ +/* + * Low-level Power Management code. + * + * Copyright (C) 2008 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/asm.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/arch/pm.h> + +#include "pm.h" +#include "sdramc.h" + +/* Same as 0xfff00000 but fits in a 21 bit signed immediate */ +#define PM_BASE -0x100000 + + .section .bss, "wa", @nobits + .global disable_idle_sleep + .type disable_idle_sleep, @object +disable_idle_sleep: + .int 4 + .size disable_idle_sleep, . - disable_idle_sleep + + /* Keep this close to the irq handlers */ + .section .irq.text, "ax", @progbits + + /* + * void cpu_enter_idle(void) + * + * Put the CPU into "idle" mode, in which it will consume + * significantly less power. + * + * If an interrupt comes along in the window between + * unmask_interrupts and the sleep instruction below, the + * interrupt code will adjust the return address so that we + * never execute the sleep instruction. This is required + * because the AP7000 doesn't unmask interrupts when entering + * sleep modes; later CPUs may not need this workaround. + */ + .global cpu_enter_idle + .type cpu_enter_idle, @function +cpu_enter_idle: + mask_interrupts + get_thread_info r8 + ld.w r9, r8[TI_flags] + bld r9, TIF_NEED_RESCHED + brcs .Lret_from_sleep + sbr r9, TIF_CPU_GOING_TO_SLEEP + st.w r8[TI_flags], r9 + unmask_interrupts + sleep CPU_SLEEP_IDLE + .size cpu_idle_sleep, . - cpu_idle_sleep + + /* + * Common return path for PM functions that don't run from + * SRAM. + */ + .global cpu_idle_skip_sleep + .type cpu_idle_skip_sleep, @function +cpu_idle_skip_sleep: + mask_interrupts + ld.w r9, r8[TI_flags] + cbr r9, TIF_CPU_GOING_TO_SLEEP + st.w r8[TI_flags], r9 +.Lret_from_sleep: + unmask_interrupts + retal r12 + .size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep + +#ifdef CONFIG_PM + .section .init.text, "ax", @progbits + + .global pm_exception + .type pm_exception, @function +pm_exception: + /* + * Exceptions are masked when we switch to this handler, so + * we'll only get "unrecoverable" exceptions (offset 0.) + */ + sub r12, pc, . - .Lpanic_msg + lddpc pc, .Lpanic_addr + + .align 2 +.Lpanic_addr: + .long panic +.Lpanic_msg: + .asciz "Unrecoverable exception during suspend\n" + .size pm_exception, . - pm_exception + + .global pm_irq0 + .type pm_irq0, @function +pm_irq0: + /* Disable interrupts and return after the sleep instruction */ + mfsr r9, SYSREG_RSR_INT0 + mtsr SYSREG_RAR_INT0, r8 + sbr r9, SYSREG_GM_OFFSET + mtsr SYSREG_RSR_INT0, r9 + rete + + /* + * void cpu_enter_standby(unsigned long sdramc_base) + * + * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers + * are suspended and interrupts are disabled. Interrupts + * marked as 'wakeup' event sources may still come along and + * get us out of here. + * + * The SDRAM will be put into self-refresh mode (which does + * not require a clock from the CPU), and the CPU will be put + * into "frozen" mode (HSB bus stopped). The SDRAM controller + * will automatically bring the SDRAM into normal mode on the + * first access, and the power manager will automatically + * start the HSB and CPU clocks upon a wakeup event. + * + * This code uses the same "skip sleep" technique as above. + * It is very important that we jump directly to + * cpu_after_sleep after the sleep instruction since that's + * where we'll end up if the interrupt handler decides that we + * need to skip the sleep instruction. + */ + .global pm_standby + .type pm_standby, @function +pm_standby: + /* + * interrupts are already masked at this point, and EVBA + * points to pm_exception above. + */ + ld.w r10, r12[SDRAMC_LPR] + sub r8, pc, . - 1f /* return address for irq handler */ + mov r11, SDRAMC_LPR_LPCB_SELF_RFR + bfins r10, r11, 0, 2 /* LPCB <- self Refresh */ + sync 0 /* flush write buffer */ + st.w r12[SDRAMC_LPR], r11 /* put SDRAM in self-refresh mode */ + ld.w r11, r12[SDRAMC_LPR] + unmask_interrupts + sleep CPU_SLEEP_FROZEN +1: mask_interrupts + retal r12 + .size pm_standby, . - pm_standby + + .global pm_suspend_to_ram + .type pm_suspend_to_ram, @function +pm_suspend_to_ram: + /* + * interrupts are already masked at this point, and EVBA + * points to pm_exception above. + */ + mov r11, 0 + cache r11[2], 8 /* clean all dcache lines */ + sync 0 /* flush write buffer */ + ld.w r10, r12[SDRAMC_LPR] + sub r8, pc, . - 1f /* return address for irq handler */ + mov r11, SDRAMC_LPR_LPCB_SELF_RFR + bfins r10, r11, 0, 2 /* LPCB <- self refresh */ + st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */ + ld.w r11, r12[SDRAMC_LPR] + + unmask_interrupts + sleep CPU_SLEEP_STOP +1: mask_interrupts + + retal r12 + .size pm_suspend_to_ram, . - pm_suspend_to_ram + + .global pm_sram_end + .type pm_sram_end, @function +pm_sram_end: + .size pm_sram_end, 0 + +#endif /* CONFIG_PM */ --- /dev/null +++ b/arch/avr32/mach-at32ap/pm.c @@ -0,0 +1,245 @@ +/* + * AVR32 AP Power Management + * + * Copyright (C) 2008 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/io.h> +#include <linux/suspend.h> +#include <linux/vmalloc.h> + +#include <asm/cacheflush.h> +#include <asm/sysreg.h> + +#include <asm/arch/pm.h> +#include <asm/arch/sram.h> + +/* FIXME: This is only valid for AP7000 */ +#define SDRAMC_BASE 0xfff03800 + +#include "sdramc.h" + +#define SRAM_PAGE_FLAGS (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1) \ + | SYSREG_BF(AP, 3) | SYSREG_BIT(G)) + + +static unsigned long pm_sram_start; +static size_t pm_sram_size; +static struct vm_struct *pm_sram_area; + +static void (*avr32_pm_enter_standby)(unsigned long sdramc_base); +static void (*avr32_pm_enter_str)(unsigned long sdramc_base); + +/* + * Must be called with interrupts disabled. Exceptions will be masked + * on return (i.e. all exceptions will be "unrecoverable".) + */ +static void *avr32_pm_map_sram(void) +{ + unsigned long vaddr; + unsigned long page_addr; + u32 tlbehi; + u32 mmucr; + + vaddr = (unsigned long)pm_sram_area->addr; + page_addr = pm_sram_start & PAGE_MASK; + + /* + * Mask exceptions and grab the first TLB entry. We won't be + * needing it while sleeping. + */ + asm volatile("ssrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory"); + + mmucr = sysreg_read(MMUCR); + tlbehi = sysreg_read(TLBEHI); + sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr)); + + tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi)); + tlbehi |= vaddr & PAGE_MASK; + tlbehi |= SYSREG_BIT(TLBEHI_V); + + sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS); + sysreg_write(TLBEHI, tlbehi); + __builtin_tlbw(); + + return (void *)(vaddr + pm_sram_start - page_addr); +} + +/* + * Must be called with interrupts disabled. Exceptions will be + * unmasked on return. + */ +static void avr32_pm_unmap_sram(void) +{ + u32 mmucr; + u32 tlbehi; + u32 tlbarlo; + + /* Going to update TLB entry at index 0 */ + mmucr = sysreg_read(MMUCR); + tlbehi = sysreg_read(TLBEHI); + sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr)); + + /* Clear the "valid" bit */ + tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi)); + sysreg_write(TLBEHI, tlbehi); + + /* Mark it as "not accessed" */ + tlbarlo = sysreg_read(TLBARLO); + sysreg_write(TLBARLO, tlbarlo | 0x80000000U); + + /* Update the TLB */ + __builtin_tlbw(); + + /* Unmask exceptions */ + asm volatile("csrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory"); +} + +static int avr32_pm_valid_state(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_ON: + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + + default: + return 0; + } +} + +static int avr32_pm_enter(suspend_state_t state) +{ + u32 lpr_saved; + u32 evba_saved; + void *sram; + + switch (state) { + case PM_SUSPEND_STANDBY: + sram = avr32_pm_map_sram(); + + /* Switch to in-sram exception handlers */ + evba_saved = sysreg_read(EVBA); + sysreg_write(EVBA, (unsigned long)sram); + + /* + * Save the LPR register so that we can re-enable + * SDRAM Low Power mode on resume. + */ + lpr_saved = sdramc_readl(LPR); + pr_debug("%s: Entering standby...\n", __func__); + avr32_pm_enter_standby(SDRAMC_BASE); + sdramc_writel(LPR, lpr_saved); + + /* Switch back to regular exception handlers */ + sysreg_write(EVBA, evba_saved); + + avr32_pm_unmap_sram(); + break; + + case PM_SUSPEND_MEM: + sram = avr32_pm_map_sram(); + + /* Switch to in-sram exception handlers */ + evba_saved = sysreg_read(EVBA); + sysreg_write(EVBA, (unsigned long)sram); + + /* + * Save the LPR register so that we can re-enable + * SDRAM Low Power mode on resume. + */ + lpr_saved = sdramc_readl(LPR); + pr_debug("%s: Entering suspend-to-ram...\n", __func__); + avr32_pm_enter_str(SDRAMC_BASE); + sdramc_writel(LPR, lpr_saved); + + /* Switch back to regular exception handlers */ + sysreg_write(EVBA, evba_saved); + + avr32_pm_unmap_sram(); + break; + + case PM_SUSPEND_ON: + pr_debug("%s: Entering idle...\n", __func__); + cpu_enter_idle(); + break; + + default: + pr_debug("%s: Invalid suspend state %d\n", __func__, state); + goto out; + } + + pr_debug("%s: wakeup\n", __func__); + +out: + return 0; +} + +static struct platform_suspend_ops avr32_pm_ops = { + .valid = avr32_pm_valid_state, + .enter = avr32_pm_enter, +}; + +static unsigned long avr32_pm_offset(void *symbol) +{ + extern u8 pm_exception[]; + + return (unsigned long)symbol - (unsigned long)pm_exception; +} + +static int __init avr32_pm_init(void) +{ + extern u8 pm_exception[]; + extern u8 pm_irq0[]; + extern u8 pm_standby[]; + extern u8 pm_suspend_to_ram[]; + extern u8 pm_sram_end[]; + void *dst; + + /* + * To keep things simple, we depend on not needing more than a + * single page. + */ + pm_sram_size = avr32_pm_offset(pm_sram_end); + if (pm_sram_size > PAGE_SIZE) + goto err; + + pm_sram_start = sram_alloc(pm_sram_size); + if (!pm_sram_start) + goto err_alloc_sram; + + /* Grab a virtual area we can use later on. */ + pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP); + if (!pm_sram_area) + goto err_vm_area; + pm_sram_area->phys_addr = pm_sram_start; + + local_irq_disable(); + dst = avr32_pm_map_sram(); + memcpy(dst, pm_exception, pm_sram_size); + flush_dcache_region(dst, pm_sram_size); + invalidate_icache_region(dst, pm_sram_size); + avr32_pm_unmap_sram(); + local_irq_enable(); + + avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby); + avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram); + intc_set_suspend_handler(avr32_pm_offset(pm_irq0)); + + suspend_set_ops(&avr32_pm_ops); + + printk("AVR32 AP Power Management enabled\n"); + + return 0; + +err_vm_area: + sram_free(pm_sram_start, pm_sram_size); +err_alloc_sram: +err: + pr_err("AVR32 Power Management initialization failed\n"); + return -ENOMEM; +} +arch_initcall(avr32_pm_init); --- /dev/null +++ b/arch/avr32/mach-at32ap/sdramc.h @@ -0,0 +1,76 @@ +/* + * Register definitions for the AT32AP SDRAM Controller + * + * Copyright (C) 2008 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. + */ + +/* Register offsets */ +#define SDRAMC_MR 0x0000 +#define SDRAMC_TR 0x0004 +#define SDRAMC_CR 0x0008 +#define SDRAMC_HSR 0x000c +#define SDRAMC_LPR 0x0010 +#define SDRAMC_IER 0x0014 +#define SDRAMC_IDR 0x0018 +#define SDRAMC_IMR 0x001c +#define SDRAMC_ISR 0x0020 +#define SDRAMC_MDR 0x0024 + +/* MR - Mode Register */ +#define SDRAMC_MR_MODE_NORMAL ( 0 << 0) +#define SDRAMC_MR_MODE_NOP ( 1 << 0) +#define SDRAMC_MR_MODE_BANKS_PRECHARGE ( 2 << 0) +#define SDRAMC_MR_MODE_LOAD_MODE ( 3 << 0) +#define SDRAMC_MR_MODE_AUTO_REFRESH ( 4 << 0) +#define SDRAMC_MR_MODE_EXT_LOAD_MODE ( 5 << 0) +#define SDRAMC_MR_MODE_POWER_DOWN ( 6 << 0) + +/* CR - Configuration Register */ +#define SDRAMC_CR_NC_8_BITS ( 0 << 0) +#define SDRAMC_CR_NC_9_BITS ( 1 << 0) +#define SDRAMC_CR_NC_10_BITS ( 2 << 0) +#define SDRAMC_CR_NC_11_BITS ( 3 << 0) +#define SDRAMC_CR_NR_11_BITS ( 0 << 2) +#define SDRAMC_CR_NR_12_BITS ( 1 << 2) +#define SDRAMC_CR_NR_13_BITS ( 2 << 2) +#define SDRAMC_CR_NB_2_BANKS ( 0 << 4) +#define SDRAMC_CR_NB_4_BANKS ( 1 << 4) +#define SDRAMC_CR_CAS(x) ((x) << 5) +#define SDRAMC_CR_DBW_32_BITS ( 0 << 7) +#define SDRAMC_CR_DBW_16_BITS ( 1 << 7) +#define SDRAMC_CR_TWR(x) ((x) << 8) +#define SDRAMC_CR_TRC(x) ((x) << 12) +#define SDRAMC_CR_TRP(x) ((x) << 16) +#define SDRAMC_CR_TRCD(x) ((x) << 20) +#define SDRAMC_CR_TRAS(x) ((x) << 24) +#define SDRAMC_CR_TXSR(x) ((x) << 28) + +/* HSR - High Speed Register */ +#define SDRAMC_HSR_DA ( 1 << 0) + +/* LPR - Low Power Register */ +#define SDRAMC_LPR_LPCB_INHIBIT ( 0 << 0) +#define SDRAMC_LPR_LPCB_SELF_RFR ( 1 << 0) +#define SDRAMC_LPR_LPCB_PDOWN ( 2 << 0) +#define SDRAMC_LPR_LPCB_DEEP_PDOWN ( 3 << 0) +#define SDRAMC_LPR_PASR(x) ((x) << 4) +#define SDRAMC_LPR_TCSR(x) ((x) << 8) +#define SDRAMC_LPR_DS(x) ((x) << 10) +#define SDRAMC_LPR_TIMEOUT(x) ((x) << 12) + +/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */ +#define SDRAMC_ISR_RES ( 1 << 0) + +/* MDR - Memory Device Register */ +#define SDRAMC_MDR_MD_SDRAM ( 0 << 0) +#define SDRAMC_MDR_MD_LOW_PWR_SDRAM ( 1 << 0) + +/* Register access macros */ +#define sdramc_readl(reg) \ + __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg) +#define sdramc_writel(reg, value) \ + __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg) --- a/arch/avr32/mach-at32ap/time-tc.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2004-2007 Atmel Corporation - * - * Based on MIPS implementation arch/mips/kernel/time.c - * Copyright 2001 MontaVista Software Inc. - * - * 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/clocksource.h> -#include <linux/time.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/profile.h> -#include <linux/sysdev.h> -#include <linux/err.h> - -#include <asm/div64.h> -#include <asm/sysreg.h> -#include <asm/io.h> -#include <asm/sections.h> - -#include <asm/arch/time.h> - -/* how many counter cycles in a jiffy? */ -static u32 cycles_per_jiffy; - -/* the count value for the next timer interrupt */ -static u32 expirelo; - -/* the I/O registers of the TC module */ -static void __iomem *ioregs; - -cycle_t read_cycle_count(void) -{ - return (cycle_t)timer_read(ioregs, 0, CV); -} - -struct clocksource clocksource_avr32 = { - .name = "avr32", - .rating = 342, - .read = read_cycle_count, - .mask = CLOCKSOURCE_MASK(16), - .shift = 16, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static void avr32_timer_ack(void) -{ - u16 count = expirelo; - - /* Ack this timer interrupt and set the next one, use a u16 - * variable so it will wrap around correctly */ - count += cycles_per_jiffy; - expirelo = count; - timer_write(ioregs, 0, RC, expirelo); - - /* Check to see if we have missed any timer interrupts */ - count = timer_read(ioregs, 0, CV); - if ((count - expirelo) < 0x7fff) { - expirelo = count + cycles_per_jiffy; - timer_write(ioregs, 0, RC, expirelo); - } -} - -u32 avr32_hpt_read(void) -{ - return timer_read(ioregs, 0, CV); -} - -static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk) -{ - unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2; - unsigned int divs[] = { 4, 8, 16, 32 }; - int divs_size = ARRAY_SIZE(divs); - int i = 0; - unsigned long count_hz; - unsigned long shift; - unsigned long mult; - int clock_div = -1; - u64 tmp; - - shift = clocksource_avr32.shift; - - do { - count_hz = clk_get_rate(pclk) / divs[i]; - mult = clocksource_hz2mult(count_hz, shift); - clocksource_avr32.mult = mult; - - tmp = TICK_NSEC; - tmp <<= shift; - tmp += mult / 2; - do_div(tmp, mult); - - cycles_per_jiffy = tmp; - } while (cycles_per_jiffy > cycles_max && ++i < divs_size); - - clock_div = i + 1; - - if (clock_div > divs_size) { - pr_debug("timer: could not calculate clock divider\n"); - return -EFAULT; - } - - /* Set the clock divider */ - timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div)); - - return 0; -} - -int avr32_hpt_init(unsigned int count) -{ - struct resource *regs; - struct clk *pclk; - int irq = -1; - int ret = 0; - - ret = -ENXIO; - - irq = platform_get_irq(&at32_systc0_device, 0); - if (irq < 0) { - pr_debug("timer: could not get irq\n"); - goto out_error; - } - - pclk = clk_get(&at32_systc0_device.dev, "pclk"); - if (IS_ERR(pclk)) { - pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk)); - goto out_error; - } - clk_enable(pclk); - - regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0); - if (!regs) { - pr_debug("timer: could not get resource\n"); - goto out_error_clk; - } - - ioregs = ioremap(regs->start, regs->end - regs->start + 1); - if (!ioregs) { - pr_debug("timer: could not get ioregs\n"); - goto out_error_clk; - } - - ret = avr32_timer_calc_div_and_set_jiffies(pclk); - if (ret) - goto out_error_io; - - ret = setup_irq(irq, &timer_irqaction); - if (ret) { - pr_debug("timer: could not request irq %d: %d\n", - irq, ret); - goto out_error_io; - } - - expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1) - * cycles_per_jiffy; - - /* Enable clock and interrupts on RC compare */ - timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN)); - timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS)); - /* Set cycles to first interrupt */ - timer_write(ioregs, 0, RC, expirelo); - - printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n", - ioregs, irq); - - return 0; - -out_error_io: - iounmap(ioregs); -out_error_clk: - clk_put(pclk); -out_error: - return ret; -} - -int avr32_hpt_start(void) -{ - timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG)); - return 0; -} - -irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - unsigned int sr = timer_read(ioregs, 0, SR); - - if (sr & TIMER_BIT(SR_CPCS)) { - /* ack timer interrupt and try to set next interrupt */ - avr32_timer_ack(); - - /* - * Call the generic timer interrupt handler - */ - write_seqlock(&xtime_lock); - do_timer(1); - write_sequnlock(&xtime_lock); - - /* - * In UP mode, we call local_timer_interrupt() to do profiling - * and process accounting. - * - * SMP is not supported yet. - */ - local_timer_interrupt(irq, dev_id); - - return IRQ_HANDLED; - } - - return IRQ_NONE; -} --- a/arch/avr32/mm/init.c +++ b/arch/avr32/mm/init.c @@ -11,6 +11,7 @@ #include <linux/swap.h> #include <linux/init.h> #include <linux/mmzone.h> +#include <linux/module.h> #include <linux/bootmem.h> #include <linux/pagemap.h> #include <linux/nodemask.h> @@ -23,20 +24,20 @@ #include <asm/setup.h> #include <asm/sections.h> +#define __page_aligned __attribute__((section(".data.page_aligned"))) + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -pgd_t swapper_pg_dir[PTRS_PER_PGD]; +pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned; struct page *empty_zero_page; +EXPORT_SYMBOL(empty_zero_page); /* * Cache of MMU context last used. */ unsigned long mmu_context_cache = NO_CONTEXT; -#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) -#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) - void show_mem(void) { int total = 0, reserved = 0, cached = 0; @@ -109,19 +110,9 @@ zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE); - { - pgd_t *pg_dir; - int i; - - pg_dir = swapper_pg_dir; - sysreg_write(PTBR, (unsigned long)pg_dir); - - for (i = 0; i < PTRS_PER_PGD; i++) - pgd_val(pg_dir[i]) = 0; - - enable_mmu(); - printk ("CPU: Paging enabled\n"); - } + sysreg_write(PTBR, (unsigned long)swapper_pg_dir); + enable_mmu(); + printk ("CPU: Paging enabled\n"); for_each_online_node(nid) { pg_data_t *pgdat = NODE_DATA(nid); --- a/arch/avr32/mm/tlb.c +++ b/arch/avr32/mm/tlb.c @@ -11,21 +11,21 @@ #include <asm/mmu_context.h> -#define _TLBEHI_I 0x100 +/* TODO: Get the correct number from the CONFIG1 system register */ +#define NR_TLB_ENTRIES 32 -void show_dtlb_entry(unsigned int index) +static void show_dtlb_entry(unsigned int index) { - unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save; + u32 tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save; unsigned long flags; local_irq_save(flags); mmucr_save = sysreg_read(MMUCR); tlbehi_save = sysreg_read(TLBEHI); - mmucr = mmucr_save & 0x13; - mmucr |= index << 14; + mmucr = SYSREG_BFINS(DRP, index, mmucr_save); sysreg_write(MMUCR, mmucr); - asm volatile("tlbr" : : : "memory"); + __builtin_tlbr(); cpu_sync_pipeline(); tlbehi = sysreg_read(TLBEHI); @@ -33,15 +33,17 @@ printk("%2u: %c %c %02x %05x %05x %o %o %c %c %c %c\n", index, - (tlbehi & 0x200)?'1':'0', - (tlbelo & 0x100)?'1':'0', - (tlbehi & 0xff), - (tlbehi >> 12), (tlbelo >> 12), - (tlbelo >> 4) & 7, (tlbelo >> 2) & 3, - (tlbelo & 0x200)?'1':'0', - (tlbelo & 0x080)?'1':'0', - (tlbelo & 0x001)?'1':'0', - (tlbelo & 0x002)?'1':'0'); + SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0', + SYSREG_BFEXT(G, tlbelo) ? '1' : '0', + SYSREG_BFEXT(ASID, tlbehi), + SYSREG_BFEXT(VPN, tlbehi) >> 2, + SYSREG_BFEXT(PFN, tlbelo) >> 2, + SYSREG_BFEXT(AP, tlbelo), + SYSREG_BFEXT(SZ, tlbelo), + SYSREG_BFEXT(TLBELO_C, tlbelo) ? 'C' : ' ', + SYSREG_BFEXT(B, tlbelo) ? 'B' : ' ', + SYSREG_BFEXT(W, tlbelo) ? 'W' : ' ', + SYSREG_BFEXT(TLBELO_D, tlbelo) ? 'D' : ' '); sysreg_write(MMUCR, mmucr_save); sysreg_write(TLBEHI, tlbehi_save); @@ -54,29 +56,33 @@ unsigned int i; printk("ID V G ASID VPN PFN AP SZ C B W D\n"); - for (i = 0; i < 32; i++) + for (i = 0; i < NR_TLB_ENTRIES; i++) show_dtlb_entry(i); } -static unsigned long last_mmucr; - -static inline void set_replacement_pointer(unsigned shift) +static void update_dtlb(unsigned long address, pte_t pte) { - unsigned long mmucr, mmucr_save; + u32 tlbehi; + u32 mmucr; - mmucr = mmucr_save = sysreg_read(MMUCR); + /* + * We're not changing the ASID here, so no need to flush the + * pipeline. + */ + tlbehi = sysreg_read(TLBEHI); + tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi)); + tlbehi |= address & MMU_VPN_MASK; + tlbehi |= SYSREG_BIT(TLBEHI_V); + sysreg_write(TLBEHI, tlbehi); /* Does this mapping already exist? */ - __asm__ __volatile__( - " tlbs\n" - " mfsr %0, %1" - : "=r"(mmucr) - : "i"(SYSREG_MMUCR)); + __builtin_tlbs(); + mmucr = sysreg_read(MMUCR); if (mmucr & SYSREG_BIT(MMUCR_N)) { /* Not found -- pick a not-recently-accessed entry */ - unsigned long rp; - unsigned long tlbar = sysreg_read(TLBARLO); + unsigned int rp; + u32 tlbar = sysreg_read(TLBARLO); rp = 32 - fls(tlbar); if (rp == 32) { @@ -84,30 +90,14 @@ sysreg_write(TLBARLO, -1L); } - mmucr &= 0x13; - mmucr |= (rp << shift); - + mmucr = SYSREG_BFINS(DRP, rp, mmucr); sysreg_write(MMUCR, mmucr); } - last_mmucr = mmucr; -} - -static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid) -{ - unsigned long vpn; - - vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid; - sysreg_write(TLBEHI, vpn); - cpu_sync_pipeline(); - - set_replacement_pointer(14); - sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK); /* Let's go */ - asm volatile("nop\n\ttlbw" : : : "memory"); - cpu_sync_pipeline(); + __builtin_tlbw(); } void update_mmu_cache(struct vm_area_struct *vma, @@ -120,39 +110,40 @@ return; local_irq_save(flags); - update_dtlb(address, pte, get_asid()); + update_dtlb(address, pte); local_irq_restore(flags); } -void __flush_tlb_page(unsigned long asid, unsigned long page) +static void __flush_tlb_page(unsigned long asid, unsigned long page) { - unsigned long mmucr, tlbehi; + u32 mmucr, tlbehi; - page |= asid; - sysreg_write(TLBEHI, page); - cpu_sync_pipeline(); - asm volatile("tlbs"); + /* + * Caller is responsible for masking out non-PFN bits in page + * and changing the current ASID if necessary. This means that + * we don't need to flush the pipeline after writing TLBEHI. + */ + tlbehi = page | asid; + sysreg_write(TLBEHI, tlbehi); + + __builtin_tlbs(); mmucr = sysreg_read(MMUCR); if (!(mmucr & SYSREG_BIT(MMUCR_N))) { - unsigned long tlbarlo; - unsigned long entry; + unsigned int entry; + u32 tlbarlo; /* Clear the "valid" bit */ - tlbehi = sysreg_read(TLBEHI); - tlbehi &= ~_TLBEHI_VALID; sysreg_write(TLBEHI, tlbehi); - cpu_sync_pipeline(); /* mark the entry as "not accessed" */ - entry = (mmucr >> 14) & 0x3f; + entry = SYSREG_BFEXT(DRP, mmucr); tlbarlo = sysreg_read(TLBARLO); - tlbarlo |= (0x80000000 >> entry); + tlbarlo |= (0x80000000UL >> entry); sysreg_write(TLBARLO, tlbarlo); /* update the entry with valid bit clear */ - asm volatile("tlbw"); - cpu_sync_pipeline(); + __builtin_tlbw(); } } @@ -190,17 +181,22 @@ local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */ mm->context = NO_CONTEXT; if (mm == current->mm) activate_context(mm); } else { - unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK; - unsigned long saved_asid = MMU_NO_ASID; + unsigned long asid; + unsigned long saved_asid; + + asid = mm->context & MMU_CONTEXT_ASID_MASK; + saved_asid = MMU_NO_ASID; start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; + if (mm != current->mm) { saved_asid = get_asid(); set_asid(asid); @@ -218,33 +214,34 @@ } /* - * TODO: If this is only called for addresses > TASK_SIZE, we can probably - * skip the ASID stuff and just use the Global bit... + * This function depends on the pages to be flushed having the G + * (global) bit set in their pte. This is true for all + * PAGE_KERNEL(_RO) pages. */ void flush_tlb_kernel_range(unsigned long start, unsigned long end) { unsigned long flags; int size; - local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */ flush_tlb_all(); } else { - unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK; - unsigned long saved_asid = get_asid(); + unsigned long asid; + + local_irq_save(flags); + asid = get_asid(); start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; - set_asid(asid); + while (start < end) { __flush_tlb_page(asid, start); start += PAGE_SIZE; } - set_asid(saved_asid); + local_irq_restore(flags); } - local_irq_restore(flags); } void flush_tlb_mm(struct mm_struct *mm) @@ -280,7 +277,7 @@ { static unsigned long tlb_index; - if (*pos >= 32) + if (*pos >= NR_TLB_ENTRIES) return NULL; tlb_index = 0; @@ -291,7 +288,7 @@ { unsigned long *index = v; - if (*index >= 31) + if (*index >= NR_TLB_ENTRIES - 1) return NULL; ++*pos; @@ -313,16 +310,16 @@ if (*index == 0) seq_puts(tlb, "ID V G ASID VPN PFN AP SZ C B W D\n"); - BUG_ON(*index >= 32); + BUG_ON(*index >= NR_TLB_ENTRIES); local_irq_save(flags); mmucr_save = sysreg_read(MMUCR); tlbehi_save = sysreg_read(TLBEHI); - mmucr = mmucr_save & 0x13; - mmucr |= *index << 14; + mmucr = SYSREG_BFINS(DRP, *index, mmucr_save); sysreg_write(MMUCR, mmucr); - asm volatile("tlbr" : : : "memory"); + /* TLBR might change the ASID */ + __builtin_tlbr(); cpu_sync_pipeline(); tlbehi = sysreg_read(TLBEHI); @@ -334,16 +331,18 @@ local_irq_restore(flags); seq_printf(tlb, "%2lu: %c %c %02x %05x %05x %o %o %c %c %c %c\n", - *index, - (tlbehi & 0x200)?'1':'0', - (tlbelo & 0x100)?'1':'0', - (tlbehi & 0xff), - (tlbehi >> 12), (tlbelo >> 12), - (tlbelo >> 4) & 7, (tlbelo >> 2) & 3, - (tlbelo & 0x200)?'1':'0', - (tlbelo & 0x080)?'1':'0', - (tlbelo & 0x001)?'1':'0', - (tlbelo & 0x002)?'1':'0'); + *index, + SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0', + SYSREG_BFEXT(G, tlbelo) ? '1' : '0', + SYSREG_BFEXT(ASID, tlbehi), + SYSREG_BFEXT(VPN, tlbehi) >> 2, + SYSREG_BFEXT(PFN, tlbelo) >> 2, + SYSREG_BFEXT(AP, tlbelo), + SYSREG_BFEXT(SZ, tlbelo), + SYSREG_BFEXT(TLBELO_C, tlbelo) ? '1' : '0', + SYSREG_BFEXT(B, tlbelo) ? '1' : '0', + SYSREG_BFEXT(W, tlbelo) ? '1' : '0', + SYSREG_BFEXT(TLBELO_D, tlbelo) ? '1' : '0'); return 0; } --- a/arch/avr32/oprofile/op_model_avr32.c +++ b/arch/avr32/oprofile/op_model_avr32.c @@ -16,7 +16,6 @@ #include <linux/sched.h> #include <linux/types.h> -#include <asm/intc.h> #include <asm/sysreg.h> #include <asm/system.h> --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -706,7 +706,7 @@ config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 + depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -776,7 +776,7 @@ config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH + depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1033,7 +1033,8 @@ #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ - (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) + (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\ + defined(CONFIG_AVR32) #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o --- /dev/null +++ b/drivers/clocksource/tcb_clksrc.c @@ -0,0 +1,302 @@ +#include <linux/init.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/atmel_tc.h> + + +/* + * We're configured to use a specific TC block, one that's not hooked + * up to external hardware, to provide a time solution: + * + * - Two channels combine to create a free-running 32 bit counter + * with a base rate of 5+ MHz, packaged as a clocksource (with + * resolution better than 200 nsec). + * + * - The third channel may be used to provide a 16-bit clockevent + * source, used in either periodic or oneshot mode. This runs + * at 32 KiHZ, and can handle delays of up to two seconds. + * + * A boot clocksource and clockevent source are also currently needed, + * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so + * this code can be used when init_timers() is called, well before most + * devices are set up. (Some low end AT91 parts, which can run uClinux, + * have only the timers in one TC block... they currently don't support + * the tclib code, because of that initialization issue.) + * + * REVISIT behavior during system suspend states... we should disable + * all clocks and save the power. Easily done for clockevent devices, + * but clocksources won't necessarily get the needed notifications. + * For deeper system sleep states, this will be mandatory... + */ + +static void __iomem *tcaddr; + +static cycle_t tc_get_cycles(void) +{ + unsigned long flags; + u32 lower, upper; + + raw_local_irq_save(flags); + do { + upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)); + lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); + } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV))); + + raw_local_irq_restore(flags); + return (upper << 16) | lower; +} + +static struct clocksource clksrc = { + .name = "tcb_clksrc", + .rating = 200, + .read = tc_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 18, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +#ifdef CONFIG_GENERIC_CLOCKEVENTS + +struct tc_clkevt_device { + struct clock_event_device clkevt; + struct clk *clk; + void __iomem *regs; +}; + +static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt) +{ + return container_of(clkevt, struct tc_clkevt_device, clkevt); +} + +/* For now, we always use the 32K clock ... this optimizes for NO_HZ, + * because using one of the divided clocks would usually mean the + * tick rate can never be less than several dozen Hz (vs 0.5 Hz). + * + * A divided clock could be good for high resolution timers, since + * 30.5 usec resolution can seem "low". + */ +static u32 timer_clock; + +static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) +{ + struct tc_clkevt_device *tcd = to_tc_clkevt(d); + void __iomem *regs = tcd->regs; + + if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC + || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { + __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); + __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); + clk_disable(tcd->clk); + } + + switch (m) { + + /* By not making the gentime core emulate periodic mode on top + * of oneshot, we get lower overhead and improved accuracy. + */ + case CLOCK_EVT_MODE_PERIODIC: + clk_enable(tcd->clk); + + /* slow clock, count up to RC, then irq and restart */ + __raw_writel(timer_clock + | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, + regs + ATMEL_TC_REG(2, CMR)); + __raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); + + /* Enable clock and interrupts on RC compare */ + __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + + /* go go gadget! */ + __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, + regs + ATMEL_TC_REG(2, CCR)); + break; + + case CLOCK_EVT_MODE_ONESHOT: + clk_enable(tcd->clk); + + /* slow clock, count up to RC, then irq and stop */ + __raw_writel(timer_clock | ATMEL_TC_CPCSTOP + | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, + regs + ATMEL_TC_REG(2, CMR)); + __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + + /* set_next_event() configures and starts the timer */ + break; + + default: + break; + } +} + +static int tc_next_event(unsigned long delta, struct clock_event_device *d) +{ + __raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC)); + + /* go go gadget! */ + __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, + tcaddr + ATMEL_TC_REG(2, CCR)); + return 0; +} + +static struct tc_clkevt_device clkevt = { + .clkevt = { + .name = "tc_clkevt", + .features = CLOCK_EVT_FEAT_PERIODIC + | CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + /* Should be lower than at91rm9200's system timer */ + .rating = 125, + .cpumask = CPU_MASK_CPU0, + .set_next_event = tc_next_event, + .set_mode = tc_mode, + }, +}; + +static irqreturn_t ch2_irq(int irq, void *handle) +{ + struct tc_clkevt_device *dev = handle; + unsigned int sr; + + sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR)); + if (sr & ATMEL_TC_CPCS) { + dev->clkevt.event_handler(&dev->clkevt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static struct irqaction tc_irqaction = { + .name = "tc_clkevt", + .flags = IRQF_TIMER | IRQF_DISABLED, + .handler = ch2_irq, +}; + +static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) +{ + struct clk *t2_clk = tc->clk[2]; + int irq = tc->irq[2]; + + clkevt.regs = tc->regs; + clkevt.clk = t2_clk; + tc_irqaction.dev_id = &clkevt; + + timer_clock = clk32k_divisor_idx; + + clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift); + clkevt.clkevt.max_delta_ns + = clockevent_delta2ns(0xffff, &clkevt.clkevt); + clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1; + + setup_irq(irq, &tc_irqaction); + + clockevents_register_device(&clkevt.clkevt); +} + +#else /* !CONFIG_GENERIC_CLOCKEVENTS */ + +static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) +{ + /* NOTHING */ +} + +#endif + +static int __init tcb_clksrc_init(void) +{ + static char bootinfo[] __initdata + = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n"; + + struct platform_device *pdev; + struct atmel_tc *tc; + struct clk *t0_clk; + u32 rate, divided_rate = 0; + int best_divisor_idx = -1; + int clk32k_divisor_idx = -1; + int i; + + tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name); + if (!tc) { + pr_debug("can't alloc TC for clocksource\n"); + return -ENODEV; + } + tcaddr = tc->regs; + pdev = tc->pdev; + + t0_clk = tc->clk[0]; + clk_enable(t0_clk); + + /* How fast will we be counting? Pick something over 5 MHz. */ + rate = (u32) clk_get_rate(t0_clk); + for (i = 0; i < 5; i++) { + unsigned divisor = atmel_tc_divisors[i]; + unsigned tmp; + + /* remember 32 KiHz clock for later */ + if (!divisor) { + clk32k_divisor_idx = i; + continue; + } + + tmp = rate / divisor; + pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp); + if (best_divisor_idx > 0) { + if (tmp < 5 * 1000 * 1000) + continue; + } + divided_rate = tmp; + best_divisor_idx = i; + } + + clksrc.mult = clocksource_hz2mult(divided_rate, clksrc.shift); + + printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK, + divided_rate / 1000000, + ((divided_rate + 500000) % 1000000) / 1000); + + /* tclib will give us three clocks no matter what the + * underlying platform supports. + */ + clk_enable(tc->clk[1]); + + /* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */ + __raw_writel(best_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_WAVE + | ATMEL_TC_WAVESEL_UP /* free-run */ + | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */ + | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */ + tcaddr + ATMEL_TC_REG(0, CMR)); + __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA)); + __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC)); + __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ + __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); + + /* channel 1: waveform mode, input TIOA0 */ + __raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */ + | ATMEL_TC_WAVE + | ATMEL_TC_WAVESEL_UP, /* free-run */ + tcaddr + ATMEL_TC_REG(1, CMR)); + __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */ + __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR)); + + /* chain channel 0 to channel 1, then reset all the timers */ + __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR); + __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); + + /* and away we go! */ + clocksource_register(&clksrc); + + /* channel 2: periodic and oneshot timer support */ + setup_clkevents(tc, clk32k_divisor_idx); + + return 0; +} +arch_initcall(tcb_clksrc_init); --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -88,6 +88,14 @@ 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 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -52,6 +52,7 @@ 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 --- /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_writel(twi, THR, + twi->buf[twi->len - twi->acks_left]); + 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"); --- /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__ */ --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -88,6 +88,17 @@ To compile this driver as a module, choose M here: the module will be called rpckbd. +config SERIO_AT32PSIF + tristate "AVR32 PSIF PS/2 keyboard and mouse controller" + depends on AVR32 + default n + help + Say Y here if you want to use the PSIF peripheral on AVR32 devices + and connect a PS/2 keyboard and/or mouse to it. + + To compile this driver as a module, choose M here: the module will + be called at32psif. + config SERIO_AMBAKMI tristate "AMBA KMI keyboard controller" depends on ARM_AMBA --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o +obj-$(CONFIG_SERIO_AT32PSIF) += at32psif.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_HP_SDC) += hp_sdc.o --- /dev/null +++ b/drivers/input/serio/at32psif.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2007 Atmel Corporation + * + * Driver for the AT32AP700X PS/2 controller (PSIF). + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/serio.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/platform_device.h> + +#include "at32psif.h" + +#define PSIF_BUF_SIZE 16 + +#define ring_is_empty(_psif) (_psif->head == _psif->tail) +#define ring_next_head(_psif) ((_psif->head + 1) & (PSIF_BUF_SIZE - 1)) +#define ring_next_tail(_psif) ((_psif->tail + 1) & (PSIF_BUF_SIZE - 1)) + +struct psif { + struct platform_device *pdev; + struct clk *pclk; + struct serio *io; + struct timer_list tx_timer; + void __iomem *regs; + unsigned int irq; + unsigned int open; + /* Prevent concurrent writes to circular buffer. */ + spinlock_t lock; + unsigned int head; + unsigned int tail; + unsigned char buffer[PSIF_BUF_SIZE]; +}; + +static irqreturn_t psif_interrupt(int irq, void *_ptr) +{ + struct psif *psif = _ptr; + int retval = IRQ_NONE; + unsigned int io_flags = 0; + unsigned long status; + + status = psif_readl(psif, SR); + + if (status & PSIF_BIT(RXRDY)) { + unsigned char val = (unsigned char) psif_readl(psif, RHR); + + if (status & PSIF_BIT(PARITY)) + io_flags |= SERIO_PARITY; + if (status & PSIF_BIT(OVRUN)) + dev_err(&psif->pdev->dev, "overrun read error\n"); + + serio_interrupt(psif->io, val, io_flags); + + retval = IRQ_HANDLED; + } + + spin_lock(&psif->lock); + + if (status & PSIF_BIT(TXEMPTY)) { + if (status & PSIF_BIT(NACK)) + dev_err(&psif->pdev->dev, "NACK error\n"); + + psif_writel(psif, IDR, PSIF_BIT(TXEMPTY)); + + if (!ring_is_empty(psif)) + mod_timer(&psif->tx_timer, + jiffies + msecs_to_jiffies(1)); + + retval = IRQ_HANDLED; + } + + spin_unlock(&psif->lock); + + return retval; +} + +static void psif_transmit_data(unsigned long data) +{ + struct psif *psif = (struct psif *)data; + unsigned long flags; + + spin_lock_irqsave(&psif->lock, flags); + + psif_writel(psif, THR, psif->buffer[psif->tail]); + psif->tail = ring_next_tail(psif); + + if (!ring_is_empty(psif)) + psif_writel(psif, IER, PSIF_BIT(TXEMPTY)); + + spin_unlock_irqrestore(&psif->lock, flags); +} + +static int psif_write(struct serio *io, unsigned char val) +{ + struct psif *psif = io->port_data; + unsigned long flags; + unsigned int head; + + spin_lock_irqsave(&psif->lock, flags); + + head = ring_next_head(psif); + + if (head != psif->tail) { + psif->buffer[psif->head] = val; + psif->head = head; + } else { + dev_err(&psif->pdev->dev, "underrun write error\n"); + } + + spin_unlock_irqrestore(&psif->lock, flags); + + /* Make sure TXEMPTY interrupt is enabled. */ + psif_writel(psif, IER, PSIF_BIT(TXEMPTY)); + + return 0; +} + +static int psif_open(struct serio *io) +{ + struct psif *psif = io->port_data; + int retval; + + retval = clk_enable(psif->pclk); + if (retval) + goto out; + + psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN)); + psif_writel(psif, IER, PSIF_BIT(RXRDY)); + + psif->open = 1; +out: + return retval; +} + +static void psif_close(struct serio *io) +{ + struct psif *psif = io->port_data; + + psif->open = 0; + + psif_writel(psif, IDR, ~0UL); + psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS)); + + clk_disable(psif->pclk); +} + +static void psif_set_prescaler(struct psif *psif) +{ + unsigned long prscv; + unsigned long rate = clk_get_rate(psif->pclk); + + /* PRSCV = Pulse length (100 us) * PSIF module frequency. */ + prscv = 100 * (rate / 1000000UL); + + if (prscv > ((1<<PSIF_PSR_PRSCV_SIZE) - 1)) { + prscv = (1<<PSIF_PSR_PRSCV_SIZE) - 1; + dev_dbg(&psif->pdev->dev, "pclk too fast, " + "prescaler set to max\n"); + } + + clk_enable(psif->pclk); + psif_writel(psif, PSR, prscv); + clk_disable(psif->pclk); +} + +static int __init psif_probe(struct platform_device *pdev) +{ + struct resource *regs; + struct psif *psif; + struct serio *io; + struct clk *pclk; + int irq; + int ret; + + psif = kzalloc(sizeof(struct psif), GFP_KERNEL); + if (!psif) { + dev_dbg(&pdev->dev, "out of memory\n"); + ret = -ENOMEM; + goto out; + } + psif->pdev = pdev; + + io = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!io) { + dev_dbg(&pdev->dev, "out of memory\n"); + ret = -ENOMEM; + goto out_free_psif; + } + psif->io = io; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_dbg(&pdev->dev, "no mmio resources defined\n"); + ret = -ENOMEM; + goto out_free_io; + } + + psif->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!psif->regs) { + ret = -ENOMEM; + dev_dbg(&pdev->dev, "could not map I/O memory\n"); + goto out_free_io; + } + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) { + dev_dbg(&pdev->dev, "could not get peripheral clock\n"); + ret = PTR_ERR(pclk); + goto out_iounmap; + } + psif->pclk = pclk; + + /* Reset the PSIF to enter at a known state. */ + ret = clk_enable(pclk); + if (ret) { + dev_dbg(&pdev->dev, "could not enable pclk\n"); + goto out_put_clk; + } + psif_writel(psif, CR, PSIF_BIT(CR_SWRST)); + clk_disable(pclk); + + setup_timer(&psif->tx_timer, psif_transmit_data, (unsigned long)psif); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_dbg(&pdev->dev, "could not get irq\n"); + ret = -ENXIO; + goto out_put_clk; + } + ret = request_irq(irq, psif_interrupt, IRQF_SHARED, "at32psif", psif); + if (ret) { + dev_dbg(&pdev->dev, "could not request irq %d\n", irq); + goto out_put_clk; + } + psif->irq = irq; + + io->id.type = SERIO_8042; + io->write = psif_write; + io->open = psif_open; + io->close = psif_close; + strlcpy(io->name, pdev->dev.bus_id, sizeof(io->name)); + strlcpy(io->phys, pdev->dev.bus_id, sizeof(io->phys)); + io->port_data = psif; + io->dev.parent = &pdev->dev; + + psif_set_prescaler(psif); + + spin_lock_init(&psif->lock); + serio_register_port(psif->io); + platform_set_drvdata(pdev, psif); + + dev_info(&pdev->dev, "Atmel AVR32 PSIF PS/2 driver on 0x%08x irq %d\n", + (int)psif->regs, psif->irq); + + return 0; + +out_put_clk: + clk_put(psif->pclk); +out_iounmap: + iounmap(psif->regs); +out_free_io: + kfree(io); +out_free_psif: + kfree(psif); +out: + return ret; +} + +static int __exit psif_remove(struct platform_device *pdev) +{ + struct psif *psif = platform_get_drvdata(pdev); + + psif_writel(psif, IDR, ~0UL); + psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS)); + + serio_unregister_port(psif->io); + iounmap(psif->regs); + free_irq(psif->irq, psif); + clk_put(psif->pclk); + kfree(psif); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int psif_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct psif *psif = platform_get_drvdata(pdev); + + if (psif->open) { + psif_writel(psif, CR, PSIF_BIT(CR_RXDIS) | PSIF_BIT(CR_TXDIS)); + clk_disable(psif->pclk); + } + + return 0; +} + +static int psif_resume(struct platform_device *pdev) +{ + struct psif *psif = platform_get_drvdata(pdev); + + if (psif->open) { + clk_enable(psif->pclk); + psif_set_prescaler(psif); + psif_writel(psif, CR, PSIF_BIT(CR_RXEN) | PSIF_BIT(CR_TXEN)); + } + + return 0; +} +#else +#define psif_suspend NULL +#define psif_resume NULL +#endif + +static struct platform_driver psif_driver = { + .remove = __exit_p(psif_remove), + .driver = { + .name = "atmel_psif", + }, + .suspend = psif_suspend, + .resume = psif_resume, +}; + +static int __init psif_init(void) +{ + return platform_driver_probe(&psif_driver, psif_probe); +} + +static void __exit psif_exit(void) +{ + platform_driver_unregister(&psif_driver); +} + +module_init(psif_init); +module_exit(psif_exit); + +MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); +MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver"); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/drivers/input/serio/at32psif.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007 Atmel Corporation + * + * Driver for the AT32AP700X PS/2 controller (PSIF). + * + * 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 _AT32PSIF_H +#define _AT32PSIF_H + +/* PSIF register offsets */ +#define PSIF_CR 0x00 +#define PSIF_RHR 0x04 +#define PSIF_THR 0x08 +#define PSIF_SR 0x10 +#define PSIF_IER 0x14 +#define PSIF_IDR 0x18 +#define PSIF_IMR 0x1c +#define PSIF_PSR 0x24 + +/* Bitfields in control register. */ +#define PSIF_CR_RXDIS_OFFSET 1 +#define PSIF_CR_RXDIS_SIZE 1 +#define PSIF_CR_RXEN_OFFSET 0 +#define PSIF_CR_RXEN_SIZE 1 +#define PSIF_CR_SWRST_OFFSET 15 +#define PSIF_CR_SWRST_SIZE 1 +#define PSIF_CR_TXDIS_OFFSET 9 +#define PSIF_CR_TXDIS_SIZE 1 +#define PSIF_CR_TXEN_OFFSET 8 +#define PSIF_CR_TXEN_SIZE 1 + +/* Bitfields in interrupt disable, enable, mask and status register. */ +#define PSIF_NACK_OFFSET 8 +#define PSIF_NACK_SIZE 1 +#define PSIF_OVRUN_OFFSET 5 +#define PSIF_OVRUN_SIZE 1 +#define PSIF_PARITY_OFFSET 9 +#define PSIF_PARITY_SIZE 1 +#define PSIF_RXRDY_OFFSET 4 +#define PSIF_RXRDY_SIZE 1 +#define PSIF_TXEMPTY_OFFSET 1 +#define PSIF_TXEMPTY_SIZE 1 +#define PSIF_TXRDY_OFFSET 0 +#define PSIF_TXRDY_SIZE 1 + +/* Bitfields in prescale register. */ +#define PSIF_PSR_PRSCV_OFFSET 0 +#define PSIF_PSR_PRSCV_SIZE 12 + +/* Bitfields in receive hold register. */ +#define PSIF_RHR_RXDATA_OFFSET 0 +#define PSIF_RHR_RXDATA_SIZE 8 + +/* Bitfields in transmit hold register. */ +#define PSIF_THR_TXDATA_OFFSET 0 +#define PSIF_THR_TXDATA_SIZE 8 + +/* Bit manipulation macros */ +#define PSIF_BIT(name) \ + (1 << PSIF_##name##_OFFSET) +#define PSIF_BF(name, value) \ + (((value) & ((1 << PSIF_##name##_SIZE) - 1)) \ + << PSIF_##name##_OFFSET) +#define PSIF_BFEXT(name, value)\ + (((value) >> PSIF_##name##_OFFSET) \ + & ((1 << PSIF_##name##_SIZE) - 1)) +#define PSIF_BFINS(name, value, old) \ + (((old) & ~(((1 << PSIF_##name##_SIZE) - 1) \ + << PSIF_##name##_OFFSET)) \ + | PSIF_BF(name, value)) + +/* Register access macros */ +#define psif_readl(port, reg) \ + __raw_readl((port)->regs + PSIF_##reg) +#define psif_writel(port, reg, value) \ + __raw_writel((value), (port)->regs + PSIF_##reg) + +#endif /* _AT32PSIF_H */ --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -22,6 +22,39 @@ purposes including software controlled power-efficent backlights on LCD displays, motor control, and waveform generation. +config ATMEL_TCLIB + bool "Atmel AT32/AT91 Timer/Counter Library" + depends on (AVR32 || ARCH_AT91) + help + Select this if you want a library to allocate the Timer/Counter + blocks found on many Atmel processors. This facilitates using + these blocks by different drivers despite processor differences. + +config ATMEL_TCB_CLKSRC + bool "TC Block Clocksource" + depends on ATMEL_TCLIB && GENERIC_TIME + default y + help + Select this to get a high precision clocksource based on a + TC block with a 5+ MHz base clock rate. Two timer channels + are combined to make a single 32-bit timer. + + When GENERIC_CLOCKEVENTS is defined, the third timer channel + may be used as a clock event device supporting oneshot mode + (delays of up to two seconds) based on the 32 KiHz clock. + +config ATMEL_TCB_CLKSRC_BLOCK + int + depends on ATMEL_TCB_CLKSRC + prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X + default 0 + range 0 1 + help + Some chips provide more than one TC block, so you have the + choice of which one to use for the clock framework. The other + TC can be used for other purposes, such as PWM generation and + interval timing. + config IBM_ASM tristate "Device driver for IBM RSA service processor" depends on X86 && PCI && INPUT && EXPERIMENTAL --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o +obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o --- /dev/null +++ b/drivers/misc/atmel_tclib.c @@ -0,0 +1,161 @@ +#include <linux/atmel_tc.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +/* Number of bytes to reserve for the iomem resource */ +#define ATMEL_TC_IOMEM_SIZE 256 + + +/* + * This is a thin library to solve the problem of how to portably allocate + * one of the TC blocks. For simplicity, it doesn't currently expect to + * share individual timers between different drivers. + */ + +#if defined(CONFIG_AVR32) +/* AVR32 has these divide PBB */ +const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, }; +EXPORT_SYMBOL(atmel_tc_divisors); + +#elif defined(CONFIG_ARCH_AT91) +/* AT91 has these divide MCK */ +const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, }; +EXPORT_SYMBOL(atmel_tc_divisors); + +#endif + +static DEFINE_SPINLOCK(tc_list_lock); +static LIST_HEAD(tc_list); + +/** + * atmel_tc_alloc - allocate a specified TC block + * @block: which block to allocate + * @name: name to be associated with the iomem resource + * + * Caller allocates a block. If it is available, a pointer to a + * pre-initialized struct atmel_tc is returned. The caller can access + * the registers directly through the "regs" field. + */ +struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) +{ + struct atmel_tc *tc; + struct platform_device *pdev = NULL; + struct resource *r; + + spin_lock(&tc_list_lock); + list_for_each_entry(tc, &tc_list, node) { + if (tc->pdev->id == block) { + pdev = tc->pdev; + break; + } + } + + if (!pdev || tc->iomem) + goto fail; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name); + if (!r) + goto fail; + + tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE); + if (!tc->regs) + goto fail_ioremap; + + tc->iomem = r; + +out: + spin_unlock(&tc_list_lock); + return tc; + +fail_ioremap: + release_resource(r); +fail: + tc = NULL; + goto out; +} +EXPORT_SYMBOL_GPL(atmel_tc_alloc); + +/** + * atmel_tc_free - release a specified TC block + * @tc: Timer/counter block that was returned by atmel_tc_alloc() + * + * This reverses the effect of atmel_tc_alloc(), unmapping the I/O + * registers, invalidating the resource returned by that routine and + * making the TC available to other drivers. + */ +void atmel_tc_free(struct atmel_tc *tc) +{ + spin_lock(&tc_list_lock); + if (tc->regs) { + iounmap(tc->regs); + release_resource(tc->iomem); + tc->regs = NULL; + tc->iomem = NULL; + } + spin_unlock(&tc_list_lock); +} +EXPORT_SYMBOL_GPL(atmel_tc_free); + +static int __init tc_probe(struct platform_device *pdev) +{ + struct atmel_tc *tc; + struct clk *clk; + int irq; + + if (!platform_get_resource(pdev, IORESOURCE_MEM, 0)) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL); + if (!tc) + return -ENOMEM; + + tc->pdev = pdev; + + clk = clk_get(&pdev->dev, "t0_clk"); + if (IS_ERR(clk)) { + kfree(tc); + return -EINVAL; + } + + tc->clk[0] = clk; + tc->clk[1] = clk_get(&pdev->dev, "t1_clk"); + if (IS_ERR(tc->clk[1])) + tc->clk[1] = clk; + tc->clk[2] = clk_get(&pdev->dev, "t2_clk"); + if (IS_ERR(tc->clk[2])) + tc->clk[2] = clk; + + tc->irq[0] = irq; + tc->irq[1] = platform_get_irq(pdev, 1); + if (tc->irq[1] < 0) + tc->irq[1] = irq; + tc->irq[2] = platform_get_irq(pdev, 2); + if (tc->irq[2] < 0) + tc->irq[2] = irq; + + spin_lock(&tc_list_lock); + list_add_tail(&tc->node, &tc_list); + spin_unlock(&tc_list_lock); + + return 0; +} + +static struct platform_driver tc_driver = { + .driver.name = "atmel_tcb", +}; + +static int __init tc_init(void) +{ + return platform_driver_probe(&tc_driver, tc_probe); +} +arch_initcall(tc_init); --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -91,6 +91,16 @@ 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 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -15,6 +15,7 @@ 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 obj-$(CONFIG_GPIOMMC) += gpiommc.o --- /dev/null +++ b/drivers/mmc/host/atmel-mci.c @@ -0,0 +1,1234 @@ +/* + * 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, +}; + +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; + + /* For detect pin debouncing */ + struct timer_list detect_timer; + + unsigned long bus_hz; + unsigned long mapbase; + struct clk *mck; + struct platform_device *pdev; + + int pending_stop; +#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) + +/* 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) + +/* 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) + +/* 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) + +/* 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) + +/* 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) + + +#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, ®s_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); + + /* + * We may "know" the card is gone even though there's still an + * electrical connection. If so, we really need to communicate + * this to the MMC core since there won't be any more + * interrupts as the card is completely removed. Otherwise, + * the MMC core might believe the card is still there even + * though the card was just removed very slowly. + */ + if (!host->present) { + mrq->cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); + return; + } + + 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 = DIV_ROUND_UP(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_detect_change(unsigned long data) +{ + struct atmel_mci *host = (struct atmel_mci *)data; + struct mmc_request *mrq = host->mrq; + int present; + + /* + * atmci_remove() sets detect_pin to -1 before freeing the + * interrupt. We must not re-enable the interrupt if it has + * been freed. + */ + smp_rmb(); + if (host->detect_pin < 0) + return; + + enable_irq(gpio_to_irq(host->detect_pin)); + present = !gpio_get_value(host->detect_pin); + + dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n", + present, host->present); + + if (present != host->present) { + dev_dbg(&host->mmc->class_dev, "card %s\n", + present ? "inserted" : "removed"); + host->present = present; + + /* Reset controller if card is gone */ + if (!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 = -ENOMEDIUM; + 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 = -ENOMEDIUM; + atmci_data_complete(host, host->data); + } + if (mrq->stop && !mci_stop_is_complete(host)) + mrq->stop->error = -ENOMEDIUM; + + host->cmd = NULL; + atmci_request_end(host->mmc, mrq); + } + + mmc_detect_change(host->mmc, 0); + } +} + +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); + } + /* See if there is a pending STOP which can be sent */ + if (host->pending_stop && mci_cmd_is_complete(host)) { + host->pending_stop = 0; + if (mrq->stop && !mci_set_stop_sent_is_completed(host)) + send_stop_cmd(host->mmc, mrq->data, 0); + } +} + +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 { + struct mmc_request *mrq = host->mrq; + + if (mrq->stop && mci_dma_is_complete(host) + && !mci_set_stop_sent_is_completed(host)) + send_stop_cmd(host->mmc, mrq->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) { + if (!mci_cmd_is_complete(host)) { + /* Just remember a STOP must be sent */ + host->pending_stop = 1; + } else if (!mci_set_stop_sent_is_completed(host)) { + send_stop_cmd(host->mmc, data, 0); + host->pending_stop = 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_interrupt(int irq, void *dev_id) +{ + struct mmc_host *mmc = dev_id; + struct atmel_mci *host = mmc_priv(mmc); + + /* + * Disable interrupts until the pin has stabilized and check + * the state then. Use mod_timer() since we may be in the + * middle of the timer routine when this interrupt triggers. + */ + disable_irq_nosync(irq); + mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20)); + + 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->wp_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) { + setup_timer(&host->detect_timer, atmci_detect_change, + (unsigned long)host); + + ret = request_irq(gpio_to_irq(host->detect_pin), + atmci_detect_interrupt, + 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) { + int pin = host->detect_pin; + + /* Make sure our timer doesn't enable the interrupt */ + host->detect_pin = -1; + smp_wmb(); + + free_irq(gpio_to_irq(pin), host->mmc); + del_timer_sync(&host->detect_timer); + cancel_delayed_work(&host->mmc->detect); + gpio_free(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"); --- /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__ */ --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -272,12 +272,54 @@ If you say "m", the module will be called "cs553x_nand.ko". -config MTD_NAND_AT91 - bool "Support for NAND Flash / SmartMedia on AT91" - depends on ARCH_AT91 +config MTD_NAND_ATMEL + bool "Support for NAND Flash / SmartMedia on AT91 and AVR32" + depends on ARCH_AT91 || AVR32 help Enables support for NAND Flash / Smart Media Card interface - on Atmel AT91 processors. + on Atmel AT91 and AVR32 processors. +choice + prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" + depends on MTD_NAND_ATMEL + +config MTD_NAND_ATMEL_ECC_HW + bool "Hardware ECC" + depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 + help + Use hardware ECC instead of software ECC when the chip + supports it. + + The hardware ECC controller is capable of single bit error + correction and 2-bit random detection per page. + + NB : hardware and software ECC schemes are incompatible. + If you switch from one to another, you'll have to erase your + mtd partition. + + If unsure, say Y + +config MTD_NAND_ATMEL_ECC_SOFT + bool "Software ECC" + help + Use software ECC. + + NB : hardware and software ECC schemes are incompatible. + If you switch from one to another, you'll have to erase your + mtd partition. + +config MTD_NAND_ATMEL_ECC_NONE + bool "No ECC (testing only, DANGEROUS)" + depends on DEBUG_KERNEL + help + No ECC will be used. + It's not a good idea and it should be reserved for testing + purpose only. + + If unsure, say N + + endchoice + +endchoice config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o -obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o +obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o --- a/drivers/mtd/nand/at91_nand.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * drivers/mtd/nand/at91_nand.c - * - * Copyright (C) 2003 Rick Bronson - * - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * Derived from drivers/mtd/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/partitions.h> - -#include <asm/io.h> -#include <asm/sizes.h> - -#include <asm/hardware.h> -#include <asm/arch/board.h> -#include <asm/arch/gpio.h> - -struct at91_nand_host { - struct nand_chip nand_chip; - struct mtd_info mtd; - void __iomem *io_base; - struct at91_nand_data *board; -}; - -/* - * Hardware specific access to control-lines - */ -static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd, host->io_base + (1 << host->board->cle)); - else - writeb(cmd, host->io_base + (1 << host->board->ale)); -} - -/* - * Read the Device Ready pin. - */ -static int at91_nand_device_ready(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct at91_nand_host *host = nand_chip->priv; - - return at91_get_gpio_value(host->board->rdy_pin); -} - -/* - * Enable NAND. - */ -static void at91_nand_enable(struct at91_nand_host *host) -{ - if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 0); -} - -/* - * Disable NAND. - */ -static void at91_nand_disable(struct at91_nand_host *host) -{ - if (host->board->enable_pin) - at91_set_gpio_value(host->board->enable_pin, 1); -} - -#ifdef CONFIG_MTD_PARTITIONS -const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - -/* - * Probe for the NAND device. - */ -static int __init at91_nand_probe(struct platform_device *pdev) -{ - struct at91_nand_host *host; - struct mtd_info *mtd; - struct nand_chip *nand_chip; - int res; - -#ifdef CONFIG_MTD_PARTITIONS - struct mtd_partition *partitions = NULL; - int num_partitions = 0; -#endif - - /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); - if (!host) { - printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); - return -ENOMEM; - } - - host->io_base = ioremap(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); - if (host->io_base == NULL) { - printk(KERN_ERR "at91_nand: ioremap failed\n"); - kfree(host); - return -EIO; - } - - mtd = &host->mtd; - nand_chip = &host->nand_chip; - host->board = pdev->dev.platform_data; - - nand_chip->priv = host; /* link the private data structures */ - mtd->priv = nand_chip; - mtd->owner = THIS_MODULE; - - /* Set address of NAND IO lines */ - nand_chip->IO_ADDR_R = host->io_base; - nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; - - if (host->board->rdy_pin) - nand_chip->dev_ready = at91_nand_device_ready; - - nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ - nand_chip->chip_delay = 20; /* 20us command delay time */ - - if (host->board->bus_width_16) /* 16-bit bus width */ - nand_chip->options |= NAND_BUSWIDTH_16; - - platform_set_drvdata(pdev, host); - at91_nand_enable(host); - - if (host->board->det_pin) { - if (at91_get_gpio_value(host->board->det_pin)) { - printk ("No SmartMedia card inserted.\n"); - res = ENXIO; - goto out; - } - } - - /* Scan to find existance of the device */ - if (nand_scan(mtd, 1)) { - res = -ENXIO; - goto out; - } - -#ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd->name = "at91_nand"; - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); -#endif - if (num_partitions <= 0 && host->board->partition_info) - partitions = host->board->partition_info(mtd->size, - &num_partitions); - - if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); - res = ENXIO; - goto release; - } - - res = add_mtd_partitions(mtd, partitions, num_partitions); -#else - res = add_mtd_device(mtd); -#endif - - if (!res) - return res; - -release: - nand_release(mtd); -out: - at91_nand_disable(host); - platform_set_drvdata(pdev, NULL); - iounmap(host->io_base); - kfree(host); - return res; -} - -/* - * Remove a NAND device. - */ -static int __devexit at91_nand_remove(struct platform_device *pdev) -{ - struct at91_nand_host *host = platform_get_drvdata(pdev); - struct mtd_info *mtd = &host->mtd; - - nand_release(mtd); - - at91_nand_disable(host); - - iounmap(host->io_base); - kfree(host); - - return 0; -} - -static struct platform_driver at91_nand_driver = { - .probe = at91_nand_probe, - .remove = at91_nand_remove, - .driver = { - .name = "at91_nand", - .owner = THIS_MODULE, - }, -}; - -static int __init at91_nand_init(void) -{ - return platform_driver_register(&at91_nand_driver); -} - - -static void __exit at91_nand_exit(void) -{ - platform_driver_unregister(&at91_nand_driver); -} - - -module_init(at91_nand_init); -module_exit(at91_nand_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Rick Bronson"); -MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); --- /dev/null +++ b/drivers/mtd/nand/atmel_nand.c @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2003 Rick Bronson + * + * Derived from drivers/mtd/nand/autcpu12.c + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * Derived from drivers/mtd/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * + * + * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 + * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 + * + * Derived from Das U-Boot source code + * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) + * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include <linux/gpio.h> +#include <linux/io.h> + +#include <asm/arch/board.h> +#include <asm/arch/cpu.h> + +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW +#define hard_ecc 1 +#else +#define hard_ecc 0 +#endif + +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE +#define no_ecc 1 +#else +#define no_ecc 0 +#endif + +/* Register access macros */ +#define ecc_readl(add, reg) \ + __raw_readl(add + ATMEL_ECC_##reg) +#define ecc_writel(add, reg, value) \ + __raw_writel((value), add + ATMEL_ECC_##reg) + +#include "atmel_nand_ecc.h" /* Hardware ECC registers */ + +/* oob layout for large page size + * bad block info is on bytes 0 and 1 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout atmel_oobinfo_large = { + .eccbytes = 4, + .eccpos = {60, 61, 62, 63}, + .oobfree = { + {2, 58} + }, +}; + +/* oob layout for small page size + * bad block info is on bytes 4 and 5 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout atmel_oobinfo_small = { + .eccbytes = 4, + .eccpos = {0, 1, 2, 3}, + .oobfree = { + {6, 10} + }, +}; + +struct atmel_nand_host { + struct nand_chip nand_chip; + struct mtd_info mtd; + void __iomem *io_base; + struct atmel_nand_data *board; + struct device *dev; + void __iomem *ecc; +}; + +/* + * Enable NAND. + */ +static void atmel_nand_enable(struct atmel_nand_host *host) +{ + if (host->board->enable_pin) + gpio_set_value(host->board->enable_pin, 0); +} + +/* + * Disable NAND. + */ +static void atmel_nand_disable(struct atmel_nand_host *host) +{ + if (host->board->enable_pin) + gpio_set_value(host->board->enable_pin, 1); +} + +/* + * Hardware specific access to control-lines + */ +static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_NCE) + atmel_nand_enable(host); + else + atmel_nand_disable(host); + } + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd, host->io_base + (1 << host->board->cle)); + else + writeb(cmd, host->io_base + (1 << host->board->ale)); +} + +/* + * Read the Device Ready pin. + */ +static int atmel_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + + return gpio_get_value(host->board->rdy_pin); +} + +/* + * Minimal-overhead PIO for data access. + */ +static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsb(nand_chip->IO_ADDR_R, buf, len); +} + +static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); +} + +static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesb(nand_chip->IO_ADDR_W, buf, len); +} + +static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); +} + +/* + * write oob for small pages + */ +static int atmel_nand_write_oob_512(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsize = chip->ecc.size, length = mtd->oobsize; + int len, pos, status = 0; + const uint8_t *bufpoi = chip->oob_poi; + + pos = eccsize + chunk; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + len = min_t(int, length, chunk); + chip->write_buf(mtd, bufpoi, len); + bufpoi += len; + length -= len; + if (length > 0) + chip->write_buf(mtd, bufpoi, length); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; + +} + +/* + * read oob for small pages + */ +static int atmel_nand_read_oob_512(struct mtd_info *mtd, + struct nand_chip *chip, int page, int sndcmd) +{ + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return sndcmd; +} + +/* + * Calculate HW ECC + * + * function called after a write + * + * mtd: MTD block structure + * dat: raw data (unused) + * ecc_code: buffer for ECC + */ +static int atmel_nand_calculate(struct mtd_info *mtd, + const u_char *dat, unsigned char *ecc_code) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + uint32_t *eccpos = nand_chip->ecc.layout->eccpos; + unsigned int ecc_value; + + /* get the first 2 ECC bytes */ + ecc_value = ecc_readl(host->ecc, PR); + + ecc_code[eccpos[0]] = ecc_value & 0xFF; + ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; + + /* get the last 2 ECC bytes */ + ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; + + ecc_code[eccpos[2]] = ecc_value & 0xFF; + ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; + + return 0; +} + +/* + * HW ECC read page function + * + * mtd: mtd info structure + * chip: nand chip info structure + * buf: buffer to store read data + */ +static int atmel_nand_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf) +{ + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + uint8_t *ecc_pos; + int stat; + + /* + * Errata: ALE is incorrectly wired up to the ECC controller + * on the AP7000, so it will include the address cycles in the + * ECC calculation. + * + * Workaround: Reset the parity registers before reading the + * actual data. + */ + if (cpu_is_at32ap7000()) { + struct atmel_nand_host *host = chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } + + /* read the page */ + chip->read_buf(mtd, p, eccsize); + + /* move to ECC position if needed */ + if (eccpos[0] != 0) { + /* This only works on large pages + * because the ECC controller waits for + * NAND_CMD_RNDOUTSTART after the + * NAND_CMD_RNDOUT. + * anyway, for small pages, the eccpos[0] == 0 + */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + eccpos[0], -1); + } + + /* the ECC controller needs to read the ECC just after the data */ + ecc_pos = oob + eccpos[0]; + chip->read_buf(mtd, ecc_pos, eccbytes); + + /* check if there's an error */ + stat = chip->ecc.correct(mtd, p, oob, NULL); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + /* get back to oob start (end of page) */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + + /* read the oob */ + chip->read_buf(mtd, oob, mtd->oobsize); + + return 0; +} + +/* + * HW ECC Correction + * + * function called after a read + * + * mtd: MTD block structure + * dat: raw data read from the chip + * read_ecc: ECC from the chip (unused) + * isnull: unused + * + * Detect and correct a 1 bit error for a page + */ +static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *isnull) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + unsigned int ecc_status; + unsigned int ecc_word, ecc_bit; + + /* get the status from the Status Register */ + ecc_status = ecc_readl(host->ecc, SR); + + /* if there's no error */ + if (likely(!(ecc_status & ATMEL_ECC_RECERR))) + return 0; + + /* get error bit offset (4 bits) */ + ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; + /* get word address (12 bits) */ + ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; + ecc_word >>= 4; + + /* if there are multiple errors */ + if (ecc_status & ATMEL_ECC_MULERR) { + /* check if it is a freshly erased block + * (filled with 0xff) */ + if ((ecc_bit == ATMEL_ECC_BITADDR) + && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { + /* the block has just been erased, return OK */ + return 0; + } + /* it doesn't seems to be a freshly + * erased block. + * We can't correct so many errors */ + dev_dbg(host->dev, "atmel_nand : multiple errors detected." + " Unable to correct.\n"); + return -EIO; + } + + /* if there's a single bit error : we can correct it */ + if (ecc_status & ATMEL_ECC_ECCERR) { + /* there's nothing much to do here. + * the bit error is on the ECC itself. + */ + dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." + " Nothing to correct\n"); + return 0; + } + + dev_dbg(host->dev, "atmel_nand : one bit error on data." + " (word offset in the page :" + " 0x%x bit offset : 0x%x)\n", + ecc_word, ecc_bit); + /* correct the error */ + if (nand_chip->options & NAND_BUSWIDTH_16) { + /* 16 bits words */ + ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); + } else { + /* 8 bits words */ + dat[ecc_word] ^= (1 << ecc_bit); + } + dev_dbg(host->dev, "atmel_nand : error corrected\n"); + return 1; +} + +/* + * Enable HW ECC : unused on most chips + */ +static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) +{ + if (cpu_is_at32ap7000()) { + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } +} + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + +/* + * Probe for the NAND device. + */ +static int __init atmel_nand_probe(struct platform_device *pdev) +{ + struct atmel_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + struct resource *regs; + struct resource *mem; + int res; + +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partitions = NULL; + int num_partitions = 0; +#endif + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n"); + return -ENXIO; + } + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); + return -ENOMEM; + } + + host->io_base = ioremap(mem->start, mem->end - mem->start + 1); + if (host->io_base == NULL) { + printk(KERN_ERR "atmel_nand: ioremap failed\n"); + res = -EIO; + goto err_nand_ioremap; + } + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + host->board = pdev->dev.platform_data; + host->dev = &pdev->dev; + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = host->io_base; + nand_chip->IO_ADDR_W = host->io_base; + nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; + + if (host->board->rdy_pin) + nand_chip->dev_ready = atmel_nand_device_ready; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!regs && hard_ecc) { + printk(KERN_ERR "atmel_nand: can't get I/O resource " + "regs\nFalling back on software ECC\n"); + } + + nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ + if (no_ecc) + nand_chip->ecc.mode = NAND_ECC_NONE; + if (hard_ecc && regs) { + host->ecc = ioremap(regs->start, regs->end - regs->start + 1); + if (host->ecc == NULL) { + printk(KERN_ERR "atmel_nand: ioremap failed\n"); + res = -EIO; + goto err_ecc_ioremap; + } + nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; + nand_chip->ecc.calculate = atmel_nand_calculate; + nand_chip->ecc.correct = atmel_nand_correct; + nand_chip->ecc.hwctl = atmel_nand_hwctl; + nand_chip->ecc.read_page = atmel_nand_read_page; + nand_chip->ecc.bytes = 4; + nand_chip->ecc.prepad = 0; + nand_chip->ecc.postpad = 0; + } + + nand_chip->chip_delay = 20; /* 20us command delay time */ + + if (host->board->bus_width_16) { /* 16-bit bus width */ + nand_chip->options |= NAND_BUSWIDTH_16; + nand_chip->read_buf = atmel_read_buf16; + nand_chip->write_buf = atmel_write_buf16; + } else { + nand_chip->read_buf = atmel_read_buf; + nand_chip->write_buf = atmel_write_buf; + } + + platform_set_drvdata(pdev, host); + atmel_nand_enable(host); + + if (host->board->det_pin) { + if (gpio_get_value(host->board->det_pin)) { + printk("No SmartMedia card inserted.\n"); + res = ENXIO; + goto err_no_card; + } + } + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1)) { + res = -ENXIO; + goto err_scan_ident; + } + + if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { + /* ECC is calculated for the whole page (1 step) */ + nand_chip->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 512: + nand_chip->ecc.layout = &atmel_oobinfo_small; + nand_chip->ecc.read_oob = atmel_nand_read_oob_512; + nand_chip->ecc.write_oob = atmel_nand_write_oob_512; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); + break; + case 1024: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); + break; + case 2048: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); + break; + case 4096: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); + break; + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand_chip->ecc.mode = NAND_ECC_SOFT; + nand_chip->ecc.calculate = NULL; + nand_chip->ecc.correct = NULL; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = NULL; + nand_chip->ecc.postpad = 0; + nand_chip->ecc.prepad = 0; + nand_chip->ecc.bytes = 0; + break; + } + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto err_scan_tail; + } + +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd->name = "atmel_nand"; + num_partitions = parse_mtd_partitions(mtd, part_probes, + &partitions, 0); +#endif + if (num_partitions <= 0 && host->board->partition_info) + partitions = host->board->partition_info(mtd->size, + &num_partitions); + + if ((!partitions) || (num_partitions == 0)) { + printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n"); + res = ENXIO; + goto err_no_partitions; + } + + res = add_mtd_partitions(mtd, partitions, num_partitions); +#else + res = add_mtd_device(mtd); +#endif + + if (!res) + return res; + +#ifdef CONFIG_MTD_PARTITIONS +err_no_partitions: +#endif + nand_release(mtd); +err_scan_tail: +err_scan_ident: +err_no_card: + atmel_nand_disable(host); + platform_set_drvdata(pdev, NULL); + if (host->ecc) + iounmap(host->ecc); +err_ecc_ioremap: + iounmap(host->io_base); +err_nand_ioremap: + kfree(host); + return res; +} + +/* + * Remove a NAND device. + */ +static int __exit atmel_nand_remove(struct platform_device *pdev) +{ + struct atmel_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + + atmel_nand_disable(host); + + if (host->ecc) + iounmap(host->ecc); + iounmap(host->io_base); + kfree(host); + + return 0; +} + +static struct platform_driver atmel_nand_driver = { + .remove = __exit_p(atmel_nand_remove), + .driver = { + .name = "atmel_nand", + .owner = THIS_MODULE, + }, +}; + +static int __init atmel_nand_init(void) +{ + return platform_driver_probe(&atmel_nand_driver, atmel_nand_probe); +} + + +static void __exit atmel_nand_exit(void) +{ + platform_driver_unregister(&atmel_nand_driver); +} + + +module_init(atmel_nand_init); +module_exit(atmel_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); +MODULE_ALIAS("platform:atmel_nand"); --- /dev/null +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -0,0 +1,36 @@ +/* + * Error Corrected Code Controller (ECC) - System peripherals regsters. + * Based on AT91SAM9260 datasheet revision B. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef ATMEL_NAND_ECC_H +#define ATMEL_NAND_ECC_H + +#define ATMEL_ECC_CR 0x00 /* Control register */ +#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ + +#define ATMEL_ECC_MR 0x04 /* Mode register */ +#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ +#define ATMEL_ECC_PAGESIZE_528 (0) +#define ATMEL_ECC_PAGESIZE_1056 (1) +#define ATMEL_ECC_PAGESIZE_2112 (2) +#define ATMEL_ECC_PAGESIZE_4224 (3) + +#define ATMEL_ECC_SR 0x08 /* Status register */ +#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ +#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ + +#define ATMEL_ECC_PR 0x0c /* Parity register */ +#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ + +#define ATMEL_ECC_NPR 0x10 /* NParity register */ +#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + +#endif --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -803,3 +803,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESC); +MODULE_ALIAS("platform:" DRV_NAME); --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -317,3 +317,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); MODULE_DESCRIPTION("Platform driver for NDFC"); +MODULE_ALIAS("platform:ndfc-chip"); +MODULE_ALIAS("platform:ndfc-nand"); --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -169,3 +169,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tzachi Perelstein"); MODULE_DESCRIPTION("NAND glue for Orion platforms"); +MODULE_ALIAS("platform:orion_nand"); --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -161,3 +161,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vitaly Wool"); MODULE_DESCRIPTION("Simple generic NAND driver"); +MODULE_ALIAS("platform:gen_nand"); --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -927,3 +927,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); +MODULE_ALIAS("platform:s3c2410-nand"); +MODULE_ALIAS("platform:s3c2412-nand"); +MODULE_ALIAS("platform:s3c2440-nand"); --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1277,8 +1277,45 @@ return 0; } +#ifdef CONFIG_PM +static int macb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + netif_device_detach(netdev); + +#ifndef CONFIG_ARCH_AT91 + clk_disable(bp->hclk); +#endif + clk_disable(bp->pclk); + + return 0; +} + +static int macb_resume(struct platform_device *pdev) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + clk_enable(bp->pclk); +#ifndef CONFIG_ARCH_AT91 + clk_enable(bp->hclk); +#endif + + netif_device_attach(netdev); + + return 0; +} +#else +#define macb_suspend NULL +#define macb_resume NULL +#endif + static struct platform_driver macb_driver = { .remove = __exit_p(macb_remove), + .suspend = macb_suspend, + .resume = macb_resume, .driver = { .name = "macb", }, --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -36,7 +36,7 @@ config PARPORT_PC tristate "PC-style hardware" depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \ - (!M68K || ISA) && !MN10300 + (!M68K || ISA) && !MN10300 && !AVR32 ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -277,6 +277,13 @@ 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 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -38,6 +38,7 @@ 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 --- /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>"); --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -262,6 +262,7 @@ } platform_set_drvdata(pdev, rtc); + device_init_wakeup(&pdev->dev, 1); dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", (unsigned long)rtc->regs, rtc->irq); @@ -281,6 +282,8 @@ { struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev); + device_init_wakeup(&pdev->dev, 0); + free_irq(rtc->irq, rtc); iounmap(rtc->regs); rtc_device_unregister(rtc->rtc); --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -957,6 +957,20 @@ } /* + * Flush any TX data submitted for DMA. Called when the TX circular + * buffer is reset. + */ +static void atmel_flush_buffer(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + UART_PUT_TCR(port, 0); + atmel_port->pdc_tx.ofs = 0; + } +} + +/* * Power / Clock management. */ static void atmel_serial_pm(struct uart_port *port, unsigned int state, @@ -1190,6 +1204,7 @@ .break_ctl = atmel_break_ctl, .startup = atmel_startup, .shutdown = atmel_shutdown, + .flush_buffer = atmel_flush_buffer, .set_termios = atmel_set_termios, .type = atmel_type, .release_port = atmel_release_port, @@ -1440,6 +1455,15 @@ }; #ifdef CONFIG_PM +static bool atmel_serial_clk_will_stop(void) +{ +#ifdef CONFIG_ARCH_AT91 + return at91_suspend_entering_slow_clock(); +#else + return false; +#endif +} + static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state) { @@ -1447,7 +1471,7 @@ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (device_may_wakeup(&pdev->dev) - && !at91_suspend_entering_slow_clock()) + && !atmel_serial_clk_will_stop()) enable_irq_wake(port->irq); else { uart_suspend_port(&atmel_uart, port); --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -552,6 +552,8 @@ spin_lock_irqsave(&port->lock, flags); uart_circ_clear(&state->info->xmit); + if (port->ops->flush_buffer) + port->ops->flush_buffer(port); spin_unlock_irqrestore(&port->lock, flags); tty_wakeup(tty); } --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -51,9 +51,7 @@ u8 stopping; struct list_head queue; struct spi_transfer *current_transfer; - unsigned long current_remaining_bytes; - struct spi_transfer *next_transfer; - unsigned long next_remaining_bytes; + unsigned long remaining_bytes; void *buffer; dma_addr_t buffer_dma; @@ -133,48 +131,6 @@ 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 @@ -184,78 +140,53 @@ { struct atmel_spi *as = spi_master_get_devdata(master); struct spi_transfer *xfer; - u32 len, remaining, total; + u32 len; dma_addr_t tx_dma, rx_dma; - 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; - - if (xfer) { - len = xfer->len; - atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); - remaining = xfer->len - len; - - spi_writel(as, RPR, rx_dma); - spi_writel(as, TPR, tx_dma); - - 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; + 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; } - as->current_transfer = xfer; - as->current_remaining_bytes = remaining; - - 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; + len = as->remaining_bytes; - as->next_transfer = xfer; + tx_dma = xfer->tx_dma + xfer->len - len; + rx_dma = xfer->rx_dma + xfer->len - len; - 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); + /* 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); + } + + spi_writel(as, RPR, rx_dma); + spi_writel(as, TPR, tx_dma); - /* REVISIT: We're waiting for ENDRX before we start the next + as->remaining_bytes -= len; + if (msg->spi->bits_per_word > 8) + len >>= 1; + + /* 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 * 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 @@ -265,7 +196,17 @@ * * 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)); } @@ -363,7 +304,6 @@ spin_lock(&as->lock); as->current_transfer = NULL; - as->next_transfer = NULL; /* continue if needed */ if (list_empty(&as->queue) || as->stopping) @@ -447,7 +387,7 @@ spi_writel(as, IDR, pending); - if (as->current_remaining_bytes == 0) { + if (as->remaining_bytes == 0) { msg->actual_length += xfer->len; if (!msg->is_dma_mapped) @@ -457,7 +397,7 @@ if (xfer->delay_usecs) udelay(xfer->delay_usecs); - if (atmel_spi_xfer_is_last(msg, xfer)) { + if (msg->transfers.prev == &xfer->transfer_list) { /* report completed message */ atmel_spi_msg_done(master, as, msg, 0, xfer->cs_change); --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -118,10 +118,10 @@ config USB_GADGET_ATMEL_USBA boolean "Atmel USBA" select USB_GADGET_DUALSPEED - depends on AVR32 + depends on AVR32 || ARCH_AT91CAP9 help USBA is the integrated high-speed USB Device controller on - the AT32AP700x processors from Atmel. + the AT32AP700x and AT91CAP9 processors from Atmel. config USB_ATMEL_USBA tristate --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/usb/atmel_usba_udc.h> #include <linux/delay.h> #include <asm/gpio.h> @@ -27,6 +28,7 @@ static struct usba_udc the_udc; +static struct usba_ep *usba_ep; #ifdef CONFIG_USB_GADGET_DEBUG_FS #include <linux/debugfs.h> @@ -324,53 +326,28 @@ return 1; } -static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) -{ - unsigned long tmp; +#if defined(CONFIG_AVR32) - DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); - for (; len > 0; len -= 4, buf += 4, fifo += 4) { - tmp = *(unsigned long *)buf; - if (len >= 4) { - DBG(DBG_FIFO, " -> %08lx\n", tmp); - __raw_writel(tmp, fifo); - } else { - do { - DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); - __raw_writeb(tmp >> 24, fifo); - fifo++; - tmp <<= 8; - } while (--len); - break; - } - } +static void toggle_bias(int is_on) +{ } -static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +#elif defined(CONFIG_ARCH_AT91) + +#include <asm/arch/at91_pmc.h> + +static void toggle_bias(int is_on) { - union { - unsigned long *w; - unsigned char *b; - } p; - unsigned long tmp; - - DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); - for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { - if (len >= 4) { - tmp = __raw_readl(fifo); - *p.w = tmp; - DBG(DBG_FIFO, " -> %08lx\n", tmp); - } else { - do { - tmp = __raw_readb(fifo); - *p.b = tmp; - DBG(DBG_FIFO, " -> %02lx\n", tmp); - fifo++, p.b++; - } while (--len); - } - } + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + + if (is_on) + at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); + else + at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); } +#endif /* CONFIG_ARCH_AT91 */ + static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) { unsigned int transaction_len; @@ -387,7 +364,7 @@ ep->ep.name, req, transaction_len, req->last_transaction ? ", done" : ""); - copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); req->req.actual += transaction_len; } @@ -476,7 +453,7 @@ bytecount = req->req.length - req->req.actual; } - copy_from_fifo(req->req.buf + req->req.actual, + memcpy_fromio(req->req.buf + req->req.actual, ep->fifo, bytecount); req->req.actual += bytecount; @@ -1029,33 +1006,6 @@ .set_selfpowered = usba_udc_set_selfpowered, }; -#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ -{ \ - .ep = { \ - .ops = &usba_ep_ops, \ - .name = nam, \ - .maxpacket = maxpkt, \ - }, \ - .udc = &the_udc, \ - .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ - .fifo_size = maxpkt, \ - .nr_banks = maxbk, \ - .index = idx, \ - .can_dma = dma, \ - .can_isoc = isoc, \ -} - -static struct usba_ep usba_ep[] = { - EP("ep0", 0, 64, 1, 0, 0), - EP("ep1in-bulk", 1, 512, 2, 1, 1), - EP("ep2out-bulk", 2, 512, 2, 1, 1), - EP("ep3in-int", 3, 64, 3, 1, 0), - EP("ep4out-int", 4, 64, 3, 1, 0), - EP("ep5in-iso", 5, 1024, 3, 1, 1), - EP("ep6out-iso", 6, 1024, 3, 1, 1), -}; -#undef EP - static struct usb_endpoint_descriptor usba_ep0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -1074,7 +1024,6 @@ static struct usba_udc the_udc = { .gadget = { .ops = &usba_udc_ops, - .ep0 = &usba_ep[0].ep, .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), .is_dualspeed = 1, .name = "atmel_usba_udc", @@ -1231,7 +1180,7 @@ } else { usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); usba_writel(udc, TST, USBA_TST_PKT_MODE); - copy_to_fifo(ep->fifo, test_packet_buffer, + memcpy_toio(ep->fifo, test_packet_buffer, sizeof(test_packet_buffer)); usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); dev_info(dev, "Entering Test_Packet mode...\n"); @@ -1530,13 +1479,13 @@ DBG(DBG_HW, "Packet length: %u\n", pkt_len); if (pkt_len != sizeof(crq)) { pr_warning("udc: Invalid packet length %u " - "(expected %lu)\n", pkt_len, sizeof(crq)); + "(expected %zu)\n", pkt_len, sizeof(crq)); set_protocol_stall(udc, ep); return; } DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); - copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + memcpy_fromio(crq.data, ep->fifo, sizeof(crq)); /* Free up one bank in the FIFO so that we can * generate or receive a reply right away. */ @@ -1688,6 +1637,7 @@ DBG(DBG_INT, "irq, status=%#08x\n", status); if (status & USBA_DET_SUSPEND) { + toggle_bias(0); usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); DBG(DBG_BUS, "Suspend detected\n"); if (udc->gadget.speed != USB_SPEED_UNKNOWN @@ -1699,6 +1649,7 @@ } if (status & USBA_WAKE_UP) { + toggle_bias(1); usba_writel(udc, INT_CLR, USBA_WAKE_UP); DBG(DBG_BUS, "Wake Up CPU detected\n"); } @@ -1792,12 +1743,14 @@ vbus = gpio_get_value(udc->vbus_pin); if (vbus != udc->vbus_prev) { if (vbus) { - usba_writel(udc, CTRL, USBA_EN_USBA); + toggle_bias(1); + usba_writel(udc, CTRL, USBA_ENABLE_MASK); usba_writel(udc, INT_ENB, USBA_END_OF_RESET); } else { udc->gadget.speed = USB_SPEED_UNKNOWN; reset_all_endpoints(udc); - usba_writel(udc, CTRL, 0); + toggle_bias(0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); spin_lock(&udc->lock); @@ -1850,7 +1803,8 @@ /* If Vbus is present, enable the controller and wait for reset */ spin_lock_irqsave(&udc->lock, flags); if (vbus_is_present(udc) && udc->vbus_prev == 0) { - usba_writel(udc, CTRL, USBA_EN_USBA); + toggle_bias(1); + usba_writel(udc, CTRL, USBA_ENABLE_MASK); usba_writel(udc, INT_ENB, USBA_END_OF_RESET); } spin_unlock_irqrestore(&udc->lock, flags); @@ -1883,7 +1837,8 @@ spin_unlock_irqrestore(&udc->lock, flags); /* This will also disable the DP pullup */ - usba_writel(udc, CTRL, 0); + toggle_bias(0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; @@ -1908,7 +1863,7 @@ regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); - if (!regs || !fifo) + if (!regs || !fifo || !pdata) return -ENXIO; irq = platform_get_irq(pdev, 0); @@ -1953,19 +1908,48 @@ /* Make sure we start from a clean slate */ clk_enable(pclk); - usba_writel(udc, CTRL, 0); + toggle_bias(0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); clk_disable(pclk); + usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep, + GFP_KERNEL); + if (!usba_ep) + goto err_alloc_ep; + + the_udc.gadget.ep0 = &usba_ep[0].ep; + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); - for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + usba_ep[0].ep.ops = &usba_ep_ops; + usba_ep[0].ep.name = pdata->ep[0].name; + usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size; + usba_ep[0].udc = &the_udc; + INIT_LIST_HEAD(&usba_ep[0].queue); + usba_ep[0].fifo_size = pdata->ep[0].fifo_size; + usba_ep[0].nr_banks = pdata->ep[0].nr_banks; + usba_ep[0].index = pdata->ep[0].index; + usba_ep[0].can_dma = pdata->ep[0].can_dma; + usba_ep[0].can_isoc = pdata->ep[0].can_isoc; + + for (i = 1; i < pdata->num_ep; i++) { struct usba_ep *ep = &usba_ep[i]; ep->ep_regs = udc->regs + USBA_EPT_BASE(i); ep->dma_regs = udc->regs + USBA_DMA_BASE(i); ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + ep->ep.ops = &usba_ep_ops; + ep->ep.name = pdata->ep[i].name; + ep->ep.maxpacket = pdata->ep[i].fifo_size; + ep->udc = &the_udc; + INIT_LIST_HEAD(&ep->queue); + ep->fifo_size = pdata->ep[i].fifo_size; + ep->nr_banks = pdata->ep[i].nr_banks; + ep->index = pdata->ep[i].index; + ep->can_dma = pdata->ep[i].can_dma; + ep->can_isoc = pdata->ep[i].can_isoc; list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } @@ -1984,7 +1968,7 @@ goto err_device_add; } - if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (pdata->vbus_pin >= 0) { if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { udc->vbus_pin = pdata->vbus_pin; @@ -2004,7 +1988,7 @@ } usba_init_debugfs(udc); - for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + for (i = 1; i < pdata->num_ep; i++) usba_ep_init_debugfs(udc, &usba_ep[i]); return 0; @@ -2012,6 +1996,8 @@ err_device_add: free_irq(irq, udc); err_request_irq: + kfree(usba_ep); +err_alloc_ep: iounmap(udc->fifo); err_map_fifo: iounmap(udc->regs); @@ -2029,10 +2015,11 @@ { struct usba_udc *udc; int i; + struct usba_platform_data *pdata = pdev->dev.platform_data; udc = platform_get_drvdata(pdev); - for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + for (i = 1; i < pdata->num_ep; i++) usba_ep_cleanup_debugfs(&usba_ep[i]); usba_cleanup_debugfs(udc); @@ -2040,6 +2027,7 @@ gpio_free(udc->vbus_pin); free_irq(udc->irq, udc); + kfree(usba_ep); iounmap(udc->fifo); iounmap(udc->regs); clk_put(udc->hclk); --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -41,6 +41,15 @@ #define USBA_EN_USBA (1 << 8) #define USBA_DETACH (1 << 9) #define USBA_REMOTE_WAKE_UP (1 << 10) +#define USBA_PULLD_DIS (1 << 11) + +#if defined(CONFIG_AVR32) +#define USBA_ENABLE_MASK USBA_EN_USBA +#define USBA_DISABLE_MASK 0 +#elif defined(CONFIG_ARCH_AT91) +#define USBA_ENABLE_MASK (USBA_EN_USBA | USBA_PULLD_DIS) +#define USBA_DISABLE_MASK USBA_DETACH +#endif /* CONFIG_ARCH_AT91 */ /* Bitfields in FNUM */ #define USBA_MICRO_FRAME_NUM_OFFSET 0 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -38,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) @@ -176,7 +178,7 @@ .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .xpanstep = 0, - .ypanstep = 0, + .ypanstep = 1, .ywrapstep = 0, .accel = FB_ACCEL_NONE, }; @@ -250,6 +252,8 @@ return -ENOMEM; } + memset(info->screen_base, 0, info->fix.smem_len); + return 0; } @@ -634,7 +638,6 @@ 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, @@ -764,6 +767,11 @@ 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); --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -385,8 +385,6 @@ * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so * that it can be located for waiting on in __writeback_single_inode(). * - * Called under inode_lock. - * * If `bdi' is non-zero then we're being asked to writeback a specific queue. * This function assumes that the blockdev superblock's inodes are backed by * a variety of queues, so all inodes are searched. For other superblocks, @@ -402,11 +400,12 @@ * on the writer throttling path, and we get decent balancing between many * throttled threads: we don't want them all piling up on inode_sync_wait. */ -static void -sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) +void generic_sync_sb_inodes(struct super_block *sb, + struct writeback_control *wbc) { const unsigned long start = jiffies; /* livelock avoidance */ + spin_lock(&inode_lock); if (!wbc->for_kupdate || list_empty(&sb->s_io)) queue_io(sb, wbc->older_than_this); @@ -485,8 +484,16 @@ if (!list_empty(&sb->s_more_io)) wbc->more_io = 1; } + spin_unlock(&inode_lock); return; /* Leave any unwritten inodes on s_io */ } +EXPORT_SYMBOL_GPL(generic_sync_sb_inodes); + +static void sync_sb_inodes(struct super_block *sb, + struct writeback_control *wbc) +{ + generic_sync_sb_inodes(sb, wbc); +} /* * Start writeback of dirty pagecache data against all unlocked inodes. @@ -526,11 +533,8 @@ * be unmounted by the time it is released. */ if (down_read_trylock(&sb->s_umount)) { - if (sb->s_root) { - spin_lock(&inode_lock); + if (sb->s_root) sync_sb_inodes(sb, wbc); - spin_unlock(&inode_lock); - } up_read(&sb->s_umount); } spin_lock(&sb_lock); @@ -568,9 +572,7 @@ (inodes_stat.nr_inodes - inodes_stat.nr_unused) + nr_dirty + nr_unstable; wbc.nr_to_write += wbc.nr_to_write / 2; /* Bit more for luck */ - spin_lock(&inode_lock); sync_sb_inodes(sb, &wbc); - spin_unlock(&inode_lock); } /* --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -8,6 +8,12 @@ #define GPIO_PIN_NONE (-1) +/* + * Clock rates for various on-board oscillators. The number of entries + * in this array is chip-dependent. + */ +extern unsigned long at32_board_osc_rates[]; + /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */ void at32_add_system_devices(void); @@ -36,11 +42,10 @@ struct atmel_lcdfb_info; struct platform_device * at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, - unsigned long fbmem_start, unsigned long fbmem_len); + unsigned long fbmem_start, unsigned long fbmem_len, + unsigned int pin_config); -struct usba_platform_data { - int vbus_pin; -}; +struct usba_platform_data; struct platform_device * at32_add_device_usba(unsigned int id, struct usba_platform_data *data); @@ -68,9 +73,27 @@ 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 platform_device *at32_add_device_ac97c(unsigned int id); +struct i2c_board_info; +struct platform_device *at32_add_device_twi(unsigned int id, + struct i2c_board_info *b, + unsigned int n); + +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 ac97c_platform_data { + unsigned short dma_rx_periph_id; + unsigned short dma_tx_periph_id; + unsigned short dma_controller_id; + int reset_pin; +}; +struct platform_device * +at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data); + struct platform_device *at32_add_device_abdac(unsigned int id); struct cf_platform_data { @@ -84,4 +107,20 @@ at32_add_device_cf(unsigned int id, unsigned int extint, struct cf_platform_data *data); +struct platform_device * +at32_add_device_psif(unsigned int id); + +/* NAND / SmartMedia */ +struct atmel_nand_data { + int enable_pin; /* chip enable */ + int det_pin; /* card detect */ + int rdy_pin; /* ready/busy */ + u8 ale; /* address line number connected to ALE */ + u8 cle; /* address line number connected to CLE */ + u8 bus_width_16; /* buswidth is 16 bit */ + struct mtd_partition *(*partition_info)(int size, int *num_partitions); +}; +struct platform_device * +at32_add_device_nand(unsigned int id, struct atmel_nand_data *data); + #endif /* __ASM_ARCH_BOARD_H */ --- a/include/asm-avr32/arch-at32ap/init.h +++ b/include/asm-avr32/arch-at32ap/init.h @@ -13,10 +13,6 @@ void setup_platform(void); void setup_board(void); -/* Called by setup_platform */ -void at32_clock_init(void); -void at32_portmux_init(void); - void at32_setup_serial_console(unsigned int usart_id); #endif /* __ASM_AVR32_AT32AP_INIT_H__ */ --- /dev/null +++ b/include/asm-avr32/arch-at32ap/pm.h @@ -0,0 +1,51 @@ +/* + * AVR32 AP Power Management. + * + * Copyright (C) 2008 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_ARCH_PM_H +#define __ASM_AVR32_ARCH_PM_H + +/* Possible arguments to the "sleep" instruction */ +#define CPU_SLEEP_IDLE 0 +#define CPU_SLEEP_FROZEN 1 +#define CPU_SLEEP_STANDBY 2 +#define CPU_SLEEP_STOP 3 +#define CPU_SLEEP_STATIC 5 + +#ifndef __ASSEMBLY__ +extern void cpu_enter_idle(void); +extern void cpu_enter_standby(unsigned long sdramc_base); + +extern bool disable_idle_sleep; + +static inline void cpu_disable_idle_sleep(void) +{ + disable_idle_sleep = true; +} + +static inline void cpu_enable_idle_sleep(void) +{ + disable_idle_sleep = false; +} + +static inline void cpu_idle_sleep(void) +{ + /* + * If we're using the COUNT and COMPARE registers for + * timekeeping, we can't use the IDLE state. + */ + if (disable_idle_sleep) + cpu_relax(); + else + cpu_enter_idle(); +} + +void intc_set_suspend_handler(unsigned long offset); +#endif + +#endif /* __ASM_AVR32_ARCH_PM_H */ --- a/include/asm-avr32/arch-at32ap/portmux.h +++ b/include/asm-avr32/arch-at32ap/portmux.h @@ -26,4 +26,16 @@ 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__ */ --- /dev/null +++ b/include/asm-avr32/arch-at32ap/sram.h @@ -0,0 +1,30 @@ +/* + * Simple SRAM allocator + * + * Copyright (C) 2008 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_ARCH_SRAM_H +#define __ASM_AVR32_ARCH_SRAM_H + +#include <linux/genalloc.h> + +extern struct gen_pool *sram_pool; + +static inline unsigned long sram_alloc(size_t len) +{ + if (!sram_pool) + return 0UL; + + return gen_pool_alloc(sram_pool, len); +} + +static inline void sram_free(unsigned long addr, size_t len) +{ + return gen_pool_free(sram_pool, addr, len); +} + +#endif /* __ASM_AVR32_ARCH_SRAM_H */ --- a/include/asm-avr32/arch-at32ap/time.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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. - */ - -#ifndef _ASM_AVR32_ARCH_AT32AP_TIME_H -#define _ASM_AVR32_ARCH_AT32AP_TIME_H - -#include <linux/platform_device.h> - -extern struct irqaction timer_irqaction; -extern struct platform_device at32_systc0_device; -extern void local_timer_interrupt(int irq, void *dev_id); - -#define TIMER_BCR 0x000000c0 -#define TIMER_BCR_SYNC 0 -#define TIMER_BMR 0x000000c4 -#define TIMER_BMR_TC0XC0S 0 -#define TIMER_BMR_TC1XC1S 2 -#define TIMER_BMR_TC2XC2S 4 -#define TIMER_CCR 0x00000000 -#define TIMER_CCR_CLKDIS 1 -#define TIMER_CCR_CLKEN 0 -#define TIMER_CCR_SWTRG 2 -#define TIMER_CMR 0x00000004 -#define TIMER_CMR_ABETRG 10 -#define TIMER_CMR_ACPA 16 -#define TIMER_CMR_ACPC 18 -#define TIMER_CMR_AEEVT 20 -#define TIMER_CMR_ASWTRG 22 -#define TIMER_CMR_BCPB 24 -#define TIMER_CMR_BCPC 26 -#define TIMER_CMR_BEEVT 28 -#define TIMER_CMR_BSWTRG 30 -#define TIMER_CMR_BURST 4 -#define TIMER_CMR_CLKI 3 -#define TIMER_CMR_CPCDIS 7 -#define TIMER_CMR_CPCSTOP 6 -#define TIMER_CMR_CPCTRG 14 -#define TIMER_CMR_EEVT 10 -#define TIMER_CMR_EEVTEDG 8 -#define TIMER_CMR_ENETRG 12 -#define TIMER_CMR_ETRGEDG 8 -#define TIMER_CMR_LDBDIS 7 -#define TIMER_CMR_LDBSTOP 6 -#define TIMER_CMR_LDRA 16 -#define TIMER_CMR_LDRB 18 -#define TIMER_CMR_TCCLKS 0 -#define TIMER_CMR_WAVE 15 -#define TIMER_CMR_WAVSEL 13 -#define TIMER_CV 0x00000010 -#define TIMER_CV_CV 0 -#define TIMER_IDR 0x00000028 -#define TIMER_IDR_COVFS 0 -#define TIMER_IDR_CPAS 2 -#define TIMER_IDR_CPBS 3 -#define TIMER_IDR_CPCS 4 -#define TIMER_IDR_ETRGS 7 -#define TIMER_IDR_LDRAS 5 -#define TIMER_IDR_LDRBS 6 -#define TIMER_IDR_LOVRS 1 -#define TIMER_IER 0x00000024 -#define TIMER_IER_COVFS 0 -#define TIMER_IER_CPAS 2 -#define TIMER_IER_CPBS 3 -#define TIMER_IER_CPCS 4 -#define TIMER_IER_ETRGS 7 -#define TIMER_IER_LDRAS 5 -#define TIMER_IER_LDRBS 6 -#define TIMER_IER_LOVRS 1 -#define TIMER_IMR 0x0000002c -#define TIMER_IMR_COVFS 0 -#define TIMER_IMR_CPAS 2 -#define TIMER_IMR_CPBS 3 -#define TIMER_IMR_CPCS 4 -#define TIMER_IMR_ETRGS 7 -#define TIMER_IMR_LDRAS 5 -#define TIMER_IMR_LDRBS 6 -#define TIMER_IMR_LOVRS 1 -#define TIMER_RA 0x00000014 -#define TIMER_RA_RA 0 -#define TIMER_RB 0x00000018 -#define TIMER_RB_RB 0 -#define TIMER_RC 0x0000001c -#define TIMER_RC_RC 0 -#define TIMER_SR 0x00000020 -#define TIMER_SR_CLKSTA 16 -#define TIMER_SR_COVFS 0 -#define TIMER_SR_CPAS 2 -#define TIMER_SR_CPBS 3 -#define TIMER_SR_CPCS 4 -#define TIMER_SR_ETRGS 7 -#define TIMER_SR_LDRAS 5 -#define TIMER_SR_LDRBS 6 -#define TIMER_SR_LOVRS 1 -#define TIMER_SR_MTIOA 17 -#define TIMER_SR_MTIOB 18 - -/* Bit manipulation macros */ -#define TIMER_BIT(name) (1 << TIMER_##name) -#define TIMER_BF(name,value) ((value) << TIMER_##name) - -/* Register access macros */ -#define timer_read(port,instance,reg) \ - __raw_readl(port + (0x40 * instance) + TIMER_##reg) -#define timer_write(port,instance,reg,value) \ - __raw_writel((value), port + (0x40 * instance) + TIMER_##reg) - -#endif /* _ASM_AVR32_ARCH_AT32AP_TIME_H */ --- a/include/asm-avr32/asm.h +++ b/include/asm-avr32/asm.h @@ -12,10 +12,10 @@ #include <asm/asm-offsets.h> #include <asm/thread_info.h> -#define mask_interrupts ssrf SR_GM_BIT -#define mask_exceptions ssrf SR_EM_BIT -#define unmask_interrupts csrf SR_GM_BIT -#define unmask_exceptions csrf SR_EM_BIT +#define mask_interrupts ssrf SYSREG_GM_OFFSET +#define mask_exceptions ssrf SYSREG_EM_OFFSET +#define unmask_interrupts csrf SYSREG_GM_OFFSET +#define unmask_exceptions csrf SYSREG_EM_OFFSET #ifdef CONFIG_FRAME_POINTER .macro save_fp --- /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 */ --- a/include/asm-avr32/intc.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef __ASM_AVR32_INTC_H -#define __ASM_AVR32_INTC_H - -#include <linux/sysdev.h> -#include <linux/interrupt.h> - -struct irq_controller; -struct irqaction; -struct pt_regs; - -struct platform_device; - -/* Information about the internal interrupt controller */ -struct intc_device { - /* ioremapped address of configuration block */ - void __iomem *regs; - - /* the physical device */ - struct platform_device *pdev; - - /* Number of interrupt lines per group. */ - unsigned int irqs_per_group; - - /* The highest group ID + 1 */ - unsigned int nr_groups; - - /* - * Bitfield indicating which groups are actually in use. The - * size of the array is - * ceil(group_max / (8 * sizeof(unsigned int))). - */ - unsigned int group_mask[]; -}; - -struct irq_controller_class { - /* - * A short name identifying this kind of controller. - */ - const char *typename; - /* - * Handle the IRQ. Must do any necessary acking and masking. - */ - irqreturn_t (*handle)(int irq, void *dev_id, struct pt_regs *regs); - /* - * Register a new IRQ handler. - */ - int (*setup)(struct irq_controller *ctrl, unsigned int irq, - struct irqaction *action); - /* - * Unregister a IRQ handler. - */ - void (*free)(struct irq_controller *ctrl, unsigned int irq, - void *dev_id); - /* - * Mask the IRQ in the interrupt controller. - */ - void (*mask)(struct irq_controller *ctrl, unsigned int irq); - /* - * Unmask the IRQ in the interrupt controller. - */ - void (*unmask)(struct irq_controller *ctrl, unsigned int irq); - /* - * Set the type of the IRQ. See below for possible types. - * Return -EINVAL if a given type is not supported - */ - int (*set_type)(struct irq_controller *ctrl, unsigned int irq, - unsigned int type); - /* - * Return the IRQ type currently set - */ - unsigned int (*get_type)(struct irq_controller *ctrl, unsigned int irq); -}; - -struct irq_controller { - struct irq_controller_class *class; - unsigned int irq_group; - unsigned int first_irq; - unsigned int nr_irqs; - struct list_head list; -}; - -struct intc_group_desc { - struct irq_controller *ctrl; - irqreturn_t (*handle)(int, void *, struct pt_regs *); - unsigned long flags; - void *dev_id; - const char *devname; -}; - -/* - * The internal interrupt controller. Defined in board/part-specific - * devices.c. - * TODO: Should probably be defined per-cpu. - */ -extern struct intc_device intc; - -extern int request_internal_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char *devname, void *dev_id); -extern void free_internal_irq(unsigned int irq); - -/* Only used by time_init() */ -extern int setup_internal_irq(unsigned int irq, struct intc_group_desc *desc); - -/* - * Set interrupt priority for a given group. `group' can be found by - * using irq_to_group(irq). Priority can be from 0 (lowest) to 3 - * (highest). Higher-priority interrupts will preempt lower-priority - * interrupts (unless interrupts are masked globally). - * - * This function does not check for conflicts within a group. - */ -extern int intc_set_priority(unsigned int group, - unsigned int priority); - -/* - * Returns a bitmask of pending interrupts in a group. - */ -extern unsigned long intc_get_pending(unsigned int group); - -/* - * Register a new external interrupt controller. Returns the first - * external IRQ number that is assigned to the new controller. - */ -extern int intc_register_controller(struct irq_controller *ctrl); - -#endif /* __ASM_AVR32_INTC_H */ --- a/include/asm-avr32/irq.h +++ b/include/asm-avr32/irq.h @@ -14,6 +14,11 @@ #ifndef __ASSEMBLER__ int nmi_enable(void); void nmi_disable(void); + +/* + * Returns a bitmask of pending interrupts in a group. + */ +extern unsigned long intc_get_pending(unsigned int group); #endif #endif /* __ASM_AVR32_IOCTLS_H */ --- a/include/asm-avr32/mmu_context.h +++ b/include/asm-avr32/mmu_context.h @@ -13,7 +13,6 @@ #define __ASM_AVR32_MMU_CONTEXT_H #include <asm/tlbflush.h> -#include <asm/pgalloc.h> #include <asm/sysreg.h> #include <asm-generic/mm_hooks.h> --- a/include/asm-avr32/page.h +++ b/include/asm-avr32/page.h @@ -8,13 +8,11 @@ #ifndef __ASM_AVR32_PAGE_H #define __ASM_AVR32_PAGE_H +#include <linux/const.h> + /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (1 << PAGE_SHIFT) -#else -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #define PTE_MASK PAGE_MASK --- a/include/asm-avr32/pci.h +++ b/include/asm-avr32/pci.h @@ -5,4 +5,6 @@ #define PCI_DMA_BUS_IS_PHYS (1) +#include <asm-generic/pci-dma-compat.h> + #endif /* __ASM_AVR32_PCI_H__ */ --- a/include/asm-avr32/pgalloc.h +++ b/include/asm-avr32/pgalloc.h @@ -8,65 +8,79 @@ #ifndef __ASM_AVR32_PGALLOC_H #define __ASM_AVR32_PGALLOC_H -#include <asm/processor.h> -#include <linux/threads.h> -#include <linux/slab.h> -#include <linux/mm.h> +#include <linux/quicklist.h> +#include <asm/page.h> +#include <asm/pgtable.h> -#define pmd_populate_kernel(mm, pmd, pte) \ - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) +#define QUICK_PGD 0 /* Preserve kernel mappings over free */ +#define QUICK_PT 1 /* Zero on free */ -static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd, +static inline void pmd_populate_kernel(struct mm_struct *mm, + pmd_t *pmd, pte_t *pte) +{ + set_pmd(pmd, __pmd((unsigned long)pte)); +} + +static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t pte) { - set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte))); + set_pmd(pmd, __pmd((unsigned long)page_address(pte))); } #define pmd_pgtable(pmd) pmd_page(pmd) +static inline void pgd_ctor(void *x) +{ + pgd_t *pgd = x; + + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); +} + /* * Allocate and free page tables */ -static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm) +static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL); + return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor); } static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) { - kfree(pgd); + quicklist_free(QUICK_PGD, NULL, pgd); } static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { - pte_t *pte; - - pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT); - - return pte; + return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); } -static inline struct page *pte_alloc_one(struct mm_struct *mm, +static inline pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) { - struct page *pte; + struct page *page; + void *pg; - pte = alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO); - if (!pte) + pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); + if (!pg) return NULL; - pgtable_page_ctor(pte); - return pte; + + page = virt_to_page(pg); + pgtable_page_ctor(page); + + return page; } static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) { - free_page((unsigned long)pte); + quicklist_free(QUICK_PT, NULL, pte); } static inline void pte_free(struct mm_struct *mm, pgtable_t pte) { pgtable_page_dtor(pte); - __free_page(pte); + quicklist_free_page(QUICK_PT, NULL, pte); } #define __pte_free_tlb(tlb,pte) \ @@ -75,6 +89,10 @@ tlb_remove_page((tlb), pte); \ } while (0) -#define check_pgt_cache() do { } while(0) +static inline void check_pgt_cache(void) +{ + quicklist_trim(QUICK_PGD, NULL, 25, 16); + quicklist_trim(QUICK_PT, NULL, 25, 16); +} #endif /* __ASM_AVR32_PGALLOC_H */ --- a/include/asm-avr32/pgtable.h +++ b/include/asm-avr32/pgtable.h @@ -129,13 +129,6 @@ #define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT) -/* TODO: Check for saneness */ -/* User-mode page table flags (to be set in a pgd or pmd entry) */ -#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \ - | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) -/* Kernel-mode page table flags */ -#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \ - | _PAGE_ACCESSED | _PAGE_DIRTY) /* Flags that may be modified by software */ #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \ | _PAGE_FLAGS_CACHE_MASK) @@ -254,10 +247,14 @@ } #define pmd_none(x) (!pmd_val(x)) -#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) -#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) -#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) \ - != _KERNPG_TABLE) +#define pmd_present(x) (pmd_val(x)) + +static inline void pmd_clear(pmd_t *pmdp) +{ + set_pmd(pmdp, __pmd(0)); +} + +#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK) /* * Permanent address of a page. We don't support highmem, so this is @@ -295,19 +292,16 @@ #define page_pte(page) page_pte_prot(page, __pgprot(0)) -#define pmd_page_vaddr(pmd) \ - ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) - -#define pmd_page(pmd) (phys_to_page(pmd_val(pmd))) +#define pmd_page_vaddr(pmd) pmd_val(pmd) +#define pmd_page(pmd) (virt_to_page(pmd_val(pmd))) /* to find an entry in a page-table-directory. */ -#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) -#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) -#define pgd_offset_current(address) \ - ((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address)) +#define pgd_index(address) (((address) >> PGDIR_SHIFT) \ + & (PTRS_PER_PGD - 1)) +#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) /* to find an entry in a kernel page-table-directory */ -#define pgd_offset_k(address) pgd_offset(&init_mm, address) +#define pgd_offset_k(address) pgd_offset(&init_mm, address) /* Find an entry in the third-level page table.. */ #define pte_index(address) \ --- /dev/null +++ b/include/asm-avr32/serial.h @@ -0,0 +1,13 @@ +#ifndef _ASM_SERIAL_H +#define _ASM_SERIAL_H + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD (1843200 / 16) + +#endif /* _ASM_SERIAL_H */ --- a/include/asm-avr32/thread_info.h +++ b/include/asm-avr32/thread_info.h @@ -88,6 +88,7 @@ #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_FREEZE 29 #define TIF_DEBUG 30 /* debugging enabled */ #define TIF_USERSPACE 31 /* true if FS sets userspace */ --- a/include/asm-avr32/tlbflush.h +++ b/include/asm-avr32/tlbflush.h @@ -26,7 +26,6 @@ extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); -extern void __flush_tlb_page(unsigned long asid, unsigned long page); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); --- /dev/null +++ b/include/asm-avr32/xor.h @@ -0,0 +1,6 @@ +#ifndef _ASM_XOR_H +#define _ASM_XOR_H + +#include <asm-generic/xor.h> + +#endif --- /dev/null +++ b/include/linux/atmel_tc.h @@ -0,0 +1,252 @@ +/* + * Timer/Counter Unit (TC) registers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef ATMEL_TC_H +#define ATMEL_TC_H + +#include <linux/compiler.h> +#include <linux/list.h> + +/* + * Many 32-bit Atmel SOCs include one or more TC blocks, each of which holds + * three general-purpose 16-bit timers. These timers share one register bank. + * Depending on the SOC, each timer may have its own clock and IRQ, or those + * may be shared by the whole TC block. + * + * These TC blocks may have up to nine external pins: TCLK0..2 signals for + * clocks or clock gates, and per-timer TIOA and TIOB signals used for PWM + * or triggering. Those pins need to be set up for use with the TC block, + * else they will be used as GPIOs or for a different controller. + * + * Although we expect each TC block to have a platform_device node, those + * nodes are not what drivers bind to. Instead, they ask for a specific + * TC block, by number ... which is a common approach on systems with many + * timers. Then they use clk_get() and platform_get_irq() to get clock and + * IRQ resources. + */ + +struct clk; + +/** + * struct atmel_tc - information about a Timer/Counter Block + * @pdev: physical device + * @iomem: resource associated with the I/O register + * @regs: mapping through which the I/O registers can be accessed + * @irq: irq for each of the three channels + * @clk: internal clock source for each of the three channels + * @node: list node, for tclib internal use + * + * On some platforms, each TC channel has its own clocks and IRQs, + * while on others, all TC channels share the same clock and IRQ. + * Drivers should clk_enable() all the clocks they need even though + * all the entries in @clk may point to the same physical clock. + * Likewise, drivers should request irqs independently for each + * channel, but they must use IRQF_SHARED in case some of the entries + * in @irq are actually the same IRQ. + */ +struct atmel_tc { + struct platform_device *pdev; + struct resource *iomem; + void __iomem *regs; + int irq[3]; + struct clk *clk[3]; + struct list_head node; +}; + +extern struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name); +extern void atmel_tc_free(struct atmel_tc *tc); + +/* platform-specific ATMEL_TC_TIMER_CLOCKx divisors (0 means 32KiHz) */ +extern const u8 atmel_tc_divisors[5]; + + +/* + * Two registers have block-wide controls. These are: configuring the three + * "external" clocks (or event sources) used by the timer channels; and + * synchronizing the timers by resetting them all at once. + * + * "External" can mean "external to chip" using the TCLK0, TCLK1, or TCLK2 + * signals. Or, it can mean "external to timer", using the TIOA output from + * one of the other two timers that's being run in waveform mode. + */ + +#define ATMEL_TC_BCR 0xc0 /* TC Block Control Register */ +#define ATMEL_TC_SYNC (1 << 0) /* synchronize timers */ + +#define ATMEL_TC_BMR 0xc4 /* TC Block Mode Register */ +#define ATMEL_TC_TC0XC0S (3 << 0) /* external clock 0 source */ +#define ATMEL_TC_TC0XC0S_TCLK0 (0 << 0) +#define ATMEL_TC_TC0XC0S_NONE (1 << 0) +#define ATMEL_TC_TC0XC0S_TIOA1 (2 << 0) +#define ATMEL_TC_TC0XC0S_TIOA2 (3 << 0) +#define ATMEL_TC_TC1XC1S (3 << 2) /* external clock 1 source */ +#define ATMEL_TC_TC1XC1S_TCLK1 (0 << 2) +#define ATMEL_TC_TC1XC1S_NONE (1 << 2) +#define ATMEL_TC_TC1XC1S_TIOA0 (2 << 2) +#define ATMEL_TC_TC1XC1S_TIOA2 (3 << 2) +#define ATMEL_TC_TC2XC2S (3 << 4) /* external clock 2 source */ +#define ATMEL_TC_TC2XC2S_TCLK2 (0 << 4) +#define ATMEL_TC_TC2XC2S_NONE (1 << 4) +#define ATMEL_TC_TC2XC2S_TIOA0 (2 << 4) +#define ATMEL_TC_TC2XC2S_TIOA1 (3 << 4) + + +/* + * Each TC block has three "channels", each with one counter and controls. + * + * Note that the semantics of ATMEL_TC_TIMER_CLOCKx (input clock selection + * when it's not "external") is silicon-specific. AT91 platforms use one + * set of definitions; AVR32 platforms use a different set. Don't hard-wire + * such knowledge into your code, use the global "atmel_tc_divisors" ... + * where index N is the divisor for clock N+1, else zero to indicate it uses + * the 32 KiHz clock. + * + * The timers can be chained in various ways, and operated in "waveform" + * generation mode (including PWM) or "capture" mode (to time events). In + * both modes, behavior can be configured in many ways. + * + * Each timer has two I/O pins, TIOA and TIOB. Waveform mode uses TIOA as a + * PWM output, and TIOB as either another PWM or as a trigger. Capture mode + * uses them only as inputs. + */ +#define ATMEL_TC_CHAN(idx) ((idx)*0x40) +#define ATMEL_TC_REG(idx, reg) (ATMEL_TC_CHAN(idx) + ATMEL_TC_ ## reg) + +#define ATMEL_TC_CCR 0x00 /* Channel Control Register */ +#define ATMEL_TC_CLKEN (1 << 0) /* clock enable */ +#define ATMEL_TC_CLKDIS (1 << 1) /* clock disable */ +#define ATMEL_TC_SWTRG (1 << 2) /* software trigger */ + +#define ATMEL_TC_CMR 0x04 /* Channel Mode Register */ + +/* Both modes share some CMR bits */ +#define ATMEL_TC_TCCLKS (7 << 0) /* clock source */ +#define ATMEL_TC_TIMER_CLOCK1 (0 << 0) +#define ATMEL_TC_TIMER_CLOCK2 (1 << 0) +#define ATMEL_TC_TIMER_CLOCK3 (2 << 0) +#define ATMEL_TC_TIMER_CLOCK4 (3 << 0) +#define ATMEL_TC_TIMER_CLOCK5 (4 << 0) +#define ATMEL_TC_XC0 (5 << 0) +#define ATMEL_TC_XC1 (6 << 0) +#define ATMEL_TC_XC2 (7 << 0) +#define ATMEL_TC_CLKI (1 << 3) /* clock invert */ +#define ATMEL_TC_BURST (3 << 4) /* clock gating */ +#define ATMEL_TC_GATE_NONE (0 << 4) +#define ATMEL_TC_GATE_XC0 (1 << 4) +#define ATMEL_TC_GATE_XC1 (2 << 4) +#define ATMEL_TC_GATE_XC2 (3 << 4) +#define ATMEL_TC_WAVE (1 << 15) /* true = Waveform mode */ + +/* CAPTURE mode CMR bits */ +#define ATMEL_TC_LDBSTOP (1 << 6) /* counter stops on RB load */ +#define ATMEL_TC_LDBDIS (1 << 7) /* counter disable on RB load */ +#define ATMEL_TC_ETRGEDG (3 << 8) /* external trigger edge */ +#define ATMEL_TC_ETRGEDG_NONE (0 << 8) +#define ATMEL_TC_ETRGEDG_RISING (1 << 8) +#define ATMEL_TC_ETRGEDG_FALLING (2 << 8) +#define ATMEL_TC_ETRGEDG_BOTH (3 << 8) +#define ATMEL_TC_ABETRG (1 << 10) /* external trigger is TIOA? */ +#define ATMEL_TC_CPCTRG (1 << 14) /* RC compare trigger enable */ +#define ATMEL_TC_LDRA (3 << 16) /* RA loading edge (of TIOA) */ +#define ATMEL_TC_LDRA_NONE (0 << 16) +#define ATMEL_TC_LDRA_RISING (1 << 16) +#define ATMEL_TC_LDRA_FALLING (2 << 16) +#define ATMEL_TC_LDRA_BOTH (3 << 16) +#define ATMEL_TC_LDRB (3 << 18) /* RB loading edge (of TIOA) */ +#define ATMEL_TC_LDRB_NONE (0 << 18) +#define ATMEL_TC_LDRB_RISING (1 << 18) +#define ATMEL_TC_LDRB_FALLING (2 << 18) +#define ATMEL_TC_LDRB_BOTH (3 << 18) + +/* WAVEFORM mode CMR bits */ +#define ATMEL_TC_CPCSTOP (1 << 6) /* RC compare stops counter */ +#define ATMEL_TC_CPCDIS (1 << 7) /* RC compare disables counter */ +#define ATMEL_TC_EEVTEDG (3 << 8) /* external event edge */ +#define ATMEL_TC_EEVTEDG_NONE (0 << 8) +#define ATMEL_TC_EEVTEDG_RISING (1 << 8) +#define ATMEL_TC_EEVTEDG_FALLING (2 << 8) +#define ATMEL_TC_EEVTEDG_BOTH (3 << 8) +#define ATMEL_TC_EEVT (3 << 10) /* external event source */ +#define ATMEL_TC_EEVT_TIOB (0 << 10) +#define ATMEL_TC_EEVT_XC0 (1 << 10) +#define ATMEL_TC_EEVT_XC1 (2 << 10) +#define ATMEL_TC_EEVT_XC2 (3 << 10) +#define ATMEL_TC_ENETRG (1 << 12) /* external event is trigger */ +#define ATMEL_TC_WAVESEL (3 << 13) /* waveform type */ +#define ATMEL_TC_WAVESEL_UP (0 << 13) +#define ATMEL_TC_WAVESEL_UPDOWN (1 << 13) +#define ATMEL_TC_WAVESEL_UP_AUTO (2 << 13) +#define ATMEL_TC_WAVESEL_UPDOWN_AUTO (3 << 13) +#define ATMEL_TC_ACPA (3 << 16) /* RA compare changes TIOA */ +#define ATMEL_TC_ACPA_NONE (0 << 16) +#define ATMEL_TC_ACPA_SET (1 << 16) +#define ATMEL_TC_ACPA_CLEAR (2 << 16) +#define ATMEL_TC_ACPA_TOGGLE (3 << 16) +#define ATMEL_TC_ACPC (3 << 18) /* RC compare changes TIOA */ +#define ATMEL_TC_ACPC_NONE (0 << 18) +#define ATMEL_TC_ACPC_SET (1 << 18) +#define ATMEL_TC_ACPC_CLEAR (2 << 18) +#define ATMEL_TC_ACPC_TOGGLE (3 << 18) +#define ATMEL_TC_AEEVT (3 << 20) /* external event changes TIOA */ +#define ATMEL_TC_AEEVT_NONE (0 << 20) +#define ATMEL_TC_AEEVT_SET (1 << 20) +#define ATMEL_TC_AEEVT_CLEAR (2 << 20) +#define ATMEL_TC_AEEVT_TOGGLE (3 << 20) +#define ATMEL_TC_ASWTRG (3 << 22) /* software trigger changes TIOA */ +#define ATMEL_TC_ASWTRG_NONE (0 << 22) +#define ATMEL_TC_ASWTRG_SET (1 << 22) +#define ATMEL_TC_ASWTRG_CLEAR (2 << 22) +#define ATMEL_TC_ASWTRG_TOGGLE (3 << 22) +#define ATMEL_TC_BCPB (3 << 24) /* RB compare changes TIOB */ +#define ATMEL_TC_BCPB_NONE (0 << 24) +#define ATMEL_TC_BCPB_SET (1 << 24) +#define ATMEL_TC_BCPB_CLEAR (2 << 24) +#define ATMEL_TC_BCPB_TOGGLE (3 << 24) +#define ATMEL_TC_BCPC (3 << 26) /* RC compare changes TIOB */ +#define ATMEL_TC_BCPC_NONE (0 << 26) +#define ATMEL_TC_BCPC_SET (1 << 26) +#define ATMEL_TC_BCPC_CLEAR (2 << 26) +#define ATMEL_TC_BCPC_TOGGLE (3 << 26) +#define ATMEL_TC_BEEVT (3 << 28) /* external event changes TIOB */ +#define ATMEL_TC_BEEVT_NONE (0 << 28) +#define ATMEL_TC_BEEVT_SET (1 << 28) +#define ATMEL_TC_BEEVT_CLEAR (2 << 28) +#define ATMEL_TC_BEEVT_TOGGLE (3 << 28) +#define ATMEL_TC_BSWTRG (3 << 30) /* software trigger changes TIOB */ +#define ATMEL_TC_BSWTRG_NONE (0 << 30) +#define ATMEL_TC_BSWTRG_SET (1 << 30) +#define ATMEL_TC_BSWTRG_CLEAR (2 << 30) +#define ATMEL_TC_BSWTRG_TOGGLE (3 << 30) + +#define ATMEL_TC_CV 0x10 /* counter Value */ +#define ATMEL_TC_RA 0x14 /* register A */ +#define ATMEL_TC_RB 0x18 /* register B */ +#define ATMEL_TC_RC 0x1c /* register C */ + +#define ATMEL_TC_SR 0x20 /* status (read-only) */ +/* Status-only flags */ +#define ATMEL_TC_CLKSTA (1 << 16) /* clock enabled */ +#define ATMEL_TC_MTIOA (1 << 17) /* TIOA mirror */ +#define ATMEL_TC_MTIOB (1 << 18) /* TIOB mirror */ + +#define ATMEL_TC_IER 0x24 /* interrupt enable (write-only) */ +#define ATMEL_TC_IDR 0x28 /* interrupt disable (write-only) */ +#define ATMEL_TC_IMR 0x2c /* interrupt mask (read-only) */ + +/* Status and IRQ flags */ +#define ATMEL_TC_COVFS (1 << 0) /* counter overflow */ +#define ATMEL_TC_LOVRS (1 << 1) /* load overrun */ +#define ATMEL_TC_CPAS (1 << 2) /* RA compare */ +#define ATMEL_TC_CPBS (1 << 3) /* RB compare */ +#define ATMEL_TC_CPCS (1 << 4) /* RC compare */ +#define ATMEL_TC_LDRAS (1 << 5) /* RA loading */ +#define ATMEL_TC_LDRBS (1 << 6) /* RB loading */ +#define ATMEL_TC_ETRGS (1 << 7) /* external trigger */ + +#endif --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1692,6 +1692,8 @@ extern int invalidate_inode_pages2(struct address_space *mapping); extern int invalidate_inode_pages2_range(struct address_space *mapping, pgoff_t start, pgoff_t end); +extern void generic_sync_sb_inodes(struct super_block *sb, + struct writeback_control *wbc); extern int write_inode_now(struct inode *, int); extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -188,6 +188,7 @@ void (*break_ctl)(struct uart_port *, int ctl); int (*startup)(struct uart_port *); void (*shutdown)(struct uart_port *); + void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); void (*pm)(struct uart_port *, unsigned int state, --- /dev/null +++ b/include/linux/usb/atmel_usba_udc.h @@ -0,0 +1,22 @@ +/* + * Platform data definitions for Atmel USBA gadget driver. + */ +#ifndef __LINUX_USB_USBA_H +#define __LINUX_USB_USBA_H + +struct usba_ep_data { + char *name; + int index; + int fifo_size; + int nr_banks; + int can_dma; + int can_isoc; +}; + +struct usba_platform_data { + int vbus_pin; + int num_ep; + struct usba_ep_data ep[0]; +}; + +#endif /* __LINUX_USB_USBA_H */ --- a/mm/Kconfig +++ b/mm/Kconfig @@ -187,7 +187,7 @@ config NR_QUICK int depends on QUICKLIST - default "2" if SUPERH + default "2" if SUPERH || AVR32 default "1" config VIRT_TO_BUS --- a/sound/Kconfig +++ b/sound/Kconfig @@ -63,6 +63,8 @@ source "sound/arm/Kconfig" +source "sound/avr32/Kconfig" + if SPI source "sound/spi/Kconfig" endif --- a/sound/Makefile +++ b/sound/Makefile @@ -6,7 +6,7 @@ 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 --- /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 --- /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 --- /dev/null +++ b/sound/avr32/ac97c.c @@ -0,0 +1,951 @@ +/* + * 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/gpio.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/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/arch/board.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; + unsigned short controller; +}; + +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; + int reset_pin; + 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; + } + udelay(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; + } + udelay(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) +{ + /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */ + if (chip->reset_pin >= 0) { + gpio_set_value(chip->reset_pin, 0); + /* AC97 v2.2 specifications says minimum 1 us. */ + udelay(5); + gpio_set_value(chip->reset_pin, 1); + } + + 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 ac97c_platform_data *pdata; + struct resource *regs; + struct clk *mck; + int err; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENXIO; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -ENXIO; + + chip->reset_pin = pdata->reset_pin; + + /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */ + if (chip->reset_pin >= 0) { + if (gpio_request(chip->reset_pin, chip->card->shortname)) { + dev_dbg(&pdev->dev, "ac97: reset pin not available\n"); + chip->reset_pin = -1; + } else { + gpio_direction_output(chip->reset_pin, 1); + } + } + + chip->dma.rx_periph_id = pdata->dma_rx_periph_id; + chip->dma.tx_periph_id = pdata->dma_tx_periph_id; + chip->dma.controller = pdata->dma_controller_id; + + 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); + chip->reset_pin = -1; + + 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; + + chip->dma.req_tx.req.dmac = find_dma_controller(chip->dma.controller); + 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(chip->dma.controller); + if (!chip->dma.req_rx.req.dmac) { + dev_dbg(&chip->pdev->dev, "DMA controller for RX missing\n"); + err = -ENODEV; + goto out_free_card; + } + + 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: + /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */ + if (chip->reset_pin >= 0) + gpio_free(chip->reset_pin); + 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 = platform_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); + struct atmel_ac97 *chip = get_chip(card); + + /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */ + if (chip->reset_pin >= 0) + gpio_free(chip->reset_pin); + 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>"); --- /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 */ --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -654,3 +654,7 @@ 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 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -9,6 +9,7 @@ # 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 --- /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"); --- /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__ */ --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -737,7 +737,7 @@ /* * Device functions */ -static int snd_at73c213_ssc_init(struct snd_at73c213 *chip) +static int __devinit snd_at73c213_ssc_init(struct snd_at73c213 *chip) { /* * Continuous clock output. @@ -767,7 +767,7 @@ return 0; } -static int snd_at73c213_chip_init(struct snd_at73c213 *chip) +static int __devinit snd_at73c213_chip_init(struct snd_at73c213 *chip) { int retval; unsigned char dac_ctrl = 0; @@ -933,7 +933,7 @@ return retval; } -static int snd_at73c213_probe(struct spi_device *spi) +static int __devinit snd_at73c213_probe(struct spi_device *spi) { struct snd_card *card; struct snd_at73c213 *chip;