diff options
Diffstat (limited to 'drivers/gpio/pca953x.c')
-rw-r--r-- | drivers/gpio/pca953x.c | 92 |
1 files changed, 55 insertions, 37 deletions
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 501866662e05..78a843947d82 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -60,6 +60,7 @@ struct pca953x_chip { unsigned gpio_start; uint16_t reg_output; uint16_t reg_direction; + struct mutex i2c_lock; #ifdef CONFIG_GPIO_PCA953X_IRQ struct mutex irq_lock; @@ -119,13 +120,17 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); reg_val = chip->reg_direction | (1u << off); ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); if (ret) - return ret; + goto exit; chip->reg_direction = reg_val; - return 0; + ret = 0; +exit: + mutex_unlock(&chip->i2c_lock); + return ret; } static int pca953x_gpio_direction_output(struct gpio_chip *gc, @@ -137,6 +142,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); /* set output level */ if (val) reg_val = chip->reg_output | (1u << off); @@ -145,7 +151,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); if (ret) - return ret; + goto exit; chip->reg_output = reg_val; @@ -153,10 +159,13 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, reg_val = chip->reg_direction & ~(1u << off); ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); if (ret) - return ret; + goto exit; chip->reg_direction = reg_val; - return 0; + ret = 0; +exit: + mutex_unlock(&chip->i2c_lock); + return ret; } static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) @@ -167,7 +176,9 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val); + mutex_unlock(&chip->i2c_lock); if (ret < 0) { /* NOTE: diagnostic already emitted; that's all we should * do unless gpio_*_value_cansleep() calls become different @@ -187,6 +198,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) chip = container_of(gc, struct pca953x_chip, gpio_chip); + mutex_lock(&chip->i2c_lock); if (val) reg_val = chip->reg_output | (1u << off); else @@ -194,9 +206,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); if (ret) - return; + goto exit; chip->reg_output = reg_val; +exit: + mutex_unlock(&chip->i2c_lock); } static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) @@ -228,30 +242,30 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) return chip->irq_base + off; } -static void pca953x_irq_mask(unsigned int irq) +static void pca953x_irq_mask(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (irq - chip->irq_base)); + chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); } -static void pca953x_irq_unmask(unsigned int irq) +static void pca953x_irq_unmask(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (irq - chip->irq_base); + chip->irq_mask |= 1 << (d->irq - chip->irq_base); } -static void pca953x_irq_bus_lock(unsigned int irq) +static void pca953x_irq_bus_lock(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); mutex_lock(&chip->irq_lock); } -static void pca953x_irq_bus_sync_unlock(unsigned int irq) +static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); uint16_t new_irqs; uint16_t level; @@ -268,15 +282,15 @@ static void pca953x_irq_bus_sync_unlock(unsigned int irq) mutex_unlock(&chip->irq_lock); } -static int pca953x_irq_set_type(unsigned int irq, unsigned int type) +static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { - struct pca953x_chip *chip = get_irq_chip_data(irq); - uint16_t level = irq - chip->irq_base; + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t level = d->irq - chip->irq_base; uint16_t mask = 1 << level; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -295,11 +309,11 @@ static int pca953x_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip pca953x_irq_chip = { .name = "pca953x", - .mask = pca953x_irq_mask, - .unmask = pca953x_irq_unmask, - .bus_lock = pca953x_irq_bus_lock, - .bus_sync_unlock = pca953x_irq_bus_sync_unlock, - .set_type = pca953x_irq_set_type, + .irq_mask = pca953x_irq_mask, + .irq_unmask = pca953x_irq_unmask, + .irq_bus_lock = pca953x_irq_bus_lock, + .irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock, + .irq_set_type = pca953x_irq_set_type, }; static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) @@ -381,13 +395,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; - set_irq_chip_data(irq, chip); - set_irq_chip_and_handler(irq, &pca953x_irq_chip, - handle_edge_irq); + irq_set_chip_data(irq, chip); + irq_set_chip_and_handler(irq, &pca953x_irq_chip, + handle_simple_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -448,7 +462,8 @@ pca953x_get_alt_pdata(struct i2c_client *client) { struct pca953x_platform_data *pdata; struct device_node *node; - const uint16_t *val; + const __be32 *val; + int size; node = client->dev.of_node; if (node == NULL) @@ -461,13 +476,13 @@ pca953x_get_alt_pdata(struct i2c_client *client) } pdata->gpio_base = -1; - val = of_get_property(node, "linux,gpio-base", NULL); + val = of_get_property(node, "linux,gpio-base", &size); if (val) { - if (*val < 0) - dev_warn(&client->dev, - "invalid gpio-base in device tree\n"); + if (size != sizeof(*val)) + dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", + node->full_name); else - pdata->gpio_base = *val; + pdata->gpio_base = be32_to_cpup(val); } val = of_get_property(node, "polarity", NULL); @@ -517,6 +532,8 @@ static int __devinit pca953x_probe(struct i2c_client *client, chip->names = pdata->names; + mutex_init(&chip->i2c_lock); + /* initialize cached registers from their original values. * we can't share this chip with another i2c master. */ @@ -541,7 +558,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, ret = gpiochip_add(&chip->gpio_chip); if (ret) - goto out_failed; + goto out_failed_irq; if (pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -553,8 +570,9 @@ static int __devinit pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; -out_failed: +out_failed_irq: pca953x_irq_teardown(chip); +out_failed: kfree(chip->dyn_pdata); kfree(chip); return ret; |