diff options
Diffstat (limited to 'target/linux/rdc/files-2.6.30/arch/x86')
4 files changed, 215 insertions, 97 deletions
diff --git a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/Makefile b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/Makefile index 8325b4ca4..15f2739ea 100644 --- a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/Makefile +++ b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/Makefile @@ -1,5 +1,5 @@ # # Makefile for the RDC321x specific parts of the kernel # -obj-$(CONFIG_X86_RDC321X) := gpio.o platform.o +obj-$(CONFIG_X86_RDC321X) := gpio.o platform.o pci.o 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 c99b3b223..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 <florian@openwrt.org> - * Copyright (C) 2008, Volker Weiss <dev@tintuc.de> + * Copyright (C) 2008, Volker Weiss <dev@tintuc.de> + * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> * * 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,121 +19,100 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ - - -#include <linux/spinlock.h> -#include <linux/io.h> -#include <linux/types.h> #include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/pci.h> #include <linux/gpio.h> -#include <asm/rdc321x_gpio.h> #include <asm/rdc321x_defs.h> +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; - -static inline void rdc321x_conf_write(unsigned addr, u32 value) -{ - outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); - outl(value, RDC3210_CFGREG_DATA); -} - -static inline void rdc321x_conf_or(unsigned addr, u32 value) -{ - outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); - value |= inl(RDC3210_CFGREG_DATA); - outl(value, RDC3210_CFGREG_DATA); -} - -static inline u32 rdc321x_conf_read(unsigned addr) +/* read GPIO pin */ +static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio) { - outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); + u32 value = 0; + int reg; - return inl(RDC3210_CFGREG_DATA); -} + reg = gpio < 32 ? RDC321X_GPIO_DATA_REG1 : RDC321X_GPIO_DATA_REG2; -/* configure pin as GPIO */ -static void rdc321x_configure_gpio(unsigned gpio) -{ - unsigned long flags; + 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); - 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); + return (1 << (gpio & 0x1f)) & value ? 1 : 0; } -/* read GPIO pin */ -static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +static void rdc_gpio_set_value_impl(struct gpio_chip *chip, + unsigned gpio, int value) { - u32 reg; - unsigned long flags; + int reg = (gpio < 32) ? 0 : 1; - 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); + if (value) + rdc321x_gpio_dev.data_reg[reg] |= 1 << (gpio & 0x1f); + else + rdc321x_gpio_dev.data_reg[reg] &= ~(1 << (gpio & 0x1f)); - return (1 << (gpio & 0x1f)) & reg ? 1 : 0; + rdc321x_pci_write(reg ? RDC321X_GPIO_DATA_REG2 : RDC321X_GPIO_DATA_REG1, + rdc321x_gpio_dev.data_reg[reg]); } /* set GPIO pin to value */ static void rdc_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) { - unsigned long flags; - u32 reg; - - 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); - } + spin_lock(&rdc321x_gpio_dev.lock); + rdc_gpio_set_value_impl(chip, gpio, value); + spin_unlock(&rdc321x_gpio_dev.lock); } -/* configure GPIO pin as input */ -static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +static int rdc_gpio_config(struct gpio_chip *chip, + unsigned gpio, int value) { - rdc321x_configure_gpio(gpio); + 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; + + reg |= 1 << (gpio & 0x1f); + + err = rdc321x_pci_write(gpio < 32 ? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2, + reg); + if (err) + goto unlock; + + rdc_gpio_set_value_impl(chip, gpio, value); + +unlock: + spin_unlock(&rdc321x_gpio_dev.lock); + + return err; } -/* configure GPIO pin as output and set value */ -static int rdc_gpio_direction_output(struct gpio_chip *chip, - unsigned gpio, int value) +/* configure GPIO pin as input */ +static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { - rdc321x_configure_gpio(gpio); - gpio_set_value(gpio, value); - - return 0; + return rdc_gpio_config(chip, gpio, 1); } static struct gpio_chip rdc321x_gpio_chip = { .label = "rdc321x-gpio", .direction_input = rdc_gpio_direction_input, - .direction_output = rdc_gpio_direction_output, + .direction_output = rdc_gpio_config, .get = rdc_gpio_get_value, .set = rdc_gpio_set_value, .base = 0, @@ -142,17 +121,54 @@ static struct gpio_chip rdc321x_gpio_chip = { /* 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 __devinit rdc321x_gpio_probe(struct platform_device *pdev) { + int err; + /* 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; + + err = rdc321x_pci_read(RDC321X_GPIO_DATA_REG2, &rdc321x_gpio_dev.data_reg[1]); + if (err) + return err; - gpio_data_reg1 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG1); - gpio_data_reg2 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG2); + spin_lock_init(&rdc321x_gpio_dev.lock); printk(KERN_INFO "rdc321x: registering %d GPIOs\n", rdc321x_gpio_chip.ngpio); return gpiochip_add(&rdc321x_gpio_chip); } -arch_initcall(rdc321x_gpio_setup); +static int __devexit rdc321x_gpio_remove(struct platform_device *pdev) +{ + gpiochip_remove(&rdc321x_gpio_chip); + return 0; +} + +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), +}; + +static int __init rdc321x_gpio_init(void) +{ + return platform_driver_register(&rdc321x_gpio_driver); +} + +static void __exit rdc321x_gpio_exit(void) +{ + platform_driver_unregister(&rdc321x_gpio_driver); +} + +module_init(rdc321x_gpio_init); +module_exit(rdc321x_gpio_exit); + +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION("RDC321x GPIO driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rdc321x-gpio"); diff --git a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/pci.c b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/pci.c new file mode 100644 index 000000000..0281485c5 --- /dev/null +++ b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/pci.c @@ -0,0 +1,110 @@ +/* + * RDC321x southbrige driver + * + * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/pci.h> + +#include <asm/rdc321x_defs.h> + +static struct pci_dev *rdc321x_sb_pdev; + +/* + * Unlocked PCI configuration space accessors + */ +int rdc321x_pci_read(int reg, u32 *val) +{ + int err; + + err = pci_read_config_dword(rdc321x_sb_pdev, reg, val); + if (err) + return err; + + return err; +} +EXPORT_SYMBOL(rdc321x_pci_read); + +int rdc321x_pci_write(int reg, u32 val) +{ + int err; + + err = pci_write_config_dword(rdc321x_sb_pdev, reg, val); + if (err) + return err; + + return err; +} +EXPORT_SYMBOL(rdc321x_pci_write); + +static struct platform_device rdc321x_wdt_device = { + .name = "rdc321x-wdt" +}; + +static struct platform_device rdc321x_gpio_device = { + .name = "rdc321x-gpio" +}; + +static int __devinit rdc321x_sb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "failed to enable device\n"); + return err; + } + + rdc321x_sb_pdev = pdev; + + err = platform_device_register(&rdc321x_wdt_device); + if (err) { + dev_err(&pdev->dev, "failed to register watchdog\n"); + return err; + } + + err = platform_device_register(&rdc321x_gpio_device); + if (err) { + dev_err(&pdev->dev, "failed to register gpiochip\n"); + return err; + } + dev_info(&rdc321x_sb_pdev->dev, "RDC321x southhridge registered\n"); + + return err; +} + +static struct pci_device_id rdc321x_sb_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, + {} +}; + +static struct pci_driver rdc321x_sb_driver = { + .name = "RDC3210 Southbridge", + .id_table = rdc321x_sb_table, + .probe = rdc321x_sb_probe +}; + +static int __init rdc321x_sb_init(void) +{ + return pci_register_driver(&rdc321x_sb_driver); +} + +device_initcall(rdc321x_sb_init); diff --git a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/platform.c b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/platform.c index 3c2cec721..d0a8578ef 100644 --- a/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/platform.c +++ b/target/linux/rdc/files-2.6.30/arch/x86/mach-rdc321x/platform.c @@ -95,13 +95,6 @@ static struct platform_device rdc321x_leds = { } }; -/* Watchdog */ -static struct platform_device rdc321x_wdt = { - .name = "rdc321x-wdt", - .id = -1, - .num_resources = 0, -}; - /* Button */ static struct gpio_keys_button rdc321x_gpio_btn[] = { { @@ -128,7 +121,6 @@ static struct platform_device rdc321x_button = { static struct platform_device *rdc321x_devs[] = { &rdc_flash_device, &rdc321x_leds, - &rdc321x_wdt, &rdc321x_button, }; |