Commit 4c8c225a authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents 3eb05225 9170100e
...@@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd) ...@@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd)
static void __init tosa_init(void) static void __init tosa_init(void)
{ {
int dummy;
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config)); pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config));
pxa_set_ffuart_info(NULL); pxa_set_ffuart_info(NULL);
...@@ -947,10 +945,6 @@ static void __init tosa_init(void) ...@@ -947,10 +945,6 @@ static void __init tosa_init(void)
/* enable batt_fault */ /* enable batt_fault */
PMCR = 0x01; 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_mci_info(&tosa_mci_platform_data);
pxa_set_ficp_info(&tosa_ficp_platform_data); pxa_set_ficp_info(&tosa_ficp_platform_data);
pxa_set_i2c_info(NULL); pxa_set_i2c_info(NULL);
......
config ARM64 config ARM64
def_bool y def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_FRAME_POINTERS
select ARM_AMBA select ARM_AMBA
...@@ -93,7 +94,7 @@ config IOMMU_HELPER ...@@ -93,7 +94,7 @@ config IOMMU_HELPER
def_bool SWIOTLB def_bool SWIOTLB
config GENERIC_GPIO config GENERIC_GPIO
def_bool y bool
source "init/Kconfig" source "init/Kconfig"
......
...@@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB ...@@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB
Selecting this from the architecture code will cause the gpiolib Selecting this from the architecture code will cause the gpiolib
code to always get built in. code to always get built in.
config GPIO_DEVRES
def_bool y
depends on HAS_IOMEM
menuconfig GPIOLIB menuconfig GPIOLIB
...@@ -298,6 +301,14 @@ config GPIO_GE_FPGA ...@@ -298,6 +301,14 @@ config GPIO_GE_FPGA
and write pin state) for GPIO implemented in a number of GE single and write pin state) for GPIO implemented in a number of GE single
board computers. 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:" comment "I2C GPIO expanders:"
config GPIO_ARIZONA config GPIO_ARIZONA
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG 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_OF_GPIO) += gpiolib-of.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
...@@ -30,6 +31,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o ...@@ -30,6 +31,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.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_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
......
...@@ -299,8 +299,9 @@ static int em_gio_probe(struct platform_device *pdev) ...@@ -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->irq_set_type = em_gio_irq_set_type;
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; 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->number_of_pins,
pdata->irq_base,
&em_gio_irq_domain_ops, p); &em_gio_irq_domain_ops, p);
if (!p->irq_domain) { if (!p->irq_domain) {
ret = -ENXIO; ret = -ENXIO;
......
...@@ -71,10 +71,12 @@ struct lnw_gpio { ...@@ -71,10 +71,12 @@ struct lnw_gpio {
struct irq_domain *domain; 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, static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
enum GPIO_REG reg_type) 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; unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 32; u8 reg = offset / 32;
void __iomem *ptr; void __iomem *ptr;
...@@ -86,7 +88,7 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, ...@@ -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, static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
enum GPIO_REG reg_type) 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; unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 16; u8 reg = offset / 16;
void __iomem *ptr; void __iomem *ptr;
...@@ -130,7 +132,7 @@ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -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) 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); void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
u32 value; u32 value;
unsigned long flags; unsigned long flags;
...@@ -153,7 +155,7 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ...@@ -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, static int lnw_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value) 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); void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
unsigned long flags; unsigned long flags;
...@@ -176,7 +178,7 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip, ...@@ -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) 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); return irq_create_mapping(lnw->domain, offset);
} }
...@@ -234,6 +236,8 @@ static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ ...@@ -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, 0x080f), .driver_data = 64 },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, { 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, 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, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
...@@ -299,17 +303,6 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = { ...@@ -299,17 +303,6 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
.xlate = irq_domain_xlate_twocell, .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) static int lnw_gpio_runtime_idle(struct device *dev)
{ {
int err = pm_schedule_suspend(dev, 500); int err = pm_schedule_suspend(dev, 500);
...@@ -320,16 +313,8 @@ static int lnw_gpio_runtime_idle(struct device *dev) ...@@ -320,16 +313,8 @@ static int lnw_gpio_runtime_idle(struct device *dev)
return -EBUSY; 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 = { static const struct dev_pm_ops lnw_gpio_pm_ops = {
.runtime_suspend = lnw_gpio_runtime_suspend, SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle)
.runtime_resume = lnw_gpio_runtime_resume,
.runtime_idle = lnw_gpio_runtime_idle,
}; };
static int lnw_gpio_probe(struct pci_dev *pdev, static int lnw_gpio_probe(struct pci_dev *pdev,
...@@ -349,7 +334,7 @@ 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"); retval = pci_request_regions(pdev, "langwell_gpio");
if (retval) { if (retval) {
dev_err(&pdev->dev, "error requesting resources\n"); dev_err(&pdev->dev, "error requesting resources\n");
goto err2; goto err_pci_req_region;
} }
/* get the gpio_base from bar1 */ /* get the gpio_base from bar1 */
start = pci_resource_start(pdev, 1); start = pci_resource_start(pdev, 1);
...@@ -358,7 +343,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, ...@@ -358,7 +343,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
if (!base) { if (!base) {
dev_err(&pdev->dev, "error mapping bar1\n"); dev_err(&pdev->dev, "error mapping bar1\n");
retval = -EFAULT; retval = -EFAULT;
goto err3; goto err_ioremap;
} }
gpio_base = *((u32 *)base + 1); gpio_base = *((u32 *)base + 1);
/* release the IO mapping, since we already get the info from bar1 */ /* 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, ...@@ -370,21 +355,21 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
if (!base) { if (!base) {
dev_err(&pdev->dev, "error mapping bar0\n"); dev_err(&pdev->dev, "error mapping bar0\n");
retval = -EFAULT; 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) { if (!lnw) {
dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
retval = -ENOMEM; retval = -ENOMEM;
goto err3; goto err_ioremap;
} }
lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
&lnw_gpio_irq_ops, lnw); &lnw_gpio_irq_ops, lnw);
if (!lnw->domain) { if (!lnw->domain) {
retval = -ENOMEM; retval = -ENOMEM;
goto err3; goto err_ioremap;
} }
lnw->reg_base = base; lnw->reg_base = base;
...@@ -403,7 +388,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, ...@@ -403,7 +388,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
retval = gpiochip_add(&lnw->chip); retval = gpiochip_add(&lnw->chip);
if (retval) { if (retval) {
dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
goto err3; goto err_ioremap;
} }
lnw_irq_init_hw(lnw); lnw_irq_init_hw(lnw);
...@@ -418,9 +403,9 @@ static int lnw_gpio_probe(struct pci_dev *pdev, ...@@ -418,9 +403,9 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
return 0; return 0;
err3: err_ioremap:
pci_release_regions(pdev); pci_release_regions(pdev);
err2: err_pci_req_region:
pci_disable_device(pdev); pci_disable_device(pdev);
return retval; return retval;
} }
......
/*
* 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);
...@@ -292,7 +292,6 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, ...@@ -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_data(virq, h->host_data);
irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
irq_set_irq_type(virq, IRQ_TYPE_NONE);
return 0; return 0;
} }
......
...@@ -66,6 +66,7 @@ struct mxs_gpio_port { ...@@ -66,6 +66,7 @@ struct mxs_gpio_port {
struct irq_domain *domain; struct irq_domain *domain;
struct bgpio_chip bgc; struct bgpio_chip bgc;
enum mxs_gpio_id devid; enum mxs_gpio_id devid;
u32 both_edges;
}; };
static inline int is_imx23_gpio(struct mxs_gpio_port *port) 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) ...@@ -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) static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{ {
u32 val;
u32 pin_mask = 1 << d->hwirq; u32 pin_mask = 1 << d->hwirq;
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mxs_gpio_port *port = gc->private; struct mxs_gpio_port *port = gc->private;
void __iomem *pin_addr; void __iomem *pin_addr;
int edge; int edge;
port->both_edges &= ~pin_mask;
switch (type) { 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: case IRQ_TYPE_EDGE_RISING:
edge = GPIO_INT_RISE_EDGE; edge = GPIO_INT_RISE_EDGE;
break; break;
...@@ -125,6 +136,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) ...@@ -125,6 +136,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
return 0; 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 */ /* MXS has one interrupt *per* gpio port */
static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) 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) ...@@ -138,6 +166,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
while (irq_stat != 0) { while (irq_stat != 0) {
int irqoffset = fls(irq_stat) - 1; 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)); generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
irq_stat &= ~(1 << irqoffset); irq_stat &= ~(1 << irqoffset);
} }
......
...@@ -1476,19 +1476,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { ...@@ -1476,19 +1476,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.fallingdetect = OMAP4_GPIO_FALLINGDETECT, .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, .regs = &omap2_gpio_regs,
.bank_width = 32, .bank_width = 32,
.dbck_flag = false, .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, .regs = &omap2_gpio_regs,
.bank_width = 32, .bank_width = 32,
.dbck_flag = true, .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, .regs = &omap4_gpio_regs,
.bank_width = 32, .bank_width = 32,
.dbck_flag = true, .dbck_flag = true,
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define PCA957X_TYPE 0x2000 #define PCA957X_TYPE 0x2000
static const struct i2c_device_id pca953x_id[] = { static const struct i2c_device_id pca953x_id[] = {
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, }, { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9536", 4 | PCA953X_TYPE, }, { "pca9536", 4 | PCA953X_TYPE, },
...@@ -71,19 +72,23 @@ static const struct i2c_device_id pca953x_id[] = { ...@@ -71,19 +72,23 @@ static const struct i2c_device_id pca953x_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, 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 { struct pca953x_chip {
unsigned gpio_start; unsigned gpio_start;
u32 reg_output; u8 reg_output[MAX_BANK];
u32 reg_direction; u8 reg_direction[MAX_BANK];
struct mutex i2c_lock; struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ #ifdef CONFIG_GPIO_PCA953X_IRQ
struct mutex irq_lock; struct mutex irq_lock;
u32 irq_mask; u8 irq_mask[MAX_BANK];
u32 irq_stat; u8 irq_stat[MAX_BANK];
u32 irq_trig_raise; u8 irq_trig_raise[MAX_BANK];
u32 irq_trig_fall; u8 irq_trig_fall[MAX_BANK];
int irq_base;
struct irq_domain *domain; struct irq_domain *domain;
#endif #endif
...@@ -93,33 +98,69 @@ struct pca953x_chip { ...@@ -93,33 +98,69 @@ struct pca953x_chip {
int chip_type; 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; int ret = 0;
if (chip->gpio_chip.ngpio <= 8) if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_write_byte_data(chip->client, reg, val); ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
else if (chip->gpio_chip.ngpio == 24) { else if (chip->gpio_chip.ngpio >= 24) {
cpu_to_le32s(&val); int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
ret = i2c_smbus_write_i2c_block_data(chip->client, ret = i2c_smbus_write_i2c_block_data(chip->client,
(reg << 2) | REG_ADDR_AI, (reg << bank_shift) | REG_ADDR_AI,
3, NBANK(chip), val);
(u8 *) &val);
} }
else { else {
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
ret = i2c_smbus_write_word_data(chip->client, ret = i2c_smbus_write_word_data(chip->client,
reg << 1, val); reg << 1, (u16) *val);
break; break;
case PCA957X_TYPE: case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1, ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
val & 0xff); val[0]);
if (ret < 0) if (ret < 0)
break; break;
ret = i2c_smbus_write_byte_data(chip->client, ret = i2c_smbus_write_byte_data(chip->client,
(reg << 1) + 1, (reg << 1) + 1,
(val & 0xff00) >> 8); val[1]);
break; break;
} }
} }
...@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) ...@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
return 0; 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; int ret;
if (chip->gpio_chip.ngpio <= 8) { if (chip->gpio_chip.ngpio <= 8) {
ret = i2c_smbus_read_byte_data(chip->client, reg); ret = i2c_smbus_read_byte_data(chip->client, reg);
*val = ret; *val = ret;
} } else if (chip->gpio_chip.ngpio >= 24) {
else if (chip->gpio_chip.ngpio == 24) { int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
*val = 0;
ret = i2c_smbus_read_i2c_block_data(chip->client, ret = i2c_smbus_read_i2c_block_data(chip->client,
(reg << 2) | REG_ADDR_AI, (reg << bank_shift) | REG_ADDR_AI,
3, NBANK(chip), val);
(u8 *) val);
le32_to_cpus(val);
} else { } else {
ret = i2c_smbus_read_word_data(chip->client, reg << 1); 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) { if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n"); dev_err(&chip->client->dev, "failed reading register\n");
return ret; return ret;
...@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) ...@@ -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) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
mutex_lock(&chip->i2c_lock); 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) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) ...@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
offset = PCA957X_CFG; offset = PCA957X_CFG;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_direction = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0; ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
...@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val) unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
/* set output level */ /* set output level */
if (val) if (val)
reg_val = chip->reg_output | (1u << off); reg_val = chip->reg_output[off / BANK_SZ]
| (1u << (off % BANK_SZ));
else else
reg_val = chip->reg_output & ~(1u << off); reg_val = chip->reg_output[off / BANK_SZ]
& ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_OUT; offset = PCA957X_OUT;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_output = reg_val; chip->reg_output[off / BANK_SZ] = reg_val;
/* then direction */ /* 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) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
offset = PCA953X_DIRECTION; offset = PCA953X_DIRECTION;
...@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_CFG; offset = PCA957X_CFG;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_direction = reg_val; chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0; ret = 0;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
...@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) ...@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &reg_val); ret = pca953x_read_single(chip, offset, &reg_val, off);
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
if (ret < 0) { if (ret < 0) {
/* NOTE: diagnostic already emitted; that's all we should /* 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) ...@@ -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) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
u32 reg_val; u8 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
mutex_lock(&chip->i2c_lock); mutex_lock(&chip->i2c_lock);
if (val) if (val)
reg_val = chip->reg_output | (1u << off); reg_val = chip->reg_output[off / BANK_SZ]
| (1u << (off % BANK_SZ));
else else
reg_val = chip->reg_output & ~(1u << off); reg_val = chip->reg_output[off / BANK_SZ]
& ~(1u << (off % BANK_SZ));
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) ...@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
offset = PCA957X_OUT; offset = PCA957X_OUT;
break; break;
} }
ret = pca953x_write_reg(chip, offset, reg_val); ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret) if (ret)
goto exit; goto exit;
chip->reg_output = reg_val; chip->reg_output[off / BANK_SZ] = reg_val;
exit: exit:
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
} }
...@@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) ...@@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
struct pca953x_chip *chip; struct pca953x_chip *chip;
chip = container_of(gc, struct pca953x_chip, gpio_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) static void pca953x_irq_mask(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_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) static void pca953x_irq_unmask(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_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) static void pca953x_irq_bus_lock(struct irq_data *d)
...@@ -355,17 +398,20 @@ 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) static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
u32 new_irqs; u8 new_irqs;
u32 level; int level, i;
/* Look for any newly setup interrupt */ /* Look for any newly setup interrupt */
new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; for (i = 0; i < NBANK(chip); i++) {
new_irqs &= ~chip->reg_direction; 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); while (new_irqs) {
pca953x_gpio_direction_input(&chip->gpio_chip, level); level = __ffs(new_irqs);
new_irqs &= ~(1 << level); pca953x_gpio_direction_input(&chip->gpio_chip,
level + (BANK_SZ * i));
new_irqs &= ~(1 << level);
}
} }
mutex_unlock(&chip->irq_lock); mutex_unlock(&chip->irq_lock);
...@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -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) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{ {
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); 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)) { if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", 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) ...@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
} }
if (type & IRQ_TYPE_EDGE_FALLING) if (type & IRQ_TYPE_EDGE_FALLING)
chip->irq_trig_fall |= mask; chip->irq_trig_fall[bank_nb] |= mask;
else else
chip->irq_trig_fall &= ~mask; chip->irq_trig_fall[bank_nb] &= ~mask;
if (type & IRQ_TYPE_EDGE_RISING) if (type & IRQ_TYPE_EDGE_RISING)
chip->irq_trig_raise |= mask; chip->irq_trig_raise[bank_nb] |= mask;
else else
chip->irq_trig_raise &= ~mask; chip->irq_trig_raise[bank_nb] &= ~mask;
return 0; return 0;
} }
...@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = { ...@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type, .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; u8 cur_stat[MAX_BANK];
u32 old_stat; u8 old_stat[MAX_BANK];
u32 pending; u8 pendings = 0;
u32 trigger; u8 trigger[MAX_BANK], triggers = 0;
int ret, offset = 0; int ret, i, offset = 0;
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip) ...@@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &cur_stat); ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret) if (ret)
return 0; return 0;
/* Remove output pins from the equation */ /* 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; for (i = 0; i < NBANK(chip); i++) {
trigger = (cur_stat ^ old_stat) & chip->irq_mask; trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
triggers += trigger[i];
}
if (!trigger) if (!triggers)
return 0; return 0;
chip->irq_stat = cur_stat; memcpy(chip->irq_stat, cur_stat, NBANK(chip));
pending = (old_stat & chip->irq_trig_fall) | for (i = 0; i < NBANK(chip); i++) {
(cur_stat & chip->irq_trig_raise); pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
pending &= trigger; (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) static irqreturn_t pca953x_irq_handler(int irq, void *devid)
{ {
struct pca953x_chip *chip = devid; struct pca953x_chip *chip = devid;
u32 pending; u8 pending[MAX_BANK];
u32 level; u8 level;
int i;
pending = pca953x_irq_pending(chip);
if (!pending) if (!pca953x_irq_pending(chip, pending))
return IRQ_HANDLED; return IRQ_HANDLED;
do { for (i = 0; i < NBANK(chip); i++) {
level = __ffs(pending); while (pending[i]) {
handle_nested_irq(irq_find_mapping(chip->domain, level)); level = __ffs(pending[i]);
handle_nested_irq(irq_find_mapping(chip->domain,
pending &= ~(1 << level); level + (BANK_SZ * i)));
} while (pending); pending[i] &= ~(1 << level);
}
}
return IRQ_HANDLED; 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, static int pca953x_irq_setup(struct pca953x_chip *chip,
const struct i2c_device_id *id, const struct i2c_device_id *id,
int irq_base) int irq_base)
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
int ret, offset = 0; int ret, i, offset = 0;
u32 temporary;
if (irq_base != -1 if (irq_base != -1
&& (id->driver_data & PCA_INT)) { && (id->driver_data & PCA_INT)) {
int lvl;
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &temporary); ret = pca953x_read_regs(chip, offset, chip->irq_stat);
chip->irq_stat = temporary;
if (ret) if (ret)
goto out_failed; return ret;
/* /*
* There is no way to know which GPIO line generated the * There is no way to know which GPIO line generated the
* interrupt. We have to rely on the previous read for * interrupt. We have to rely on the previous read for
* this purpose. * 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); mutex_init(&chip->irq_lock);
chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); chip->domain = irq_domain_add_simple(client->dev.of_node,
if (chip->irq_base < 0)
goto out_failed;
chip->domain = irq_domain_add_legacy(client->dev.of_node,
chip->gpio_chip.ngpio, chip->gpio_chip.ngpio,
chip->irq_base, irq_base,
0, &pca953x_irq_simple_ops,
&irq_domain_simple_ops,
NULL); NULL);
if (!chip->domain) { if (!chip->domain)
ret = -ENODEV; return -ENODEV;
goto out_irqdesc_free;
}
for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { ret = devm_request_threaded_irq(&client->dev,
int irq = lvl + chip->irq_base; client->irq,
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,
NULL, NULL,
pca953x_irq_handler, pca953x_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
...@@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
if (ret) { if (ret) {
dev_err(&client->dev, "failed to request irq %d\n", dev_err(&client->dev, "failed to request irq %d\n",
client->irq); client->irq);
goto out_irqdesc_free; return ret;
} }
chip->gpio_chip.to_irq = pca953x_gpio_to_irq; chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
} }
return 0; 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 */ #else /* CONFIG_GPIO_PCA953X_IRQ */
static int pca953x_irq_setup(struct pca953x_chip *chip, static int pca953x_irq_setup(struct pca953x_chip *chip,
const struct i2c_device_id *id, const struct i2c_device_id *id,
...@@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return 0; return 0;
} }
static void pca953x_irq_teardown(struct pca953x_chip *chip)
{
}
#endif #endif
/* /*
...@@ -619,18 +657,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) ...@@ -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) static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
{ {
int ret; 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) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA953X_DIRECTION, ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
&chip->reg_direction); chip->reg_direction);
if (ret) if (ret)
goto out; goto out;
/* set platform specific polarity inversion */ /* 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: out:
return ret; return ret;
} }
...@@ -638,28 +682,36 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) ...@@ -638,28 +682,36 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
{ {
int ret; int ret;
u32 val = 0; u8 val[MAX_BANK];
/* Let every port in proper state, that could save power */ /* Let every port in proper state, that could save power */
pca953x_write_reg(chip, PCA957X_PUPD, 0x0); memset(val, 0, NBANK(chip));
pca953x_write_reg(chip, PCA957X_CFG, 0xffff); pca953x_write_regs(chip, PCA957X_PUPD, val);
pca953x_write_reg(chip, PCA957X_OUT, 0x0); memset(val, 0xFF, NBANK(chip));
pca953x_write_regs(chip, PCA957X_CFG, val);
ret = pca953x_read_reg(chip, PCA957X_IN, &val); memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_OUT, val);
ret = pca953x_read_regs(chip, PCA957X_IN, val);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output); ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
if (ret) if (ret)
goto out; goto out;
ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction); ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
if (ret) if (ret)
goto out; goto out;
/* set platform specific polarity inversion */ /* 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 */ /* 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; return 0;
out: out:
...@@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client,
int ret; int ret;
u32 invert = 0; 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) if (chip == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client,
else else
ret = device_pca957x_init(chip, invert); ret = device_pca957x_init(chip, invert);
if (ret) if (ret)
goto out_failed; return ret;
ret = pca953x_irq_setup(chip, id, irq_base); ret = pca953x_irq_setup(chip, id, irq_base);
if (ret) if (ret)
goto out_failed; return ret;
ret = gpiochip_add(&chip->gpio_chip); ret = gpiochip_add(&chip->gpio_chip);
if (ret) if (ret)
goto out_failed_irq; return ret;
if (pdata && pdata->setup) { if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base, ret = pdata->setup(client, chip->gpio_chip.base,
...@@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client, ...@@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip); i2c_set_clientdata(client, chip);
return 0; return 0;
out_failed_irq:
pca953x_irq_teardown(chip);
out_failed:
kfree(chip);
return ret;
} }
static int pca953x_remove(struct i2c_client *client) static int pca953x_remove(struct i2c_client *client)
...@@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client) ...@@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client)
return ret; return ret;
} }
pca953x_irq_teardown(chip);
kfree(chip);
return 0; return 0;
} }
static const struct of_device_id pca953x_dt_ids[] = { static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pca9505", },
{ .compatible = "nxp,pca9534", }, { .compatible = "nxp,pca9534", },
{ .compatible = "nxp,pca9535", }, { .compatible = "nxp,pca9535", },
{ .compatible = "nxp,pca9536", }, { .compatible = "nxp,pca9536", },
......
...@@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void) ...@@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void)
{ {
return amba_driver_register(&pl061_gpio_driver); 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_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("PL061 GPIO driver"); MODULE_DESCRIPTION("PL061 GPIO driver");
......
...@@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = { ...@@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = {
.of_match_table = of_match_ptr(pxa_gpio_dt_ids), .of_match_table = of_match_ptr(pxa_gpio_dt_ids),
}, },
}; };
module_platform_driver(pxa_gpio_driver);
static int __init pxa_gpio_init(void)
{
return platform_driver_register(&pxa_gpio_driver);
}
postcore_initcall(pxa_gpio_init);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pxa_gpio_suspend(void) static int pxa_gpio_suspend(void)
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <linux/i2c/twl.h> #include <linux/i2c/twl.h>
/* /*
* The GPIO "subchip" supports 18 GPIOs which can be configured as * The GPIO "subchip" supports 18 GPIOs which can be configured as
* inputs or outputs, with pullups or pulldowns on each pin. Each * inputs or outputs, with pullups or pulldowns on each pin. Each
...@@ -49,11 +48,6 @@ ...@@ -49,11 +48,6 @@
* There are also two LED pins used sometimes as output-only GPIOs. * 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 */ /* genirq interfaces are not available to modules */
#ifdef MODULE #ifdef MODULE
#define is_module() true #define is_module() true
...@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base; ...@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base;
/* Mask for GPIO registers when aggregated into a 32-bit integer */ /* Mask for GPIO registers when aggregated into a 32-bit integer */
#define GPIO_32_MASK 0x0003ffff #define GPIO_32_MASK 0x0003ffff
/* Data structures */ struct gpio_twl4030_priv {
static DEFINE_MUTEX(gpio_lock); struct gpio_chip gpio_chip;
struct mutex mutex;
int irq_base;
/* store usage of each GPIO. - each bit represents one GPIO */ /* Bitfields for state caching */
static unsigned int gpio_usage_count; 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 * To configure TWL4030 GPIO module registers
*/ */
...@@ -126,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address) ...@@ -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 /* 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 * 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) ...@@ -140,14 +144,12 @@ static void twl4030_led_set_value(int led, int value)
if (led) if (led)
mask <<= 1; mask <<= 1;
mutex_lock(&gpio_lock);
if (value) if (value)
cached_leden &= ~mask; cached_leden &= ~mask;
else else
cached_leden |= mask; cached_leden |= mask;
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN_REG); TWL4030_LED_LEDEN_REG);
mutex_unlock(&gpio_lock);
} }
static int twl4030_set_gpio_direction(int gpio, int is_input) 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) ...@@ -158,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
u8 base = REG_GPIODATADIR1 + d_bnk; u8 base = REG_GPIODATADIR1 + d_bnk;
int ret = 0; int ret = 0;
mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base); ret = gpio_twl4030_read(base);
if (ret >= 0) { if (ret >= 0) {
if (is_input) if (is_input)
...@@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) ...@@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
ret = gpio_twl4030_write(base, reg); ret = gpio_twl4030_write(base, reg);
} }
mutex_unlock(&gpio_lock);
return ret; return ret;
} }
...@@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio) ...@@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio)
u8 base = 0; u8 base = 0;
int ret = 0; int ret = 0;
if (unlikely((gpio >= TWL4030_GPIO_MAX)
|| !(gpio_usage_count & BIT(gpio))))
return -EPERM;
base = REG_GPIODATAIN1 + d_bnk; base = REG_GPIODATAIN1 + d_bnk;
ret = gpio_twl4030_read(base); ret = gpio_twl4030_read(base);
if (ret > 0) if (ret > 0)
...@@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio) ...@@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio)
static int twl_request(struct gpio_chip *chip, unsigned offset) static int twl_request(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int status = 0; int status = 0;
mutex_lock(&gpio_lock); mutex_lock(&priv->mutex);
/* Support the two LED outputs as output-only GPIOs. */ /* Support the two LED outputs as output-only GPIOs. */
if (offset >= TWL4030_GPIO_MAX) { if (offset >= TWL4030_GPIO_MAX) {
...@@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) ...@@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
} }
/* on first use, turn GPIO module "on" */ /* on first use, turn GPIO module "on" */
if (!gpio_usage_count) { if (!priv->usage_count) {
struct twl4030_gpio_platform_data *pdata; struct twl4030_gpio_platform_data *pdata;
u8 value = MASK_GPIO_CTRL_GPIO_ON; u8 value = MASK_GPIO_CTRL_GPIO_ON;
...@@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) ...@@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
status = gpio_twl4030_write(REG_GPIO_CTRL, value); status = gpio_twl4030_write(REG_GPIO_CTRL, value);
} }
done:
if (!status) if (!status)
gpio_usage_count |= (0x1 << offset); priv->usage_count |= BIT(offset);
done: mutex_unlock(&priv->mutex);
mutex_unlock(&gpio_lock);
return status; return status;
} }
static void twl_free(struct gpio_chip *chip, unsigned offset) 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) { if (offset >= TWL4030_GPIO_MAX) {
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
return; goto out;
} }
mutex_lock(&gpio_lock); priv->usage_count &= ~BIT(offset);
gpio_usage_count &= ~BIT(offset);
/* on last use, switch off GPIO module */ /* on last use, switch off GPIO module */
if (!gpio_usage_count) if (!priv->usage_count)
gpio_twl4030_write(REG_GPIO_CTRL, 0x0); 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) static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
{ {
return (offset < TWL4030_GPIO_MAX) struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
? twl4030_set_gpio_direction(offset, 1) int ret;
: -EINVAL;
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) static int twl_get(struct gpio_chip *chip, unsigned offset)
{ {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int ret;
int status = 0; int status = 0;
if (offset < TWL4030_GPIO_MAX) mutex_lock(&priv->mutex);
status = twl4030_get_gpio_datain(offset); if (!(priv->usage_count & BIT(offset))) {
else if (offset == TWL4030_GPIO_MAX) ret = -EPERM;
status = cached_leden & LEDEN_LEDAON; goto out;
}
if (priv->direction & BIT(offset))
status = priv->out_state & BIT(offset);
else else
status = cached_leden & LEDEN_LEDBON; status = twl4030_get_gpio_datain(offset);
return (status < 0) ? 0 : status;
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); twl4030_set_gpio_dataout(offset, value);
return twl4030_set_gpio_direction(offset, 0); else
} else {
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); 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) if (offset < TWL4030_GPIO_MAX)
twl4030_set_gpio_dataout(offset, value); 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) static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX)) struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
? (twl4030_gpio_irq_base + offset)
return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
? (priv->irq_base + offset)
: -EINVAL; : -EINVAL;
} }
static struct gpio_chip twl_gpiochip = { static struct gpio_chip template_chip = {
.label = "twl4030", .label = "twl4030",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.request = twl_request, .request = twl_request,
...@@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
{ {
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct gpio_twl4030_priv *priv;
int ret, irq_base; int ret, irq_base;
priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* maybe setup IRQs */ /* maybe setup IRQs */
if (is_module()) { if (is_module()) {
dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
...@@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
return ret; return ret;
twl4030_gpio_irq_base = irq_base; priv->irq_base = irq_base;
no_irqs: no_irqs:
twl_gpiochip.base = -1; priv->gpio_chip = template_chip;
twl_gpiochip.ngpio = TWL4030_GPIO_MAX; priv->gpio_chip.base = -1;
twl_gpiochip.dev = &pdev->dev; priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
priv->gpio_chip.dev = &pdev->dev;
mutex_init(&priv->mutex);
if (node) if (node)
pdata = of_gpio_twl4030(&pdev->dev); pdata = of_gpio_twl4030(&pdev->dev);
...@@ -481,23 +528,23 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -481,23 +528,23 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
* is (still) clear if use_leds is set. * is (still) clear if use_leds is set.
*/ */
if (pdata->use_leds) 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) { if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
twl_gpiochip.ngpio = 0; priv->gpio_chip.ngpio = 0;
gpio_twl4030_remove(pdev); gpio_twl4030_remove(pdev);
goto out; goto out;
} }
twl4030_gpio_base = twl_gpiochip.base; platform_set_drvdata(pdev, priv);
if (pdata && pdata->setup) { if (pdata && pdata->setup) {
int status; int status;
status = pdata->setup(&pdev->dev, status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
twl4030_gpio_base, TWL4030_GPIO_MAX); TWL4030_GPIO_MAX);
if (status) if (status)
dev_dbg(&pdev->dev, "setup --> %d\n", status); dev_dbg(&pdev->dev, "setup --> %d\n", status);
} }
...@@ -510,18 +557,19 @@ static int gpio_twl4030_probe(struct platform_device *pdev) ...@@ -510,18 +557,19 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
static int gpio_twl4030_remove(struct platform_device *pdev) static int gpio_twl4030_remove(struct platform_device *pdev)
{ {
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
int status; int status;
if (pdata && pdata->teardown) { if (pdata && pdata->teardown) {
status = pdata->teardown(&pdev->dev, status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
twl4030_gpio_base, TWL4030_GPIO_MAX); TWL4030_GPIO_MAX);
if (status) { if (status) {
dev_dbg(&pdev->dev, "teardown --> %d\n", status); dev_dbg(&pdev->dev, "teardown --> %d\n", status);
return status; return status;
} }
} }
status = gpiochip_remove(&twl_gpiochip); status = gpiochip_remove(&priv->gpio_chip);
if (status < 0) if (status < 0)
return status; return status;
......
...@@ -73,19 +73,20 @@ struct vt8500_gpio_data { ...@@ -73,19 +73,20 @@ struct vt8500_gpio_data {
static struct vt8500_gpio_data vt8500_data = { static struct vt8500_gpio_data vt8500_data = {
.num_banks = 7, .num_banks = 7,
.banks = { .banks = {
VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
}, },
}; };
static struct vt8500_gpio_data wm8505_data = { static struct vt8500_gpio_data wm8505_data = {
.num_banks = 10, .num_banks = 10,
.banks = { .banks = {
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
...@@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = { ...@@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = {
VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
}, },
}; };
...@@ -127,6 +127,12 @@ struct vt8500_gpio_chip { ...@@ -127,6 +127,12 @@ struct vt8500_gpio_chip {
void __iomem *base; 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) #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, ...@@ -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, static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
const struct vt8500_gpio_data *data) const struct vt8500_gpio_data *data)
{ {
struct vt8500_data *priv;
struct vt8500_gpio_chip *vtchip; struct vt8500_gpio_chip *vtchip;
struct gpio_chip *chip; struct gpio_chip *chip;
int i; int i;
int pin_cnt = 0; 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, sizeof(struct vt8500_gpio_chip) * data->num_banks,
GFP_KERNEL); GFP_KERNEL);
if (!vtchip) { if (!priv->chip) {
pr_err("%s: failed to allocate chip memory\n", __func__); dev_err(&pdev->dev, "failed to allocate chip memory\n");
return -ENOMEM; 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++) { for (i = 0; i < data->num_banks; i++) {
vtchip[i].base = base; vtchip[i].base = base;
vtchip[i].regs = &data->banks[i]; vtchip[i].regs = &data->banks[i];
...@@ -273,36 +292,54 @@ static struct of_device_id vt8500_gpio_dt_ids[] = { ...@@ -273,36 +292,54 @@ static struct of_device_id vt8500_gpio_dt_ids[] = {
static int vt8500_gpio_probe(struct platform_device *pdev) static int vt8500_gpio_probe(struct platform_device *pdev)
{ {
int ret;
void __iomem *gpio_base; void __iomem *gpio_base;
struct device_node *np; struct resource *res;
const struct of_device_id *of_id = const struct of_device_id *of_id =
of_match_device(vt8500_gpio_dt_ids, &pdev->dev); of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
if (!of_id) { if (!of_id) {
dev_err(&pdev->dev, "Failed to find gpio controller\n"); dev_err(&pdev->dev, "No matching driver data\n");
return -ENODEV; return -ENODEV;
} }
np = pdev->dev.of_node; res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!np) { if (!res) {
dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); dev_err(&pdev->dev, "Unable to get IO resource\n");
return -EFAULT; return -ENODEV;
} }
gpio_base = of_iomap(np, 0); gpio_base = devm_request_and_ioremap(&pdev->dev, res);
if (!gpio_base) { if (!gpio_base) {
dev_err(&pdev->dev, "Unable to map GPIO registers\n"); dev_err(&pdev->dev, "Unable to map GPIO registers\n");
of_node_put(np);
return -ENOMEM; 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; return 0;
} }
static struct platform_driver vt8500_gpio_driver = { static struct platform_driver vt8500_gpio_driver = {
.probe = vt8500_gpio_probe, .probe = vt8500_gpio_probe,
.remove = vt8500_gpio_remove,
.driver = { .driver = {
.name = "vt8500-gpio", .name = "vt8500-gpio",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/acpi_gpio.h> #include <linux/acpi_gpio.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/interrupt.h>
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{ {
...@@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin) ...@@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin)
return chip->base + pin; return chip->base + pin;
} }
EXPORT_SYMBOL_GPL(acpi_get_gpio); 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);
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -52,14 +53,13 @@ struct gpio_desc { ...@@ -52,14 +53,13 @@ struct gpio_desc {
/* flag symbols are bit numbers */ /* flag symbols are bit numbers */
#define FLAG_REQUESTED 0 #define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1 #define FLAG_IS_OUT 1
#define FLAG_RESERVED 2 #define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_EXPORT 3 /* protected by sysfs_lock */ #define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ #define FLAG_TRIG_FALL 4 /* trigger on falling edge */
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */ #define FLAG_TRIG_RISE 5 /* trigger on rising edge */
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
#define ID_SHIFT 16 /* add new flags before this one */ #define ID_SHIFT 16 /* add new flags before this one */
...@@ -72,10 +72,36 @@ struct gpio_desc { ...@@ -72,10 +72,36 @@ struct gpio_desc {
}; };
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; 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 #ifdef CONFIG_GPIO_SYSFS
static DEFINE_IDR(dirent_idr); static DEFINE_IDR(dirent_idr);
#endif #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) static inline void desc_set_label(struct gpio_desc *d, const char *label)
{ {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -83,6 +109,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) ...@@ -83,6 +109,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
#endif #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 /* Warn when drivers omit gpio_request() calls -- legal but ill-advised
* when setting direction, and otherwise illegal. Until board setup code * when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when * 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) ...@@ -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, * only "legal" in the sense that (old) code using it won't break yet,
* but instead only triggers a WARN() stack dump. * 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 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, if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
"autorequest GPIO-%d\n", gpio)) { "autorequest GPIO-%d\n", gpio)) {
...@@ -116,95 +172,54 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) ...@@ -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 */ /* 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) 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 */ /* dynamic allocation of GPIOs, e.g. on a hotplugged device */
static int gpiochip_find_base(int ngpio) static int gpiochip_find_base(int ngpio)
{ {
int i; struct gpio_chip *chip;
int spare = 0; int base = ARCH_NR_GPIOS - ngpio;
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;
if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { list_for_each_entry_reverse(chip, &gpio_chips, list) {
spare++; /* found a free space? */
if (spare == ngpio) { if (chip->base + chip->ngpio <= base)
base = i; break;
break; else
} /* nope, check the space right before the chip */
} else { base = chip->base - ngpio;
spare = 0;
if (chip)
i -= chip->ngpio - 1;
}
} }
if (gpio_is_valid(base)) if (gpio_is_valid(base)) {
pr_debug("%s: found new base at %d\n", __func__, base); pr_debug("%s: found new base at %d\n", __func__, base);
return base; return base;
} } else {
pr_err("%s: cannot find free range\n", __func__);
/** return -ENOSPC;
* 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);
} }
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 */ /* 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_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio]; unsigned offset;
int status = -EINVAL; int status = -EINVAL;
chip = gpio_to_chip(gpio); chip = gpiod_to_chip(desc);
gpio -= chip->base; offset = gpio_chip_hwgpio(desc);
if (!chip->get_direction) if (!chip->get_direction)
return status; return status;
status = chip->get_direction(chip, gpio); status = chip->get_direction(chip, offset);
if (status > 0) { if (status > 0) {
/* GPIOF_DIR_IN, or other positive */ /* GPIOF_DIR_IN, or other positive */
status = 1; status = 1;
...@@ -248,19 +263,19 @@ static DEFINE_MUTEX(sysfs_lock); ...@@ -248,19 +263,19 @@ static DEFINE_MUTEX(sysfs_lock);
static ssize_t gpio_direction_show(struct device *dev, static ssize_t gpio_direction_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
if (!test_bit(FLAG_EXPORT, &desc->flags)) if (!test_bit(FLAG_EXPORT, &desc->flags)) {
status = -EIO; status = -EIO;
else } else {
gpio_get_direction(gpio); gpiod_get_direction(desc);
status = sprintf(buf, "%s\n", status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags) test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in"); ? "out" : "in");
}
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
return status; return status;
...@@ -269,8 +284,7 @@ static ssize_t gpio_direction_show(struct device *dev, ...@@ -269,8 +284,7 @@ static ssize_t gpio_direction_show(struct device *dev,
static ssize_t gpio_direction_store(struct device *dev, static ssize_t gpio_direction_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size) struct device_attribute *attr, const char *buf, size_t size)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -278,11 +292,11 @@ static ssize_t gpio_direction_store(struct device *dev, ...@@ -278,11 +292,11 @@ static ssize_t gpio_direction_store(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags)) if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO; status = -EIO;
else if (sysfs_streq(buf, "high")) 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")) 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")) else if (sysfs_streq(buf, "in"))
status = gpio_direction_input(gpio); status = gpiod_direction_input(desc);
else else
status = -EINVAL; status = -EINVAL;
...@@ -296,8 +310,7 @@ static /* const */ DEVICE_ATTR(direction, 0644, ...@@ -296,8 +310,7 @@ static /* const */ DEVICE_ATTR(direction, 0644,
static ssize_t gpio_value_show(struct device *dev, static ssize_t gpio_value_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -307,7 +320,7 @@ static ssize_t gpio_value_show(struct device *dev, ...@@ -307,7 +320,7 @@ static ssize_t gpio_value_show(struct device *dev,
} else { } else {
int value; int value;
value = !!gpio_get_value_cansleep(gpio); value = !!gpiod_get_value_cansleep(desc);
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
...@@ -321,8 +334,7 @@ static ssize_t gpio_value_show(struct device *dev, ...@@ -321,8 +334,7 @@ static ssize_t gpio_value_show(struct device *dev,
static ssize_t gpio_value_store(struct device *dev, static ssize_t gpio_value_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size) struct device_attribute *attr, const char *buf, size_t size)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -338,7 +350,7 @@ static ssize_t gpio_value_store(struct device *dev, ...@@ -338,7 +350,7 @@ static ssize_t gpio_value_store(struct device *dev,
if (status == 0) { if (status == 0) {
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
gpio_set_value_cansleep(gpio, value != 0); gpiod_set_value_cansleep(desc, value != 0);
status = size; status = size;
} }
} }
...@@ -368,7 +380,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, ...@@ -368,7 +380,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
return 0; return 0;
irq = gpio_to_irq(desc - gpio_desc); irq = gpiod_to_irq(desc);
if (irq < 0) if (irq < 0)
return -EIO; return -EIO;
...@@ -638,29 +650,32 @@ static ssize_t export_store(struct class *class, ...@@ -638,29 +650,32 @@ static ssize_t export_store(struct class *class,
struct class_attribute *attr, struct class_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
{ {
long gpio; long gpio;
int status; struct gpio_desc *desc;
int status;
status = strict_strtol(buf, 0, &gpio); status = strict_strtol(buf, 0, &gpio);
if (status < 0) if (status < 0)
goto done; goto done;
desc = gpio_to_desc(gpio);
/* No extra locking here; FLAG_SYSFS just signifies that the /* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace, so * request and export were done by on behalf of userspace, so
* they may be undone on its behalf too. * they may be undone on its behalf too.
*/ */
status = gpio_request(gpio, "sysfs"); status = gpiod_request(desc, "sysfs");
if (status < 0) { if (status < 0) {
if (status == -EPROBE_DEFER) if (status == -EPROBE_DEFER)
status = -ENODEV; status = -ENODEV;
goto done; goto done;
} }
status = gpio_export(gpio, true); status = gpiod_export(desc, true);
if (status < 0) if (status < 0)
gpio_free(gpio); gpiod_free(desc);
else else
set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags); set_bit(FLAG_SYSFS, &desc->flags);
done: done:
if (status) if (status)
...@@ -672,8 +687,9 @@ static ssize_t unexport_store(struct class *class, ...@@ -672,8 +687,9 @@ static ssize_t unexport_store(struct class *class,
struct class_attribute *attr, struct class_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
{ {
long gpio; long gpio;
int status; struct gpio_desc *desc;
int status;
status = strict_strtol(buf, 0, &gpio); status = strict_strtol(buf, 0, &gpio);
if (status < 0) if (status < 0)
...@@ -681,17 +697,18 @@ static ssize_t unexport_store(struct class *class, ...@@ -681,17 +697,18 @@ static ssize_t unexport_store(struct class *class,
status = -EINVAL; status = -EINVAL;
desc = gpio_to_desc(gpio);
/* reject bogus commands (gpio_unexport ignores them) */ /* reject bogus commands (gpio_unexport ignores them) */
if (!gpio_is_valid(gpio)) if (!desc)
goto done; goto done;
/* No extra locking here; FLAG_SYSFS just signifies that the /* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace, so * request and export were done by on behalf of userspace, so
* they may be undone on its behalf too. * 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; status = 0;
gpio_free(gpio); gpiod_free(desc);
} }
done: done:
if (status) if (status)
...@@ -728,13 +745,13 @@ static struct class gpio_class = { ...@@ -728,13 +745,13 @@ static struct class gpio_class = {
* *
* Returns zero on success, else an error. * 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; unsigned long flags;
struct gpio_desc *desc;
int status; int status;
const char *ioname = NULL; const char *ioname = NULL;
struct device *dev; struct device *dev;
int offset;
/* can't export until sysfs is available ... */ /* can't export until sysfs is available ... */
if (!gpio_class.p) { if (!gpio_class.p) {
...@@ -742,20 +759,19 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -742,20 +759,19 @@ int gpio_export(unsigned gpio, bool direction_may_change)
return -ENOENT; return -ENOENT;
} }
if (!gpio_is_valid(gpio)) { if (!desc) {
pr_debug("%s: gpio %d is not valid\n", __func__, gpio); pr_debug("%s: invalid gpio descriptor\n", __func__);
return -EINVAL; return -EINVAL;
} }
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
if (!test_bit(FLAG_REQUESTED, &desc->flags) || if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) { test_bit(FLAG_EXPORT, &desc->flags)) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", 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_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags)); test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM; status = -EPERM;
...@@ -766,11 +782,13 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -766,11 +782,13 @@ int gpio_export(unsigned gpio, bool direction_may_change)
direction_may_change = false; direction_may_change = false;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) offset = gpio_chip_hwgpio(desc);
ioname = desc->chip->names[gpio - desc->chip->base]; if (desc->chip->names && desc->chip->names[offset])
ioname = desc->chip->names[offset];
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), 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)) { if (IS_ERR(dev)) {
status = PTR_ERR(dev); status = PTR_ERR(dev);
goto fail_unlock; goto fail_unlock;
...@@ -786,7 +804,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -786,7 +804,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
goto fail_unregister_device; 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))) { !test_bit(FLAG_IS_OUT, &desc->flags))) {
status = device_create_file(dev, &dev_attr_edge); status = device_create_file(dev, &dev_attr_edge);
if (status) if (status)
...@@ -801,9 +819,15 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -801,9 +819,15 @@ int gpio_export(unsigned gpio, bool direction_may_change)
device_unregister(dev); device_unregister(dev);
fail_unlock: fail_unlock:
mutex_unlock(&sysfs_lock); 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; 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); EXPORT_SYMBOL_GPL(gpio_export);
static int match_export(struct device *dev, const void *data) static int match_export(struct device *dev, const void *data)
...@@ -822,18 +846,16 @@ 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. * 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; int status = -EINVAL;
if (!gpio_is_valid(gpio)) if (!desc)
goto done; goto done;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) { if (test_bit(FLAG_EXPORT, &desc->flags)) {
struct device *tdev; struct device *tdev;
...@@ -850,12 +872,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio) ...@@ -850,12 +872,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
done: done:
if (status) 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; 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 * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value
...@@ -869,19 +896,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link); ...@@ -869,19 +896,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link);
* *
* Returns zero on success, else an error. * 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; struct device *dev = NULL;
int status = -EINVAL; int status = -EINVAL;
if (!gpio_is_valid(gpio)) if (!desc)
goto done; goto done;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) { if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export); dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev == NULL) { if (dev == NULL) {
...@@ -897,10 +921,16 @@ int gpio_sysfs_set_active_low(unsigned gpio, int value) ...@@ -897,10 +921,16 @@ int gpio_sysfs_set_active_low(unsigned gpio, int value)
done: done:
if (status) 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; 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); EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
/** /**
...@@ -909,21 +939,18 @@ 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(). * 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; int status = 0;
struct device *dev = NULL; struct device *dev = NULL;
if (!gpio_is_valid(gpio)) { if (!desc) {
status = -EINVAL; status = -EINVAL;
goto done; goto done;
} }
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) { if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export); dev = class_find_device(&gpio_class, NULL, desc, match_export);
...@@ -935,13 +962,20 @@ void gpio_unexport(unsigned gpio) ...@@ -935,13 +962,20 @@ void gpio_unexport(unsigned gpio)
} }
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
if (dev) { if (dev) {
device_unregister(dev); device_unregister(dev);
put_device(dev); put_device(dev);
} }
done: done:
if (status) 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); EXPORT_SYMBOL_GPL(gpio_unexport);
...@@ -975,9 +1009,9 @@ static int gpiochip_export(struct gpio_chip *chip) ...@@ -975,9 +1009,9 @@ static int gpiochip_export(struct gpio_chip *chip)
unsigned gpio; unsigned gpio;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
gpio = chip->base; gpio = 0;
while (gpio_desc[gpio].chip == chip) while (gpio < chip->ngpio)
gpio_desc[gpio++].chip = NULL; chip->desc[gpio++].chip = NULL;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
pr_debug("%s: chip %s status %d\n", __func__, pr_debug("%s: chip %s status %d\n", __func__,
...@@ -1012,7 +1046,7 @@ static int __init gpiolib_sysfs_init(void) ...@@ -1012,7 +1046,7 @@ static int __init gpiolib_sysfs_init(void)
{ {
int status; int status;
unsigned long flags; unsigned long flags;
unsigned gpio; struct gpio_chip *chip;
status = class_register(&gpio_class); status = class_register(&gpio_class);
if (status < 0) if (status < 0)
...@@ -1025,10 +1059,7 @@ static int __init gpiolib_sysfs_init(void) ...@@ -1025,10 +1059,7 @@ static int __init gpiolib_sysfs_init(void)
* registered, and so arch_initcall() can always gpio_export(). * registered, and so arch_initcall() can always gpio_export().
*/ */
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { list_for_each_entry(chip, &gpio_chips, list) {
struct gpio_chip *chip;
chip = gpio_desc[gpio].chip;
if (!chip || chip->exported) if (!chip || chip->exported)
continue; continue;
...@@ -1053,8 +1084,66 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) ...@@ -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 */ #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 * gpiochip_add() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized * @chip: the chip to register, with chip->base initialized
...@@ -1096,16 +1185,14 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -1096,16 +1185,14 @@ int gpiochip_add(struct gpio_chip *chip)
chip->base = base; chip->base = base;
} }
/* these GPIO numbers must not be managed by another gpio_chip */ status = gpiochip_add_to_list(chip);
for (id = base; id < base + chip->ngpio; id++) {
if (gpio_desc[id].chip != NULL) {
status = -EBUSY;
break;
}
}
if (status == 0) { if (status == 0) {
for (id = base; id < base + chip->ngpio; id++) { chip->desc = &gpio_desc[chip->base];
gpio_desc[id].chip = chip;
for (id = 0; id < chip->ngpio; id++) {
struct gpio_desc *desc = &chip->desc[id];
desc->chip = chip;
/* REVISIT: most hardware initializes GPIOs as /* REVISIT: most hardware initializes GPIOs as
* inputs (often with pullups enabled) so power * inputs (often with pullups enabled) so power
...@@ -1114,7 +1201,7 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -1114,7 +1201,7 @@ int gpiochip_add(struct gpio_chip *chip)
* and in case chip->get_direction is not set, * and in case chip->get_direction is not set,
* we may expose the wrong direction in sysfs. * we may expose the wrong direction in sysfs.
*/ */
gpio_desc[id].flags = !chip->direction_input desc->flags = !chip->direction_input
? (1 << FLAG_IS_OUT) ? (1 << FLAG_IS_OUT)
: 0; : 0;
} }
...@@ -1167,15 +1254,17 @@ int gpiochip_remove(struct gpio_chip *chip) ...@@ -1167,15 +1254,17 @@ int gpiochip_remove(struct gpio_chip *chip)
gpiochip_remove_pin_ranges(chip); gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip); of_gpiochip_remove(chip);
for (id = chip->base; id < chip->base + chip->ngpio; id++) { for (id = 0; id < chip->ngpio; id++) {
if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
status = -EBUSY; status = -EBUSY;
break; break;
} }
} }
if (status == 0) { if (status == 0) {
for (id = chip->base; id < chip->base + chip->ngpio; id++) for (id = 0; id < chip->ngpio; id++)
gpio_desc[id].chip = NULL; chip->desc[id].chip = NULL;
list_del(&chip->list);
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
...@@ -1202,20 +1291,17 @@ struct gpio_chip *gpiochip_find(void *data, ...@@ -1202,20 +1291,17 @@ struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, int (*match)(struct gpio_chip *chip,
void *data)) void *data))
{ {
struct gpio_chip *chip = NULL; struct gpio_chip *chip;
unsigned long flags; unsigned long flags;
int i;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
for (i = 0; i < ARCH_NR_GPIOS; i++) { list_for_each_entry(chip, &gpio_chips, list)
if (!gpio_desc[i].chip) if (match(chip, data))
continue;
if (match(gpio_desc[i].chip, data)) {
chip = gpio_desc[i].chip;
break; break;
}
} /* No match? */
if (&chip->list == &gpio_chips)
chip = NULL;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return chip; return chip;
...@@ -1297,20 +1383,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); ...@@ -1297,20 +1383,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
* on each other, and help provide better diagnostics in debugfs. * on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls. * 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; struct gpio_chip *chip;
int status = -EPROBE_DEFER; int status = -EPROBE_DEFER;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) { if (!desc) {
status = -EINVAL; status = -EINVAL;
goto done; goto done;
} }
desc = &gpio_desc[gpio];
chip = desc->chip; chip = desc->chip;
if (chip == NULL) if (chip == NULL)
goto done; goto done;
...@@ -1334,7 +1418,7 @@ int gpio_request(unsigned gpio, const char *label) ...@@ -1334,7 +1418,7 @@ int gpio_request(unsigned gpio, const char *label)
if (chip->request) { if (chip->request) {
/* chip->request may sleep */ /* chip->request may sleep */
spin_unlock_irqrestore(&gpio_lock, flags); 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); spin_lock_irqsave(&gpio_lock, flags);
if (status < 0) { if (status < 0) {
...@@ -1347,42 +1431,46 @@ int gpio_request(unsigned gpio, const char *label) ...@@ -1347,42 +1431,46 @@ int gpio_request(unsigned gpio, const char *label)
if (chip->get_direction) { if (chip->get_direction) {
/* chip->get_direction may sleep */ /* chip->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
gpio_get_direction(gpio); gpiod_get_direction(desc);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
done: done:
if (status) if (status)
pr_debug("gpio_request: gpio-%d (%s) status %d\n", pr_debug("_gpio_request: gpio-%d (%s) status %d\n",
gpio, label ? : "?", status); desc ? desc_to_gpio(desc) : -1,
label ? : "?", status);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return status; return status;
} }
int gpio_request(unsigned gpio, const char *label)
{
return gpiod_request(gpio_to_desc(gpio), label);
}
EXPORT_SYMBOL_GPL(gpio_request); EXPORT_SYMBOL_GPL(gpio_request);
void gpio_free(unsigned gpio) static void gpiod_free(struct gpio_desc *desc)
{ {
unsigned long flags; unsigned long flags;
struct gpio_desc *desc;
struct gpio_chip *chip; struct gpio_chip *chip;
might_sleep(); might_sleep();
if (!gpio_is_valid(gpio)) { if (!desc) {
WARN_ON(extra_checks); WARN_ON(extra_checks);
return; return;
} }
gpio_unexport(gpio); gpiod_unexport(desc);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
chip = desc->chip; chip = desc->chip;
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
if (chip->free) { if (chip->free) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
might_sleep_if(chip->can_sleep); 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); spin_lock_irqsave(&gpio_lock, flags);
} }
desc_set_label(desc, NULL); desc_set_label(desc, NULL);
...@@ -1396,6 +1484,11 @@ void gpio_free(unsigned gpio) ...@@ -1396,6 +1484,11 @@ void gpio_free(unsigned gpio)
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
} }
void gpio_free(unsigned gpio)
{
gpiod_free(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_free); EXPORT_SYMBOL_GPL(gpio_free);
/** /**
...@@ -1406,29 +1499,32 @@ 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) int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
{ {
struct gpio_desc *desc;
int err; int err;
err = gpio_request(gpio, label); desc = gpio_to_desc(gpio);
err = gpiod_request(desc, label);
if (err) if (err)
return err; return err;
if (flags & GPIOF_OPEN_DRAIN) 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) 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) if (flags & GPIOF_DIR_IN)
err = gpio_direction_input(gpio); err = gpiod_direction_input(desc);
else else
err = gpio_direction_output(gpio, err = gpiod_direction_output(desc,
(flags & GPIOF_INIT_HIGH) ? 1 : 0); (flags & GPIOF_INIT_HIGH) ? 1 : 0);
if (err) if (err)
goto free_gpio; goto free_gpio;
if (flags & GPIOF_EXPORT) { if (flags & GPIOF_EXPORT) {
err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE); err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
if (err) if (err)
goto free_gpio; goto free_gpio;
} }
...@@ -1436,7 +1532,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) ...@@ -1436,7 +1532,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
return 0; return 0;
free_gpio: free_gpio:
gpio_free(gpio); gpiod_free(desc);
return err; return err;
} }
EXPORT_SYMBOL_GPL(gpio_request_one); EXPORT_SYMBOL_GPL(gpio_request_one);
...@@ -1491,14 +1587,17 @@ EXPORT_SYMBOL_GPL(gpio_free_array); ...@@ -1491,14 +1587,17 @@ EXPORT_SYMBOL_GPL(gpio_free_array);
*/ */
const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) 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; 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; return NULL;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
return gpio_desc[gpio].label; return desc->label;
#else #else
return "?"; return "?";
#endif #endif
...@@ -1515,24 +1614,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); ...@@ -1515,24 +1614,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* rely on gpio_request() having been called beforehand. * 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; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL; int status = -EINVAL;
int offset;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) if (!desc)
goto fail; goto fail;
chip = desc->chip; chip = desc->chip;
if (!chip || !chip->get || !chip->direction_input) if (!chip || !chip->get || !chip->direction_input)
goto fail; goto fail;
gpio -= chip->base; status = gpio_ensure_requested(desc);
if (gpio >= chip->ngpio)
goto fail;
status = gpio_ensure_requested(desc, gpio);
if (status < 0) if (status < 0)
goto fail; goto fail;
...@@ -1542,11 +1638,12 @@ int gpio_direction_input(unsigned gpio) ...@@ -1542,11 +1638,12 @@ int gpio_direction_input(unsigned gpio)
might_sleep_if(chip->can_sleep); might_sleep_if(chip->can_sleep);
offset = gpio_chip_hwgpio(desc);
if (status) { if (status) {
status = chip->request(chip, gpio); status = chip->request(chip, offset);
if (status < 0) { if (status < 0) {
pr_debug("GPIO-%d: chip request fail, %d\n", 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 ... /* and it's not available to anyone else ...
* gpio_request() is the fully clean solution. * gpio_request() is the fully clean solution.
*/ */
...@@ -1554,48 +1651,54 @@ int gpio_direction_input(unsigned gpio) ...@@ -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) if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags); 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: lose:
return status; return status;
fail: fail:
spin_unlock_irqrestore(&gpio_lock, flags); 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", pr_debug("%s: gpio-%d status %d\n",
__func__, gpio, status); __func__, gpio, status);
}
return status; return status;
} }
int gpio_direction_input(unsigned gpio)
{
return gpiod_direction_input(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_direction_input); 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; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL; int status = -EINVAL;
int offset;
/* Open drain pin should not be driven to 1 */ /* Open drain pin should not be driven to 1 */
if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) 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 */ /* Open source pin should not be driven to 0 */
if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) 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); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) if (!desc)
goto fail; goto fail;
chip = desc->chip; chip = desc->chip;
if (!chip || !chip->set || !chip->direction_output) if (!chip || !chip->set || !chip->direction_output)
goto fail; goto fail;
gpio -= chip->base; status = gpio_ensure_requested(desc);
if (gpio >= chip->ngpio)
goto fail;
status = gpio_ensure_requested(desc, gpio);
if (status < 0) if (status < 0)
goto fail; goto fail;
...@@ -1605,11 +1708,12 @@ int gpio_direction_output(unsigned gpio, int value) ...@@ -1605,11 +1708,12 @@ int gpio_direction_output(unsigned gpio, int value)
might_sleep_if(chip->can_sleep); might_sleep_if(chip->can_sleep);
offset = gpio_chip_hwgpio(desc);
if (status) { if (status) {
status = chip->request(chip, gpio); status = chip->request(chip, offset);
if (status < 0) { if (status < 0) {
pr_debug("GPIO-%d: chip request fail, %d\n", 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 ... /* and it's not available to anyone else ...
* gpio_request() is the fully clean solution. * gpio_request() is the fully clean solution.
*/ */
...@@ -1617,20 +1721,29 @@ int gpio_direction_output(unsigned gpio, int value) ...@@ -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) if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags); set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(chip->base + gpio, 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
trace_gpio_direction(chip->base + gpio, 0, status); trace_gpio_direction(desc_to_gpio(desc), 0, status);
lose: lose:
return status; return status;
fail: fail:
spin_unlock_irqrestore(&gpio_lock, flags); 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", pr_debug("%s: gpio-%d status %d\n",
__func__, gpio, status); __func__, gpio, status);
}
return 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); EXPORT_SYMBOL_GPL(gpio_direction_output);
/** /**
...@@ -1638,24 +1751,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output); ...@@ -1638,24 +1751,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output);
* @gpio: the gpio to set debounce time * @gpio: the gpio to set debounce time
* @debounce: debounce time is microseconds * @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; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL; int status = -EINVAL;
int offset;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) if (!desc)
goto fail; goto fail;
chip = desc->chip; chip = desc->chip;
if (!chip || !chip->set || !chip->set_debounce) if (!chip || !chip->set || !chip->set_debounce)
goto fail; goto fail;
gpio -= chip->base;
if (gpio >= chip->ngpio) status = gpio_ensure_requested(desc);
goto fail;
status = gpio_ensure_requested(desc, gpio);
if (status < 0) if (status < 0)
goto fail; goto fail;
...@@ -1665,16 +1776,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce) ...@@ -1665,16 +1776,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce)
might_sleep_if(chip->can_sleep); 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: fail:
spin_unlock_irqrestore(&gpio_lock, flags); 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", pr_debug("%s: gpio-%d status %d\n",
__func__, gpio, status); __func__, gpio, status);
}
return 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); EXPORT_SYMBOL_GPL(gpio_set_debounce);
/* I/O calls are only valid after configuration completed; the relevant /* I/O calls are only valid after configuration completed; the relevant
...@@ -1708,18 +1829,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); ...@@ -1708,18 +1829,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
* It returns the zero or nonzero value provided by the associated * It returns the zero or nonzero value provided by the associated
* gpio_chip.get() method; or zero if no such method is provided. * 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; struct gpio_chip *chip;
int value; int value;
int offset;
chip = gpio_to_chip(gpio); chip = desc->chip;
offset = gpio_chip_hwgpio(desc);
/* Should be using gpio_get_value_cansleep() */ /* Should be using gpio_get_value_cansleep() */
WARN_ON(chip->can_sleep); WARN_ON(chip->can_sleep);
value = chip->get ? chip->get(chip, gpio - chip->base) : 0; value = chip->get ? chip->get(chip, offset) : 0;
trace_gpio_value(gpio, 1, value); trace_gpio_value(desc_to_gpio(desc), 1, value);
return value; return value;
} }
int __gpio_get_value(unsigned gpio)
{
return gpiod_get_value(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(__gpio_get_value); EXPORT_SYMBOL_GPL(__gpio_get_value);
/* /*
...@@ -1728,23 +1856,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value); ...@@ -1728,23 +1856,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value);
* @chip: Gpio chip. * @chip: Gpio chip.
* @value: Non-zero for setting it HIGH otherise it will set to LOW. * @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/ */
static void _gpio_set_open_drain_value(unsigned gpio, static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
struct gpio_chip *chip, int value)
{ {
int err = 0; int err = 0;
struct gpio_chip *chip = desc->chip;
int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
err = chip->direction_input(chip, gpio - chip->base); err = chip->direction_input(chip, offset);
if (!err) if (!err)
clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); clear_bit(FLAG_IS_OUT, &desc->flags);
} else { } else {
err = chip->direction_output(chip, gpio - chip->base, 0); err = chip->direction_output(chip, offset, 0);
if (!err) 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) if (err < 0)
pr_err("%s: Error in set_value for open drain gpio%d err %d\n", 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, ...@@ -1753,26 +1883,27 @@ static void _gpio_set_open_drain_value(unsigned gpio,
* @chip: Gpio chip. * @chip: Gpio chip.
* @value: Non-zero for setting it HIGH otherise it will set to LOW. * @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/ */
static void _gpio_set_open_source_value(unsigned gpio, static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
struct gpio_chip *chip, int value)
{ {
int err = 0; int err = 0;
struct gpio_chip *chip = desc->chip;
int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
err = chip->direction_output(chip, gpio - chip->base, 1); err = chip->direction_output(chip, offset, 1);
if (!err) if (!err)
set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); set_bit(FLAG_IS_OUT, &desc->flags);
} else { } else {
err = chip->direction_input(chip, gpio - chip->base); err = chip->direction_input(chip, offset);
if (!err) 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) if (err < 0)
pr_err("%s: Error in set_value for open source gpio%d err %d\n", 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_set_value() - assign a gpio's value
* @gpio: gpio whose value will be assigned * @gpio: gpio whose value will be assigned
...@@ -1782,20 +1913,25 @@ static void _gpio_set_open_source_value(unsigned gpio, ...@@ -1782,20 +1913,25 @@ static void _gpio_set_open_source_value(unsigned gpio,
* This is used directly or indirectly to implement gpio_set_value(). * This is used directly or indirectly to implement gpio_set_value().
* It invokes the associated gpio_chip.set() method. * 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; struct gpio_chip *chip;
chip = gpio_to_chip(gpio); chip = desc->chip;
/* Should be using gpio_set_value_cansleep() */ /* Should be using gpio_set_value_cansleep() */
WARN_ON(chip->can_sleep); WARN_ON(chip->can_sleep);
trace_gpio_value(gpio, 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
_gpio_set_open_drain_value(gpio, chip, value); _gpio_set_open_drain_value(desc, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
_gpio_set_open_source_value(gpio, chip, value); _gpio_set_open_source_value(desc, value);
else 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); EXPORT_SYMBOL_GPL(__gpio_set_value);
...@@ -1807,14 +1943,15 @@ 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 * This is used directly or indirectly to implement gpio_cansleep(). It
* returns nonzero if access reading or writing the GPIO value can sleep. * 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! */ /* 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); EXPORT_SYMBOL_GPL(__gpio_cansleep);
...@@ -1827,50 +1964,67 @@ 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, * It returns the number of the IRQ signaled by this (input) GPIO,
* or a negative errno. * or a negative errno.
*/ */
int __gpio_to_irq(unsigned gpio) static int gpiod_to_irq(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
int offset;
chip = gpio_to_chip(gpio); chip = desc->chip;
return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; 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. /* 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. * 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; struct gpio_chip *chip;
int value; int value;
int offset;
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio); chip = desc->chip;
value = chip->get ? chip->get(chip, gpio - chip->base) : 0; offset = gpio_chip_hwgpio(desc);
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; 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); 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; struct gpio_chip *chip;
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio); chip = desc->chip;
trace_gpio_value(gpio, 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
_gpio_set_open_drain_value(gpio, chip, value); _gpio_set_open_drain_value(desc, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
_gpio_set_open_source_value(gpio, chip, value); _gpio_set_open_source_value(desc, value);
else 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 #ifdef CONFIG_DEBUG_FS
...@@ -1878,14 +2032,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -1878,14 +2032,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{ {
unsigned i; unsigned i;
unsigned gpio = chip->base; unsigned gpio = chip->base;
struct gpio_desc *gdesc = &gpio_desc[gpio]; struct gpio_desc *gdesc = &chip->desc[0];
int is_out; int is_out;
for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue; continue;
gpio_get_direction(gpio); gpiod_get_direction(gdesc);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
gpio, gdesc->label, gpio, gdesc->label,
...@@ -1899,46 +2053,35 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -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) static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
{ {
unsigned long flags;
struct gpio_chip *chip = NULL; struct gpio_chip *chip = NULL;
unsigned int gpio; loff_t index = *pos;
void *ret = NULL;
loff_t index = 0;
/* REVISIT this isn't locked against gpio_chip removal ... */
for (gpio = 0; gpio_is_valid(gpio); gpio++) { s->private = "";
if (gpio_desc[gpio].chip == chip)
continue;
chip = gpio_desc[gpio].chip;
if (!chip)
continue;
if (index++ >= *pos) { spin_lock_irqsave(&gpio_lock, flags);
ret = chip; list_for_each_entry(chip, &gpio_chips, list)
break; if (index-- == 0) {
spin_unlock_irqrestore(&gpio_lock, flags);
return chip;
} }
} spin_unlock_irqrestore(&gpio_lock, flags);
s->private = "";
return ret; return NULL;
} }
static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
{ {
unsigned long flags;
struct gpio_chip *chip = v; struct gpio_chip *chip = v;
unsigned int gpio;
void *ret = NULL; void *ret = NULL;
/* skip GPIOs provided by the current chip */ spin_lock_irqsave(&gpio_lock, flags);
for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) { if (list_is_last(&chip->list, &gpio_chips))
chip = gpio_desc[gpio].chip; ret = NULL;
if (chip) { else
ret = chip; ret = list_entry(chip->list.next, struct gpio_chip, list);
break; spin_unlock_irqrestore(&gpio_lock, flags);
}
}
s->private = "\n"; s->private = "\n";
++*pos; ++*pos;
......
...@@ -47,12 +47,14 @@ struct gpio; ...@@ -47,12 +47,14 @@ struct gpio;
struct seq_file; struct seq_file;
struct module; struct module;
struct device_node; struct device_node;
struct gpio_desc;
/** /**
* struct gpio_chip - abstract a GPIO controller * struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics * @label: for diagnostics
* @dev: optional device providing the GPIOs * @dev: optional device providing the GPIOs
* @owner: helps prevent removal of modules exporting active 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 * @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep * enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as * @free: optional hook for chip-specific deactivation, such as
...@@ -75,6 +77,7 @@ struct device_node; ...@@ -75,6 +77,7 @@ struct device_node;
* negative during registration, requests dynamic ID allocation. * negative during registration, requests dynamic ID allocation.
* @ngpio: the number of GPIOs handled by this controller; the last GPIO * @ngpio: the number of GPIOs handled by this controller; the last GPIO
* handled is (base + ngpio - 1). * handled is (base + ngpio - 1).
* @desc: array of ngpio descriptors. Private.
* @can_sleep: flag must be set iff get()/set() methods sleep, as they * @can_sleep: flag must be set iff get()/set() methods sleep, as they
* must while accessing GPIO expander chips over I2C or SPI * must while accessing GPIO expander chips over I2C or SPI
* @names: if set, must be an array of strings to use as alternative * @names: if set, must be an array of strings to use as alternative
...@@ -98,6 +101,7 @@ struct gpio_chip { ...@@ -98,6 +101,7 @@ struct gpio_chip {
const char *label; const char *label;
struct device *dev; struct device *dev;
struct module *owner; struct module *owner;
struct list_head list;
int (*request)(struct gpio_chip *chip, int (*request)(struct gpio_chip *chip,
unsigned offset); unsigned offset);
...@@ -124,6 +128,7 @@ struct gpio_chip { ...@@ -124,6 +128,7 @@ struct gpio_chip {
struct gpio_chip *chip); struct gpio_chip *chip);
int base; int base;
u16 ngpio; u16 ngpio;
struct gpio_desc *desc;
const char *const *names; const char *const *names;
unsigned can_sleep:1; unsigned can_sleep:1;
unsigned exported:1; unsigned exported:1;
...@@ -152,7 +157,6 @@ struct gpio_chip { ...@@ -152,7 +157,6 @@ struct gpio_chip {
extern const char *gpiochip_is_requested(struct gpio_chip *chip, extern const char *gpiochip_is_requested(struct gpio_chip *chip,
unsigned offset); unsigned offset);
extern struct gpio_chip *gpio_to_chip(unsigned gpio); extern struct gpio_chip *gpio_to_chip(unsigned gpio);
extern int __must_check gpiochip_reserve(int start, int ngpio);
/* add/remove chips */ /* add/remove chips */
extern int gpiochip_add(struct gpio_chip *chip); 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 ...@@ -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 int gpio_request_array(const struct gpio *array, size_t num);
extern void gpio_free_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 #ifdef CONFIG_GPIO_SYSFS
/* /*
...@@ -212,6 +210,43 @@ extern void gpio_unexport(unsigned gpio); ...@@ -212,6 +210,43 @@ extern void gpio_unexport(unsigned gpio);
#endif /* CONFIG_GPIO_SYSFS */ #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 */ #else /* !CONFIG_GPIOLIB */
static inline bool gpio_is_valid(int number) static inline bool gpio_is_valid(int number)
...@@ -270,41 +305,4 @@ static inline void gpio_unexport(unsigned gpio) ...@@ -270,41 +305,4 @@ static inline void gpio_unexport(unsigned gpio)
} }
#endif /* CONFIG_GPIO_SYSFS */ #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 */ #endif /* _ASM_GENERIC_GPIO_H */
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
#define _LINUX_ACPI_GPIO_H_ #define _LINUX_ACPI_GPIO_H_
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h>
#ifdef CONFIG_GPIO_ACPI #ifdef CONFIG_GPIO_ACPI
int acpi_get_gpio(char *path, int pin); int acpi_get_gpio(char *path, int pin);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
#else /* CONFIG_GPIO_ACPI */ #else /* CONFIG_GPIO_ACPI */
...@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin) ...@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin)
return -ENODEV; return -ENODEV;
} }
static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
#endif /* CONFIG_GPIO_ACPI */ #endif /* CONFIG_GPIO_ACPI */
#endif /* _LINUX_ACPI_GPIO_H_ */ #endif /* _LINUX_ACPI_GPIO_H_ */
...@@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label) ...@@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label)
return -ENOSYS; 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, static inline int gpio_request_one(unsigned gpio,
unsigned long flags, const char *label) unsigned long flags, const char *label)
{ {
return -ENOSYS; 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) static inline int gpio_request_array(const struct gpio *array, size_t num)
{ {
return -ENOSYS; return -ENOSYS;
...@@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio) ...@@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio)
WARN_ON(1); 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) static inline void gpio_free_array(const struct gpio *array, size_t num)
{ {
might_sleep(); might_sleep();
...@@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip) ...@@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip)
#endif /* ! CONFIG_GENERIC_GPIO */ #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 */ #endif /* __LINUX_GPIO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment