diff options
Diffstat (limited to 'arch/avr32')
27 files changed, 713 insertions, 291 deletions
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 7c239a916275..33a5b2969eb4 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -72,6 +72,8 @@ config GENERIC_BUG source "init/Kconfig" +source "kernel/Kconfig.freezer" + menu "System Type and features" source "kernel/time/Kconfig" diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index b8286f1ce854..6c54580a66df 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -9,6 +9,7 @@ */ #include <linux/clk.h> #include <linux/etherdevice.h> +#include <linux/gpio.h> #include <linux/irq.h> #include <linux/i2c.h> #include <linux/i2c-gpio.h> @@ -53,8 +54,11 @@ static struct spi_board_info spi0_board_info[] __initdata = { }; static struct mci_platform_data __initdata mci0_data = { - .detect_pin = GPIO_PIN_PC(25), - .wp_pin = GPIO_PIN_PE(0), + .slot[0] = { + .bus_width = 4, + .detect_pin = GPIO_PIN_PC(25), + .wp_pin = GPIO_PIN_PE(0), + }, }; /* @@ -190,7 +194,7 @@ static int __init atngw100_init(void) * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus), * but it's not available off-board. */ - at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP); + at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP); 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, @@ -204,6 +208,15 @@ postcore_initcall(atngw100_init); static int __init atngw100_arch_init(void) { + /* PB30 is the otherwise unused jumper on the mainboard, with an + * external pullup; the jumper grounds it. Use it however you + * like, including letting U-Boot or Linux tweak boot sequences. + */ + at32_select_gpio(GPIO_PIN_PB(30), 0); + gpio_request(GPIO_PIN_PB(30), "j15"); + gpio_direction_input(GPIO_PIN_PB(30)); + gpio_export(GPIO_PIN_PB(30), false); + /* set_irq_type() after the arch_initcall for EIC has run, and * before the I2C subsystem could try using this IRQ. */ diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index dfc3443e23aa..29e5b51a7fd2 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -232,7 +232,7 @@ static void __init atstk1002_setup_extdac(void) goto err_set_clk; } - at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); + at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0); at73c213_data.dac_clk = gclk; err_set_clk: @@ -264,16 +264,20 @@ void __init setup_board(void) #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM +static struct mci_platform_data __initdata mci0_data = { + .slot[0] = { + .bus_width = 4, + /* MMC card detect requires MACB0 *NOT* be used */ #ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM -static struct mci_platform_data __initdata mci0_data = { - .detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */ - .wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */ -}; -#define MCI_PDATA &mci0_data + .detect_pin = GPIO_PIN_PC(14), /* gpio30/sdcd */ + .wp_pin = GPIO_PIN_PC(15), /* gpio31/sdwp */ #else -#define MCI_PDATA NULL + .detect_pin = -ENODEV, + .wp_pin = -ENODEV, #endif /* SW6 for sd{cd,wp} routing */ + }, +}; #endif /* SW2 for MMC signal routing */ @@ -326,13 +330,14 @@ static int __init atstk1002_init(void) 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, MCI_PDATA); + at32_add_device_mci(0, &mci0_data); #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, 0); + fbmem_start, fbmem_size, + ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL); #endif at32_add_device_usba(0, NULL); #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c index 0cf664174c17..be089d7f37eb 100644 --- a/arch/avr32/boards/atstk1000/atstk1003.c +++ b/arch/avr32/boards/atstk1000/atstk1003.c @@ -19,6 +19,7 @@ #include <linux/spi/spi.h> #include <asm/setup.h> +#include <asm/atmel-mci.h> #include <mach/at32ap700x.h> #include <mach/board.h> @@ -66,6 +67,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { { } }; #endif +#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM +static struct mci_platform_data __initdata mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -ENODEV, + .wp_pin = -ENODEV, + }, +}; +#endif + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC static void __init atstk1003_setup_extdac(void) { @@ -84,7 +95,7 @@ static void __init atstk1003_setup_extdac(void) goto err_set_clk; } - at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); + at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0); at73c213_data.dac_clk = gclk; err_set_clk: @@ -154,7 +165,7 @@ static int __init atstk1003_init(void) at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); #endif #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM - at32_add_device_mci(0, NULL); + at32_add_device_mci(0, &mci0_data); #endif at32_add_device_usba(0, NULL); #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c index 50a5273e5916..248ef237c167 100644 --- a/arch/avr32/boards/atstk1000/atstk1004.c +++ b/arch/avr32/boards/atstk1000/atstk1004.c @@ -21,6 +21,7 @@ #include <video/atmel_lcdc.h> #include <asm/setup.h> +#include <asm/atmel-mci.h> #include <mach/at32ap700x.h> #include <mach/board.h> @@ -71,6 +72,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { { } }; #endif +#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM +static struct mci_platform_data __initdata mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -ENODEV, + .wp_pin = -ENODEV, + }, +}; +#endif + #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC static void __init atstk1004_setup_extdac(void) { @@ -89,7 +100,7 @@ static void __init atstk1004_setup_extdac(void) goto err_set_clk; } - at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); + at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0); at73c213_data.dac_clk = gclk; err_set_clk: @@ -137,10 +148,11 @@ static int __init atstk1004_init(void) at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); #endif #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM - at32_add_device_mci(0, NULL); + at32_add_device_mci(0, &mci0_data); #endif at32_add_device_lcdc(0, &atstk1000_lcdc_data, - fbmem_start, fbmem_size, 0); + fbmem_start, fbmem_size, + ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL); at32_add_device_usba(0, NULL); #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM at32_add_device_ssc(0, ATMEL_SSC_TX); diff --git a/arch/avr32/include/asm/a.out.h b/arch/avr32/include/asm/a.out.h deleted file mode 100644 index e46375a34a72..000000000000 --- a/arch/avr32/include/asm/a.out.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_AVR32_A_OUT_H -#define __ASM_AVR32_A_OUT_H - -struct exec -{ - unsigned long a_info; /* Use macros N_MAGIC, etc for access */ - unsigned a_text; /* length of text, in bytes */ - unsigned a_data; /* length of data, in bytes */ - unsigned a_bss; /* length of uninitialized data area for file, in bytes */ - unsigned a_syms; /* length of symbol table data in file, in bytes */ - unsigned a_entry; /* start address */ - unsigned a_trsize; /* length of relocation info for text, in bytes */ - unsigned a_drsize; /* length of relocation info for data, in bytes */ -}; - -#define N_TRSIZE(a) ((a).a_trsize) -#define N_DRSIZE(a) ((a).a_drsize) -#define N_SYMSIZE(a) ((a).a_syms) - -#endif /* __ASM_AVR32_A_OUT_H */ diff --git a/arch/avr32/include/asm/atmel-mci.h b/arch/avr32/include/asm/atmel-mci.h index c2ea6e1c9aa1..59f3fadd0b68 100644 --- a/arch/avr32/include/asm/atmel-mci.h +++ b/arch/avr32/include/asm/atmel-mci.h @@ -1,9 +1,39 @@ #ifndef __ASM_AVR32_ATMEL_MCI_H #define __ASM_AVR32_ATMEL_MCI_H -struct mci_platform_data { +#define ATMEL_MCI_MAX_NR_SLOTS 2 + +struct dma_slave; + +/** + * struct mci_slot_pdata - board-specific per-slot configuration + * @bus_width: Number of data lines wired up the slot + * @detect_pin: GPIO pin wired to the card detect switch + * @wp_pin: GPIO pin wired to the write protect sensor + * + * If a given slot is not present on the board, @bus_width should be + * set to 0. The other fields are ignored in this case. + * + * Any pins that aren't available should be set to a negative value. + * + * Note that support for multiple slots is experimental -- some cards + * might get upset if we don't get the clock management exactly right. + * But in most cases, it should work just fine. + */ +struct mci_slot_pdata { + unsigned int bus_width; int detect_pin; int wp_pin; }; +/** + * struct mci_platform_data - board-specific MMC/SDcard configuration + * @dma_slave: DMA slave interface to use in data transfers, or NULL. + * @slot: Per-slot configuration data. + */ +struct mci_platform_data { + struct dma_slave *dma_slave; + struct mci_slot_pdata slot[ATMEL_MCI_MAX_NR_SLOTS]; +}; + #endif /* __ASM_AVR32_ATMEL_MCI_H */ diff --git a/arch/avr32/include/asm/byteorder.h b/arch/avr32/include/asm/byteorder.h index d77b48ba7338..8e3af02076dd 100644 --- a/arch/avr32/include/asm/byteorder.h +++ b/arch/avr32/include/asm/byteorder.h @@ -7,6 +7,9 @@ #include <asm/types.h> #include <linux/compiler.h> +#define __BIG_ENDIAN +#define __SWAB_64_THRU_32__ + #ifdef __CHECKER__ extern unsigned long __builtin_bswap_32(unsigned long x); extern unsigned short __builtin_bswap_16(unsigned short x); @@ -17,15 +20,18 @@ extern unsigned short __builtin_bswap_16(unsigned short x); * the result. */ #if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2) -#define __arch__swab32(x) __builtin_bswap_32(x) -#define __arch__swab16(x) __builtin_bswap_16(x) -#endif +static inline __attribute_const__ __u16 __arch_swab16(__u16 val) +{ + return __builtin_bswap_16(val); +} +#define __arch_swab16 __arch_swab16 -#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) -# define __BYTEORDER_HAS_U64__ -# define __SWAB_64_THRU_32__ +static inline __attribute_const__ __u32 __arch_swab32(__u32 val) +{ + return __builtin_bswap_32(val); +} +#define __arch_swab32 __arch_swab32 #endif -#include <linux/byteorder/big_endian.h> - +#include <linux/byteorder.h> #endif /* __ASM_AVR32_BYTEORDER_H */ diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h index 64ce40ee1d58..d5d1d41c600a 100644 --- a/arch/avr32/include/asm/elf.h +++ b/arch/avr32/include/asm/elf.h @@ -103,6 +103,6 @@ typedef struct user_fpu_struct elf_fpregset_t; #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) +#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) #endif /* __ASM_AVR32_ELF_H */ diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h index a520f77ead96..22c97ef92201 100644 --- a/arch/avr32/include/asm/io.h +++ b/arch/avr32/include/asm/io.h @@ -160,6 +160,14 @@ BUILDIO_IOPORT(l, u32) #define readw_relaxed readw #define readl_relaxed readl +#define readb_be __raw_readb +#define readw_be __raw_readw +#define readl_be __raw_readl + +#define writeb_be __raw_writeb +#define writew_be __raw_writew +#define writel_be __raw_writel + #define __BUILD_MEMORY_STRING(bwl, type) \ static inline void writes##bwl(volatile void __iomem *addr, \ const void *data, unsigned int count) \ diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h index 294b25f9323d..4442f8d2d423 100644 --- a/arch/avr32/include/asm/thread_info.h +++ b/arch/avr32/include/asm/thread_info.h @@ -96,6 +96,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_MEMDIE (1 << TIF_MEMDIE) #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP) +#define _TIF_FREEZE (1 << TIF_FREEZE) /* Note: The masks below must never span more than 16 bits! */ diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index 2c08ac992ac3..134d5302b6dd 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/fs.h> +#include <linux/pm.h> #include <linux/ptrace.h> #include <linux/reboot.h> #include <linux/tick.h> @@ -20,7 +21,7 @@ #include <mach/pm.h> -void (*pm_power_off)(void) = NULL; +void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); /* diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index d8e623c426c1..5c7083916c33 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -283,6 +283,25 @@ static int __init early_parse_fbmem(char *p) } early_param("fbmem", early_parse_fbmem); +/* + * Pick out the memory size. We look for mem=size@start, + * where start and size are "size[KkMmGg]" + */ +static int __init early_mem(char *p) +{ + resource_size_t size, start; + + start = system_ram->start; + size = memparse(p, &p); + if (*p == '@') + start = memparse(p + 1, &p); + + system_ram->start = start; + system_ram->end = system_ram->start + size - 1; + return 0; +} +early_param("mem", early_mem); + static int __init parse_tag_core(struct tag *tag) { if (tag->hdr.size > 2) { diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index e01dbe4ebb40..813b6844cdf6 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -82,8 +82,9 @@ static struct platform_device _name##_id##_device = { \ .num_resources = ARRAY_SIZE(_name##_id##_resource), \ } -#define select_peripheral(pin, periph, flags) \ - at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags) +#define select_peripheral(port, pin_mask, periph, flags) \ + at32_select_periph(GPIO_##port##_BASE, pin_mask, \ + GPIO_##periph, flags) #define DEV_CLK(_name, devname, bus, _index) \ static struct clk devname##_##_name = { \ @@ -871,6 +872,7 @@ static struct clk atmel_psif1_pclk = { struct platform_device *__init at32_add_device_psif(unsigned int id) { struct platform_device *pdev; + u32 pin_mask; if (!(id == 0 || id == 1)) return NULL; @@ -881,20 +883,22 @@ struct platform_device *__init at32_add_device_psif(unsigned int id) switch (id) { case 0: + pin_mask = (1 << 8) | (1 << 9); /* CLOCK & DATA */ + 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 */ + select_peripheral(PIOA, pin_mask, PERIPH_A, 0); break; case 1: + pin_mask = (1 << 11) | (1 << 12); /* CLOCK & DATA */ + 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 */ + select_peripheral(PIOB, pin_mask, PERIPH_A, 0); break; default: return NULL; @@ -958,26 +962,30 @@ DEV_CLK(usart, atmel_usart3, pba, 6); static inline void configure_usart0_pins(void) { - select_peripheral(PA(8), PERIPH_B, 0); /* RXD */ - select_peripheral(PA(9), PERIPH_B, 0); /* TXD */ + u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */ + + select_peripheral(PIOA, pin_mask, PERIPH_B, 0); } static inline void configure_usart1_pins(void) { - select_peripheral(PA(17), PERIPH_A, 0); /* RXD */ - select_peripheral(PA(18), PERIPH_A, 0); /* TXD */ + u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */ + + select_peripheral(PIOA, pin_mask, PERIPH_A, 0); } static inline void configure_usart2_pins(void) { - select_peripheral(PB(26), PERIPH_B, 0); /* RXD */ - select_peripheral(PB(27), PERIPH_B, 0); /* TXD */ + u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */ + + select_peripheral(PIOB, pin_mask, PERIPH_B, 0); } static inline void configure_usart3_pins(void) { - select_peripheral(PB(18), PERIPH_B, 0); /* RXD */ - select_peripheral(PB(17), PERIPH_B, 0); /* TXD */ + u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */ + + select_peripheral(PIOB, pin_mask, PERIPH_B, 0); } static struct platform_device *__initdata at32_usarts[4]; @@ -1057,59 +1065,69 @@ struct platform_device *__init at32_add_device_eth(unsigned int id, struct eth_platform_data *data) { struct platform_device *pdev; + u32 pin_mask; switch (id) { case 0: pdev = &macb0_device; - select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */ - select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */ - select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */ - select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */ - select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */ - select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */ - select_peripheral(PC(13), PERIPH_A, 0); /* RXER */ - select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */ - select_peripheral(PC(16), PERIPH_A, 0); /* MDC */ - select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */ + pin_mask = (1 << 3); /* TXD0 */ + pin_mask |= (1 << 4); /* TXD1 */ + pin_mask |= (1 << 7); /* TXEN */ + pin_mask |= (1 << 8); /* TXCK */ + pin_mask |= (1 << 9); /* RXD0 */ + pin_mask |= (1 << 10); /* RXD1 */ + pin_mask |= (1 << 13); /* RXER */ + pin_mask |= (1 << 15); /* RXDV */ + pin_mask |= (1 << 16); /* MDC */ + pin_mask |= (1 << 17); /* MDIO */ if (!data->is_rmii) { - select_peripheral(PC(0), PERIPH_A, 0); /* COL */ - select_peripheral(PC(1), PERIPH_A, 0); /* CRS */ - select_peripheral(PC(2), PERIPH_A, 0); /* TXER */ - select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */ - select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */ - select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */ - select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */ - select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */ - select_peripheral(PC(18), PERIPH_A, 0); /* SPD */ + pin_mask |= (1 << 0); /* COL */ + pin_mask |= (1 << 1); /* CRS */ + pin_mask |= (1 << 2); /* TXER */ + pin_mask |= (1 << 5); /* TXD2 */ + pin_mask |= (1 << 6); /* TXD3 */ + pin_mask |= (1 << 11); /* RXD2 */ + pin_mask |= (1 << 12); /* RXD3 */ + pin_mask |= (1 << 14); /* RXCK */ + pin_mask |= (1 << 18); /* SPD */ } + + select_peripheral(PIOC, pin_mask, PERIPH_A, 0); + break; case 1: pdev = &macb1_device; - select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */ - select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */ - select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */ - select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */ - select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */ - select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */ - select_peripheral(PD(5), PERIPH_B, 0); /* RXER */ - select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */ - select_peripheral(PD(3), PERIPH_B, 0); /* MDC */ - select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */ + pin_mask = (1 << 13); /* TXD0 */ + pin_mask |= (1 << 14); /* TXD1 */ + pin_mask |= (1 << 11); /* TXEN */ + pin_mask |= (1 << 12); /* TXCK */ + pin_mask |= (1 << 10); /* RXD0 */ + pin_mask |= (1 << 6); /* RXD1 */ + pin_mask |= (1 << 5); /* RXER */ + pin_mask |= (1 << 4); /* RXDV */ + pin_mask |= (1 << 3); /* MDC */ + pin_mask |= (1 << 2); /* MDIO */ + + if (!data->is_rmii) + pin_mask |= (1 << 15); /* SPD */ + + select_peripheral(PIOD, pin_mask, PERIPH_B, 0); if (!data->is_rmii) { - select_peripheral(PC(19), PERIPH_B, 0); /* COL */ - select_peripheral(PC(23), PERIPH_B, 0); /* CRS */ - select_peripheral(PC(26), PERIPH_B, 0); /* TXER */ - select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */ - select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */ - select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */ - select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */ - select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */ - select_peripheral(PD(15), PERIPH_B, 0); /* SPD */ + pin_mask = (1 << 19); /* COL */ + pin_mask |= (1 << 23); /* CRS */ + pin_mask |= (1 << 26); /* TXER */ + pin_mask |= (1 << 27); /* TXD2 */ + pin_mask |= (1 << 28); /* TXD3 */ + pin_mask |= (1 << 29); /* RXD2 */ + pin_mask |= (1 << 30); /* RXD3 */ + pin_mask |= (1 << 24); /* RXCK */ + + select_peripheral(PIOC, pin_mask, PERIPH_B, 0); } break; @@ -1177,23 +1195,28 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n) { GPIO_PIN_PB(2), GPIO_PIN_PB(3), GPIO_PIN_PB(4), GPIO_PIN_PA(27), }; struct platform_device *pdev; + u32 pin_mask; switch (id) { case 0: pdev = &atmel_spi0_device; + pin_mask = (1 << 1) | (1 << 2); /* MOSI & SCK */ + /* 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 */ + select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP); + select_peripheral(PIOA, pin_mask, PERIPH_A, 0); + at32_spi_setup_slaves(0, b, n, spi0_pins); break; case 1: pdev = &atmel_spi1_device; + pin_mask = (1 << 1) | (1 << 5); /* MOSI */ + /* 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 */ + select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP); + select_peripheral(PIOB, pin_mask, PERIPH_B, 0); + at32_spi_setup_slaves(1, b, n, spi1_pins); break; @@ -1226,6 +1249,7 @@ struct platform_device *__init at32_add_device_twi(unsigned int id, unsigned int n) { struct platform_device *pdev; + u32 pin_mask; if (id != 0) return NULL; @@ -1238,8 +1262,9 @@ struct platform_device *__init at32_add_device_twi(unsigned int id, ARRAY_SIZE(atmel_twi0_resource))) goto err_add_resources; - select_peripheral(PA(6), PERIPH_A, 0); /* SDA */ - select_peripheral(PA(7), PERIPH_A, 0); /* SDL */ + pin_mask = (1 << 6) | (1 << 7); /* SDA & SDL */ + + select_peripheral(PIOA, pin_mask, PERIPH_A, 0); atmel_twi0_pclk.dev = &pdev->dev; @@ -1272,10 +1297,16 @@ static struct clk atmel_mci0_pclk = { struct platform_device *__init at32_add_device_mci(unsigned int id, struct mci_platform_data *data) { - struct mci_platform_data _data; struct platform_device *pdev; + struct dw_dma_slave *dws; + u32 pioa_mask; + u32 piob_mask; - if (id != 0) + if (id != 0 || !data) + return NULL; + + /* Must have at least one usable slot */ + if (!data->slot[0].bus_width && !data->slot[1].bus_width) return NULL; pdev = platform_device_alloc("atmel_mci", id); @@ -1286,28 +1317,80 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data) ARRAY_SIZE(atmel_mci0_resource))) goto fail; - if (!data) { - data = &_data; - memset(data, -1, sizeof(struct mci_platform_data)); - data->detect_pin = GPIO_PIN_NONE; - data->wp_pin = GPIO_PIN_NONE; - } + if (data->dma_slave) + dws = kmemdup(to_dw_dma_slave(data->dma_slave), + sizeof(struct dw_dma_slave), GFP_KERNEL); + else + dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL); + + dws->slave.dev = &pdev->dev; + dws->slave.dma_dev = &dw_dmac0_device.dev; + dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT; + dws->cfg_hi = (DWC_CFGH_SRC_PER(0) + | DWC_CFGH_DST_PER(1)); + dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL + | DWC_CFGL_HS_SRC_POL); + + data->dma_slave = &dws->slave; if (platform_device_add_data(pdev, data, sizeof(struct mci_platform_data))) goto fail; - select_peripheral(PA(10), PERIPH_A, 0); /* CLK */ - select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ - select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */ - select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */ - select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ - select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ + /* CLK line is common to both slots */ + pioa_mask = 1 << 10; - if (gpio_is_valid(data->detect_pin)) - at32_select_gpio(data->detect_pin, 0); - if (gpio_is_valid(data->wp_pin)) - at32_select_gpio(data->wp_pin, 0); + switch (data->slot[0].bus_width) { + case 4: + pioa_mask |= 1 << 13; /* DATA1 */ + pioa_mask |= 1 << 14; /* DATA2 */ + pioa_mask |= 1 << 15; /* DATA3 */ + /* fall through */ + case 1: + pioa_mask |= 1 << 11; /* CMD */ + pioa_mask |= 1 << 12; /* DATA0 */ + + if (gpio_is_valid(data->slot[0].detect_pin)) + at32_select_gpio(data->slot[0].detect_pin, 0); + if (gpio_is_valid(data->slot[0].wp_pin)) + at32_select_gpio(data->slot[0].wp_pin, 0); + break; + case 0: + /* Slot is unused */ + break; + default: + goto fail; + } + + select_peripheral(PIOA, pioa_mask, PERIPH_A, 0); + piob_mask = 0; + + switch (data->slot[1].bus_width) { + case 4: + piob_mask |= 1 << 8; /* DATA1 */ + piob_mask |= 1 << 9; /* DATA2 */ + piob_mask |= 1 << 10; /* DATA3 */ + /* fall through */ + case 1: + piob_mask |= 1 << 6; /* CMD */ + piob_mask |= 1 << 7; /* DATA0 */ + select_peripheral(PIOB, piob_mask, PERIPH_B, 0); + + if (gpio_is_valid(data->slot[1].detect_pin)) + at32_select_gpio(data->slot[1].detect_pin, 0); + if (gpio_is_valid(data->slot[1].wp_pin)) + at32_select_gpio(data->slot[1].wp_pin, 0); + break; + case 0: + /* Slot is unused */ + break; + default: + if (!data->slot[0].bus_width) + goto fail; + + data->slot[1].bus_width = 0; + break; + } atmel_mci0_pclk.dev = &pdev->dev; @@ -1353,13 +1436,14 @@ static struct clk atmel_lcdfb0_pixclk = { 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 int pin_config) + u64 pin_mask) { struct platform_device *pdev; struct atmel_lcdfb_info *info; struct fb_monspecs *monspecs; struct fb_videomode *modedb; unsigned int modedb_size; + u32 portc_mask, portd_mask, porte_mask; /* * Do a deep copy of the fb data, monspecs and modedb. Make @@ -1381,76 +1465,21 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, case 0: pdev = &atmel_lcdfb0_device; - 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; - } + if (pin_mask == 0ULL) + /* Default to "full" lcdc control signals and 24bit */ + pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL; + + /* LCDC on port C */ + portc_mask = (pin_mask & 0xfff80000) >> 19; + select_peripheral(PIOC, portc_mask, PERIPH_A, 0); + + /* LCDC on port D */ + portd_mask = pin_mask & 0x0003ffff; + select_peripheral(PIOD, portd_mask, PERIPH_A, 0); + + /* LCDC on port E */ + porte_mask = (pin_mask >> 32) & 0x0007ffff; + select_peripheral(PIOE, porte_mask, PERIPH_B, 0); clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); @@ -1499,6 +1528,7 @@ static struct clk atmel_pwm0_mck = { struct platform_device *__init at32_add_device_pwm(u32 mask) { struct platform_device *pdev; + u32 pin_mask; if (!mask) return NULL; @@ -1514,14 +1544,21 @@ struct platform_device *__init at32_add_device_pwm(u32 mask) if (platform_device_add_data(pdev, &mask, sizeof(mask))) goto out_free_pdev; + pin_mask = 0; if (mask & (1 << 0)) - select_peripheral(PA(28), PERIPH_A, 0); + pin_mask |= (1 << 28); if (mask & (1 << 1)) - select_peripheral(PA(29), PERIPH_A, 0); + pin_mask |= (1 << 29); + if (pin_mask > 0) + select_peripheral(PIOA, pin_mask, PERIPH_A, 0); + + pin_mask = 0; if (mask & (1 << 2)) - select_peripheral(PA(21), PERIPH_B, 0); + pin_mask |= (1 << 21); if (mask & (1 << 3)) - select_peripheral(PA(22), PERIPH_B, 0); + pin_mask |= (1 << 22); + if (pin_mask > 0) + select_peripheral(PIOA, pin_mask, PERIPH_B, 0); atmel_pwm0_mck.dev = &pdev->dev; @@ -1562,52 +1599,65 @@ struct platform_device *__init at32_add_device_ssc(unsigned int id, unsigned int flags) { struct platform_device *pdev; + u32 pin_mask = 0; switch (id) { case 0: pdev = &ssc0_device; if (flags & ATMEL_SSC_RF) - select_peripheral(PA(21), PERIPH_A, 0); /* RF */ + pin_mask |= (1 << 21); /* RF */ if (flags & ATMEL_SSC_RK) - select_peripheral(PA(22), PERIPH_A, 0); /* RK */ + pin_mask |= (1 << 22); /* RK */ if (flags & ATMEL_SSC_TK) - select_peripheral(PA(23), PERIPH_A, 0); /* TK */ + pin_mask |= (1 << 23); /* TK */ if (flags & ATMEL_SSC_TF) - select_peripheral(PA(24), PERIPH_A, 0); /* TF */ + pin_mask |= (1 << 24); /* TF */ if (flags & ATMEL_SSC_TD) - select_peripheral(PA(25), PERIPH_A, 0); /* TD */ + pin_mask |= (1 << 25); /* TD */ if (flags & ATMEL_SSC_RD) - select_peripheral(PA(26), PERIPH_A, 0); /* RD */ + pin_mask |= (1 << 26); /* RD */ + + if (pin_mask > 0) + select_peripheral(PIOA, pin_mask, PERIPH_A, 0); + break; case 1: pdev = &ssc1_device; if (flags & ATMEL_SSC_RF) - select_peripheral(PA(0), PERIPH_B, 0); /* RF */ + pin_mask |= (1 << 0); /* RF */ if (flags & ATMEL_SSC_RK) - select_peripheral(PA(1), PERIPH_B, 0); /* RK */ + pin_mask |= (1 << 1); /* RK */ if (flags & ATMEL_SSC_TK) - select_peripheral(PA(2), PERIPH_B, 0); /* TK */ + pin_mask |= (1 << 2); /* TK */ if (flags & ATMEL_SSC_TF) - select_peripheral(PA(3), PERIPH_B, 0); /* TF */ + pin_mask |= (1 << 3); /* TF */ if (flags & ATMEL_SSC_TD) - select_peripheral(PA(4), PERIPH_B, 0); /* TD */ + pin_mask |= (1 << 4); /* TD */ if (flags & ATMEL_SSC_RD) - select_peripheral(PA(5), PERIPH_B, 0); /* RD */ + pin_mask |= (1 << 5); /* RD */ + + if (pin_mask > 0) + select_peripheral(PIOA, pin_mask, PERIPH_B, 0); + break; case 2: pdev = &ssc2_device; if (flags & ATMEL_SSC_TD) - select_peripheral(PB(13), PERIPH_A, 0); /* TD */ + pin_mask |= (1 << 13); /* TD */ if (flags & ATMEL_SSC_RD) - select_peripheral(PB(14), PERIPH_A, 0); /* RD */ + pin_mask |= (1 << 14); /* RD */ if (flags & ATMEL_SSC_TK) - select_peripheral(PB(15), PERIPH_A, 0); /* TK */ + pin_mask |= (1 << 15); /* TK */ if (flags & ATMEL_SSC_TF) - select_peripheral(PB(16), PERIPH_A, 0); /* TF */ + pin_mask |= (1 << 16); /* TF */ if (flags & ATMEL_SSC_RF) - select_peripheral(PB(17), PERIPH_A, 0); /* RF */ + pin_mask |= (1 << 17); /* RF */ if (flags & ATMEL_SSC_RK) - select_peripheral(PB(18), PERIPH_A, 0); /* RK */ + pin_mask |= (1 << 18); /* RK */ + + if (pin_mask > 0) + select_peripheral(PIOB, pin_mask, PERIPH_A, 0); + break; default: return NULL; @@ -1745,14 +1795,15 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev, unsigned int cs, unsigned int extint) { static unsigned int extint_pin_map[4] __initdata = { - GPIO_PIN_PB(25), - GPIO_PIN_PB(26), - GPIO_PIN_PB(27), - GPIO_PIN_PB(28), + (1 << 25), + (1 << 26), + (1 << 27), + (1 << 28), }; static bool common_pins_initialized __initdata = false; unsigned int extint_pin; int ret; + u32 pin_mask; if (extint >= ARRAY_SIZE(extint_pin_map)) return -EINVAL; @@ -1766,7 +1817,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev, if (ret) return ret; - select_peripheral(PE(21), PERIPH_A, 0); /* NCS4 -> OE_N */ + /* NCS4 -> OE_N */ + select_peripheral(PIOE, (1 << 21), PERIPH_A, 0); hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE); break; case 5: @@ -1776,7 +1828,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev, if (ret) return ret; - select_peripheral(PE(22), PERIPH_A, 0); /* NCS5 -> OE_N */ + /* NCS5 -> OE_N */ + select_peripheral(PIOE, (1 << 22), PERIPH_A, 0); hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE); break; default: @@ -1784,14 +1837,17 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev, } if (!common_pins_initialized) { - select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1 -> CS0_N */ - select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2 -> CS1_N */ - select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW -> DIR */ - select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT <- IORDY */ + pin_mask = (1 << 19); /* CFCE1 -> CS0_N */ + pin_mask |= (1 << 20); /* CFCE2 -> CS1_N */ + pin_mask |= (1 << 23); /* CFRNW -> DIR */ + pin_mask |= (1 << 24); /* NWAIT <- IORDY */ + + select_peripheral(PIOE, pin_mask, PERIPH_A, 0); + common_pins_initialized = true; } - at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH); + select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH); pdev->resource[1].start = EIM_IRQ_BASE + extint; pdev->resource[1].end = pdev->resource[1].start; @@ -1930,6 +1986,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data) { struct platform_device *pdev; struct ac97c_platform_data _data; + u32 pin_mask; if (id != 0) return NULL; @@ -1956,10 +2013,10 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *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 */ + pin_mask = (1 << 20) | (1 << 21); /* SDO & SYNC */ + pin_mask |= (1 << 22) | (1 << 23); /* SCLK & SDI */ + + select_peripheral(PIOB, pin_mask, PERIPH_B, 0); /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */ if (data->reset_pin != GPIO_PIN_NONE) @@ -2001,6 +2058,7 @@ static struct clk abdac0_sample_clk = { struct platform_device *__init at32_add_device_abdac(unsigned int id) { struct platform_device *pdev; + u32 pin_mask; if (id != 0) return NULL; @@ -2013,10 +2071,10 @@ struct platform_device *__init at32_add_device_abdac(unsigned int id) ARRAY_SIZE(abdac0_resource))) goto err_add_resources; - select_peripheral(PB(20), PERIPH_A, 0); /* DATA1 */ - select_peripheral(PB(21), PERIPH_A, 0); /* DATA0 */ - select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1 */ - select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0 */ + pin_mask = (1 << 20) | (1 << 22); /* DATA1 & DATAN1 */ + pin_mask |= (1 << 21) | (1 << 23); /* DATA0 & DATAN0 */ + + select_peripheral(PIOB, pin_mask, PERIPH_A, 0); abdac0_pclk.dev = &pdev->dev; abdac0_sample_clk.dev = &pdev->dev; @@ -2073,7 +2131,7 @@ static struct clk gclk4 = { .index = 4, }; -struct clk *at32_clock_list[] = { +static __initdata struct clk *init_clocks[] = { &osc32k, &osc0, &osc1, @@ -2137,7 +2195,6 @@ struct clk *at32_clock_list[] = { &gclk3, &gclk4, }; -unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); void __init setup_platform(void) { @@ -2168,14 +2225,19 @@ void __init setup_platform(void) genclk_init_parent(&abdac0_sample_clk); /* - * Turn on all clocks that have at least one user already, and - * turn off everything else. We only do this for module - * clocks, and even though it isn't particularly pretty to - * check the address of the mode function, it should do the - * trick... + * Build initial dynamic clock list by registering all clocks + * from the array. + * At the same time, turn on all clocks that have at least one + * user already, and turn off everything else. We only do this + * for module clocks, and even though it isn't particularly + * pretty to check the address of the mode function, it should + * do the trick... */ - for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { - struct clk *clk = at32_clock_list[i]; + for (i = 0; i < ARRAY_SIZE(init_clocks); i++) { + struct clk *clk = init_clocks[i]; + + /* first, register clock */ + at32_clk_register(clk); if (clk->users == 0) continue; diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 6c27ddac5adf..138a00a2a2d0 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -15,24 +15,40 @@ #include <linux/err.h> #include <linux/device.h> #include <linux/string.h> +#include <linux/list.h> #include <mach/chip.h> #include "clock.h" +/* at32 clock list */ +static LIST_HEAD(at32_clock_list); + static DEFINE_SPINLOCK(clk_lock); +static DEFINE_SPINLOCK(clk_list_lock); + +void at32_clk_register(struct clk *clk) +{ + spin_lock(&clk_list_lock); + /* add the new item to the end of the list */ + list_add_tail(&clk->list, &at32_clock_list); + spin_unlock(&clk_list_lock); +} struct clk *clk_get(struct device *dev, const char *id) { - int i; + struct clk *clk; - for (i = 0; i < at32_nr_clocks; i++) { - struct clk *clk = at32_clock_list[i]; + spin_lock(&clk_list_lock); - if (clk->dev == dev && strcmp(id, clk->name) == 0) + list_for_each_entry(clk, &at32_clock_list, list) { + if (clk->dev == dev && strcmp(id, clk->name) == 0) { + spin_unlock(&clk_list_lock); return clk; + } } + spin_unlock(&clk_list_lock); return ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get); @@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r) /* cost of this scan is small, but not linear... */ r->nest = nest + NEST_DELTA; - for (i = 3; i < at32_nr_clocks; i++) { - clk = at32_clock_list[i]; + + list_for_each_entry(clk, &at32_clock_list, list) { if (clk->parent == parent) dump_clock(clk, r); } @@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused) { struct clkinf r; int i; + struct clk *clk; /* show all the power manager registers */ seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); @@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused) seq_printf(s, "\n"); - /* show clock tree as derived from the three oscillators - * we "know" are at the head of the list - */ r.s = s; r.nest = 0; - dump_clock(at32_clock_list[0], &r); - dump_clock(at32_clock_list[1], &r); - dump_clock(at32_clock_list[2], &r); + /* protected from changes on the list while dumping */ + spin_lock(&clk_list_lock); + + /* show clock tree as derived from the three oscillators */ + clk = clk_get(NULL, "osc32k"); + dump_clock(clk, &r); + clk_put(clk); + + clk = clk_get(NULL, "osc0"); + dump_clock(clk, &r); + clk_put(clk); + + clk = clk_get(NULL, "osc1"); + dump_clock(clk, &r); + clk_put(clk); + + spin_unlock(&clk_list_lock); return 0; } diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h index bb8e1f295835..623bf0e9a1e7 100644 --- a/arch/avr32/mach-at32ap/clock.h +++ b/arch/avr32/mach-at32ap/clock.h @@ -12,8 +12,13 @@ * published by the Free Software Foundation. */ #include <linux/clk.h> +#include <linux/list.h> + + +void at32_clk_register(struct clk *clk); struct clk { + struct list_head list; /* linking element */ const char *name; /* Clock name/function */ struct device *dev; /* Device the clock is used by */ struct clk *parent; /* Parent clock, if any */ @@ -25,6 +30,3 @@ struct clk { u16 users; /* Enabled if non-zero */ u16 index; /* Sibling index */ }; - -extern struct clk *at32_clock_list[]; -extern unsigned int at32_nr_clocks; diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c index 5dd8d25428bf..d84efe4984ab 100644 --- a/arch/avr32/mach-at32ap/cpufreq.c +++ b/arch/avr32/mach-at32ap/cpufreq.c @@ -87,7 +87,6 @@ static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy) policy->cur = at32_get_speed(0); policy->min = policy->cpuinfo.min_freq; policy->max = policy->cpuinfo.max_freq; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; printk("cpufreq: AT32AP CPU frequency driver\n"); diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index c36a6d59d6f0..310477ba1bbf 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -191,7 +191,7 @@ static int __init eic_probe(struct platform_device *pdev) struct eic *eic; struct resource *regs; unsigned int i; - unsigned int nr_irqs; + unsigned int nr_of_irqs; unsigned int int_irq; int ret; u32 pattern; @@ -224,7 +224,7 @@ static int __init eic_probe(struct platform_device *pdev) eic_writel(eic, IDR, ~0UL); eic_writel(eic, MODE, ~0UL); pattern = eic_readl(eic, MODE); - nr_irqs = fls(pattern); + nr_of_irqs = fls(pattern); /* Trigger on low level unless overridden by driver */ eic_writel(eic, EDGE, 0UL); @@ -232,7 +232,7 @@ static int __init eic_probe(struct platform_device *pdev) eic->chip = &eic_chip; - for (i = 0; i < nr_irqs; i++) { + for (i = 0; i < nr_of_irqs; i++) { set_irq_chip_and_handler(eic->first_irq + i, &eic_chip, handle_level_irq); set_irq_chip_data(eic->first_irq + i, eic); @@ -256,7 +256,7 @@ static int __init eic_probe(struct platform_device *pdev) eic->regs, int_irq); dev_info(&pdev->dev, "Handling %u external IRQs, starting with IRQ %u\n", - nr_irqs, eic->first_irq); + nr_of_irqs, eic->first_irq); return 0; diff --git a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h index 1e9852d65cca..a77d372f6f3e 100644 --- a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h +++ b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h @@ -83,4 +83,132 @@ #define HMATRIX_BASE 0xfff00800 #define SDRAMC_BASE 0xfff03800 +/* LCDC on port C */ +#define ATMEL_LCDC_PC_CC (1ULL << 19) +#define ATMEL_LCDC_PC_HSYNC (1ULL << 20) +#define ATMEL_LCDC_PC_PCLK (1ULL << 21) +#define ATMEL_LCDC_PC_VSYNC (1ULL << 22) +#define ATMEL_LCDC_PC_DVAL (1ULL << 23) +#define ATMEL_LCDC_PC_MODE (1ULL << 24) +#define ATMEL_LCDC_PC_PWR (1ULL << 25) +#define ATMEL_LCDC_PC_DATA0 (1ULL << 26) +#define ATMEL_LCDC_PC_DATA1 (1ULL << 27) +#define ATMEL_LCDC_PC_DATA2 (1ULL << 28) +#define ATMEL_LCDC_PC_DATA3 (1ULL << 29) +#define ATMEL_LCDC_PC_DATA4 (1ULL << 30) +#define ATMEL_LCDC_PC_DATA5 (1ULL << 31) + +/* LCDC on port D */ +#define ATMEL_LCDC_PD_DATA6 (1ULL << 0) +#define ATMEL_LCDC_PD_DATA7 (1ULL << 1) +#define ATMEL_LCDC_PD_DATA8 (1ULL << 2) +#define ATMEL_LCDC_PD_DATA9 (1ULL << 3) +#define ATMEL_LCDC_PD_DATA10 (1ULL << 4) +#define ATMEL_LCDC_PD_DATA11 (1ULL << 5) +#define ATMEL_LCDC_PD_DATA12 (1ULL << 6) +#define ATMEL_LCDC_PD_DATA13 (1ULL << 7) +#define ATMEL_LCDC_PD_DATA14 (1ULL << 8) +#define ATMEL_LCDC_PD_DATA15 (1ULL << 9) +#define ATMEL_LCDC_PD_DATA16 (1ULL << 10) +#define ATMEL_LCDC_PD_DATA17 (1ULL << 11) +#define ATMEL_LCDC_PD_DATA18 (1ULL << 12) +#define ATMEL_LCDC_PD_DATA19 (1ULL << 13) +#define ATMEL_LCDC_PD_DATA20 (1ULL << 14) +#define ATMEL_LCDC_PD_DATA21 (1ULL << 15) +#define ATMEL_LCDC_PD_DATA22 (1ULL << 16) +#define ATMEL_LCDC_PD_DATA23 (1ULL << 17) + +/* LCDC on port E */ +#define ATMEL_LCDC_PE_CC (1ULL << (32 + 0)) +#define ATMEL_LCDC_PE_DVAL (1ULL << (32 + 1)) +#define ATMEL_LCDC_PE_MODE (1ULL << (32 + 2)) +#define ATMEL_LCDC_PE_DATA0 (1ULL << (32 + 3)) +#define ATMEL_LCDC_PE_DATA1 (1ULL << (32 + 4)) +#define ATMEL_LCDC_PE_DATA2 (1ULL << (32 + 5)) +#define ATMEL_LCDC_PE_DATA3 (1ULL << (32 + 6)) +#define ATMEL_LCDC_PE_DATA4 (1ULL << (32 + 7)) +#define ATMEL_LCDC_PE_DATA8 (1ULL << (32 + 8)) +#define ATMEL_LCDC_PE_DATA9 (1ULL << (32 + 9)) +#define ATMEL_LCDC_PE_DATA10 (1ULL << (32 + 10)) +#define ATMEL_LCDC_PE_DATA11 (1ULL << (32 + 11)) +#define ATMEL_LCDC_PE_DATA12 (1ULL << (32 + 12)) +#define ATMEL_LCDC_PE_DATA16 (1ULL << (32 + 13)) +#define ATMEL_LCDC_PE_DATA17 (1ULL << (32 + 14)) +#define ATMEL_LCDC_PE_DATA18 (1ULL << (32 + 15)) +#define ATMEL_LCDC_PE_DATA19 (1ULL << (32 + 16)) +#define ATMEL_LCDC_PE_DATA20 (1ULL << (32 + 17)) +#define ATMEL_LCDC_PE_DATA21 (1ULL << (32 + 18)) + + +#define ATMEL_LCDC(PORT, PIN) (ATMEL_LCDC_##PORT##_##PIN) + + +#define ATMEL_LCDC_PRI_24B_DATA ( \ + ATMEL_LCDC(PC, DATA0) | ATMEL_LCDC(PC, DATA1) | \ + ATMEL_LCDC(PC, DATA2) | ATMEL_LCDC(PC, DATA3) | \ + ATMEL_LCDC(PC, DATA4) | ATMEL_LCDC(PC, DATA5) | \ + ATMEL_LCDC(PD, DATA6) | ATMEL_LCDC(PD, DATA7) | \ + ATMEL_LCDC(PD, DATA8) | ATMEL_LCDC(PD, DATA9) | \ + ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) | \ + ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) | \ + ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) | \ + ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) | \ + ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) | \ + ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) | \ + ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23)) + +#define ATMEL_LCDC_ALT_24B_DATA ( \ + ATMEL_LCDC(PE, DATA0) | ATMEL_LCDC(PE, DATA1) | \ + ATMEL_LCDC(PE, DATA2) | ATMEL_LCDC(PE, DATA3) | \ + ATMEL_LCDC(PE, DATA4) | ATMEL_LCDC(PC, DATA5) | \ + ATMEL_LCDC(PD, DATA6) | ATMEL_LCDC(PD, DATA7) | \ + ATMEL_LCDC(PE, DATA8) | ATMEL_LCDC(PE, DATA9) | \ + ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) | \ + ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) | \ + ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) | \ + ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) | \ + ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) | \ + ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) | \ + ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23)) + +#define ATMEL_LCDC_PRI_15B_DATA ( \ + ATMEL_LCDC(PC, DATA0) | ATMEL_LCDC(PC, DATA1) | \ + ATMEL_LCDC(PC, DATA2) | ATMEL_LCDC(PC, DATA3) | \ + ATMEL_LCDC(PC, DATA4) | ATMEL_LCDC(PC, DATA5) | \ + ATMEL_LCDC(PD, DATA8) | ATMEL_LCDC(PD, DATA9) | \ + ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) | \ + ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) | \ + ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) | \ + ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20)) + +#define ATMEL_LCDC_ALT_15B_DATA ( \ + ATMEL_LCDC(PE, DATA0) | ATMEL_LCDC(PE, DATA1) | \ + ATMEL_LCDC(PE, DATA2) | ATMEL_LCDC(PE, DATA3) | \ + ATMEL_LCDC(PE, DATA4) | ATMEL_LCDC(PC, DATA5) | \ + ATMEL_LCDC(PE, DATA8) | ATMEL_LCDC(PE, DATA9) | \ + ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) | \ + ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) | \ + ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) | \ + ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20)) + +#define ATMEL_LCDC_PRI_CONTROL ( \ + ATMEL_LCDC(PC, CC) | ATMEL_LCDC(PC, DVAL) | \ + ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR)) + +#define ATMEL_LCDC_ALT_CONTROL ( \ + ATMEL_LCDC(PE, CC) | ATMEL_LCDC(PE, DVAL) | \ + ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR)) + +#define ATMEL_LCDC_CONTROL ( \ + ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) | \ + ATMEL_LCDC(PC, PCLK)) + +#define ATMEL_LCDC_PRI_24BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA) + +#define ATMEL_LCDC_ALT_24BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA) + +#define ATMEL_LCDC_PRI_15BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA) + +#define ATMEL_LCDC_ALT_15BIT (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA) + #endif /* __ASM_ARCH_AT32AP700X_H__ */ diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h index e60e9076544d..c48386d66bc3 100644 --- a/arch/avr32/mach-at32ap/include/mach/board.h +++ b/arch/avr32/mach-at32ap/include/mach/board.h @@ -43,7 +43,7 @@ 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 int pin_config); + u64 pin_mask); struct usba_platform_data; struct platform_device * diff --git a/arch/avr32/mach-at32ap/include/mach/io.h b/arch/avr32/mach-at32ap/include/mach/io.h index 4ec6abc68ea3..22ea79b74052 100644 --- a/arch/avr32/mach-at32ap/include/mach/io.h +++ b/arch/avr32/mach-at32ap/include/mach/io.h @@ -1,8 +1,7 @@ #ifndef __ASM_AVR32_ARCH_AT32AP_IO_H #define __ASM_AVR32_ARCH_AT32AP_IO_H -/* For "bizarre" halfword swapping */ -#include <linux/byteorder/swabb.h> +#include <linux/swab.h> #if defined(CONFIG_AP700X_32_BIT_SMC) # define __swizzle_addr_b(addr) (addr ^ 3UL) diff --git a/arch/avr32/mach-at32ap/include/mach/portmux.h b/arch/avr32/mach-at32ap/include/mach/portmux.h index b1abe6b4e4ef..21c79373b53f 100644 --- a/arch/avr32/mach-at32ap/include/mach/portmux.h +++ b/arch/avr32/mach-at32ap/include/mach/portmux.h @@ -21,9 +21,10 @@ #define AT32_GPIOF_DEGLITCH 0x00000008 /* (IN) Filter glitches */ #define AT32_GPIOF_MULTIDRV 0x00000010 /* Enable multidriver option */ -void at32_select_periph(unsigned int pin, unsigned int periph, - unsigned long flags); +void at32_select_periph(unsigned int port, unsigned int pin, + unsigned int periph, unsigned long flags); void at32_select_gpio(unsigned int pin, unsigned long flags); +void at32_deselect_pin(unsigned int pin); void at32_reserve_pin(unsigned int pin); #endif /* __ASM_ARCH_PORTMUX_H__ */ diff --git a/arch/avr32/mach-at32ap/pdc.c b/arch/avr32/mach-at32ap/pdc.c index 1040bda4fda7..61ab15aae970 100644 --- a/arch/avr32/mach-at32ap/pdc.c +++ b/arch/avr32/mach-at32ap/pdc.c @@ -35,7 +35,6 @@ static int __init pdc_probe(struct platform_device *pdev) } static struct platform_driver pdc_driver = { - .probe = pdc_probe, .driver = { .name = "pdc", }, @@ -43,6 +42,6 @@ static struct platform_driver pdc_driver = { static int __init pdc_init(void) { - return platform_driver_register(&pdc_driver); + return platform_driver_probe(&pdc_driver, pdc_probe); } arch_initcall(pdc_init); diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 405ee6bad4ce..ed81a8bcb22d 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -50,35 +50,48 @@ static struct pio_device *gpio_to_pio(unsigned int gpio) } /* Pin multiplexing API */ +static DEFINE_SPINLOCK(pio_lock); -void __init at32_select_periph(unsigned int pin, unsigned int periph, - unsigned long flags) +void __init at32_select_periph(unsigned int port, u32 pin_mask, + unsigned int periph, unsigned long flags) { struct pio_device *pio; - unsigned int pin_index = pin & 0x1f; - u32 mask = 1 << pin_index; - pio = gpio_to_pio(pin); + /* assign and verify pio */ + pio = gpio_to_pio(port); if (unlikely(!pio)) { - printk("pio: invalid pin %u\n", pin); + printk(KERN_WARNING "pio: invalid port %u\n", port); goto fail; } - if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask) - || gpiochip_is_requested(&pio->chip, pin_index))) { - printk("%s: pin %u is busy\n", pio->name, pin_index); + /* Test if any of the requested pins is already muxed */ + spin_lock(&pio_lock); + if (unlikely(pio->pinmux_mask & pin_mask)) { + printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n", + pio->name, pin_mask, pio->pinmux_mask & pin_mask); + spin_unlock(&pio_lock); goto fail; } - pio_writel(pio, PUER, mask); + pio->pinmux_mask |= pin_mask; + + /* enable pull ups */ + pio_writel(pio, PUER, pin_mask); + + /* select either peripheral A or B */ if (periph) - pio_writel(pio, BSR, mask); + pio_writel(pio, BSR, pin_mask); else - pio_writel(pio, ASR, mask); + pio_writel(pio, ASR, pin_mask); + + /* enable peripheral control */ + pio_writel(pio, PDR, pin_mask); - pio_writel(pio, PDR, mask); + /* Disable pull ups if not requested. */ if (!(flags & AT32_GPIOF_PULLUP)) - pio_writel(pio, PUDR, mask); + pio_writel(pio, PUDR, pin_mask); + + spin_unlock(&pio_lock); return; @@ -134,6 +147,25 @@ fail: dump_stack(); } +/* + * Undo a previous pin reservation. Will not affect the hardware + * configuration. + */ +void at32_deselect_pin(unsigned int pin) +{ + struct pio_device *pio; + unsigned int pin_index = pin & 0x1f; + + pio = gpio_to_pio(pin); + if (unlikely(!pio)) { + printk("pio: invalid pin %u\n", pin); + dump_stack(); + return; + } + + clear_bit(pin_index, &pio->pinmux_mask); +} + /* Reserve a pin, preventing anyone else from changing its configuration. */ void __init at32_reserve_pin(unsigned int pin) { @@ -382,7 +414,6 @@ static int __init pio_probe(struct platform_device *pdev) } static struct platform_driver pio_driver = { - .probe = pio_probe, .driver = { .name = "pio", }, @@ -390,7 +421,7 @@ static struct platform_driver pio_driver = { static int __init pio_init(void) { - return platform_driver_register(&pio_driver); + return platform_driver_probe(&pio_driver, pio_probe); } postcore_initcall(pio_init); diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile index 1fe81c3c1e86..e0eb520e0287 100644 --- a/arch/avr32/oprofile/Makefile +++ b/arch/avr32/oprofile/Makefile @@ -5,4 +5,4 @@ oprofile-y := $(addprefix ../../../drivers/oprofile/, \ event_buffer.o oprofile_files.o \ oprofilefs.o oprofile_stats.o \ timer_int.o) -oprofile-y += op_model_avr32.o +oprofile-y += op_model_avr32.o backtrace.o diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c new file mode 100644 index 000000000000..75d9ad6f99cf --- /dev/null +++ b/arch/avr32/oprofile/backtrace.c @@ -0,0 +1,81 @@ +/* + * AVR32 specific backtracing code for oprofile + * + * Copyright 2008 Weinmann GmbH + * + * Author: Nikolaus Voss <n.voss@weinmann.de> + * + * Based on i386 oprofile backtrace code by John Levon and David Smith + * + * 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/oprofile.h> +#include <linux/sched.h> +#include <linux/uaccess.h> + +/* The first two words of each frame on the stack look like this if we have + * frame pointers */ +struct frame_head { + unsigned long lr; + struct frame_head *fp; +}; + +/* copied from arch/avr32/kernel/process.c */ +static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p) +{ + return (p > (unsigned long)tinfo) + && (p < (unsigned long)tinfo + THREAD_SIZE - 3); +} + +/* copied from arch/x86/oprofile/backtrace.c */ +static struct frame_head *dump_user_backtrace(struct frame_head *head) +{ + struct frame_head bufhead[2]; + + /* Also check accessibility of one struct frame_head beyond */ + if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) + return NULL; + if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) + return NULL; + + oprofile_add_trace(bufhead[0].lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (bufhead[0].fp <= head) + return NULL; + + return bufhead[0].fp; +} + +void avr32_backtrace(struct pt_regs * const regs, unsigned int depth) +{ + /* Get first frame pointer */ + struct frame_head *head = (struct frame_head *)(regs->r7); + + if (!user_mode(regs)) { +#ifdef CONFIG_FRAME_POINTER + /* + * Traverse the kernel stack from frame to frame up to + * "depth" steps. + */ + while (depth-- && valid_stack_ptr(task_thread_info(current), + (unsigned long)head)) { + oprofile_add_trace(head->lr); + if (head->fp <= head) + break; + head = head->fp; + } +#endif + } else { + /* Assume we have frame pointers in user mode process */ + while (depth-- && head) + head = dump_user_backtrace(head); + } +} + + diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c index df42325c7f81..a3e9b3c4845a 100644 --- a/arch/avr32/oprofile/op_model_avr32.c +++ b/arch/avr32/oprofile/op_model_avr32.c @@ -22,6 +22,8 @@ #define AVR32_PERFCTR_IRQ_GROUP 0 #define AVR32_PERFCTR_IRQ_LINE 1 +void avr32_backtrace(struct pt_regs * const regs, unsigned int depth); + enum { PCCNT, PCNT0, PCNT1, NR_counter }; struct avr32_perf_counter { @@ -223,6 +225,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) memcpy(ops, &avr32_perf_counter_ops, sizeof(struct oprofile_operations)); + ops->backtrace = avr32_backtrace; + printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n"); return 0; |