X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/550454d4b6186e712a1b48e27a3dce788dd54ca9..57563ffd07c2b88f6bd9625d9913854e41222393:/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/gpio.c diff --git a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/gpio.c b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/gpio.c index c7eff5d2c..408a4158d 100644 --- a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/gpio.c +++ b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/gpio.c @@ -1,8 +1,8 @@ /* - * GPIO support for RDC SoC R3210/R8610 + * RDC321x GPIO driver * - * Copyright (C) 2007, Florian Fainelli - * Copyright (C) 2008, Volker Weiss + * Copyright (C) 2008, Volker Weiss + * Copyright (C) 2007-2010 Florian Fainelli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,180 +19,156 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ - - -#include -#include -#include #include +#include +#include +#include +#include +#include +#include -#include -#include +#include +struct rdc321x_gpio { + spinlock_t lock; + u32 data_reg[2]; +} rdc321x_gpio_dev; -/* spin lock to protect our private copy of GPIO data register plus - the access to PCI conf registers. */ -static DEFINE_SPINLOCK(gpio_lock); +extern int rdc321x_pci_write(int reg, u32 val); +extern int rdc321x_pci_read(int reg, u32 *val); -/* copy of GPIO data registers */ -static u32 gpio_data_reg1; -static u32 gpio_data_reg2; +/* read GPIO pin */ +static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + u32 value = 0; + int reg; -static u32 gpio_request_data[2]; + reg = gpio < 32 ? RDC321X_GPIO_DATA_REG1 : RDC321X_GPIO_DATA_REG2; + spin_lock(&rdc321x_gpio_dev.lock); + rdc321x_pci_write(reg, rdc321x_gpio_dev.data_reg[gpio < 32 ? 0 : 1]); + rdc321x_pci_read(reg, &value); + spin_unlock(&rdc321x_gpio_dev.lock); -static inline void rdc321x_conf_write(unsigned addr, u32 value) -{ - outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); - outl(value, RDC3210_CFGREG_DATA); + return (1 << (gpio & 0x1f)) & value ? 1 : 0; } -static inline void rdc321x_conf_or(unsigned addr, u32 value) +static void rdc_gpio_set_value_impl(struct gpio_chip *chip, + unsigned gpio, int value) { - outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); - value |= inl(RDC3210_CFGREG_DATA); - outl(value, RDC3210_CFGREG_DATA); -} + int reg = (gpio < 32) ? 0 : 1; -static inline u32 rdc321x_conf_read(unsigned addr) -{ - outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); + if (value) + rdc321x_gpio_dev.data_reg[reg] |= 1 << (gpio & 0x1f); + else + rdc321x_gpio_dev.data_reg[reg] &= ~(1 << (gpio & 0x1f)); - return inl(RDC3210_CFGREG_DATA); + rdc321x_pci_write(reg ? RDC321X_GPIO_DATA_REG2 : RDC321X_GPIO_DATA_REG1, + rdc321x_gpio_dev.data_reg[reg]); } -/* configure pin as GPIO */ -static void rdc321x_configure_gpio(unsigned gpio) +/* set GPIO pin to value */ +static void rdc_gpio_set_value(struct gpio_chip *chip, + unsigned gpio, int value) { - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - rdc321x_conf_or(gpio < 32 - ? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2, - 1 << (gpio & 0x1f)); - spin_unlock_irqrestore(&gpio_lock, flags); + spin_lock(&rdc321x_gpio_dev.lock); + rdc_gpio_set_value_impl(chip, gpio, value); + spin_unlock(&rdc321x_gpio_dev.lock); } -/* initially setup the 2 copies of the gpio data registers. - This function is called before the platform setup code. */ -static int __init rdc321x_gpio_setup(void) +static int rdc_gpio_config(struct gpio_chip *chip, + unsigned gpio, int value) { - /* this might not be, what others (BIOS, bootloader, etc.) - wrote to these registers before, but it's a good guess. Still - better than just using 0xffffffff. */ - - gpio_data_reg1 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG1); - gpio_data_reg2 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG2); + int err; + u32 reg; - return 0; -} + spin_lock(&rdc321x_gpio_dev.lock); + err = rdc321x_pci_read(gpio < 32 ? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2, + ®); + if (err) + goto unlock; -/* determine, if gpio number is valid */ -static inline int rdc321x_is_gpio(unsigned gpio) -{ - return gpio <= RDC321X_MAX_GPIO; -} + reg |= 1 << (gpio & 0x1f); -/* request GPIO */ -int rdc_gpio_request(unsigned gpio, const char *label) -{ - unsigned long flags; + err = rdc321x_pci_write(gpio < 32 ? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2, + reg); + if (err) + goto unlock; - if (!rdc321x_is_gpio(gpio)) - return -EINVAL; + rdc_gpio_set_value_impl(chip, gpio, value); - spin_lock_irqsave(&gpio_lock, flags); - if (gpio_request_data[(gpio & 0x20) ? 1 : 0] & (1 << (gpio & 0x1f))) - goto inuse; - gpio_request_data[(gpio & 0x20) ? 1 : 0] |= (1 << (gpio & 0x1f)); - spin_unlock_irqrestore(&gpio_lock, flags); +unlock: + spin_unlock(&rdc321x_gpio_dev.lock); - return 0; -inuse: - spin_unlock_irqrestore(&gpio_lock, flags); - return -EINVAL; + return err; } -EXPORT_SYMBOL(rdc_gpio_request); -/* release previously-claimed GPIO */ -void rdc_gpio_free(unsigned gpio) +/* configure GPIO pin as input */ +static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { - unsigned long flags; - - if (!rdc321x_is_gpio(gpio)) - return; - - spin_lock_irqsave(&gpio_lock, flags); - gpio_request_data[(gpio & 0x20) ? 1 : 0] &= ~(1 << (gpio & 0x1f)); - spin_unlock_irqrestore(&gpio_lock, flags); + return rdc_gpio_config(chip, gpio, 1); } -EXPORT_SYMBOL(rdc_gpio_free); -/* read GPIO pin */ -int rdc_gpio_get_value(unsigned gpio) +static struct gpio_chip rdc321x_gpio_chip = { + .label = "rdc321x-gpio", + .direction_input = rdc_gpio_direction_input, + .direction_output = rdc_gpio_config, + .get = rdc_gpio_get_value, + .set = rdc_gpio_set_value, + .base = 0, + .ngpio = RDC321X_MAX_GPIO, +}; + +/* initially setup the 2 copies of the gpio data registers. + This function is called before the platform setup code. */ +static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) { - u32 reg; - unsigned long flags; + int err; - spin_lock_irqsave(&gpio_lock, flags); - reg = rdc321x_conf_read(gpio < 32 - ? RDC321X_GPIO_DATA_REG1 : RDC321X_GPIO_DATA_REG2); - spin_unlock_irqrestore(&gpio_lock, flags); + /* this might not be, what others (BIOS, bootloader, etc.) + wrote to these registers before, but it's a good guess. Still + better than just using 0xffffffff. */ + err = rdc321x_pci_read(RDC321X_GPIO_DATA_REG1, &rdc321x_gpio_dev.data_reg[0]); + if (err) + return err; - return (1 << (gpio & 0x1f)) & reg ? 1 : 0; -} -EXPORT_SYMBOL(rdc_gpio_get_value); + err = rdc321x_pci_read(RDC321X_GPIO_DATA_REG2, &rdc321x_gpio_dev.data_reg[1]); + if (err) + return err; -/* set GPIO pin to value */ -void rdc_gpio_set_value(unsigned gpio, int value) -{ - unsigned long flags; - u32 reg; + spin_lock_init(&rdc321x_gpio_dev.lock); - reg = 1 << (gpio & 0x1f); - if (gpio < 32) { - spin_lock_irqsave(&gpio_lock, flags); - if (value) - gpio_data_reg1 |= reg; - else - gpio_data_reg1 &= ~reg; - rdc321x_conf_write(RDC321X_GPIO_DATA_REG1, gpio_data_reg1); - spin_unlock_irqrestore(&gpio_lock, flags); - } else { - spin_lock_irqsave(&gpio_lock, flags); - if (value) - gpio_data_reg2 |= reg; - else - gpio_data_reg2 &= ~reg; - rdc321x_conf_write(RDC321X_GPIO_DATA_REG2, gpio_data_reg2); - spin_unlock_irqrestore(&gpio_lock, flags); - } + printk(KERN_INFO "rdc321x: registering %d GPIOs\n", rdc321x_gpio_chip.ngpio); + return gpiochip_add(&rdc321x_gpio_chip); } -EXPORT_SYMBOL(rdc_gpio_set_value); -/* configure GPIO pin as input */ -int rdc_gpio_direction_input(unsigned gpio) +static int __devexit rdc321x_gpio_remove(struct platform_device *pdev) { - if (!rdc321x_is_gpio(gpio)) - return -EINVAL; - - rdc321x_configure_gpio(gpio); - + gpiochip_remove(&rdc321x_gpio_chip); return 0; } -EXPORT_SYMBOL(rdc_gpio_direction_input); -/* configure GPIO pin as output and set value */ -int rdc_gpio_direction_output(unsigned gpio, int value) -{ - if (!rdc321x_is_gpio(gpio)) - return -EINVAL; +static struct platform_driver rdc321x_gpio_driver = { + .driver.name = "rdc321x-gpio", + .driver.owner = THIS_MODULE, + .probe = rdc321x_gpio_probe, + .remove = __devexit_p(rdc321x_gpio_remove), +}; - gpio_set_value(gpio, value); - rdc321x_configure_gpio(gpio); +static int __init rdc321x_gpio_init(void) +{ + return platform_driver_register(&rdc321x_gpio_driver); +} - return 0; +static void __exit rdc321x_gpio_exit(void) +{ + platform_driver_unregister(&rdc321x_gpio_driver); } -EXPORT_SYMBOL(rdc_gpio_direction_output); -arch_initcall(rdc321x_gpio_setup); +module_init(rdc321x_gpio_init); +module_exit(rdc321x_gpio_exit); + +MODULE_AUTHOR("Florian Fainelli "); +MODULE_DESCRIPTION("RDC321x GPIO driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rdc321x-gpio");