diff options
Diffstat (limited to 'target/device/valka/v100sc2/kernel-patches/linux-2.6.24-300-avr32-psif.patch')
-rw-r--r-- | target/device/valka/v100sc2/kernel-patches/linux-2.6.24-300-avr32-psif.patch | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/target/device/valka/v100sc2/kernel-patches/linux-2.6.24-300-avr32-psif.patch b/target/device/valka/v100sc2/kernel-patches/linux-2.6.24-300-avr32-psif.patch new file mode 100644 index 000000000..f395b5837 --- /dev/null +++ b/target/device/valka/v100sc2/kernel-patches/linux-2.6.24-300-avr32-psif.patch @@ -0,0 +1,592 @@ +diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c +index d30de89..a2dacee 100644 +--- a/arch/avr32/boards/atstk1000/atstk1002.c ++++ b/arch/avr32/boards/atstk1000/atstk1002.c +@@ -268,6 +268,8 @@ static int __init atstk1002_init(void) + + atstk1000_setup_j2_leds(); + atstk1002_setup_extdac(); ++ at32_add_device_psif(0); ++ at32_add_device_psif(1); + + return 0; + } +--- 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); +diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c +index 5e3fae0..4ee9c51 100644 +--- a/arch/avr32/mach-at32ap/at32ap700x.c ++++ b/arch/avr32/mach-at32ap/at32ap700x.c +@@ -678,6 +678,55 @@ void __init at32_add_system_devices(void) + } + + /* -------------------------------------------------------------------- ++ * PSIF ++ * -------------------------------------------------------------------- */ ++static struct resource atmel_psif0_resource[] = { ++ { ++ .start = 0xffe03c00, ++ .end = 0xffe03cff, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ(18), ++}; ++DEFINE_DEV(atmel_psif, 0); ++DEV_CLK(pclk, atmel_psif0, pba, 15); ++ ++static struct resource atmel_psif1_resource[] = { ++ { ++ .start = 0xffe03d00, ++ .end = 0xffe03dff, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ(18), ++}; ++DEFINE_DEV(atmel_psif, 1); ++DEV_CLK(pclk, atmel_psif1, pba, 15); ++ ++struct platform_device *__init ++at32_add_device_psif(unsigned int id) ++{ ++ struct platform_device *pdev; ++ ++ switch (id) { ++ case 0: ++ pdev = &atmel_psif0_device; ++ select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */ ++ select_peripheral(PA(9), PERIPH_A, 0); /* DATA */ ++ break; ++ case 1: ++ pdev = &atmel_psif1_device; ++ select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */ ++ select_peripheral(PB(12), PERIPH_A, 0); /* DATA */ ++ break; ++ default: ++ return NULL; ++ } ++ ++ platform_device_register(pdev); ++ return pdev; ++} ++ ++/* -------------------------------------------------------------------- + * USART + * -------------------------------------------------------------------- */ + +@@ -1653,6 +1702,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 7aa1c29..0f31573 100644 +--- a/include/asm-avr32/arch-at32ap/board.h ++++ b/include/asm-avr32/arch-at32ap/board.h +@@ -89,4 +89,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/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig +index 5ce632c..40731ff 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..bc7e2cb +--- /dev/null ++++ b/drivers/input/serio/at32psif.c +@@ -0,0 +1,302 @@ ++/* ++ * 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 "at32psif.h" ++ ++struct psif { ++ struct platform_device *pdev; ++ struct clk *pclk; ++ struct serio *io; ++ void __iomem *regs; ++ unsigned int irq; ++ spinlock_t lock; ++ unsigned int head; ++ unsigned int tail; ++ unsigned char buffer[8]; ++}; ++ ++static irqreturn_t psif_interrupt(int irq, void *_ptr) ++{ ++ struct psif *psif = _ptr; ++ int retval = IRQ_NONE; ++ unsigned int flags = 0; ++ unsigned long status; ++ ++ status = psif_readl(psif, SR); ++ ++ if (status & PSIF_BIT(SR_RXRDY)) { ++ if (status & PSIF_BIT(SR_PARITY)) ++ flags |= SERIO_PARITY; ++ if (status & PSIF_BIT(SR_OVRUN)) ++ dev_err(&psif->pdev->dev, "overrun error\n"); ++ serio_interrupt(psif->io, psif_readl(psif, RHR), flags); ++ retval = IRQ_HANDLED; ++ } ++ ++ spin_lock(&psif->lock); ++ ++ if (status & PSIF_BIT(SR_TXEMPTY) && psif->head == psif->tail) { ++ psif_writel(psif, IDR, PSIF_BIT(IDR_TXEMPTY)); ++ } ++ else if (status & PSIF_BIT(SR_TXEMPTY)) { ++ psif_writel(psif, THR, (unsigned long)psif->buffer[psif->tail]); ++ psif->tail = (psif->tail + 1) & ((sizeof(psif->buffer) - 1)); ++ } ++ ++ spin_unlock(&psif->lock); ++ ++ 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(SR_TXEMPTY)) { ++ psif_writel(psif, THR, val); ++ } else { ++ if (psif->head == psif->tail) ++ psif_writel(psif, IER, PSIF_BIT(IER_TXEMPTY)); ++ head = (psif->head + 1) & ((sizeof(psif->buffer) - 1)); ++ if (head != psif->tail) { ++ psif->buffer[psif->head] = val; ++ psif->head = head; ++ } ++ } ++ ++ 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(IER_RXRDY)); ++out: ++ return retval; ++} ++ ++static void psif_close(struct serio *io) ++{ ++ struct psif *psif = io->port_data; ++ ++ psif_writel(psif, IDR, ~0UL); ++ psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS)); ++ ++ clk_disable(psif->pclk); ++} ++ ++static int 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 > 0xfff) ++ prscv = 0xfff; ++ ++ psif_writel(psif, PSR, prscv); ++ ++ return prscv; ++} ++ ++static int __devinit 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; ++ } ++ ++ 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_free_io; ++ } ++ psif->pclk = 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, "psif_kbd", psif); ++ if (ret) { ++ dev_dbg(&pdev->dev, "could not request irq %d\n", irq); ++ goto out_put_clk; ++ } ++ psif->irq = irq; ++ ++ 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_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; ++ ++ ret = psif_set_prescaler(psif); ++ if (ret < 0) { ++ dev_dbg(&pdev->dev, "could not set prescaler\n"); ++ goto out_iounmap; ++ } ++ ++ 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_iounmap: ++ iounmap(psif->regs); ++out_free_irq: ++ free_irq(psif->irq, psif); ++out_put_clk: ++ clk_put(psif->pclk); ++out_free_io: ++ kfree(io); ++out_free_psif: ++ kfree(psif); ++out: ++ return ret; ++} ++ ++static int __devexit psif_remove(struct platform_device *pdev) ++{ ++ struct psif *psif = platform_get_drvdata(pdev); ++ ++ if (psif) { ++ serio_unregister_port(psif->io); ++ iounmap(psif->regs); ++ free_irq(psif->irq, psif); ++ clk_put(psif->pclk); ++ kfree(psif->io); ++ 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); ++ ++ 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); ++ ++ clk_enable(psif->pclk); ++ psif_writel(psif, CR, PSIF_BIT(CR_RXEN) | PSIF_BIT(CR_TXEN)); ++ psif_set_prescaler(psif); ++ ++ return 0; ++} ++#else ++#define psif_suspend NULL ++#define psif_resume NULL ++#endif ++ ++static struct platform_driver psif_driver = { ++ .remove = __devexit_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 at 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..b0f19b7 +--- /dev/null ++++ b/drivers/input/serio/at32psif.h +@@ -0,0 +1,124 @@ ++/* ++ * 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 _AT32AP700X_PSIF ++#define _AT32AP700X_PSIF ++ ++/* PSIF register offsets */ ++#define PSIF_CR 0x0000 ++#define PSIF_IDR 0x0018 ++#define PSIF_IER 0x0014 ++#define PSIF_IMR 0x001c ++#define PSIF_PSR 0x0024 ++#define PSIF_RHR 0x0004 ++#define PSIF_SR 0x0010 ++#define PSIF_THR 0x0008 ++ ++/* 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 register. */ ++#define PSIF_IDR_NACK_OFFSET 8 ++#define PSIF_IDR_NACK_SIZE 1 ++#define PSIF_IDR_OVRUN_OFFSET 5 ++#define PSIF_IDR_OVRUN_SIZE 1 ++#define PSIF_IDR_PARITY_OFFSET 9 ++#define PSIF_IDR_PARITY_SIZE 1 ++#define PSIF_IDR_RXRDY_OFFSET 4 ++#define PSIF_IDR_RXRDY_SIZE 1 ++#define PSIF_IDR_TXEMPTY_OFFSET 1 ++#define PSIF_IDR_TXEMPTY_SIZE 1 ++#define PSIF_IDR_TXRDY_OFFSET 0 ++#define PSIF_IDR_TXRDY_SIZE 1 ++ ++/* Bitfields in interrupt enable register. */ ++#define PSIF_IER_NACK_OFFSET 8 ++#define PSIF_IER_NACK_SIZE 1 ++#define PSIF_IER_OVRUN_OFFSET 5 ++#define PSIF_IER_OVRUN_SIZE 1 ++#define PSIF_IER_PARITY_OFFSET 9 ++#define PSIF_IER_PARITY_SIZE 1 ++#define PSIF_IER_RXRDY_OFFSET 4 ++#define PSIF_IER_RXRDY_SIZE 1 ++#define PSIF_IER_TXEMPTY_OFFSET 1 ++#define PSIF_IER_TXEMPTY_SIZE 1 ++#define PSIF_IER_TXRDY_OFFSET 0 ++#define PSIF_IER_TXRDY_SIZE 1 ++ ++/* Bitfields in interrupt mask register. */ ++#define PSIF_IMR_NACK_OFFSET 8 ++#define PSIF_IMR_NACK_SIZE 1 ++#define PSIF_IMR_OVRUN_OFFSET 5 ++#define PSIF_IMR_OVRUN_SIZE 1 ++#define PSIF_IMR_PARITY_OFFSET 9 ++#define PSIF_IMR_PARITY_SIZE 1 ++#define PSIF_IMR_RXRDY_OFFSET 4 ++#define PSIF_IMR_RXRDY_SIZE 1 ++#define PSIF_IMR_TXEMPTY_OFFSET 1 ++#define PSIF_IMR_TXEMPTY_SIZE 1 ++#define PSIF_IMR_TXRDY_OFFSET 0 ++#define PSIF_IMR_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 status register. */ ++#define PSIF_SR_NACK_OFFSET 8 ++#define PSIF_SR_NACK_SIZE 1 ++#define PSIF_SR_OVRUN_OFFSET 5 ++#define PSIF_SR_OVRUN_SIZE 1 ++#define PSIF_SR_PARITY_OFFSET 9 ++#define PSIF_SR_PARITY_SIZE 1 ++#define PSIF_SR_RXRDY_OFFSET 4 ++#define PSIF_SR_RXRDY_SIZE 1 ++#define PSIF_SR_TXEMPTY_OFFSET 1 ++#define PSIF_SR_TXEMPTY_SIZE 1 ++#define PSIF_SR_TXRDY_OFFSET 0 ++#define PSIF_SR_TXRDY_SIZE 1 ++ ++/* 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 /* _AT32AP700X_PSIF */ |