From aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 22 Jan 2009 13:55:32 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green fix-stray-endmenu.patch Signed-off-by: Andy Green --- drivers/gpio/Kconfig | 15 ++- drivers/gpio/Makefile | 1 + drivers/gpio/gpiolib.c | 4 +- drivers/gpio/max7301.c | 6 +- drivers/gpio/max732x.c | 6 +- drivers/gpio/mcp23s08.c | 6 +- drivers/gpio/pca953x.c | 18 ++-- drivers/gpio/pcf857x.c | 12 ++- drivers/gpio/twl4030-gpio.c | 54 +++++----- drivers/gpio/xilinx_gpio.c | 235 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 304 insertions(+), 53 deletions(-) create mode 100644 drivers/gpio/xilinx_gpio.c (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7f2ee27fe76..3d2565441b3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -65,6 +65,14 @@ config GPIO_SYSFS # put expanders in the right section, in alphabetical order +comment "Memory mapped GPIO expanders:" + +config GPIO_XILINX + bool "Xilinx GPIO support" + depends on PPC_OF + help + Say yes here to support the Xilinx FPGA GPIO device + comment "I2C GPIO expanders:" config GPIO_MAX732X @@ -87,7 +95,7 @@ config GPIO_MAX732X number for these GPIOs. config GPIO_PCA953X - tristate "PCA953x, PCA955x, and MAX7310 I/O ports" + tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports" depends on I2C help Say yes here to provide access to several register-oriented @@ -96,9 +104,10 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 - 8 bits: max7310, pca9534, pca9538, pca9554, pca9557 + 8 bits: max7310, pca9534, pca9538, pca9554, pca9557, + tca6408 - 16 bits: pca9535, pca9539, pca9555 + 16 bits: pca9535, pca9539, pca9555, tca6416 This driver can also be built as a module. If so, the module will be called pca953x. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 6aafdeb9ad0..49ac64e515e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o obj-$(CONFIG_GPIO_PCA953X) += pca953x.o obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o +obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e33adc4dc05..7d6f55b0e79 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1133,7 +1133,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) continue; is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-12s) %s %s", + seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", gpio, gdesc->label, is_out ? "out" : "in ", chip->get @@ -1212,7 +1212,7 @@ static int gpiolib_show(struct seq_file *s, void *unused) if (dev) seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus", - dev->bus_id); + dev_name(dev)); if (chip->label) seq_printf(s, ", %s", chip->label); if (chip->can_sleep) diff --git a/drivers/gpio/max7301.c b/drivers/gpio/max7301.c index 8b24d784db9..3e7f4e06386 100644 --- a/drivers/gpio/max7301.c +++ b/drivers/gpio/max7301.c @@ -217,8 +217,10 @@ static int __devinit max7301_probe(struct spi_device *spi) int i, ret; pdata = spi->dev.platform_data; - if (!pdata || !pdata->base) - return -ENODEV; + if (!pdata || !pdata->base) { + dev_dbg(&spi->dev, "incorrect or missing platform data\n"); + return -EINVAL; + } /* * bits_per_word cannot be configured in platform data diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c index 55ae9a41897..f7868243af8 100644 --- a/drivers/gpio/max732x.c +++ b/drivers/gpio/max732x.c @@ -267,8 +267,10 @@ static int __devinit max732x_probe(struct i2c_client *client, int ret, nr_port; pdata = client->dev.platform_data; - if (pdata == NULL) - return -ENODEV; + if (pdata == NULL) { + dev_dbg(&client->dev, "no platform data\n"); + return -EINVAL; + } chip = kzalloc(sizeof(struct max732x_chip), GFP_KERNEL); if (chip == NULL) diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c index 89c1d222e9d..f6fae0e50e6 100644 --- a/drivers/gpio/mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -310,8 +310,10 @@ static int mcp23s08_probe(struct spi_device *spi) unsigned base; pdata = spi->dev.platform_data; - if (!pdata || !gpio_is_valid(pdata->base)) - return -ENODEV; + if (!pdata || !gpio_is_valid(pdata->base)) { + dev_dbg(&spi->dev, "invalid or missing platform data\n"); + return -EINVAL; + } for (addr = 0; addr < 4; addr++) { if (!pdata->chip[addr].is_present) diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 9ceeb89f132..8dc0164bd51 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -33,7 +33,12 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9554", 8, }, { "pca9555", 16, }, { "pca9557", 8, }, + { "max7310", 8, }, + { "pca6107", 8, }, + { "tca6408", 8, }, + { "tca6416", 16, }, + /* NYET: { "tca6424", 24, }, */ { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); @@ -47,9 +52,6 @@ struct pca953x_chip { struct gpio_chip gpio_chip; }; -/* NOTE: we can't currently rely on fault codes to come from SMBus - * calls, so we map all errors to EIO here and return zero otherwise. - */ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) { int ret; @@ -61,7 +63,7 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) if (ret < 0) { dev_err(&chip->client->dev, "failed writing register\n"); - return -EIO; + return ret; } return 0; @@ -78,7 +80,7 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); - return -EIO; + return ret; } *val = (uint16_t)ret; @@ -200,8 +202,10 @@ static int __devinit pca953x_probe(struct i2c_client *client, int ret; pdata = client->dev.platform_data; - if (pdata == NULL) - return -ENODEV; + if (pdata == NULL) { + dev_dbg(&client->dev, "no platform data\n"); + return -EINVAL; + } chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c index 4bc2070dd4a..9525724be73 100644 --- a/drivers/gpio/pcf857x.c +++ b/drivers/gpio/pcf857x.c @@ -188,8 +188,10 @@ static int pcf857x_probe(struct i2c_client *client, int status; pdata = client->dev.platform_data; - if (!pdata) - return -ENODEV; + if (!pdata) { + dev_dbg(&client->dev, "no platform data\n"); + return -EINVAL; + } /* Allocate, initialize, and register this gpio_chip. */ gpio = kzalloc(sizeof *gpio, GFP_KERNEL); @@ -248,8 +250,10 @@ static int pcf857x_probe(struct i2c_client *client, else status = i2c_read_le16(client); - } else - status = -ENODEV; + } else { + dev_dbg(&client->dev, "unsupported number of gpios\n"); + status = -EINVAL; + } if (status < 0) goto fail; diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c index 37d3eec8730..afad1479214 100644 --- a/drivers/gpio/twl4030-gpio.c +++ b/drivers/gpio/twl4030-gpio.c @@ -202,37 +202,6 @@ static int twl4030_get_gpio_datain(int gpio) return ret; } -/* - * Configure debounce timing value for a GPIO pin on TWL4030 - */ -int twl4030_set_gpio_debounce(int gpio, int enable) -{ - u8 d_bnk = gpio >> 3; - u8 d_msk = BIT(gpio & 0x7); - u8 reg = 0; - u8 base = 0; - int ret = 0; - - if (unlikely((gpio >= TWL4030_GPIO_MAX) - || !(gpio_usage_count & BIT(gpio)))) - return -EPERM; - - base = REG_GPIO_DEBEN1 + d_bnk; - mutex_lock(&gpio_lock); - ret = gpio_twl4030_read(base); - if (ret >= 0) { - if (enable) - reg = ret | d_msk; - else - reg = ret & ~d_msk; - - ret = gpio_twl4030_write(base, reg); - } - mutex_unlock(&gpio_lock); - return ret; -} -EXPORT_SYMBOL(twl4030_set_gpio_debounce); - /*----------------------------------------------------------------------*/ static int twl_request(struct gpio_chip *chip, unsigned offset) @@ -405,6 +374,23 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) REG_GPIOPUPDCTR1, 5); } +static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) +{ + u8 message[4]; + + /* 30 msec of debouncing is always used for MMC card detect, + * and is optional for everything else. + */ + message[1] = (debounce & 0xff) | (mmc_cd & 0x03); + debounce >>= 8; + message[2] = (debounce & 0xff); + debounce >>= 8; + message[3] = (debounce & 0x03); + + return twl4030_i2c_write(TWL4030_MODULE_GPIO, message, + REG_GPIO_DEBEN1, 3); +} + static int gpio_twl4030_remove(struct platform_device *pdev); static int __devinit gpio_twl4030_probe(struct platform_device *pdev) @@ -439,6 +425,12 @@ no_irqs: pdata->pullups, pdata->pulldowns, ret); + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, + ret); + twl_gpiochip.base = pdata->gpio_base; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c new file mode 100644 index 00000000000..3c1177abebd --- /dev/null +++ b/drivers/gpio/xilinx_gpio.c @@ -0,0 +1,235 @@ +/* + * Xilinx gpio driver + * + * Copyright 2008 Xilinx, Inc. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Register Offset Definitions */ +#define XGPIO_DATA_OFFSET (0x0) /* Data register */ +#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ + +struct xgpio_instance { + struct of_mm_gpio_chip mmchip; + u32 gpio_state; /* GPIO state shadow register */ + u32 gpio_dir; /* GPIO direction shadow register */ + spinlock_t gpio_lock; /* Lock used for synchronization */ +}; + +/** + * xgpio_get - Read the specified signal of the GPIO device. + * @gc: Pointer to gpio_chip device structure. + * @gpio: GPIO signal number. + * + * This function reads the specified signal of the GPIO device. It returns 0 if + * the signal clear, 1 if signal is set or negative value on error. + */ +static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + + return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1; +} + +/** + * xgpio_set - Write the specified signal of the GPIO device. + * @gc: Pointer to gpio_chip device structure. + * @gpio: GPIO signal number. + * @val: Value to be written to specified signal. + * + * This function writes the specified value in to the specified signal of the + * GPIO device. + */ +static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + unsigned long flags; + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + /* Write to GPIO signal and set its direction to output */ + if (val) + chip->gpio_state |= 1 << gpio; + else + chip->gpio_state &= ~(1 << gpio); + out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); +} + +/** + * xgpio_dir_in - Set the direction of the specified GPIO signal as input. + * @gc: Pointer to gpio_chip device structure. + * @gpio: GPIO signal number. + * + * This function sets the direction of specified GPIO signal as input. + * It returns 0 if direction of GPIO signals is set as input otherwise it + * returns negative error value. + */ +static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + unsigned long flags; + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + /* Set the GPIO bit in shadow register and set direction as input */ + chip->gpio_dir |= (1 << gpio); + out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + return 0; +} + +/** + * xgpio_dir_out - Set the direction of the specified GPIO signal as output. + * @gc: Pointer to gpio_chip device structure. + * @gpio: GPIO signal number. + * @val: Value to be written to specified signal. + * + * This function sets the direction of specified GPIO signal as output. If all + * GPIO signals of GPIO chip is configured as input then it returns + * error otherwise it returns 0. + */ +static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + unsigned long flags; + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + /* Write state of GPIO signal */ + if (val) + chip->gpio_state |= 1 << gpio; + else + chip->gpio_state &= ~(1 << gpio); + out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); + + /* Clear the GPIO bit in shadow register and set direction as output */ + chip->gpio_dir &= (~(1 << gpio)); + out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + return 0; +} + +/** + * xgpio_save_regs - Set initial values of GPIO pins + * @mm_gc: pointer to memory mapped GPIO chip structure + */ +static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) +{ + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + + out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); + out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); +} + +/** + * xgpio_of_probe - Probe method for the GPIO device. + * @np: pointer to device tree node + * + * This function probes the GPIO device in the device tree. It initializes the + * driver data structure. It returns 0, if the driver is bound to the GPIO + * device, or a negative value if there is an error. + */ +static int __devinit xgpio_of_probe(struct device_node *np) +{ + struct xgpio_instance *chip; + struct of_gpio_chip *ofchip; + int status = 0; + const u32 *tree_info; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + ofchip = &chip->mmchip.of_gc; + + /* Update GPIO state shadow register with default value */ + tree_info = of_get_property(np, "xlnx,dout-default", NULL); + if (tree_info) + chip->gpio_state = *tree_info; + + /* Update GPIO direction shadow register with default value */ + chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */ + tree_info = of_get_property(np, "xlnx,tri-default", NULL); + if (tree_info) + chip->gpio_dir = *tree_info; + + /* Check device node and parent device node for device width */ + ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */ + tree_info = of_get_property(np, "xlnx,gpio-width", NULL); + if (!tree_info) + tree_info = of_get_property(np->parent, + "xlnx,gpio-width", NULL); + if (tree_info) + ofchip->gc.ngpio = *tree_info; + + spin_lock_init(&chip->gpio_lock); + + ofchip->gpio_cells = 2; + ofchip->gc.direction_input = xgpio_dir_in; + ofchip->gc.direction_output = xgpio_dir_out; + ofchip->gc.get = xgpio_get; + ofchip->gc.set = xgpio_set; + + chip->mmchip.save_regs = xgpio_save_regs; + + /* Call the OF gpio helper to setup and register the GPIO device */ + status = of_mm_gpiochip_add(np, &chip->mmchip); + if (status) { + kfree(chip); + pr_err("%s: error in probe function with status %d\n", + np->full_name, status); + return status; + } + pr_info("XGpio: %s: registered\n", np->full_name); + return 0; +} + +static struct of_device_id xgpio_of_match[] __devinitdata = { + { .compatible = "xlnx,xps-gpio-1.00.a", }, + { /* end of list */ }, +}; + +static int __init xgpio_init(void) +{ + struct device_node *np; + + for_each_matching_node(np, xgpio_of_match) + xgpio_of_probe(np); + + return 0; +} + +/* Make sure we get initialized before anyone else tries to use us */ +subsys_initcall(xgpio_init); +/* No exit call at the moment as we cannot unregister of GPIO chips */ + +MODULE_AUTHOR("Xilinx, Inc."); +MODULE_DESCRIPTION("Xilinx GPIO driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3