diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 09:35:29 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 09:35:29 -0800 |
commit | 4c8c225abf972ce422c241579ce1d4d27eaeb166 (patch) | |
tree | 77bc67defdc53c494b20632e66b82ce9be3c06af | |
parent | 3eb05225ee8efb81fe50558f5f9d94e7477ade8f (diff) | |
parent | 9170100ee46402af6d318134525c728027318d67 (diff) | |
download | op-kernel-dev-4c8c225abf972ce422c241579ce1d4d27eaeb166.zip op-kernel-dev-4c8c225abf972ce422c241579ce1d4d27eaeb166.tar.gz |
Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux
Pull GPIO changes from Grant Likely:
"This branch contains the usual set of individual driver improvements
and bug fixes, as well as updates to the core code. The more notable
changes include:
- Internally add new API for referencing GPIOs by gpio_desc instead
of number. Eventually this will become a public API
- ACPI GPIO binding support"
* tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux: (33 commits)
arm64: select ARCH_WANT_OPTIONAL_GPIOLIB
gpio: em: Use irq_domain_add_simple() to fix runtime error
gpio: using common order: let 'static const' instead of 'const static'
gpio/vt8500: memory cleanup missing
gpiolib: Fix locking on gpio debugfs files
gpiolib: let gpio_chip reference its descriptors
gpiolib: use descriptors internally
gpiolib: use gpio_chips list in gpiochip_find_base
gpiolib: use gpio_chips list in sysfs ops
gpiolib: use gpio_chips list in gpiochip_find
gpiolib: use gpio_chips list in gpiolib_sysfs_init
gpiolib: link all gpio_chips using a list
gpio/langwell: cleanup driver
gpio/langwell: Add Cloverview ids to pci device table
gpio/lynxpoint: add chipset gpio driver.
gpiolib: add missing braces in gpio_direction_show
gpiolib-acpi: Fix error checks in interrupt requesting
gpio: mpc8xxx: don't set IRQ_TYPE_NONE when creating irq mapping
gpiolib: remove gpiochip_reserve()
arm: pxa: tosa: do not use gpiochip_reserve()
...
-rw-r--r-- | arch/arm/mach-pxa/tosa.c | 6 | ||||
-rw-r--r-- | arch/arm64/Kconfig | 3 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 11 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 4 | ||||
-rw-r--r-- | drivers/gpio/gpio-em.c | 3 | ||||
-rw-r--r-- | drivers/gpio/gpio-langwell.c | 53 | ||||
-rw-r--r-- | drivers/gpio/gpio-lynxpoint.c | 469 | ||||
-rw-r--r-- | drivers/gpio/gpio-mpc8xxx.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-mxs.c | 31 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 6 | ||||
-rw-r--r-- | drivers/gpio/gpio-pca953x.c | 380 | ||||
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-pxa.c | 7 | ||||
-rw-r--r-- | drivers/gpio/gpio-twl4030.c | 176 | ||||
-rw-r--r-- | drivers/gpio/gpio-vt8500.c | 65 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 87 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 759 | ||||
-rw-r--r-- | include/asm-generic/gpio.h | 86 | ||||
-rw-r--r-- | include/linux/acpi_gpio.h | 4 | ||||
-rw-r--r-- | include/linux/gpio.h | 28 |
20 files changed, 1510 insertions, 671 deletions
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 9e7998d..3d91d2e 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd) static void __init tosa_init(void) { - int dummy; - pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config)); pxa_set_ffuart_info(NULL); @@ -947,10 +945,6 @@ static void __init tosa_init(void) /* enable batt_fault */ PMCR = 0x01; - dummy = gpiochip_reserve(TOSA_SCOOP_GPIO_BASE, 12); - dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12); - dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16); - pxa_set_mci_info(&tosa_mci_platform_data); pxa_set_ficp_info(&tosa_ficp_platform_data); pxa_set_i2c_info(NULL); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f532ce5..fd70a68 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1,6 +1,7 @@ config ARM64 def_bool y select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE + select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARCH_WANT_FRAME_POINTERS select ARM_AMBA @@ -93,7 +94,7 @@ config IOMMU_HELPER def_bool SWIOTLB config GENERIC_GPIO - def_bool y + bool source "init/Kconfig" diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 74e17f1..93aaadf 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB Selecting this from the architecture code will cause the gpiolib code to always get built in. +config GPIO_DEVRES + def_bool y + depends on HAS_IOMEM menuconfig GPIOLIB @@ -298,6 +301,14 @@ config GPIO_GE_FPGA and write pin state) for GPIO implemented in a number of GE single board computers. +config GPIO_LYNXPOINT + bool "Intel Lynxpoint GPIO support" + depends on ACPI + select IRQ_DOMAIN + help + driver for GPIO functionality on Intel Lynxpoint PCH chipset + Requires ACPI device enumeration code to set up a platform device. + comment "I2C GPIO expanders:" config GPIO_ARIZONA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 6dbcba2..22e07bc 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -2,7 +2,8 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG -obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o +obj-$(CONFIG_GPIO_DEVRES) += devres.o +obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o @@ -30,6 +31,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o +obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index bdc8302..deca78f 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -299,8 +299,9 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_set_type = em_gio_irq_set_type; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; - p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, pdata->number_of_pins, + pdata->irq_base, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index e77b2b3..634c3d3 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -71,10 +71,12 @@ struct lnw_gpio { struct irq_domain *domain; }; +#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip) + static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, enum GPIO_REG reg_type) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); unsigned nreg = chip->ngpio / 32; u8 reg = offset / 32; void __iomem *ptr; @@ -86,7 +88,7 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, enum GPIO_REG reg_type) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); unsigned nreg = chip->ngpio / 32; u8 reg = offset / 16; void __iomem *ptr; @@ -130,7 +132,7 @@ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); void __iomem *gpdr = gpio_reg(chip, offset, GPDR); u32 value; unsigned long flags; @@ -153,7 +155,7 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int lnw_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); void __iomem *gpdr = gpio_reg(chip, offset, GPDR); unsigned long flags; @@ -176,7 +178,7 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip, static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); return irq_create_mapping(lnw->domain, offset); } @@ -234,6 +236,8 @@ static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 }, { 0, } }; MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); @@ -299,17 +303,6 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; -#ifdef CONFIG_PM -static int lnw_gpio_runtime_resume(struct device *dev) -{ - return 0; -} - -static int lnw_gpio_runtime_suspend(struct device *dev) -{ - return 0; -} - static int lnw_gpio_runtime_idle(struct device *dev) { int err = pm_schedule_suspend(dev, 500); @@ -320,16 +313,8 @@ static int lnw_gpio_runtime_idle(struct device *dev) return -EBUSY; } -#else -#define lnw_gpio_runtime_suspend NULL -#define lnw_gpio_runtime_resume NULL -#define lnw_gpio_runtime_idle NULL -#endif - static const struct dev_pm_ops lnw_gpio_pm_ops = { - .runtime_suspend = lnw_gpio_runtime_suspend, - .runtime_resume = lnw_gpio_runtime_resume, - .runtime_idle = lnw_gpio_runtime_idle, + SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle) }; static int lnw_gpio_probe(struct pci_dev *pdev, @@ -349,7 +334,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, retval = pci_request_regions(pdev, "langwell_gpio"); if (retval) { dev_err(&pdev->dev, "error requesting resources\n"); - goto err2; + goto err_pci_req_region; } /* get the gpio_base from bar1 */ start = pci_resource_start(pdev, 1); @@ -358,7 +343,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, if (!base) { dev_err(&pdev->dev, "error mapping bar1\n"); retval = -EFAULT; - goto err3; + goto err_ioremap; } gpio_base = *((u32 *)base + 1); /* release the IO mapping, since we already get the info from bar1 */ @@ -370,21 +355,21 @@ static int lnw_gpio_probe(struct pci_dev *pdev, if (!base) { dev_err(&pdev->dev, "error mapping bar0\n"); retval = -EFAULT; - goto err3; + goto err_ioremap; } - lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL); + lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL); if (!lnw) { dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); retval = -ENOMEM; - goto err3; + goto err_ioremap; } lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, &lnw_gpio_irq_ops, lnw); if (!lnw->domain) { retval = -ENOMEM; - goto err3; + goto err_ioremap; } lnw->reg_base = base; @@ -403,7 +388,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, retval = gpiochip_add(&lnw->chip); if (retval) { dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); - goto err3; + goto err_ioremap; } lnw_irq_init_hw(lnw); @@ -418,9 +403,9 @@ static int lnw_gpio_probe(struct pci_dev *pdev, return 0; -err3: +err_ioremap: pci_release_regions(pdev); -err2: +err_pci_req_region: pci_disable_device(pdev); return retval; } diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c new file mode 100644 index 0000000..3472b05 --- /dev/null +++ b/drivers/gpio/gpio-lynxpoint.c @@ -0,0 +1,469 @@ +/* + * GPIO controller driver for Intel Lynxpoint PCH chipset> + * Copyright (c) 2012, Intel Corporation. + * + * Author: Mathias Nyman <mathias.nyman@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/irqdomain.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +/* LynxPoint chipset has support for 94 gpio pins */ + +#define LP_NUM_GPIO 94 + +/* Bitmapped register offsets */ +#define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ +#define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ +#define LP_INT_STAT 0x80 +#define LP_INT_ENABLE 0x90 + +/* Each pin has two 32 bit config registers, starting at 0x100 */ +#define LP_CONFIG1 0x100 +#define LP_CONFIG2 0x104 + +/* LP_CONFIG1 reg bits */ +#define OUT_LVL_BIT BIT(31) +#define IN_LVL_BIT BIT(30) +#define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ +#define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ +#define DIR_BIT BIT(2) /* 0: Output, 1: Input */ +#define USE_SEL_BIT BIT(0) /* 0: Native, 1: GPIO */ + +/* LP_CONFIG2 reg bits */ +#define GPINDIS_BIT BIT(2) /* disable input sensing */ +#define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */ + +struct lp_gpio { + struct gpio_chip chip; + struct irq_domain *domain; + struct platform_device *pdev; + spinlock_t lock; + unsigned long reg_base; +}; + +/* + * Lynxpoint gpios are controlled through both bitmapped registers and + * per gpio specific registers. The bitmapped registers are in chunks of + * 3 x 32bit registers to cover all 94 gpios + * + * per gpio specific registers consist of two 32bit registers per gpio + * (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of + * 188 config registes. + * + * A simplified view of the register layout look like this: + * + * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) + * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 + * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 + * ... + * LP_INT_ENABLE[31:0] ... + * LP_INT_ENABLE[63:31] ... + * LP_INT_ENABLE[94:64] ... + * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) + * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 + * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 + * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 + * LP2_CONFIG1 (gpio 2) ... + * LP2_CONFIG2 (gpio 2) ... + * ... + * LP94_CONFIG1 (gpio 94) ... + * LP94_CONFIG2 (gpio 94) ... + */ + +static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset, + int reg) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + int reg_offset; + + if (reg == LP_CONFIG1 || reg == LP_CONFIG2) + /* per gpio specific config registers */ + reg_offset = offset * 8; + else + /* bitmapped registers */ + reg_offset = (offset / 32) * 4; + + return lg->reg_base + reg + reg_offset; +} + +static int lp_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); + unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED); + + pm_runtime_get(&lg->pdev->dev); /* should we put if failed */ + + /* Fail if BIOS reserved pin for ACPI use */ + if (!(inl(acpi_use) & BIT(offset % 32))) { + dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset); + return -EBUSY; + } + /* Fail if pin is in alternate function mode (not GPIO mode) */ + if (!(inl(reg) & USE_SEL_BIT)) + return -ENODEV; + + /* enable input sensing */ + outl(inl(conf2) & ~GPINDIS_BIT, conf2); + + + return 0; +} + +static void lp_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); + + /* disable input sensing */ + outl(inl(conf2) | GPINDIS_BIT, conf2); + + pm_runtime_put(&lg->pdev->dev); +} + +static int lp_irq_type(struct irq_data *d, unsigned type) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + u32 hwirq = irqd_to_hwirq(d); + unsigned long flags; + u32 value; + unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); + + if (hwirq >= lg->chip.ngpio) + return -EINVAL; + + spin_lock_irqsave(&lg->lock, flags); + value = inl(reg); + + /* set both TRIG_SEL and INV bits to 0 for rising edge */ + if (type & IRQ_TYPE_EDGE_RISING) + value &= ~(TRIG_SEL_BIT | INT_INV_BIT); + + /* TRIG_SEL bit 0, INV bit 1 for falling edge */ + if (type & IRQ_TYPE_EDGE_FALLING) + value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; + + /* TRIG_SEL bit 1, INV bit 0 for level low */ + if (type & IRQ_TYPE_LEVEL_LOW) + value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; + + /* TRIG_SEL bit 1, INV bit 1 for level high */ + if (type & IRQ_TYPE_LEVEL_HIGH) + value |= TRIG_SEL_BIT | INT_INV_BIT; + + outl(value, reg); + spin_unlock_irqrestore(&lg->lock, flags); + + return 0; +} + +static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + return inl(reg) & IN_LVL_BIT; +} + +static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + + if (value) + outl(inl(reg) | OUT_LVL_BIT, reg); + else + outl(inl(reg) & ~OUT_LVL_BIT, reg); + + spin_unlock_irqrestore(&lg->lock, flags); +} + +static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) | DIR_BIT, reg); + spin_unlock_irqrestore(&lg->lock, flags); + + return 0; +} + +static int lp_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long flags; + + lp_gpio_set(chip, offset, value); + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) & ~DIR_BIT, reg); + spin_unlock_irqrestore(&lg->lock, flags); + + return 0; +} + +static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + return irq_create_mapping(lg->domain, offset); +} + +static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct lp_gpio *lg = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, pin, mask; + unsigned long reg, pending; + unsigned virq; + + /* check from GPIO controller which pin triggered the interrupt */ + for (base = 0; base < lg->chip.ngpio; base += 32) { + reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); + + while ((pending = inl(reg))) { + pin = __ffs(pending); + mask = BIT(pin); + /* Clear before handling so we don't lose an edge */ + outl(mask, reg); + virq = irq_find_mapping(lg->domain, base + pin); + generic_handle_irq(virq); + } + } + chip->irq_eoi(data); +} + +static void lp_irq_unmask(struct irq_data *d) +{ +} + +static void lp_irq_mask(struct irq_data *d) +{ +} + +static void lp_irq_enable(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + u32 hwirq = irqd_to_hwirq(d); + unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) | BIT(hwirq % 32), reg); + spin_unlock_irqrestore(&lg->lock, flags); +} + +static void lp_irq_disable(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + u32 hwirq = irqd_to_hwirq(d); + unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) & ~BIT(hwirq % 32), reg); + spin_unlock_irqrestore(&lg->lock, flags); +} + +static struct irq_chip lp_irqchip = { + .name = "LP-GPIO", + .irq_mask = lp_irq_mask, + .irq_unmask = lp_irq_unmask, + .irq_enable = lp_irq_enable, + .irq_disable = lp_irq_disable, + .irq_set_type = lp_irq_type, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static void lp_gpio_irq_init_hw(struct lp_gpio *lg) +{ + unsigned long reg; + unsigned base; + + for (base = 0; base < lg->chip.ngpio; base += 32) { + /* disable gpio pin interrupts */ + reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); + outl(0, reg); + /* Clear interrupt status register */ + reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); + outl(0xffffffff, reg); + } +} + +static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct lp_gpio *lg = d->host_data; + + irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq, + "demux"); + irq_set_chip_data(virq, lg); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops lp_gpio_irq_ops = { + .map = lp_gpio_irq_map, +}; + +static int lp_gpio_probe(struct platform_device *pdev) +{ + struct lp_gpio *lg; + struct gpio_chip *gc; + struct resource *io_rc, *irq_rc; + struct device *dev = &pdev->dev; + unsigned long reg_len; + unsigned hwirq; + int ret = -ENODEV; + + lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL); + if (!lg) { + dev_err(dev, "can't allocate lp_gpio chip data\n"); + return -ENOMEM; + } + + lg->pdev = pdev; + platform_set_drvdata(pdev, lg); + + io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); + irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!io_rc) { + dev_err(dev, "missing IO resources\n"); + return -EINVAL; + } + + lg->reg_base = io_rc->start; + reg_len = resource_size(io_rc); + + if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) { + dev_err(dev, "failed requesting IO region 0x%x\n", + (unsigned int)lg->reg_base); + return -EBUSY; + } + + spin_lock_init(&lg->lock); + + gc = &lg->chip; + gc->label = dev_name(dev); + gc->owner = THIS_MODULE; + gc->request = lp_gpio_request; + gc->free = lp_gpio_free; + gc->direction_input = lp_gpio_direction_input; + gc->direction_output = lp_gpio_direction_output; + gc->get = lp_gpio_get; + gc->set = lp_gpio_set; + gc->base = -1; + gc->ngpio = LP_NUM_GPIO; + gc->can_sleep = 0; + gc->dev = dev; + + /* set up interrupts */ + if (irq_rc && irq_rc->start) { + hwirq = irq_rc->start; + gc->to_irq = lp_gpio_to_irq; + + lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO, + &lp_gpio_irq_ops, lg); + if (!lg->domain) + return -ENXIO; + + lp_gpio_irq_init_hw(lg); + + irq_set_handler_data(hwirq, lg); + irq_set_chained_handler(hwirq, lp_gpio_irq_handler); + } + + ret = gpiochip_add(gc); + if (ret) { + dev_err(dev, "failed adding lp-gpio chip\n"); + return ret; + } + pm_runtime_enable(dev); + + return 0; +} + +static int lp_gpio_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int lp_gpio_runtime_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops lp_gpio_pm_ops = { + .runtime_suspend = lp_gpio_runtime_suspend, + .runtime_resume = lp_gpio_runtime_resume, +}; + +static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { + { "INT33C7", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); + +static int lp_gpio_remove(struct platform_device *pdev) +{ + struct lp_gpio *lg = platform_get_drvdata(pdev); + int err; + err = gpiochip_remove(&lg->chip); + if (err) + dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver lp_gpio_driver = { + .probe = lp_gpio_probe, + .remove = lp_gpio_remove, + .driver = { + .name = "lp_gpio", + .owner = THIS_MODULE, + .pm = &lp_gpio_pm_ops, + .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), + }, +}; + +static int __init lp_gpio_init(void) +{ + return platform_driver_register(&lp_gpio_driver); +} + +subsys_initcall(lp_gpio_init); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 9ae29cc..a0b33a2 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -292,7 +292,6 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); - irq_set_irq_type(virq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 45d97c4..25000b0 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -66,6 +66,7 @@ struct mxs_gpio_port { struct irq_domain *domain; struct bgpio_chip bgc; enum mxs_gpio_id devid; + u32 both_edges; }; static inline int is_imx23_gpio(struct mxs_gpio_port *port) @@ -82,13 +83,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port) static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) { + u32 val; u32 pin_mask = 1 << d->hwirq; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxs_gpio_port *port = gc->private; void __iomem *pin_addr; int edge; + port->both_edges &= ~pin_mask; switch (type) { + case IRQ_TYPE_EDGE_BOTH: + val = gpio_get_value(port->bgc.gc.base + d->hwirq); + if (val) + edge = GPIO_INT_FALL_EDGE; + else + edge = GPIO_INT_RISE_EDGE; + port->both_edges |= pin_mask; + break; case IRQ_TYPE_EDGE_RISING: edge = GPIO_INT_RISE_EDGE; break; @@ -125,6 +136,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) return 0; } +static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio) +{ + u32 bit, val, edge; + void __iomem *pin_addr; + + bit = 1 << gpio; + + pin_addr = port->base + PINCTRL_IRQPOL(port); + val = readl(pin_addr); + edge = val & bit; + + if (edge) + writel(bit, pin_addr + MXS_CLR); + else + writel(bit, pin_addr + MXS_SET); +} + /* MXS has one interrupt *per* gpio port */ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) { @@ -138,6 +166,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) while (irq_stat != 0) { int irqoffset = fls(irq_stat) - 1; + if (port->both_edges & (1 << irqoffset)) + mxs_flip_edge(port, irqoffset); + generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); irq_stat &= ~(1 << irqoffset); } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f1fbedb2..159f5c5 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1476,19 +1476,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .fallingdetect = OMAP4_GPIO_FALLINGDETECT, }; -const static struct omap_gpio_platform_data omap2_pdata = { +static const struct omap_gpio_platform_data omap2_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = false, }; -const static struct omap_gpio_platform_data omap3_pdata = { +static const struct omap_gpio_platform_data omap3_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = true, }; -const static struct omap_gpio_platform_data omap4_pdata = { +static const struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cc102d2..2405946 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -46,6 +46,7 @@ #define PCA957X_TYPE 0x2000 static const struct i2c_device_id pca953x_id[] = { + { "pca9505", 40 | PCA953X_TYPE | PCA_INT, }, { "pca9534", 8 | PCA953X_TYPE | PCA_INT, }, { "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, { "pca9536", 4 | PCA953X_TYPE, }, @@ -71,19 +72,23 @@ static const struct i2c_device_id pca953x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca953x_id); +#define MAX_BANK 5 +#define BANK_SZ 8 + +#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ) + struct pca953x_chip { unsigned gpio_start; - u32 reg_output; - u32 reg_direction; + u8 reg_output[MAX_BANK]; + u8 reg_direction[MAX_BANK]; struct mutex i2c_lock; #ifdef CONFIG_GPIO_PCA953X_IRQ struct mutex irq_lock; - u32 irq_mask; - u32 irq_stat; - u32 irq_trig_raise; - u32 irq_trig_fall; - int irq_base; + u8 irq_mask[MAX_BANK]; + u8 irq_stat[MAX_BANK]; + u8 irq_trig_raise[MAX_BANK]; + u8 irq_trig_fall[MAX_BANK]; struct irq_domain *domain; #endif @@ -93,33 +98,69 @@ struct pca953x_chip { int chip_type; }; -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, + int off) +{ + int ret; + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + int offset = off / BANK_SZ; + + ret = i2c_smbus_read_byte_data(chip->client, + (reg << bank_shift) + offset); + *val = ret; + + if (ret < 0) { + dev_err(&chip->client->dev, "failed reading register\n"); + return ret; + } + + return 0; +} + +static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val, + int off) +{ + int ret = 0; + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + int offset = off / BANK_SZ; + + ret = i2c_smbus_write_byte_data(chip->client, + (reg << bank_shift) + offset, val); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed writing register\n"); + return ret; + } + + return 0; +} + +static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) { int ret = 0; if (chip->gpio_chip.ngpio <= 8) - ret = i2c_smbus_write_byte_data(chip->client, reg, val); - else if (chip->gpio_chip.ngpio == 24) { - cpu_to_le32s(&val); + ret = i2c_smbus_write_byte_data(chip->client, reg, *val); + else if (chip->gpio_chip.ngpio >= 24) { + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); ret = i2c_smbus_write_i2c_block_data(chip->client, - (reg << 2) | REG_ADDR_AI, - 3, - (u8 *) &val); + (reg << bank_shift) | REG_ADDR_AI, + NBANK(chip), val); } else { switch (chip->chip_type) { case PCA953X_TYPE: ret = i2c_smbus_write_word_data(chip->client, - reg << 1, val); + reg << 1, (u16) *val); break; case PCA957X_TYPE: ret = i2c_smbus_write_byte_data(chip->client, reg << 1, - val & 0xff); + val[0]); if (ret < 0) break; ret = i2c_smbus_write_byte_data(chip->client, (reg << 1) + 1, - (val & 0xff00) >> 8); + val[1]); break; } } @@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) return 0; } -static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) +static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) { int ret; if (chip->gpio_chip.ngpio <= 8) { ret = i2c_smbus_read_byte_data(chip->client, reg); *val = ret; - } - else if (chip->gpio_chip.ngpio == 24) { - *val = 0; + } else if (chip->gpio_chip.ngpio >= 24) { + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + ret = i2c_smbus_read_i2c_block_data(chip->client, - (reg << 2) | REG_ADDR_AI, - 3, - (u8 *) val); - le32_to_cpus(val); + (reg << bank_shift) | REG_ADDR_AI, + NBANK(chip), val); } else { ret = i2c_smbus_read_word_data(chip->client, reg << 1); - *val = ret; + val[0] = (u16)ret & 0xFF; + val[1] = (u16)ret >> 8; } - if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); return ret; @@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip; - uint reg_val; + u8 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); mutex_lock(&chip->i2c_lock); - reg_val = chip->reg_direction | (1u << off); + reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: @@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) offset = PCA957X_CFG; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_direction = reg_val; + chip->reg_direction[off / BANK_SZ] = reg_val; ret = 0; exit: mutex_unlock(&chip->i2c_lock); @@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip; - uint reg_val; + u8 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); @@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, mutex_lock(&chip->i2c_lock); /* set output level */ if (val) - reg_val = chip->reg_output | (1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + | (1u << (off % BANK_SZ)); else - reg_val = chip->reg_output & ~(1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: @@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, offset = PCA957X_OUT; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_output = reg_val; + chip->reg_output[off / BANK_SZ] = reg_val; /* then direction */ - reg_val = chip->reg_direction & ~(1u << off); + reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: offset = PCA953X_DIRECTION; @@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, offset = PCA957X_CFG; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_direction = reg_val; + chip->reg_direction[off / BANK_SZ] = reg_val; ret = 0; exit: mutex_unlock(&chip->i2c_lock); @@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, ®_val); + ret = pca953x_read_single(chip, offset, ®_val, off); mutex_unlock(&chip->i2c_lock); if (ret < 0) { /* NOTE: diagnostic already emitted; that's all we should @@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip; - u32 reg_val; + u8 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); mutex_lock(&chip->i2c_lock); if (val) - reg_val = chip->reg_output | (1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + | (1u << (off % BANK_SZ)); else - reg_val = chip->reg_output & ~(1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: @@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) offset = PCA957X_OUT; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_output = reg_val; + chip->reg_output[off / BANK_SZ] = reg_val; exit: mutex_unlock(&chip->i2c_lock); } @@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) struct pca953x_chip *chip; chip = container_of(gc, struct pca953x_chip, gpio_chip); - return chip->irq_base + off; + return irq_create_mapping(chip->domain, off); } static void pca953x_irq_mask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << d->hwirq); + chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ)); } static void pca953x_irq_unmask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << d->hwirq; + chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ); } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d) static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 new_irqs; - u32 level; + u8 new_irqs; + int level, i; /* Look for any newly setup interrupt */ - new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; - new_irqs &= ~chip->reg_direction; - - while (new_irqs) { - level = __ffs(new_irqs); - pca953x_gpio_direction_input(&chip->gpio_chip, level); - new_irqs &= ~(1 << level); + for (i = 0; i < NBANK(chip); i++) { + new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i]; + new_irqs &= ~chip->reg_direction[i]; + + while (new_irqs) { + level = __ffs(new_irqs); + pca953x_gpio_direction_input(&chip->gpio_chip, + level + (BANK_SZ * i)); + new_irqs &= ~(1 << level); + } } mutex_unlock(&chip->irq_lock); @@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 mask = 1 << d->hwirq; + int bank_nb = d->hwirq / BANK_SZ; + u8 mask = 1 << (d->hwirq % BANK_SZ); if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) } if (type & IRQ_TYPE_EDGE_FALLING) - chip->irq_trig_fall |= mask; + chip->irq_trig_fall[bank_nb] |= mask; else - chip->irq_trig_fall &= ~mask; + chip->irq_trig_fall[bank_nb] &= ~mask; if (type & IRQ_TYPE_EDGE_RISING) - chip->irq_trig_raise |= mask; + chip->irq_trig_raise[bank_nb] |= mask; else - chip->irq_trig_raise &= ~mask; + chip->irq_trig_raise[bank_nb] &= ~mask; return 0; } @@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = { .irq_set_type = pca953x_irq_set_type, }; -static u32 pca953x_irq_pending(struct pca953x_chip *chip) +static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) { - u32 cur_stat; - u32 old_stat; - u32 pending; - u32 trigger; - int ret, offset = 0; + u8 cur_stat[MAX_BANK]; + u8 old_stat[MAX_BANK]; + u8 pendings = 0; + u8 trigger[MAX_BANK], triggers = 0; + int ret, i, offset = 0; switch (chip->chip_type) { case PCA953X_TYPE: @@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip) offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, &cur_stat); + ret = pca953x_read_regs(chip, offset, cur_stat); if (ret) return 0; /* Remove output pins from the equation */ - cur_stat &= chip->reg_direction; + for (i = 0; i < NBANK(chip); i++) + cur_stat[i] &= chip->reg_direction[i]; + + memcpy(old_stat, chip->irq_stat, NBANK(chip)); - old_stat = chip->irq_stat; - trigger = (cur_stat ^ old_stat) & chip->irq_mask; + for (i = 0; i < NBANK(chip); i++) { + trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i]; + triggers += trigger[i]; + } - if (!trigger) + if (!triggers) return 0; - chip->irq_stat = cur_stat; + memcpy(chip->irq_stat, cur_stat, NBANK(chip)); - pending = (old_stat & chip->irq_trig_fall) | - (cur_stat & chip->irq_trig_raise); - pending &= trigger; + for (i = 0; i < NBANK(chip); i++) { + pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) | + (cur_stat[i] & chip->irq_trig_raise[i]); + pending[i] &= trigger[i]; + pendings += pending[i]; + } - return pending; + return pendings; } static irqreturn_t pca953x_irq_handler(int irq, void *devid) { struct pca953x_chip *chip = devid; - u32 pending; - u32 level; - - pending = pca953x_irq_pending(chip); + u8 pending[MAX_BANK]; + u8 level; + int i; - if (!pending) + if (!pca953x_irq_pending(chip, pending)) return IRQ_HANDLED; - do { - level = __ffs(pending); - handle_nested_irq(irq_find_mapping(chip->domain, level)); - - pending &= ~(1 << level); - } while (pending); + for (i = 0; i < NBANK(chip); i++) { + while (pending[i]) { + level = __ffs(pending[i]); + handle_nested_irq(irq_find_mapping(chip->domain, + level + (BANK_SZ * i))); + pending[i] &= ~(1 << level); + } + } return IRQ_HANDLED; } +static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_clear_status_flags(irq, IRQ_NOREQUEST); + irq_set_chip_data(irq, d->host_data); + irq_set_chip(irq, &pca953x_irq_chip); + irq_set_nested_thread(irq, true); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return 0; +} + +static const struct irq_domain_ops pca953x_irq_simple_ops = { + .map = pca953x_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + static int pca953x_irq_setup(struct pca953x_chip *chip, const struct i2c_device_id *id, int irq_base) { struct i2c_client *client = chip->client; - int ret, offset = 0; - u32 temporary; + int ret, i, offset = 0; if (irq_base != -1 && (id->driver_data & PCA_INT)) { - int lvl; switch (chip->chip_type) { case PCA953X_TYPE: @@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, &temporary); - chip->irq_stat = temporary; + ret = pca953x_read_regs(chip, offset, chip->irq_stat); if (ret) - goto out_failed; + return ret; /* * There is no way to know which GPIO line generated the * interrupt. We have to rely on the previous read for * this purpose. */ - chip->irq_stat &= chip->reg_direction; + for (i = 0; i < NBANK(chip); i++) + chip->irq_stat[i] &= chip->reg_direction[i]; mutex_init(&chip->irq_lock); - chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); - if (chip->irq_base < 0) - goto out_failed; - - chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->domain = irq_domain_add_simple(client->dev.of_node, chip->gpio_chip.ngpio, - chip->irq_base, - 0, - &irq_domain_simple_ops, + irq_base, + &pca953x_irq_simple_ops, NULL); - if (!chip->domain) { - ret = -ENODEV; - goto out_irqdesc_free; - } + if (!chip->domain) + return -ENODEV; - for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { - int irq = lvl + chip->irq_base; - - irq_clear_status_flags(irq, IRQ_NOREQUEST); - irq_set_chip_data(irq, chip); - irq_set_chip(irq, &pca953x_irq_chip); - irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - } - - ret = request_threaded_irq(client->irq, + ret = devm_request_threaded_irq(&client->dev, + client->irq, NULL, pca953x_irq_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, @@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_irqdesc_free; + return ret; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; } return 0; - -out_irqdesc_free: - irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); -out_failed: - chip->irq_base = -1; - return ret; } -static void pca953x_irq_teardown(struct pca953x_chip *chip) -{ - if (chip->irq_base != -1) { - irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); - free_irq(chip->client->irq, chip); - } -} #else /* CONFIG_GPIO_PCA953X_IRQ */ static int pca953x_irq_setup(struct pca953x_chip *chip, const struct i2c_device_id *id, @@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; } - -static void pca953x_irq_teardown(struct pca953x_chip *chip) -{ -} #endif /* @@ -619,18 +657,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) { int ret; + u8 val[MAX_BANK]; - ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); + ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output); if (ret) goto out; - ret = pca953x_read_reg(chip, PCA953X_DIRECTION, - &chip->reg_direction); + ret = pca953x_read_regs(chip, PCA953X_DIRECTION, + chip->reg_direction); if (ret) goto out; /* set platform specific polarity inversion */ - ret = pca953x_write_reg(chip, PCA953X_INVERT, invert); + if (invert) + memset(val, 0xFF, NBANK(chip)); + else + memset(val, 0, NBANK(chip)); + + ret = pca953x_write_regs(chip, PCA953X_INVERT, val); out: return ret; } @@ -638,28 +682,36 @@ out: static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) { int ret; - u32 val = 0; + u8 val[MAX_BANK]; /* Let every port in proper state, that could save power */ - pca953x_write_reg(chip, PCA957X_PUPD, 0x0); - pca953x_write_reg(chip, PCA957X_CFG, 0xffff); - pca953x_write_reg(chip, PCA957X_OUT, 0x0); - - ret = pca953x_read_reg(chip, PCA957X_IN, &val); + memset(val, 0, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_PUPD, val); + memset(val, 0xFF, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_CFG, val); + memset(val, 0, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_OUT, val); + + ret = pca953x_read_regs(chip, PCA957X_IN, val); if (ret) goto out; - ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output); + ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); if (ret) goto out; - ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction); + ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction); if (ret) goto out; /* set platform specific polarity inversion */ - pca953x_write_reg(chip, PCA957X_INVRT, invert); + if (invert) + memset(val, 0xFF, NBANK(chip)); + else + memset(val, 0, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_INVRT, val); /* To enable register 6, 7 to controll pull up and pull down */ - pca953x_write_reg(chip, PCA957X_BKEN, 0x202); + memset(val, 0x02, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_BKEN, val); return 0; out: @@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client, int ret; u32 invert = 0; - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, + sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client, else ret = device_pca957x_init(chip, invert); if (ret) - goto out_failed; + return ret; ret = pca953x_irq_setup(chip, id, irq_base); if (ret) - goto out_failed; + return ret; ret = gpiochip_add(&chip->gpio_chip); if (ret) - goto out_failed_irq; + return ret; if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; - -out_failed_irq: - pca953x_irq_teardown(chip); -out_failed: - kfree(chip); - return ret; } static int pca953x_remove(struct i2c_client *client) @@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client) return ret; } - pca953x_irq_teardown(chip); - kfree(chip); return 0; } static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9505", }, { .compatible = "nxp,pca9534", }, { .compatible = "nxp,pca9535", }, { .compatible = "nxp,pca9536", }, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index c1720de..b820869 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void) { return amba_driver_register(&pl061_gpio_driver); } -subsys_initcall(pl061_gpio_init); +module_init(pl061_gpio_init); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); MODULE_DESCRIPTION("PL061 GPIO driver"); diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 8325f58..9cc108d 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = { .of_match_table = of_match_ptr(pxa_gpio_dt_ids), }, }; - -static int __init pxa_gpio_init(void) -{ - return platform_driver_register(&pxa_gpio_driver); -} -postcore_initcall(pxa_gpio_init); +module_platform_driver(pxa_gpio_driver); #ifdef CONFIG_PM static int pxa_gpio_suspend(void) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 9572aa1..4d330e3 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -37,7 +37,6 @@ #include <linux/i2c/twl.h> - /* * The GPIO "subchip" supports 18 GPIOs which can be configured as * inputs or outputs, with pullups or pulldowns on each pin. Each @@ -49,11 +48,6 @@ * There are also two LED pins used sometimes as output-only GPIOs. */ - -static struct gpio_chip twl_gpiochip; -static int twl4030_gpio_base; -static int twl4030_gpio_irq_base; - /* genirq interfaces are not available to modules */ #ifdef MODULE #define is_module() true @@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base; /* Mask for GPIO registers when aggregated into a 32-bit integer */ #define GPIO_32_MASK 0x0003ffff -/* Data structures */ -static DEFINE_MUTEX(gpio_lock); +struct gpio_twl4030_priv { + struct gpio_chip gpio_chip; + struct mutex mutex; + int irq_base; -/* store usage of each GPIO. - each bit represents one GPIO */ -static unsigned int gpio_usage_count; + /* Bitfields for state caching */ + unsigned int usage_count; + unsigned int direction; + unsigned int out_state; +}; /*----------------------------------------------------------------------*/ +static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip) +{ + return container_of(chip, struct gpio_twl4030_priv, gpio_chip); +} + /* * To configure TWL4030 GPIO module registers */ @@ -126,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address) /*----------------------------------------------------------------------*/ -static u8 cached_leden; /* protected by gpio_lock */ +static u8 cached_leden; /* The LED lines are open drain outputs ... a FET pulls to GND, so an * external pullup is needed. We could also expose the integrated PWM @@ -140,14 +144,12 @@ static void twl4030_led_set_value(int led, int value) if (led) mask <<= 1; - mutex_lock(&gpio_lock); if (value) cached_leden &= ~mask; else cached_leden |= mask; status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, TWL4030_LED_LEDEN_REG); - mutex_unlock(&gpio_lock); } static int twl4030_set_gpio_direction(int gpio, int is_input) @@ -158,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) u8 base = REG_GPIODATADIR1 + d_bnk; int ret = 0; - mutex_lock(&gpio_lock); ret = gpio_twl4030_read(base); if (ret >= 0) { if (is_input) @@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) ret = gpio_twl4030_write(base, reg); } - mutex_unlock(&gpio_lock); return ret; } @@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio) u8 base = 0; int ret = 0; - if (unlikely((gpio >= TWL4030_GPIO_MAX) - || !(gpio_usage_count & BIT(gpio)))) - return -EPERM; - base = REG_GPIODATAIN1 + d_bnk; ret = gpio_twl4030_read(base); if (ret > 0) @@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio) static int twl_request(struct gpio_chip *chip, unsigned offset) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); int status = 0; - mutex_lock(&gpio_lock); + mutex_lock(&priv->mutex); /* Support the two LED outputs as output-only GPIOs. */ if (offset >= TWL4030_GPIO_MAX) { @@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) } /* on first use, turn GPIO module "on" */ - if (!gpio_usage_count) { + if (!priv->usage_count) { struct twl4030_gpio_platform_data *pdata; u8 value = MASK_GPIO_CTRL_GPIO_ON; @@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) status = gpio_twl4030_write(REG_GPIO_CTRL, value); } +done: if (!status) - gpio_usage_count |= (0x1 << offset); + priv->usage_count |= BIT(offset); -done: - mutex_unlock(&gpio_lock); + mutex_unlock(&priv->mutex); return status; } static void twl_free(struct gpio_chip *chip, unsigned offset) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + mutex_lock(&priv->mutex); if (offset >= TWL4030_GPIO_MAX) { twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); - return; + goto out; } - mutex_lock(&gpio_lock); - - gpio_usage_count &= ~BIT(offset); + priv->usage_count &= ~BIT(offset); /* on last use, switch off GPIO module */ - if (!gpio_usage_count) + if (!priv->usage_count) gpio_twl4030_write(REG_GPIO_CTRL, 0x0); - mutex_unlock(&gpio_lock); +out: + mutex_unlock(&priv->mutex); } static int twl_direction_in(struct gpio_chip *chip, unsigned offset) { - return (offset < TWL4030_GPIO_MAX) - ? twl4030_set_gpio_direction(offset, 1) - : -EINVAL; + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + int ret; + + mutex_lock(&priv->mutex); + if (offset < TWL4030_GPIO_MAX) + ret = twl4030_set_gpio_direction(offset, 1); + else + ret = -EINVAL; + + if (!ret) + priv->direction &= ~BIT(offset); + + mutex_unlock(&priv->mutex); + + return ret; } static int twl_get(struct gpio_chip *chip, unsigned offset) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + int ret; int status = 0; - if (offset < TWL4030_GPIO_MAX) - status = twl4030_get_gpio_datain(offset); - else if (offset == TWL4030_GPIO_MAX) - status = cached_leden & LEDEN_LEDAON; + mutex_lock(&priv->mutex); + if (!(priv->usage_count & BIT(offset))) { + ret = -EPERM; + goto out; + } + + if (priv->direction & BIT(offset)) + status = priv->out_state & BIT(offset); else - status = cached_leden & LEDEN_LEDBON; - return (status < 0) ? 0 : status; + status = twl4030_get_gpio_datain(offset); + + ret = (status <= 0) ? 0 : 1; +out: + mutex_unlock(&priv->mutex); + return ret; } -static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) +static void twl_set(struct gpio_chip *chip, unsigned offset, int value) { - if (offset < TWL4030_GPIO_MAX) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + mutex_lock(&priv->mutex); + if (offset < TWL4030_GPIO_MAX) twl4030_set_gpio_dataout(offset, value); - return twl4030_set_gpio_direction(offset, 0); - } else { + else twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); - return 0; - } + + if (value) + priv->out_state |= BIT(offset); + else + priv->out_state &= ~BIT(offset); + + mutex_unlock(&priv->mutex); } -static void twl_set(struct gpio_chip *chip, unsigned offset, int value) +static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX) twl4030_set_gpio_dataout(offset, value); - else - twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); + + priv->direction |= BIT(offset); + mutex_unlock(&priv->mutex); + + twl_set(chip, offset, value); + + return 0; } static int twl_to_irq(struct gpio_chip *chip, unsigned offset) { - return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX)) - ? (twl4030_gpio_irq_base + offset) + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + return (priv->irq_base && (offset < TWL4030_GPIO_MAX)) + ? (priv->irq_base + offset) : -EINVAL; } -static struct gpio_chip twl_gpiochip = { +static struct gpio_chip template_chip = { .label = "twl4030", .owner = THIS_MODULE, .request = twl_request, @@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; + struct gpio_twl4030_priv *priv; int ret, irq_base; + priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + /* maybe setup IRQs */ if (is_module()) { dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); @@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev) if (ret < 0) return ret; - twl4030_gpio_irq_base = irq_base; + priv->irq_base = irq_base; no_irqs: - twl_gpiochip.base = -1; - twl_gpiochip.ngpio = TWL4030_GPIO_MAX; - twl_gpiochip.dev = &pdev->dev; + priv->gpio_chip = template_chip; + priv->gpio_chip.base = -1; + priv->gpio_chip.ngpio = TWL4030_GPIO_MAX; + priv->gpio_chip.dev = &pdev->dev; + + mutex_init(&priv->mutex); if (node) pdata = of_gpio_twl4030(&pdev->dev); @@ -481,23 +528,23 @@ no_irqs: * is (still) clear if use_leds is set. */ if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + priv->gpio_chip.ngpio += 2; - ret = gpiochip_add(&twl_gpiochip); + ret = gpiochip_add(&priv->gpio_chip); if (ret < 0) { dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); - twl_gpiochip.ngpio = 0; + priv->gpio_chip.ngpio = 0; gpio_twl4030_remove(pdev); goto out; } - twl4030_gpio_base = twl_gpiochip.base; + platform_set_drvdata(pdev, priv); if (pdata && pdata->setup) { int status; - status = pdata->setup(&pdev->dev, - twl4030_gpio_base, TWL4030_GPIO_MAX); + status = pdata->setup(&pdev->dev, priv->gpio_chip.base, + TWL4030_GPIO_MAX); if (status) dev_dbg(&pdev->dev, "setup --> %d\n", status); } @@ -510,18 +557,19 @@ out: static int gpio_twl4030_remove(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; + struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); int status; if (pdata && pdata->teardown) { - status = pdata->teardown(&pdev->dev, - twl4030_gpio_base, TWL4030_GPIO_MAX); + status = pdata->teardown(&pdev->dev, priv->gpio_chip.base, + TWL4030_GPIO_MAX); if (status) { dev_dbg(&pdev->dev, "teardown --> %d\n", status); return status; } } - status = gpiochip_remove(&twl_gpiochip); + status = gpiochip_remove(&priv->gpio_chip); if (status < 0) return status; diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index b53320a..81683ca 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -73,19 +73,20 @@ struct vt8500_gpio_data { static struct vt8500_gpio_data vt8500_data = { .num_banks = 7, .banks = { + VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), - VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), }, }; static struct vt8500_gpio_data wm8505_data = { .num_banks = 10, .banks = { + VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), @@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = { VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), - VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; @@ -127,6 +127,12 @@ struct vt8500_gpio_chip { void __iomem *base; }; +struct vt8500_data { + struct vt8500_gpio_chip *chip; + void __iomem *iobase; + int num_banks; +}; + #define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) @@ -224,19 +230,32 @@ static int vt8500_of_xlate(struct gpio_chip *gc, static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, const struct vt8500_gpio_data *data) { + struct vt8500_data *priv; struct vt8500_gpio_chip *vtchip; struct gpio_chip *chip; int i; int pin_cnt = 0; - vtchip = devm_kzalloc(&pdev->dev, + priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + priv->chip = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_gpio_chip) * data->num_banks, GFP_KERNEL); - if (!vtchip) { - pr_err("%s: failed to allocate chip memory\n", __func__); + if (!priv->chip) { + dev_err(&pdev->dev, "failed to allocate chip memory\n"); return -ENOMEM; } + priv->iobase = base; + priv->num_banks = data->num_banks; + platform_set_drvdata(pdev, priv); + + vtchip = priv->chip; + for (i = 0; i < data->num_banks; i++) { vtchip[i].base = base; vtchip[i].regs = &data->banks[i]; @@ -273,36 +292,54 @@ static struct of_device_id vt8500_gpio_dt_ids[] = { static int vt8500_gpio_probe(struct platform_device *pdev) { + int ret; void __iomem *gpio_base; - struct device_node *np; + struct resource *res; const struct of_device_id *of_id = of_match_device(vt8500_gpio_dt_ids, &pdev->dev); if (!of_id) { - dev_err(&pdev->dev, "Failed to find gpio controller\n"); + dev_err(&pdev->dev, "No matching driver data\n"); return -ENODEV; } - np = pdev->dev.of_node; - if (!np) { - dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); - return -EFAULT; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get IO resource\n"); + return -ENODEV; } - gpio_base = of_iomap(np, 0); + gpio_base = devm_request_and_ioremap(&pdev->dev, res); if (!gpio_base) { dev_err(&pdev->dev, "Unable to map GPIO registers\n"); - of_node_put(np); return -ENOMEM; } - vt8500_add_chips(pdev, gpio_base, of_id->data); + ret = vt8500_add_chips(pdev, gpio_base, of_id->data); + + return ret; +} + +static int vt8500_gpio_remove(struct platform_device *pdev) +{ + int i; + int ret; + struct vt8500_data *priv = platform_get_drvdata(pdev); + struct vt8500_gpio_chip *vtchip = priv->chip; + + for (i = 0; i < priv->num_banks; i++) { + ret = gpiochip_remove(&vtchip[i].chip); + if (ret) + dev_warn(&pdev->dev, "gpiochip_remove returned %d\n", + ret); + } return 0; } static struct platform_driver vt8500_gpio_driver = { .probe = vt8500_gpio_probe, + .remove = vt8500_gpio_remove, .driver = { .name = "vt8500-gpio", .owner = THIS_MODULE, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index cbad6e9..a063eb0 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -15,6 +15,7 @@ #include <linux/export.h> #include <linux/acpi_gpio.h> #include <linux/acpi.h> +#include <linux/interrupt.h> static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { @@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin) return chip->base + pin; } EXPORT_SYMBOL_GPL(acpi_get_gpio); + + +static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) +{ + acpi_handle handle = data; + + acpi_evaluate_object(handle, NULL, NULL, NULL); + + return IRQ_HANDLED; +} + +/** + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events + * @chip: gpio chip + * + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. + * + * Interrupts are automatically freed on driver detach + */ + +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_resource *res; + acpi_handle handle, ev_handle; + acpi_status status; + unsigned int pin; + int irq, ret; + char ev_name[5]; + + if (!chip->dev || !chip->to_irq) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_event_resources(handle, &buf); + if (ACPI_FAILURE(status)) + return; + + /* If a gpio interrupt has an acpi event handler method, then + * set up an interrupt handler that calls the acpi event handler + */ + + for (res = buf.pointer; + res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); + res = ACPI_NEXT_RESOURCE(res)) { + + if (res->type != ACPI_RESOURCE_TYPE_GPIO || + res->data.gpio.connection_type != + ACPI_RESOURCE_GPIO_TYPE_INT) + continue; + + pin = res->data.gpio.pin_table[0]; + if (pin > chip->ngpio) + continue; + + sprintf(ev_name, "_%c%02X", + res->data.gpio.triggering ? 'E' : 'L', pin); + + status = acpi_get_handle(handle, ev_name, &ev_handle); + if (ACPI_FAILURE(status)) + continue; + + irq = chip->to_irq(chip, pin); + if (irq < 0) + continue; + + /* Assume BIOS sets the triggering, so no flags */ + ret = devm_request_threaded_irq(chip->dev, irq, NULL, + acpi_gpio_irq_handler, + 0, + "GPIO-signaled-ACPI-event", + ev_handle); + if (ret) + dev_err(chip->dev, + "Failed to request IRQ %d ACPI event handler\n", + irq); + } +} +EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5359ca7..4828fe7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3,6 +3,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/spinlock.h> +#include <linux/list.h> #include <linux/device.h> #include <linux/err.h> #include <linux/debugfs.h> @@ -52,14 +53,13 @@ struct gpio_desc { /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 -#define FLAG_RESERVED 2 -#define FLAG_EXPORT 3 /* protected by sysfs_lock */ -#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ -#define FLAG_TRIG_FALL 5 /* trigger on falling edge */ -#define FLAG_TRIG_RISE 6 /* trigger on rising edge */ -#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ -#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ -#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */ +#define FLAG_EXPORT 2 /* protected by sysfs_lock */ +#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ +#define FLAG_TRIG_FALL 4 /* trigger on falling edge */ +#define FLAG_TRIG_RISE 5 /* trigger on rising edge */ +#define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ +#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ +#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -72,10 +72,36 @@ struct gpio_desc { }; static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; +#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) + +static LIST_HEAD(gpio_chips); + #ifdef CONFIG_GPIO_SYSFS static DEFINE_IDR(dirent_idr); #endif +/* + * Internal gpiod_* API using descriptors instead of the integer namespace. + * Most of this should eventually go public. + */ +static int gpiod_request(struct gpio_desc *desc, const char *label); +static void gpiod_free(struct gpio_desc *desc); +static int gpiod_direction_input(struct gpio_desc *desc); +static int gpiod_direction_output(struct gpio_desc *desc, int value); +static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); +static int gpiod_get_value_cansleep(struct gpio_desc *desc); +static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +static int gpiod_get_value(struct gpio_desc *desc); +static void gpiod_set_value(struct gpio_desc *desc, int value); +static int gpiod_cansleep(struct gpio_desc *desc); +static int gpiod_to_irq(struct gpio_desc *desc); +static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +static int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); +static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); +static void gpiod_unexport(struct gpio_desc *desc); + + static inline void desc_set_label(struct gpio_desc *d, const char *label) { #ifdef CONFIG_DEBUG_FS @@ -83,6 +109,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) #endif } +/* + * Return the GPIO number of the passed descriptor relative to its chip + */ +static int gpio_chip_hwgpio(const struct gpio_desc *desc) +{ + return desc - &desc->chip->desc[0]; +} + +/** + * Convert a GPIO number to its descriptor + */ +static struct gpio_desc *gpio_to_desc(unsigned gpio) +{ + if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio)) + return NULL; + else + return &gpio_desc[gpio]; +} + +/** + * Convert a GPIO descriptor to the integer namespace. + * This should disappear in the future but is needed since we still + * use GPIO numbers for error messages and sysfs nodes + */ +static int desc_to_gpio(const struct gpio_desc *desc) +{ + return desc->chip->base + gpio_chip_hwgpio(desc); +} + + /* Warn when drivers omit gpio_request() calls -- legal but ill-advised * when setting direction, and otherwise illegal. Until board setup code * and drivers use explicit requests everywhere (which won't happen when @@ -94,10 +150,10 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) * only "legal" in the sense that (old) code using it won't break yet, * but instead only triggers a WARN() stack dump. */ -static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) +static int gpio_ensure_requested(struct gpio_desc *desc) { const struct gpio_chip *chip = desc->chip; - const int gpio = chip->base + offset; + const int gpio = desc_to_gpio(desc); if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, "autorequest GPIO-%d\n", gpio)) { @@ -116,95 +172,54 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) } /* caller holds gpio_lock *OR* gpio is marked as requested */ +static struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc) +{ + return desc->chip; +} + struct gpio_chip *gpio_to_chip(unsigned gpio) { - return gpio_desc[gpio].chip; + return gpiod_to_chip(gpio_to_desc(gpio)); } /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ static int gpiochip_find_base(int ngpio) { - int i; - int spare = 0; - int base = -ENOSPC; - - for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { - struct gpio_desc *desc = &gpio_desc[i]; - struct gpio_chip *chip = desc->chip; + struct gpio_chip *chip; + int base = ARCH_NR_GPIOS - ngpio; - if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { - spare++; - if (spare == ngpio) { - base = i; - break; - } - } else { - spare = 0; - if (chip) - i -= chip->ngpio - 1; - } + list_for_each_entry_reverse(chip, &gpio_chips, list) { + /* found a free space? */ + if (chip->base + chip->ngpio <= base) + break; + else + /* nope, check the space right before the chip */ + base = chip->base - ngpio; } - if (gpio_is_valid(base)) + if (gpio_is_valid(base)) { pr_debug("%s: found new base at %d\n", __func__, base); - return base; -} - -/** - * gpiochip_reserve() - reserve range of gpios to use with platform code only - * @start: starting gpio number - * @ngpio: number of gpios to reserve - * Context: platform init, potentially before irqs or kmalloc will work - * - * Returns a negative errno if any gpio within the range is already reserved - * or registered, else returns zero as a success code. Use this function - * to mark a range of gpios as unavailable for dynamic gpio number allocation, - * for example because its driver support is not yet loaded. - */ -int __init gpiochip_reserve(int start, int ngpio) -{ - int ret = 0; - unsigned long flags; - int i; - - if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1)) - return -EINVAL; - - spin_lock_irqsave(&gpio_lock, flags); - - for (i = start; i < start + ngpio; i++) { - struct gpio_desc *desc = &gpio_desc[i]; - - if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) { - ret = -EBUSY; - goto err; - } - - set_bit(FLAG_RESERVED, &desc->flags); + return base; + } else { + pr_err("%s: cannot find free range\n", __func__); + return -ENOSPC; } - - pr_debug("%s: reserved gpios from %d to %d\n", - __func__, start, start + ngpio - 1); -err: - spin_unlock_irqrestore(&gpio_lock, flags); - - return ret; } /* caller ensures gpio is valid and requested, chip->get_direction may sleep */ -static int gpio_get_direction(unsigned gpio) +static int gpiod_get_direction(struct gpio_desc *desc) { struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; + unsigned offset; int status = -EINVAL; - chip = gpio_to_chip(gpio); - gpio -= chip->base; + chip = gpiod_to_chip(desc); + offset = gpio_chip_hwgpio(desc); if (!chip->get_direction) return status; - status = chip->get_direction(chip, gpio); + status = chip->get_direction(chip, offset); if (status > 0) { /* GPIOF_DIR_IN, or other positive */ status = 1; @@ -248,19 +263,19 @@ static DEFINE_MUTEX(sysfs_lock); static ssize_t gpio_direction_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); - if (!test_bit(FLAG_EXPORT, &desc->flags)) + if (!test_bit(FLAG_EXPORT, &desc->flags)) { status = -EIO; - else - gpio_get_direction(gpio); + } else { + gpiod_get_direction(desc); status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); + } mutex_unlock(&sysfs_lock); return status; @@ -269,8 +284,7 @@ static ssize_t gpio_direction_show(struct device *dev, static ssize_t gpio_direction_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -278,11 +292,11 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpio_direction_output(gpio, 1); + status = gpiod_direction_output(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpio_direction_output(gpio, 0); + status = gpiod_direction_output(desc, 0); else if (sysfs_streq(buf, "in")) - status = gpio_direction_input(gpio); + status = gpiod_direction_input(desc); else status = -EINVAL; @@ -296,8 +310,7 @@ static /* const */ DEVICE_ATTR(direction, 0644, static ssize_t gpio_value_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -307,7 +320,7 @@ static ssize_t gpio_value_show(struct device *dev, } else { int value; - value = !!gpio_get_value_cansleep(gpio); + value = !!gpiod_get_value_cansleep(desc); if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -321,8 +334,7 @@ static ssize_t gpio_value_show(struct device *dev, static ssize_t gpio_value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -338,7 +350,7 @@ static ssize_t gpio_value_store(struct device *dev, if (status == 0) { if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; - gpio_set_value_cansleep(gpio, value != 0); + gpiod_set_value_cansleep(desc, value != 0); status = size; } } @@ -368,7 +380,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) return 0; - irq = gpio_to_irq(desc - gpio_desc); + irq = gpiod_to_irq(desc); if (irq < 0) return -EIO; @@ -638,29 +650,32 @@ static ssize_t export_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { - long gpio; - int status; + long gpio; + struct gpio_desc *desc; + int status; status = strict_strtol(buf, 0, &gpio); if (status < 0) goto done; + desc = gpio_to_desc(gpio); + /* No extra locking here; FLAG_SYSFS just signifies that the * request and export were done by on behalf of userspace, so * they may be undone on its behalf too. */ - status = gpio_request(gpio, "sysfs"); + status = gpiod_request(desc, "sysfs"); if (status < 0) { if (status == -EPROBE_DEFER) status = -ENODEV; goto done; } - status = gpio_export(gpio, true); + status = gpiod_export(desc, true); if (status < 0) - gpio_free(gpio); + gpiod_free(desc); else - set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags); + set_bit(FLAG_SYSFS, &desc->flags); done: if (status) @@ -672,8 +687,9 @@ static ssize_t unexport_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { - long gpio; - int status; + long gpio; + struct gpio_desc *desc; + int status; status = strict_strtol(buf, 0, &gpio); if (status < 0) @@ -681,17 +697,18 @@ static ssize_t unexport_store(struct class *class, status = -EINVAL; + desc = gpio_to_desc(gpio); /* reject bogus commands (gpio_unexport ignores them) */ - if (!gpio_is_valid(gpio)) + if (!desc) goto done; /* No extra locking here; FLAG_SYSFS just signifies that the * request and export were done by on behalf of userspace, so * they may be undone on its behalf too. */ - if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) { + if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) { status = 0; - gpio_free(gpio); + gpiod_free(desc); } done: if (status) @@ -728,13 +745,13 @@ static struct class gpio_class = { * * Returns zero on success, else an error. */ -int gpio_export(unsigned gpio, bool direction_may_change) +static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { unsigned long flags; - struct gpio_desc *desc; int status; const char *ioname = NULL; struct device *dev; + int offset; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -742,20 +759,19 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -ENOENT; } - if (!gpio_is_valid(gpio)) { - pr_debug("%s: gpio %d is not valid\n", __func__, gpio); + if (!desc) { + pr_debug("%s: invalid gpio descriptor\n", __func__); return -EINVAL; } mutex_lock(&sysfs_lock); spin_lock_irqsave(&gpio_lock, flags); - desc = &gpio_desc[gpio]; if (!test_bit(FLAG_REQUESTED, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags)) { spin_unlock_irqrestore(&gpio_lock, flags); pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", - __func__, gpio, + __func__, desc_to_gpio(desc), test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); status = -EPERM; @@ -766,11 +782,13 @@ int gpio_export(unsigned gpio, bool direction_may_change) direction_may_change = false; spin_unlock_irqrestore(&gpio_lock, flags); - if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) - ioname = desc->chip->names[gpio - desc->chip->base]; + offset = gpio_chip_hwgpio(desc); + if (desc->chip->names && desc->chip->names[offset]) + ioname = desc->chip->names[offset]; dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", gpio); + desc, ioname ? ioname : "gpio%u", + desc_to_gpio(desc)); if (IS_ERR(dev)) { status = PTR_ERR(dev); goto fail_unlock; @@ -786,7 +804,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) goto fail_unregister_device; } - if (gpio_to_irq(gpio) >= 0 && (direction_may_change || + if (gpiod_to_irq(desc) >= 0 && (direction_may_change || !test_bit(FLAG_IS_OUT, &desc->flags))) { status = device_create_file(dev, &dev_attr_edge); if (status) @@ -801,9 +819,15 @@ fail_unregister_device: device_unregister(dev); fail_unlock: mutex_unlock(&sysfs_lock); - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); return status; } + +int gpio_export(unsigned gpio, bool direction_may_change) +{ + return gpiod_export(gpio_to_desc(gpio), direction_may_change); +} EXPORT_SYMBOL_GPL(gpio_export); static int match_export(struct device *dev, const void *data) @@ -822,18 +846,16 @@ static int match_export(struct device *dev, const void *data) * * Returns zero on success, else an error. */ -int gpio_export_link(struct device *dev, const char *name, unsigned gpio) +static int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) { - struct gpio_desc *desc; int status = -EINVAL; - if (!gpio_is_valid(gpio)) + if (!desc) goto done; mutex_lock(&sysfs_lock); - desc = &gpio_desc[gpio]; - if (test_bit(FLAG_EXPORT, &desc->flags)) { struct device *tdev; @@ -850,12 +872,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio) done: if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); return status; } -EXPORT_SYMBOL_GPL(gpio_export_link); +int gpio_export_link(struct device *dev, const char *name, unsigned gpio) +{ + return gpiod_export_link(dev, name, gpio_to_desc(gpio)); +} +EXPORT_SYMBOL_GPL(gpio_export_link); /** * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value @@ -869,19 +896,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link); * * Returns zero on success, else an error. */ -int gpio_sysfs_set_active_low(unsigned gpio, int value) +static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) { - struct gpio_desc *desc; struct device *dev = NULL; int status = -EINVAL; - if (!gpio_is_valid(gpio)) + if (!desc) goto done; mutex_lock(&sysfs_lock); - desc = &gpio_desc[gpio]; - if (test_bit(FLAG_EXPORT, &desc->flags)) { dev = class_find_device(&gpio_class, NULL, desc, match_export); if (dev == NULL) { @@ -897,10 +921,16 @@ unlock: done: if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); return status; } + +int gpio_sysfs_set_active_low(unsigned gpio, int value) +{ + return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value); +} EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); /** @@ -909,21 +939,18 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); * * This is implicit on gpio_free(). */ -void gpio_unexport(unsigned gpio) +static void gpiod_unexport(struct gpio_desc *desc) { - struct gpio_desc *desc; int status = 0; struct device *dev = NULL; - if (!gpio_is_valid(gpio)) { + if (!desc) { status = -EINVAL; goto done; } mutex_lock(&sysfs_lock); - desc = &gpio_desc[gpio]; - if (test_bit(FLAG_EXPORT, &desc->flags)) { dev = class_find_device(&gpio_class, NULL, desc, match_export); @@ -935,13 +962,20 @@ void gpio_unexport(unsigned gpio) } mutex_unlock(&sysfs_lock); + if (dev) { device_unregister(dev); put_device(dev); } done: if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); +} + +void gpio_unexport(unsigned gpio) +{ + gpiod_unexport(gpio_to_desc(gpio)); } EXPORT_SYMBOL_GPL(gpio_unexport); @@ -975,9 +1009,9 @@ static int gpiochip_export(struct gpio_chip *chip) unsigned gpio; spin_lock_irqsave(&gpio_lock, flags); - gpio = chip->base; - while (gpio_desc[gpio].chip == chip) - gpio_desc[gpio++].chip = NULL; + gpio = 0; + while (gpio < chip->ngpio) + chip->desc[gpio++].chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); pr_debug("%s: chip %s status %d\n", __func__, @@ -1012,7 +1046,7 @@ static int __init gpiolib_sysfs_init(void) { int status; unsigned long flags; - unsigned gpio; + struct gpio_chip *chip; status = class_register(&gpio_class); if (status < 0) @@ -1025,10 +1059,7 @@ static int __init gpiolib_sysfs_init(void) * registered, and so arch_initcall() can always gpio_export(). */ spin_lock_irqsave(&gpio_lock, flags); - for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { - struct gpio_chip *chip; - - chip = gpio_desc[gpio].chip; + list_for_each_entry(chip, &gpio_chips, list) { if (!chip || chip->exported) continue; @@ -1053,8 +1084,66 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) { } +static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) +{ + return -ENOSYS; +} + +static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +{ + return -ENOSYS; +} + +static inline void gpiod_unexport(struct gpio_desc *desc) +{ +} + #endif /* CONFIG_GPIO_SYSFS */ +/* + * Add a new chip to the global chips list, keeping the list of chips sorted + * by base order. + * + * Return -EBUSY if the new chip overlaps with some other chip's integer + * space. + */ +static int gpiochip_add_to_list(struct gpio_chip *chip) +{ + struct list_head *pos = &gpio_chips; + struct gpio_chip *_chip; + int err = 0; + + /* find where to insert our chip */ + list_for_each(pos, &gpio_chips) { + _chip = list_entry(pos, struct gpio_chip, list); + /* shall we insert before _chip? */ + if (_chip->base >= chip->base + chip->ngpio) + break; + } + + /* are we stepping on the chip right before? */ + if (pos != &gpio_chips && pos->prev != &gpio_chips) { + _chip = list_entry(pos->prev, struct gpio_chip, list); + if (_chip->base + _chip->ngpio > chip->base) { + dev_err(chip->dev, + "GPIO integer space overlap, cannot add chip\n"); + err = -EBUSY; + } + } + + if (!err) + list_add_tail(&chip->list, pos); + + return err; +} + /** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized @@ -1096,16 +1185,14 @@ int gpiochip_add(struct gpio_chip *chip) chip->base = base; } - /* these GPIO numbers must not be managed by another gpio_chip */ - for (id = base; id < base + chip->ngpio; id++) { - if (gpio_desc[id].chip != NULL) { - status = -EBUSY; - break; - } - } + status = gpiochip_add_to_list(chip); + if (status == 0) { - for (id = base; id < base + chip->ngpio; id++) { - gpio_desc[id].chip = chip; + chip->desc = &gpio_desc[chip->base]; + + for (id = 0; id < chip->ngpio; id++) { + struct gpio_desc *desc = &chip->desc[id]; + desc->chip = chip; /* REVISIT: most hardware initializes GPIOs as * inputs (often with pullups enabled) so power @@ -1114,7 +1201,7 @@ int gpiochip_add(struct gpio_chip *chip) * and in case chip->get_direction is not set, * we may expose the wrong direction in sysfs. */ - gpio_desc[id].flags = !chip->direction_input + desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } @@ -1167,15 +1254,17 @@ int gpiochip_remove(struct gpio_chip *chip) gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); - for (id = chip->base; id < chip->base + chip->ngpio; id++) { - if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) { + for (id = 0; id < chip->ngpio; id++) { + if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { status = -EBUSY; break; } } if (status == 0) { - for (id = chip->base; id < chip->base + chip->ngpio; id++) - gpio_desc[id].chip = NULL; + for (id = 0; id < chip->ngpio; id++) + chip->desc[id].chip = NULL; + + list_del(&chip->list); } spin_unlock_irqrestore(&gpio_lock, flags); @@ -1202,20 +1291,17 @@ struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, void *data)) { - struct gpio_chip *chip = NULL; + struct gpio_chip *chip; unsigned long flags; - int i; spin_lock_irqsave(&gpio_lock, flags); - for (i = 0; i < ARCH_NR_GPIOS; i++) { - if (!gpio_desc[i].chip) - continue; - - if (match(gpio_desc[i].chip, data)) { - chip = gpio_desc[i].chip; + list_for_each_entry(chip, &gpio_chips, list) + if (match(chip, data)) break; - } - } + + /* No match? */ + if (&chip->list == &gpio_chips) + chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); return chip; @@ -1297,20 +1383,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -int gpio_request(unsigned gpio, const char *label) +static int gpiod_request(struct gpio_desc *desc, const char *label) { - struct gpio_desc *desc; struct gpio_chip *chip; int status = -EPROBE_DEFER; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) { + if (!desc) { status = -EINVAL; goto done; } - desc = &gpio_desc[gpio]; chip = desc->chip; if (chip == NULL) goto done; @@ -1334,7 +1418,7 @@ int gpio_request(unsigned gpio, const char *label) if (chip->request) { /* chip->request may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); - status = chip->request(chip, gpio - chip->base); + status = chip->request(chip, gpio_chip_hwgpio(desc)); spin_lock_irqsave(&gpio_lock, flags); if (status < 0) { @@ -1347,42 +1431,46 @@ int gpio_request(unsigned gpio, const char *label) if (chip->get_direction) { /* chip->get_direction may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); - gpio_get_direction(gpio); + gpiod_get_direction(desc); spin_lock_irqsave(&gpio_lock, flags); } done: if (status) - pr_debug("gpio_request: gpio-%d (%s) status %d\n", - gpio, label ? : "?", status); + pr_debug("_gpio_request: gpio-%d (%s) status %d\n", + desc ? desc_to_gpio(desc) : -1, + label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } + +int gpio_request(unsigned gpio, const char *label) +{ + return gpiod_request(gpio_to_desc(gpio), label); +} EXPORT_SYMBOL_GPL(gpio_request); -void gpio_free(unsigned gpio) +static void gpiod_free(struct gpio_desc *desc) { unsigned long flags; - struct gpio_desc *desc; struct gpio_chip *chip; might_sleep(); - if (!gpio_is_valid(gpio)) { + if (!desc) { WARN_ON(extra_checks); return; } - gpio_unexport(gpio); + gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); - desc = &gpio_desc[gpio]; chip = desc->chip; if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (chip->free) { spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); - chip->free(chip, gpio - chip->base); + chip->free(chip, gpio_chip_hwgpio(desc)); spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); @@ -1396,6 +1484,11 @@ void gpio_free(unsigned gpio) spin_unlock_irqrestore(&gpio_lock, flags); } + +void gpio_free(unsigned gpio) +{ + gpiod_free(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(gpio_free); /** @@ -1406,29 +1499,32 @@ EXPORT_SYMBOL_GPL(gpio_free); */ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) { + struct gpio_desc *desc; int err; - err = gpio_request(gpio, label); + desc = gpio_to_desc(gpio); + + err = gpiod_request(desc, label); if (err) return err; if (flags & GPIOF_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags); + set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (flags & GPIOF_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags); + set_bit(FLAG_OPEN_SOURCE, &desc->flags); if (flags & GPIOF_DIR_IN) - err = gpio_direction_input(gpio); + err = gpiod_direction_input(desc); else - err = gpio_direction_output(gpio, + err = gpiod_direction_output(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) goto free_gpio; if (flags & GPIOF_EXPORT) { - err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE); + err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE); if (err) goto free_gpio; } @@ -1436,7 +1532,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) return 0; free_gpio: - gpio_free(gpio); + gpiod_free(desc); return err; } EXPORT_SYMBOL_GPL(gpio_request_one); @@ -1491,14 +1587,17 @@ EXPORT_SYMBOL_GPL(gpio_free_array); */ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { - unsigned gpio = chip->base + offset; + struct gpio_desc *desc; - if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) + if (!GPIO_OFFSET_VALID(chip, offset)) return NULL; - if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) + + desc = &chip->desc[offset]; + + if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) return NULL; #ifdef CONFIG_DEBUG_FS - return gpio_desc[gpio].label; + return desc->label; #else return "?"; #endif @@ -1515,24 +1614,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * rely on gpio_request() having been called beforehand. */ -int gpio_direction_input(unsigned gpio) +static int gpiod_direction_input(struct gpio_desc *desc) { unsigned long flags; struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + int offset; spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!desc) goto fail; chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) goto fail; - gpio -= chip->base; - if (gpio >= chip->ngpio) - goto fail; - status = gpio_ensure_requested(desc, gpio); + status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1542,11 +1638,12 @@ int gpio_direction_input(unsigned gpio) might_sleep_if(chip->can_sleep); + offset = gpio_chip_hwgpio(desc); if (status) { - status = chip->request(chip, gpio); + status = chip->request(chip, offset); if (status < 0) { pr_debug("GPIO-%d: chip request fail, %d\n", - chip->base + gpio, status); + desc_to_gpio(desc), status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1554,48 +1651,54 @@ int gpio_direction_input(unsigned gpio) } } - status = chip->direction_input(chip, gpio); + status = chip->direction_input(chip, offset); if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); - trace_gpio_direction(chip->base + gpio, 1, status); + trace_gpio_direction(desc_to_gpio(desc), 1, status); lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) + if (status) { + int gpio = -1; + if (desc) + gpio = desc_to_gpio(desc); pr_debug("%s: gpio-%d status %d\n", __func__, gpio, status); + } return status; } + +int gpio_direction_input(unsigned gpio) +{ + return gpiod_direction_input(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(gpio_direction_input); -int gpio_direction_output(unsigned gpio, int value) +static int gpiod_direction_output(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + int offset; /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - return gpio_direction_input(gpio); + return gpiod_direction_input(desc); /* Open source pin should not be driven to 0 */ if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - return gpio_direction_input(gpio); + return gpiod_direction_input(desc); spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!desc) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->direction_output) goto fail; - gpio -= chip->base; - if (gpio >= chip->ngpio) - goto fail; - status = gpio_ensure_requested(desc, gpio); + status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1605,11 +1708,12 @@ int gpio_direction_output(unsigned gpio, int value) might_sleep_if(chip->can_sleep); + offset = gpio_chip_hwgpio(desc); if (status) { - status = chip->request(chip, gpio); + status = chip->request(chip, offset); if (status < 0) { pr_debug("GPIO-%d: chip request fail, %d\n", - chip->base + gpio, status); + desc_to_gpio(desc), status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1617,20 +1721,29 @@ int gpio_direction_output(unsigned gpio, int value) } } - status = chip->direction_output(chip, gpio, value); + status = chip->direction_output(chip, offset, value); if (status == 0) set_bit(FLAG_IS_OUT, &desc->flags); - trace_gpio_value(chip->base + gpio, 0, value); - trace_gpio_direction(chip->base + gpio, 0, status); + trace_gpio_value(desc_to_gpio(desc), 0, value); + trace_gpio_direction(desc_to_gpio(desc), 0, status); lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) + if (status) { + int gpio = -1; + if (desc) + gpio = desc_to_gpio(desc); pr_debug("%s: gpio-%d status %d\n", __func__, gpio, status); + } return status; } + +int gpio_direction_output(unsigned gpio, int value) +{ + return gpiod_direction_output(gpio_to_desc(gpio), value); +} EXPORT_SYMBOL_GPL(gpio_direction_output); /** @@ -1638,24 +1751,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output); * @gpio: the gpio to set debounce time * @debounce: debounce time is microseconds */ -int gpio_set_debounce(unsigned gpio, unsigned debounce) +static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { unsigned long flags; struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + int offset; spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!desc) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->set_debounce) goto fail; - gpio -= chip->base; - if (gpio >= chip->ngpio) - goto fail; - status = gpio_ensure_requested(desc, gpio); + + status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1665,16 +1776,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce) might_sleep_if(chip->can_sleep); - return chip->set_debounce(chip, gpio, debounce); + offset = gpio_chip_hwgpio(desc); + return chip->set_debounce(chip, offset, debounce); fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) + if (status) { + int gpio = -1; + if (desc) + gpio = desc_to_gpio(desc); pr_debug("%s: gpio-%d status %d\n", __func__, gpio, status); + } return status; } + +int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + return gpiod_set_debounce(gpio_to_desc(gpio), debounce); +} EXPORT_SYMBOL_GPL(gpio_set_debounce); /* I/O calls are only valid after configuration completed; the relevant @@ -1708,18 +1829,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); * It returns the zero or nonzero value provided by the associated * gpio_chip.get() method; or zero if no such method is provided. */ -int __gpio_get_value(unsigned gpio) +static int gpiod_get_value(struct gpio_desc *desc) { struct gpio_chip *chip; int value; + int offset; - chip = gpio_to_chip(gpio); + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); /* Should be using gpio_get_value_cansleep() */ WARN_ON(chip->can_sleep); - value = chip->get ? chip->get(chip, gpio - chip->base) : 0; - trace_gpio_value(gpio, 1, value); + value = chip->get ? chip->get(chip, offset) : 0; + trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } + +int __gpio_get_value(unsigned gpio) +{ + return gpiod_get_value(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(__gpio_get_value); /* @@ -1728,23 +1856,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value); * @chip: Gpio chip. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_drain_value(unsigned gpio, - struct gpio_chip *chip, int value) +static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) { int err = 0; + struct gpio_chip *chip = desc->chip; + int offset = gpio_chip_hwgpio(desc); + if (value) { - err = chip->direction_input(chip, gpio - chip->base); + err = chip->direction_input(chip, offset); if (!err) - clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + clear_bit(FLAG_IS_OUT, &desc->flags); } else { - err = chip->direction_output(chip, gpio - chip->base, 0); + err = chip->direction_output(chip, offset, 0); if (!err) - set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + set_bit(FLAG_IS_OUT, &desc->flags); } - trace_gpio_direction(gpio, value, err); + trace_gpio_direction(desc_to_gpio(desc), value, err); if (err < 0) pr_err("%s: Error in set_value for open drain gpio%d err %d\n", - __func__, gpio, err); + __func__, desc_to_gpio(desc), err); } /* @@ -1753,26 +1883,27 @@ static void _gpio_set_open_drain_value(unsigned gpio, * @chip: Gpio chip. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_source_value(unsigned gpio, - struct gpio_chip *chip, int value) +static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) { int err = 0; + struct gpio_chip *chip = desc->chip; + int offset = gpio_chip_hwgpio(desc); + if (value) { - err = chip->direction_output(chip, gpio - chip->base, 1); + err = chip->direction_output(chip, offset, 1); if (!err) - set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + set_bit(FLAG_IS_OUT, &desc->flags); } else { - err = chip->direction_input(chip, gpio - chip->base); + err = chip->direction_input(chip, offset); if (!err) - clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + clear_bit(FLAG_IS_OUT, &desc->flags); } - trace_gpio_direction(gpio, !value, err); + trace_gpio_direction(desc_to_gpio(desc), !value, err); if (err < 0) pr_err("%s: Error in set_value for open source gpio%d err %d\n", - __func__, gpio, err); + __func__, desc_to_gpio(desc), err); } - /** * __gpio_set_value() - assign a gpio's value * @gpio: gpio whose value will be assigned @@ -1782,20 +1913,25 @@ static void _gpio_set_open_source_value(unsigned gpio, * This is used directly or indirectly to implement gpio_set_value(). * It invokes the associated gpio_chip.set() method. */ -void __gpio_set_value(unsigned gpio, int value) +static void gpiod_set_value(struct gpio_desc *desc, int value) { struct gpio_chip *chip; - chip = gpio_to_chip(gpio); + chip = desc->chip; /* Should be using gpio_set_value_cansleep() */ WARN_ON(chip->can_sleep); - trace_gpio_value(gpio, 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) - _gpio_set_open_drain_value(gpio, chip, value); - else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) - _gpio_set_open_source_value(gpio, chip, value); + trace_gpio_value(desc_to_gpio(desc), 0, value); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + _gpio_set_open_drain_value(desc, value); + else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + _gpio_set_open_source_value(desc, value); else - chip->set(chip, gpio - chip->base, value); + chip->set(chip, gpio_chip_hwgpio(desc), value); +} + +void __gpio_set_value(unsigned gpio, int value) +{ + return gpiod_set_value(gpio_to_desc(gpio), value); } EXPORT_SYMBOL_GPL(__gpio_set_value); @@ -1807,14 +1943,15 @@ EXPORT_SYMBOL_GPL(__gpio_set_value); * This is used directly or indirectly to implement gpio_cansleep(). It * returns nonzero if access reading or writing the GPIO value can sleep. */ -int __gpio_cansleep(unsigned gpio) +static int gpiod_cansleep(struct gpio_desc *desc) { - struct gpio_chip *chip; - /* only call this on GPIOs that are valid! */ - chip = gpio_to_chip(gpio); + return desc->chip->can_sleep; +} - return chip->can_sleep; +int __gpio_cansleep(unsigned gpio) +{ + return gpiod_cansleep(gpio_to_desc(gpio)); } EXPORT_SYMBOL_GPL(__gpio_cansleep); @@ -1827,50 +1964,67 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep); * It returns the number of the IRQ signaled by this (input) GPIO, * or a negative errno. */ -int __gpio_to_irq(unsigned gpio) +static int gpiod_to_irq(struct gpio_desc *desc) { struct gpio_chip *chip; + int offset; - chip = gpio_to_chip(gpio); - return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); + return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; } -EXPORT_SYMBOL_GPL(__gpio_to_irq); +int __gpio_to_irq(unsigned gpio) +{ + return gpiod_to_irq(gpio_to_desc(gpio)); +} +EXPORT_SYMBOL_GPL(__gpio_to_irq); /* There's no value in making it easy to inline GPIO calls that may sleep. * Common examples include ones connected to I2C or SPI chips. */ -int gpio_get_value_cansleep(unsigned gpio) +static int gpiod_get_value_cansleep(struct gpio_desc *desc) { struct gpio_chip *chip; int value; + int offset; might_sleep_if(extra_checks); - chip = gpio_to_chip(gpio); - value = chip->get ? chip->get(chip, gpio - chip->base) : 0; - trace_gpio_value(gpio, 1, value); + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); + value = chip->get ? chip->get(chip, offset) : 0; + trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } + +int gpio_get_value_cansleep(unsigned gpio) +{ + return gpiod_get_value_cansleep(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); -void gpio_set_value_cansleep(unsigned gpio, int value) +static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { struct gpio_chip *chip; might_sleep_if(extra_checks); - chip = gpio_to_chip(gpio); - trace_gpio_value(gpio, 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) - _gpio_set_open_drain_value(gpio, chip, value); - else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) - _gpio_set_open_source_value(gpio, chip, value); + chip = desc->chip; + trace_gpio_value(desc_to_gpio(desc), 0, value); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + _gpio_set_open_drain_value(desc, value); + else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + _gpio_set_open_source_value(desc, value); else - chip->set(chip, gpio - chip->base, value); + chip->set(chip, gpio_chip_hwgpio(desc), value); } -EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); +void gpio_set_value_cansleep(unsigned gpio, int value) +{ + return gpiod_set_value_cansleep(gpio_to_desc(gpio), value); +} +EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); #ifdef CONFIG_DEBUG_FS @@ -1878,14 +2032,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) { unsigned i; unsigned gpio = chip->base; - struct gpio_desc *gdesc = &gpio_desc[gpio]; + struct gpio_desc *gdesc = &chip->desc[0]; int is_out; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) continue; - gpio_get_direction(gpio); + gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", gpio, gdesc->label, @@ -1899,46 +2053,35 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos) { + unsigned long flags; struct gpio_chip *chip = NULL; - unsigned int gpio; - void *ret = NULL; - loff_t index = 0; - - /* REVISIT this isn't locked against gpio_chip removal ... */ + loff_t index = *pos; - for (gpio = 0; gpio_is_valid(gpio); gpio++) { - if (gpio_desc[gpio].chip == chip) - continue; - - chip = gpio_desc[gpio].chip; - if (!chip) - continue; + s->private = ""; - if (index++ >= *pos) { - ret = chip; - break; + spin_lock_irqsave(&gpio_lock, flags); + list_for_each_entry(chip, &gpio_chips, list) + if (index-- == 0) { + spin_unlock_irqrestore(&gpio_lock, flags); + return chip; } - } - - s->private = ""; + spin_unlock_irqrestore(&gpio_lock, flags); - return ret; + return NULL; } static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) { + unsigned long flags; struct gpio_chip *chip = v; - unsigned int gpio; void *ret = NULL; - /* skip GPIOs provided by the current chip */ - for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) { - chip = gpio_desc[gpio].chip; - if (chip) { - ret = chip; - break; - } - } + spin_lock_irqsave(&gpio_lock, flags); + if (list_is_last(&chip->list, &gpio_chips)) + ret = NULL; + else + ret = list_entry(chip->list.next, struct gpio_chip, list); + spin_unlock_irqrestore(&gpio_lock, flags); s->private = "\n"; ++*pos; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 20ca766..bde6469 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -47,12 +47,14 @@ struct gpio; struct seq_file; struct module; struct device_node; +struct gpio_desc; /** * struct gpio_chip - abstract a GPIO controller * @label: for diagnostics * @dev: optional device providing the GPIOs * @owner: helps prevent removal of modules exporting active GPIOs + * @list: links gpio_chips together for traversal * @request: optional hook for chip-specific activation, such as * enabling module power and clock; may sleep * @free: optional hook for chip-specific deactivation, such as @@ -75,6 +77,7 @@ struct device_node; * negative during registration, requests dynamic ID allocation. * @ngpio: the number of GPIOs handled by this controller; the last GPIO * handled is (base + ngpio - 1). + * @desc: array of ngpio descriptors. Private. * @can_sleep: flag must be set iff get()/set() methods sleep, as they * must while accessing GPIO expander chips over I2C or SPI * @names: if set, must be an array of strings to use as alternative @@ -98,6 +101,7 @@ struct gpio_chip { const char *label; struct device *dev; struct module *owner; + struct list_head list; int (*request)(struct gpio_chip *chip, unsigned offset); @@ -124,6 +128,7 @@ struct gpio_chip { struct gpio_chip *chip); int base; u16 ngpio; + struct gpio_desc *desc; const char *const *names; unsigned can_sleep:1; unsigned exported:1; @@ -152,7 +157,6 @@ struct gpio_chip { extern const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset); extern struct gpio_chip *gpio_to_chip(unsigned gpio); -extern int __must_check gpiochip_reserve(int start, int ngpio); /* add/remove chips */ extern int gpiochip_add(struct gpio_chip *chip); @@ -192,12 +196,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); -/* bindings for managed devices that want to request gpios */ -int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); -int devm_gpio_request_one(struct device *dev, unsigned gpio, - unsigned long flags, const char *label); -void devm_gpio_free(struct device *dev, unsigned int gpio); - #ifdef CONFIG_GPIO_SYSFS /* @@ -212,6 +210,43 @@ extern void gpio_unexport(unsigned gpio); #endif /* CONFIG_GPIO_SYSFS */ +#ifdef CONFIG_PINCTRL + +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; + +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + +#else + +static inline int +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins) +{ + return 0; +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + #else /* !CONFIG_GPIOLIB */ static inline bool gpio_is_valid(int number) @@ -270,41 +305,4 @@ static inline void gpio_unexport(unsigned gpio) } #endif /* CONFIG_GPIO_SYSFS */ -#ifdef CONFIG_PINCTRL - -/** - * struct gpio_pin_range - pin range controlled by a gpio chip - * @head: list for maintaining set of pin ranges, used internally - * @pctldev: pinctrl device which handles corresponding pins - * @range: actual range of pins controlled by a gpio controller - */ - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); - -#else - -static inline int -gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins) -{ - return 0; -} - -static inline void -gpiochip_remove_pin_ranges(struct gpio_chip *chip) -{ -} - -#endif /* CONFIG_PINCTRL */ - #endif /* _ASM_GENERIC_GPIO_H */ diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index 91615a38..b76ebd0 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h @@ -2,10 +2,12 @@ #define _LINUX_ACPI_GPIO_H_ #include <linux/errno.h> +#include <linux/gpio.h> #ifdef CONFIG_GPIO_ACPI int acpi_get_gpio(char *path, int pin); +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); #else /* CONFIG_GPIO_ACPI */ @@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin) return -ENODEV; } +static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } + #endif /* CONFIG_GPIO_ACPI */ #endif /* _LINUX_ACPI_GPIO_H_ */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index bfe6656..f6c7ae3 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label) return -ENOSYS; } -static inline int devm_gpio_request(struct device *dev, unsigned gpio, - const char *label) -{ - return -ENOSYS; -} - static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) { return -ENOSYS; } -static inline int devm_gpio_request_one(struct device *dev, unsigned gpio, - unsigned long flags, const char *label) -{ - return -ENOSYS; -} - static inline int gpio_request_array(const struct gpio *array, size_t num) { return -ENOSYS; @@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio) WARN_ON(1); } -static inline void devm_gpio_free(struct device *dev, unsigned gpio) -{ - might_sleep(); - - /* GPIO can never have been requested */ - WARN_ON(1); -} - static inline void gpio_free_array(const struct gpio *array, size_t num) { might_sleep(); @@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip) #endif /* ! CONFIG_GENERIC_GPIO */ +struct device; + +/* bindings for managed devices that want to request gpios */ +int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); +int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label); +void devm_gpio_free(struct device *dev, unsigned int gpio); + #endif /* __LINUX_GPIO_H */ |