Commit 0fa2fd9a authored by Grant Likely's avatar Grant Likely

Merge branch 'linusw/devel' of...

Merge branch 'linusw/devel' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git into gpio/next

Device driver features, cleanups and bug fixes.
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parents 46ebfbc3 476171ce
...@@ -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);
......
...@@ -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
......
...@@ -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
......
...@@ -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;
} }
......
...@@ -65,6 +65,7 @@ struct mxs_gpio_port { ...@@ -65,6 +65,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)
...@@ -81,13 +82,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port) ...@@ -81,13 +82,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;
...@@ -124,6 +135,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) ...@@ -124,6 +135,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)
{ {
...@@ -137,6 +165,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) ...@@ -137,6 +165,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);
} }
......
This diff is collapsed.
...@@ -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),
}, },
}; };
......
...@@ -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);
...@@ -52,14 +52,13 @@ struct gpio_desc { ...@@ -52,14 +52,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 */
...@@ -132,7 +131,7 @@ static int gpiochip_find_base(int ngpio) ...@@ -132,7 +131,7 @@ static int gpiochip_find_base(int ngpio)
struct gpio_desc *desc = &gpio_desc[i]; struct gpio_desc *desc = &gpio_desc[i];
struct gpio_chip *chip = desc->chip; struct gpio_chip *chip = desc->chip;
if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { if (!chip) {
spare++; spare++;
if (spare == ngpio) { if (spare == ngpio) {
base = i; base = i;
...@@ -150,47 +149,6 @@ static int gpiochip_find_base(int ngpio) ...@@ -150,47 +149,6 @@ static int gpiochip_find_base(int ngpio)
return base; return base;
} }
/**
* gpiochip_reserve() - reserve range of gpios to use with platform code only
* @start: starting gpio number
* @ngpio: number of gpios to reserve
* Context: platform init, potentially before irqs or kmalloc will work
*
* Returns a negative errno if any gpio within the range is already reserved
* or registered, else returns zero as a success code. Use this function
* to mark a range of gpios as unavailable for dynamic gpio number allocation,
* for example because its driver support is not yet loaded.
*/
int __init gpiochip_reserve(int start, int ngpio)
{
int ret = 0;
unsigned long flags;
int i;
if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
return -EINVAL;
spin_lock_irqsave(&gpio_lock, flags);
for (i = start; i < start + ngpio; i++) {
struct gpio_desc *desc = &gpio_desc[i];
if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
ret = -EBUSY;
goto err;
}
set_bit(FLAG_RESERVED, &desc->flags);
}
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 gpio_get_direction(unsigned gpio)
{ {
...@@ -254,13 +212,14 @@ static ssize_t gpio_direction_show(struct device *dev, ...@@ -254,13 +212,14 @@ static ssize_t gpio_direction_show(struct device *dev,
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); gpio_get_direction(gpio);
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;
......
...@@ -152,7 +152,6 @@ struct gpio_chip { ...@@ -152,7 +152,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 +191,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe ...@@ -192,12 +191,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 +205,43 @@ extern void gpio_unexport(unsigned gpio); ...@@ -212,6 +205,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 +300,4 @@ static inline void gpio_unexport(unsigned gpio) ...@@ -270,41 +300,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