diff options
Diffstat (limited to 'target/device/Atmel/misc-patches/linux-2.6.24-avr32-psif-2.patch')
-rw-r--r-- | target/device/Atmel/misc-patches/linux-2.6.24-avr32-psif-2.patch | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/target/device/Atmel/misc-patches/linux-2.6.24-avr32-psif-2.patch b/target/device/Atmel/misc-patches/linux-2.6.24-avr32-psif-2.patch new file mode 100644 index 000000000..4f9d652a5 --- /dev/null +++ b/target/device/Atmel/misc-patches/linux-2.6.24-avr32-psif-2.patch @@ -0,0 +1,671 @@ +diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig +index b88569e..2df47ed 100644 +--- a/drivers/input/serio/Kconfig ++++ b/drivers/input/serio/Kconfig +@@ -88,6 +88,17 @@ config SERIO_RPCKBD + 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 +diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile +index 4155197..38b8868 100644 +--- a/drivers/input/serio/Makefile ++++ b/drivers/input/serio/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o + 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 +diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c +new file mode 100644 +index 0000000..228ab15 +--- /dev/null ++++ b/drivers/input/serio/at32psif.c +@@ -0,0 +1,342 @@ ++/* ++ * 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/interrupt.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/platform_device.h> ++#include <linux/delay.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; ++ 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 lock_flags; ++ 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"); ++ ++ /* TODO: why do we have to wait? Are we too fast for serio? */ ++ udelay(100); ++ ++ serio_interrupt(psif->io, val, io_flags); ++ ++ retval = IRQ_HANDLED; ++ } ++ ++ spin_lock_irqsave(&psif->lock, lock_flags); ++ ++ if (status & PSIF_BIT(TXEMPTY)) { ++ if (status & PSIF_BIT(NACK)) ++ dev_err(&psif->pdev->dev, "NACK error\n"); ++ if (ring_is_empty(psif)) { ++ psif_writel(psif, IDR, PSIF_BIT(TXEMPTY)); ++ } else { ++ psif_writel(psif, THR, psif->buffer[psif->tail]); ++ psif->tail = ring_next_tail(psif); ++ } ++ ++ retval = IRQ_HANDLED; ++ } ++ ++ spin_unlock_irqrestore(&psif->lock, lock_flags); ++ ++ return retval; ++} ++ ++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); ++ ++ /* Write directly if TX is ready. */ ++ if (psif_readl(psif, SR) & PSIF_BIT(TXEMPTY)) { ++ psif_writel(psif, THR, val); ++ } else { ++ 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"); ++ } ++ ++ /* Make sure TXEMPTY interrupt is enabled. */ ++ psif_writel(psif, IER, PSIF_BIT(TXEMPTY)); ++ } ++ ++ spin_unlock_irqrestore(&psif->lock, flags); ++ ++ 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 / 1000000); ++ ++ 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); ++ ++ 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"); +diff --git a/drivers/input/serio/at32psif.h b/drivers/input/serio/at32psif.h +new file mode 100644 +index 0000000..b0cc5e4 +--- /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 0x20 ++ ++/* 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 13 ++ ++/* 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 */ +diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig +index 56a8d8e..e125205 100644 +--- a/arch/avr32/boards/atstk1000/Kconfig ++++ b/arch/avr32/boards/atstk1000/Kconfig +@@ -145,4 +145,17 @@ config BOARD_ATSTK1000_CF_DETECT_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 +diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c +index f19f54d..2ba37d5 100644 +--- a/arch/avr32/boards/atstk1000/atstk1002.c ++++ b/arch/avr32/boards/atstk1000/atstk1002.c +@@ -261,6 +261,10 @@ static int __init atstk1002_init(void) + 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(); +diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c +index 768d204..2cc0bbc 100644 +--- a/arch/avr32/boards/atstk1000/atstk1003.c ++++ b/arch/avr32/boards/atstk1000/atstk1003.c +@@ -172,6 +172,10 @@ static int __init atstk1003_init(void) + 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(); +diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c +index 96015dd..9e8c293 100644 +--- a/arch/avr32/boards/atstk1000/atstk1004.c ++++ b/arch/avr32/boards/atstk1000/atstk1004.c +@@ -143,6 +143,10 @@ static int __init atstk1004_init(void) + #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(); +diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c +index 3300944..cfec920 100644 +--- a/arch/avr32/mach-at32ap/at32ap700x.c ++++ b/arch/avr32/mach-at32ap/at32ap700x.c +@@ -679,6 +679,81 @@ void __init at32_add_system_devices(void) + } + + /* -------------------------------------------------------------------- ++ * 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 + * -------------------------------------------------------------------- */ + +@@ -1712,6 +1787,8 @@ struct clk *at32_clock_list[] = { + &pio3_mck, + &pio4_mck, + &at32_systc0_pclk, ++ &atmel_psif0_pclk, ++ &atmel_psif1_pclk, + &atmel_usart0_usart, + &atmel_usart1_usart, + &atmel_usart2_usart, +diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h +index 1a6e02c..19cfec7 100644 +--- a/include/asm-avr32/arch-at32ap/board.h ++++ b/include/asm-avr32/arch-at32ap/board.h +@@ -93,4 +93,7 @@ struct platform_device * + 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); ++ + #endif /* __ASM_ARCH_BOARD_H */ +diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c +index d95f316..20a7193 100644 +--- a/drivers/char/keyboard.c ++++ b/drivers/char/keyboard.c +@@ -1000,7 +1000,8 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); + #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)) +diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c +--- a/arch/avr32/boards/atngw100/setup.c 2008-01-31 13:38:32.000000000 -0500 ++++ b/arch/avr32/boards/atngw100/setup.c 2008-01-31 13:44:09.000000000 -0500 +@@ -224,6 +224,9 @@ static int __init atngw100_init(void) + at32_add_device_usba(0, NULL); + at32_add_device_ac97c(0); + ++ at32_add_device_psif(0); ++ at32_add_device_psif(1); ++ + for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) { + at32_select_gpio(ngw_leds[i].gpio, + AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); |