From be28e9d4385b70ca3648d71128a5a75a19b39324 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 8 Jan 2009 15:40:46 +0000 Subject: [PATCH] Convert au1000 to using gpiolib, fixes an oops on startup SVN-Revision: 13935 --- target/linux/au1000/config-2.6.27 | 1 + .../au1000/patches-2.6.27/007-gpiolib.patch | 399 ++++++++++++++++++ 2 files changed, 400 insertions(+) create mode 100644 target/linux/au1000/patches-2.6.27/007-gpiolib.patch diff --git a/target/linux/au1000/config-2.6.27 b/target/linux/au1000/config-2.6.27 index c0c4234956..6908f49061 100644 --- a/target/linux/au1000/config-2.6.27 +++ b/target/linux/au1000/config-2.6.27 @@ -99,6 +99,7 @@ CONFIG_INPUT_KEYBOARD=y CONFIG_IRQ_CPU=y CONFIG_KEXEC=y # CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_STOWAWAY is not set diff --git a/target/linux/au1000/patches-2.6.27/007-gpiolib.patch b/target/linux/au1000/patches-2.6.27/007-gpiolib.patch new file mode 100644 index 0000000000..1cd73d7dcf --- /dev/null +++ b/target/linux/au1000/patches-2.6.27/007-gpiolib.patch @@ -0,0 +1,399 @@ +diff -urN linux-2.6.27.7/arch/mips/au1000/Kconfig linux-2.6.27.7.new/arch/mips/au1000/Kconfig +--- linux-2.6.27.7/arch/mips/au1000/Kconfig 2008-11-21 00:02:37.000000000 +0100 ++++ linux-2.6.27.7.new/arch/mips/au1000/Kconfig 2008-12-08 11:44:09.000000000 +0100 +@@ -134,3 +134,4 @@ + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_APM_EMULATION ++ select ARCH_REQUIRE_GPIOLIB +diff -urN linux-2.6.27.7/arch/mips/au1000/common/gpio.c linux-2.6.27.7.new/arch/mips/au1000/common/gpio.c +--- linux-2.6.27.7/arch/mips/au1000/common/gpio.c 2008-11-21 00:02:37.000000000 +0100 ++++ linux-2.6.27.7.new/arch/mips/au1000/common/gpio.c 2008-12-08 11:58:30.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2007, OpenWrt.org, Florian Fainelli ++ * Copyright (C) 2007-2008, OpenWrt.org, Florian Fainelli + * Architecture specific GPIO support + * + * This program is free software; you can redistribute it and/or modify it +@@ -27,122 +27,222 @@ + * others have a second one : GPIO2 + */ + ++#include + #include ++#include ++#include ++#include + + #include +-#include ++#include + +-#define gpio1 sys +-#if !defined(CONFIG_SOC_AU1000) ++struct au1000_gpio_chip { ++ struct gpio_chip chip; ++ void __iomem *regbase; ++}; + +-static struct au1x00_gpio2 *const gpio2 = (struct au1x00_gpio2 *) GPIO2_BASE; ++#if !defined(CONFIG_SOC_AU1000) + #define GPIO2_OUTPUT_ENABLE_MASK 0x00010000 + +-static int au1xxx_gpio2_read(unsigned gpio) ++/* ++ * Return GPIO bank 2 level ++ */ ++static int au1000_gpio2_get(struct gpio_chip *chip, unsigned offset) + { +- gpio -= AU1XXX_GPIO_BASE; +- return ((gpio2->pinstate >> gpio) & 0x01); ++ u32 mask = 1 << offset; ++ struct au1000_gpio_chip *gpch; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ return readl(gpch->regbase + AU1000_GPIO2_ST) & mask; + } + +-static void au1xxx_gpio2_write(unsigned gpio, int value) ++/* ++ * Set output GPIO bank 2 level ++ */ ++static void au1000_gpio2_set(struct gpio_chip *chip, ++ unsigned offset, int value) + { +- gpio -= AU1XXX_GPIO_BASE; +- +- gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); ++ u32 mask = (!!value) << offset; ++ struct au1000_gpio_chip *gpch; ++ unsigned long flags; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ ++ local_irq_save(flags); ++ writel((GPIO2_OUTPUT_ENABLE_MASK << offset) | mask, ++ gpch->regbase + AU1000_GPIO2_OUT); ++ local_irq_restore(flags); + } + +-static int au1xxx_gpio2_direction_input(unsigned gpio) ++/* ++ * Set GPIO bank 2 direction to input ++ */ ++static int au1000_gpio2_direction_input(struct gpio_chip *chip, unsigned offset) + { +- gpio -= AU1XXX_GPIO_BASE; +- gpio2->dir &= ~(0x01 << gpio); ++ unsigned long flags; ++ u32 mask = 1 << offset; ++ u32 value; ++ struct au1000_gpio_chip *gpch; ++ void __iomem *gpdr; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ gpdr = gpch->regbase + AU1000_GPIO2_DIR; ++ ++ local_irq_save(flags); ++ value = readl(gpdr); ++ value &= ~mask; ++ writel(value, gpdr); ++ local_irq_restore(flags); ++ + return 0; + } + +-static int au1xxx_gpio2_direction_output(unsigned gpio, int value) ++/* ++ * Set GPIO bank2 direction to output ++ */ ++static int au1000_gpio2_direction_output(struct gpio_chip *chip, ++ unsigned offset, int value) + { +- gpio -= AU1XXX_GPIO_BASE; +- gpio2->dir |= 0x01 << gpio; +- gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << gpio) | ((!!value) << gpio); ++ unsigned long flags; ++ u32 mask = 1 << offset; ++ u32 tmp; ++ struct au1000_gpio_chip *gpch; ++ void __iomem *gpdr; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ gpdr = gpch->regbase + AU1000_GPIO2_DIR; ++ ++ local_irq_save(flags); ++ tmp = readl(gpdr); ++ tmp |= mask; ++ writel(tmp, gpdr); ++ mask = (!!value) << offset; ++ writel((GPIO2_OUTPUT_ENABLE_MASK << offset) | mask, ++ gpch->regbase + AU1000_GPIO2_OUT); ++ local_irq_restore(flags); ++ + return 0; + } +- + #endif /* !defined(CONFIG_SOC_AU1000) */ + +-static int au1xxx_gpio1_read(unsigned gpio) ++/* ++ * Return GPIO bank 2 level ++ */ ++static int au1000_gpio1_get(struct gpio_chip *chip, unsigned offset) + { +- return (gpio1->pinstaterd >> gpio) & 0x01; ++ u32 mask = 1 << offset; ++ struct au1000_gpio_chip *gpch; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ return readl(gpch->regbase + 0x0110) & mask; + } + +-static void au1xxx_gpio1_write(unsigned gpio, int value) ++/* ++ * Set GPIO bank 1 level ++ */ ++static void au1000_gpio1_set(struct gpio_chip *chip, ++ unsigned offset, int value) + { ++ unsigned long flags; ++ u32 mask = 1 << offset; ++ struct au1000_gpio_chip *gpch; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ ++ local_irq_save(flags); + if (value) +- gpio1->outputset = (0x01 << gpio); ++ writel(mask, gpch->regbase + 0x0108); + else +- /* Output a zero */ +- gpio1->outputclr = (0x01 << gpio); ++ writel(mask, gpch->regbase + 0x010C); ++ local_irq_restore(flags); + } + +-static int au1xxx_gpio1_direction_input(unsigned gpio) ++/* ++ * Set GPIO bank 1 direction to input ++ */ ++static int au1000_gpio1_direction_input(struct gpio_chip *chip, unsigned offset) + { +- gpio1->pininputen = (0x01 << gpio); +- return 0; +-} ++ unsigned long flags; ++ u32 mask = 1 << offset; ++ u32 value; ++ struct au1000_gpio_chip *gpch; ++ void __iomem *gpdr; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ gpdr = gpch->regbase + 0x0110; ++ ++ local_irq_save(flags); ++ value = readl(gpdr); ++ value |= mask; ++ writel(mask, gpdr); ++ local_irq_restore(flags); + +-static int au1xxx_gpio1_direction_output(unsigned gpio, int value) +-{ +- gpio1->trioutclr = (0x01 & gpio); +- au1xxx_gpio1_write(gpio, value); + return 0; + } + +-int au1xxx_gpio_get_value(unsigned gpio) ++/* ++ * Set GPIO bank 1 direction to output ++ */ ++static int au1000_gpio1_direction_output(struct gpio_chip *chip, ++ unsigned offset, int value) + { +- if (gpio >= AU1XXX_GPIO_BASE) +-#if defined(CONFIG_SOC_AU1000) +- return 0; +-#else +- return au1xxx_gpio2_read(gpio); +-#endif ++ unsigned long flags; ++ u32 mask = 1 << offset; ++ u32 tmp; ++ struct au1000_gpio_chip *gpch; ++ void __iomem *gpdr; ++ ++ gpch = container_of(chip, struct au1000_gpio_chip, chip); ++ gpdr = gpch->regbase + 0x0100; ++ ++ local_irq_save(flags); ++ tmp = readl(gpdr); ++ writel(tmp, gpdr); ++ if (value) ++ writel(mask, gpch->regbase + 0x0108); + else +- return au1xxx_gpio1_read(gpio); +-} +-EXPORT_SYMBOL(au1xxx_gpio_get_value); ++ writel(mask, gpch->regbase + 0x0108); ++ local_irq_restore(flags); + +-void au1xxx_gpio_set_value(unsigned gpio, int value) +-{ +- if (gpio >= AU1XXX_GPIO_BASE) +-#if defined(CONFIG_SOC_AU1000) +- ; +-#else +- au1xxx_gpio2_write(gpio, value); +-#endif +- else +- au1xxx_gpio1_write(gpio, value); ++ return 0; + } +-EXPORT_SYMBOL(au1xxx_gpio_set_value); + +-int au1xxx_gpio_direction_input(unsigned gpio) +-{ +- if (gpio >= AU1XXX_GPIO_BASE) +-#if defined(CONFIG_SOC_AU1000) +- return -ENODEV; +-#else +- return au1xxx_gpio2_direction_input(gpio); ++struct au1000_gpio_chip au1000_gpio_chip[] = { ++ [0] = { ++ .regbase = (void __iomem *)SYS_BASE, ++ .chip = { ++ .label = "au1000-gpio1", ++ .direction_input = au1000_gpio1_direction_input, ++ .direction_output = au1000_gpio1_direction_output, ++ .get = au1000_gpio1_get, ++ .set = au1000_gpio1_set, ++ .base = 0, ++ .ngpio = 32, ++ }, ++ }, ++#if !defined(CONFIG_SOC_AU1000) ++ [1] = { ++ .regbase = (void __iomem *)GPIO2_BASE, ++ .chip = { ++ .label = "au1000-gpio2", ++ .direction_input = au1000_gpio2_direction_input, ++ .direction_output = au1000_gpio2_direction_output, ++ .get = au1000_gpio2_get, ++ .set = au1000_gpio2_set, ++ .base = AU1XXX_GPIO_BASE, ++ .ngpio = 32, ++ }, ++ }, + #endif ++}; + +- return au1xxx_gpio1_direction_input(gpio); +-} +-EXPORT_SYMBOL(au1xxx_gpio_direction_input); +- +-int au1xxx_gpio_direction_output(unsigned gpio, int value) ++int __init au1000_gpio_init(void) + { +- if (gpio >= AU1XXX_GPIO_BASE) +-#if defined(CONFIG_SOC_AU1000) +- return -ENODEV; +-#else +- return au1xxx_gpio2_direction_output(gpio, value); ++ gpiochip_add(&au1000_gpio_chip[0].chip); ++#if !defined(CONFIG_SOC_AU1000) ++ gpiochip_add(&au1000_gpio_chip[1].chip); + #endif + +- return au1xxx_gpio1_direction_output(gpio, value); ++ return 0; + } +-EXPORT_SYMBOL(au1xxx_gpio_direction_output); ++arch_initcall(au1000_gpio_init); +diff -urN linux-2.6.27.7/include/asm-mips/mach-au1x00/gpio.h linux-2.6.27.7.new/include/asm-mips/mach-au1x00/gpio.h +--- linux-2.6.27.7/include/asm-mips/mach-au1x00/gpio.h 2008-11-21 00:02:37.000000000 +0100 ++++ linux-2.6.27.7.new/include/asm-mips/mach-au1x00/gpio.h 2008-12-08 11:43:37.000000000 +0100 +@@ -1,69 +1,21 @@ + #ifndef _AU1XXX_GPIO_H_ + #define _AU1XXX_GPIO_H_ + +-#include +- + #define AU1XXX_GPIO_BASE 200 + +-struct au1x00_gpio2 { +- u32 dir; +- u32 reserved; +- u32 output; +- u32 pinstate; +- u32 inten; +- u32 enable; +-}; +- +-extern int au1xxx_gpio_get_value(unsigned gpio); +-extern void au1xxx_gpio_set_value(unsigned gpio, int value); +-extern int au1xxx_gpio_direction_input(unsigned gpio); +-extern int au1xxx_gpio_direction_output(unsigned gpio, int value); +- +- +-/* Wrappers for the arch-neutral GPIO API */ +- +-static inline int gpio_request(unsigned gpio, const char *label) +-{ +- /* Not yet implemented */ +- return 0; +-} +- +-static inline void gpio_free(unsigned gpio) +-{ +- /* Not yet implemented */ +-} +- +-static inline int gpio_direction_input(unsigned gpio) +-{ +- return au1xxx_gpio_direction_input(gpio); +-} +- +-static inline int gpio_direction_output(unsigned gpio, int value) +-{ +- return au1xxx_gpio_direction_output(gpio, value); +-} +- +-static inline int gpio_get_value(unsigned gpio) +-{ +- return au1xxx_gpio_get_value(gpio); +-} +- +-static inline void gpio_set_value(unsigned gpio, int value) +-{ +- au1xxx_gpio_set_value(gpio, value); +-} +- +-static inline int gpio_to_irq(unsigned gpio) +-{ +- return gpio; +-} +- +-static inline int irq_to_gpio(unsigned irq) +-{ +- return irq; +-} ++#define AU1000_GPIO2_DIR 0x00 ++#define AU1000_GPIO2_RSVD 0x04 ++#define AU1000_GPIO2_OUT 0x08 ++#define AU1000_GPIO2_ST 0x0C ++#define AU1000_GPIO2_INT 0x10 ++#define AU1000_GPIO2_EN 0x14 ++ ++#define gpio_get_value __gpio_get_value ++#define gpio_set_value __gpio_set_value ++ ++#define gpio_to_irq(gpio) NULL ++#define irq_to_gpio(irq) NULL + +-/* For cansleep */ + #include + + #endif /* _AU1XXX_GPIO_H_ */