summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpio-aggregator.c20
-rw-r--r--drivers/gpio/gpio-pca953x.c114
-rw-r--r--drivers/gpio/gpio-rcar.c31
-rw-r--r--drivers/gpio/gpio-tegra186.c27
-rw-r--r--drivers/gpio/gpio-zynq.c1
5 files changed, 108 insertions, 85 deletions
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 0cb2664085cf..836e21fde028 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -116,10 +116,15 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf,
struct platform_device *pdev;
int res, id;
+ if (!try_module_get(THIS_MODULE))
+ return -ENOENT;
+
/* kernfs guarantees string termination, so count + 1 is safe */
aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL);
- if (!aggr)
- return -ENOMEM;
+ if (!aggr) {
+ res = -ENOMEM;
+ goto put_module;
+ }
memcpy(aggr->args, buf, count + 1);
@@ -158,6 +163,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf,
}
aggr->pdev = pdev;
+ module_put(THIS_MODULE);
return count;
remove_table:
@@ -172,6 +178,8 @@ free_table:
kfree(aggr->lookups);
free_ga:
kfree(aggr);
+put_module:
+ module_put(THIS_MODULE);
return res;
}
@@ -200,13 +208,19 @@ static ssize_t delete_device_store(struct device_driver *driver,
if (error)
return error;
+ if (!try_module_get(THIS_MODULE))
+ return -ENOENT;
+
mutex_lock(&gpio_aggregator_lock);
aggr = idr_remove(&gpio_aggregator_idr, id);
mutex_unlock(&gpio_aggregator_lock);
- if (!aggr)
+ if (!aggr) {
+ module_put(THIS_MODULE);
return -ENOENT;
+ }
gpio_aggregator_free(aggr);
+ module_put(THIS_MODULE);
return count;
}
static DRIVER_ATTR_WO(delete_device);
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 262b3d276df7..f81d79a297a5 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -10,8 +10,9 @@
#include <linux/acpi.h>
#include <linux/bitmap.h>
-#include <linux/gpio/driver.h>
+#include <linux/cleanup.h>
#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -20,6 +21,7 @@
#include <linux/platform_data/pca953x.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/seq_file.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
@@ -522,12 +524,10 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = BIT(off % BANK_SZ);
- int ret;
- mutex_lock(&chip->i2c_lock);
- ret = regmap_write_bits(chip->regmap, dirreg, bit, bit);
- mutex_unlock(&chip->i2c_lock);
- return ret;
+ guard(mutex)(&chip->i2c_lock);
+
+ return regmap_write_bits(chip->regmap, dirreg, bit, bit);
}
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
@@ -539,17 +539,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
u8 bit = BIT(off % BANK_SZ);
int ret;
- mutex_lock(&chip->i2c_lock);
+ guard(mutex)(&chip->i2c_lock);
+
/* set output level */
ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
if (ret)
- goto exit;
+ return ret;
/* then direction */
- ret = regmap_write_bits(chip->regmap, dirreg, bit, 0);
-exit:
- mutex_unlock(&chip->i2c_lock);
- return ret;
+ return regmap_write_bits(chip->regmap, dirreg, bit, 0);
}
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
@@ -560,9 +558,8 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
u32 reg_val;
int ret;
- mutex_lock(&chip->i2c_lock);
- ret = regmap_read(chip->regmap, inreg, &reg_val);
- mutex_unlock(&chip->i2c_lock);
+ scoped_guard(mutex, &chip->i2c_lock)
+ ret = regmap_read(chip->regmap, inreg, &reg_val);
if (ret < 0)
return ret;
@@ -575,9 +572,9 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
u8 bit = BIT(off % BANK_SZ);
- mutex_lock(&chip->i2c_lock);
+ guard(mutex)(&chip->i2c_lock);
+
regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
- mutex_unlock(&chip->i2c_lock);
}
static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
@@ -588,9 +585,8 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
u32 reg_val;
int ret;
- mutex_lock(&chip->i2c_lock);
- ret = regmap_read(chip->regmap, dirreg, &reg_val);
- mutex_unlock(&chip->i2c_lock);
+ scoped_guard(mutex, &chip->i2c_lock)
+ ret = regmap_read(chip->regmap, dirreg, &reg_val);
if (ret < 0)
return ret;
@@ -607,9 +603,8 @@ static int pca953x_gpio_get_multiple(struct gpio_chip *gc,
DECLARE_BITMAP(reg_val, MAX_LINE);
int ret;
- mutex_lock(&chip->i2c_lock);
- ret = pca953x_read_regs(chip, chip->regs->input, reg_val);
- mutex_unlock(&chip->i2c_lock);
+ scoped_guard(mutex, &chip->i2c_lock)
+ ret = pca953x_read_regs(chip, chip->regs->input, reg_val);
if (ret)
return ret;
@@ -624,16 +619,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
DECLARE_BITMAP(reg_val, MAX_LINE);
int ret;
- mutex_lock(&chip->i2c_lock);
+ guard(mutex)(&chip->i2c_lock);
+
ret = pca953x_read_regs(chip, chip->regs->output, reg_val);
if (ret)
- goto exit;
+ return;
bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio);
pca953x_write_regs(chip, chip->regs->output, reg_val);
-exit:
- mutex_unlock(&chip->i2c_lock);
}
static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
@@ -641,7 +635,6 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
unsigned long config)
{
enum pin_config_param param = pinconf_to_config_param(config);
-
u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset);
u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset);
u8 bit = BIT(offset % BANK_SZ);
@@ -654,7 +647,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
if (!(chip->driver_data & PCA_PCAL))
return -ENOTSUPP;
- mutex_lock(&chip->i2c_lock);
+ guard(mutex)(&chip->i2c_lock);
/* Configure pull-up/pull-down */
if (param == PIN_CONFIG_BIAS_PULL_UP)
@@ -664,17 +657,13 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
else
ret = 0;
if (ret)
- goto exit;
+ return ret;
/* Disable/Enable pull-up/pull-down */
if (param == PIN_CONFIG_BIAS_DISABLE)
- ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
+ return regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
else
- ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
-
-exit:
- mutex_unlock(&chip->i2c_lock);
- return ret;
+ return regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
}
static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
@@ -887,10 +876,8 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
bitmap_zero(pending, MAX_LINE);
- mutex_lock(&chip->i2c_lock);
- ret = pca953x_irq_pending(chip, pending);
- mutex_unlock(&chip->i2c_lock);
-
+ scoped_guard(mutex, &chip->i2c_lock)
+ ret = pca953x_irq_pending(chip, pending);
if (ret) {
ret = 0;
@@ -1199,9 +1186,9 @@ static void pca953x_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM_SLEEP
-static int pca953x_regcache_sync(struct device *dev)
+static int pca953x_regcache_sync(struct pca953x_chip *chip)
{
- struct pca953x_chip *chip = dev_get_drvdata(dev);
+ struct device *dev = &chip->client->dev;
int ret;
u8 regaddr;
@@ -1248,13 +1235,38 @@ static int pca953x_regcache_sync(struct device *dev)
return 0;
}
+static int pca953x_restore_context(struct pca953x_chip *chip)
+{
+ int ret;
+
+ guard(mutex)(&chip->i2c_lock);
+
+ if (chip->client->irq > 0)
+ enable_irq(chip->client->irq);
+ regcache_cache_only(chip->regmap, false);
+ regcache_mark_dirty(chip->regmap);
+ ret = pca953x_regcache_sync(chip);
+ if (ret)
+ return ret;
+
+ return regcache_sync(chip->regmap);
+}
+
+static void pca953x_save_context(struct pca953x_chip *chip)
+{
+ guard(mutex)(&chip->i2c_lock);
+
+ /* Disable IRQ to prevent early triggering while regmap "cache only" is on */
+ if (chip->client->irq > 0)
+ disable_irq(chip->client->irq);
+ regcache_cache_only(chip->regmap, true);
+}
+
static int pca953x_suspend(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
- mutex_lock(&chip->i2c_lock);
- regcache_cache_only(chip->regmap, true);
- mutex_unlock(&chip->i2c_lock);
+ pca953x_save_context(chip);
if (atomic_read(&chip->wakeup_path))
device_set_wakeup_path(dev);
@@ -1277,17 +1289,7 @@ static int pca953x_resume(struct device *dev)
}
}
- mutex_lock(&chip->i2c_lock);
- regcache_cache_only(chip->regmap, false);
- regcache_mark_dirty(chip->regmap);
- ret = pca953x_regcache_sync(dev);
- if (ret) {
- mutex_unlock(&chip->i2c_lock);
- return ret;
- }
-
- ret = regcache_sync(chip->regmap);
- mutex_unlock(&chip->i2c_lock);
+ ret = pca953x_restore_context(chip);
if (ret) {
dev_err(dev, "Failed to restore register map: %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 5b117f3bd322..ab200e625010 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -41,7 +41,7 @@ struct gpio_rcar_info {
struct gpio_rcar_priv {
void __iomem *base;
- spinlock_t lock;
+ raw_spinlock_t lock;
struct device *dev;
struct gpio_chip gpio_chip;
unsigned int irq_parent;
@@ -124,7 +124,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
* "Setting Level-Sensitive Interrupt Input Mode"
*/
- spin_lock_irqsave(&p->lock, flags);
+ raw_spin_lock_irqsave(&p->lock, flags);
/* Configure positive or negative logic in POSNEG */
gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
@@ -143,7 +143,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
if (!level_trigger)
gpio_rcar_write(p, INTCLR, BIT(hwirq));
- spin_unlock_irqrestore(&p->lock, flags);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
@@ -247,7 +247,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
* "Setting General Input Mode"
*/
- spin_lock_irqsave(&p->lock, flags);
+ raw_spin_lock_irqsave(&p->lock, flags);
/* Configure positive logic in POSNEG */
gpio_rcar_modify_bit(p, POSNEG, gpio, false);
@@ -262,7 +262,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
if (p->info.has_outdtsel && output)
gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);
- spin_unlock_irqrestore(&p->lock, flags);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
@@ -348,7 +348,7 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
return 0;
}
- spin_lock_irqsave(&p->lock, flags);
+ raw_spin_lock_irqsave(&p->lock, flags);
outputs = gpio_rcar_read(p, INOUTSEL);
m = outputs & bankmask;
if (m)
@@ -357,7 +357,7 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
m = ~outputs & bankmask;
if (m)
val |= gpio_rcar_read(p, INDT) & m;
- spin_unlock_irqrestore(&p->lock, flags);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
bits[0] = val;
return 0;
@@ -368,9 +368,9 @@ static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
unsigned long flags;
- spin_lock_irqsave(&p->lock, flags);
+ raw_spin_lock_irqsave(&p->lock, flags);
gpio_rcar_modify_bit(p, OUTDT, offset, value);
- spin_unlock_irqrestore(&p->lock, flags);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
@@ -387,12 +387,12 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
if (!bankmask)
return;
- spin_lock_irqsave(&p->lock, flags);
+ raw_spin_lock_irqsave(&p->lock, flags);
val = gpio_rcar_read(p, OUTDT);
val &= ~bankmask;
val |= (bankmask & bits[0]);
gpio_rcar_write(p, OUTDT, val);
- spin_unlock_irqrestore(&p->lock, flags);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
@@ -469,7 +469,12 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
p->info = *info;
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
- *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
+ if (ret) {
+ *npins = RCAR_MAX_GPIO_PER_BANK;
+ } else {
+ *npins = args.args[2];
+ of_node_put(args.np);
+ }
if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",
@@ -506,7 +511,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
return -ENOMEM;
p->dev = dev;
- spin_lock_init(&p->lock);
+ raw_spin_lock_init(&p->lock);
/* Get device configuration from DT node */
ret = gpio_rcar_parse_dt(p, &npins);
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 54d9fa7da9c1..7185554b025e 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -753,6 +753,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
struct gpio_irq_chip *irq;
struct tegra_gpio *gpio;
struct device_node *np;
+ struct resource *res;
char **names;
int err;
@@ -772,19 +773,19 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->num_banks++;
/* get register apertures */
- gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
- if (IS_ERR(gpio->secure)) {
- gpio->secure = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(gpio->secure))
- return PTR_ERR(gpio->secure);
- }
-
- gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
- if (IS_ERR(gpio->base)) {
- gpio->base = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(gpio->base))
- return PTR_ERR(gpio->base);
- }
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "security");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gpio->secure = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpio->secure))
+ return PTR_ERR(gpio->secure);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
+ if (!res)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ gpio->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpio->base))
+ return PTR_ERR(gpio->base);
err = platform_irq_count(pdev);
if (err < 0)
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 06c6401f02b8..1d8168153a1c 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -1012,6 +1012,7 @@ static int zynq_gpio_remove(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
dev_warn(&pdev->dev, "pm_runtime_get_sync() Failed\n");
+ device_init_wakeup(&pdev->dev, 0);
gpiochip_remove(&gpio->chip);
clk_disable_unprepare(gpio->clk);
device_set_wakeup_capable(&pdev->dev, 0);