diff options
Diffstat (limited to 'drivers/gpio/gpiolib-sysfs.c')
-rw-r--r-- | drivers/gpio/gpiolib-sysfs.c | 74 |
1 files changed, 37 insertions, 37 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 201b757ad0db..d9b3faa01fee 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -13,6 +13,7 @@ struct gpiod_data { struct gpio_desc *desc; struct kernfs_node *value_kn; + int irq; }; /* lock protects against unexport_gpio() being called while @@ -132,27 +133,20 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv) return IRQ_HANDLED; } -static int gpio_setup_irq(struct device *dev, unsigned long gpio_flags) +static int gpio_sysfs_request_irq(struct device *dev, unsigned long gpio_flags) { struct gpiod_data *data = dev_get_drvdata(dev); struct gpio_desc *desc = data->desc; unsigned long irq_flags; - int ret, irq; + int ret; - irq = gpiod_to_irq(desc); - if (irq < 0) + data->irq = gpiod_to_irq(desc); + if (data->irq < 0) return -EIO; - if (data->value_kn) - free_irq(irq, data); - - desc->flags &= ~GPIO_TRIGGER_MASK; - - if (!gpio_flags) { - gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); - ret = 0; - goto free_kn; - } + data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value"); + if (!data->value_kn) + return -ENODEV; irq_flags = IRQF_SHARED; if (test_bit(FLAG_TRIG_FALL, &gpio_flags)) @@ -162,14 +156,6 @@ static int gpio_setup_irq(struct device *dev, unsigned long gpio_flags) irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; - if (!data->value_kn) { - data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value"); - if (!data->value_kn) { - ret = -ENODEV; - goto err_out; - } - } - /* * FIXME: This should be done in the irq_request_resources callback * when the irq is requested, but a few drivers currently fail @@ -180,27 +166,36 @@ static int gpio_setup_irq(struct device *dev, unsigned long gpio_flags) */ ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); if (ret < 0) - goto free_kn; + goto err_put_kn; - ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags, + ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags, "gpiolib", data); if (ret < 0) goto err_unlock; desc->flags |= gpio_flags; + return 0; err_unlock: gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); -free_kn: - if (data->value_kn) { - sysfs_put(data->value_kn); - data->value_kn = NULL; - } -err_out: +err_put_kn: + sysfs_put(data->value_kn); + return ret; } +static void gpio_sysfs_free_irq(struct device *dev) +{ + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; + + desc->flags &= ~GPIO_TRIGGER_MASK; + free_irq(data->irq, data); + gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); + sysfs_put(data->value_kn); +} + static const struct { const char *name; unsigned long flags; @@ -240,7 +235,7 @@ static ssize_t edge_store(struct device *dev, struct gpiod_data *data = dev_get_drvdata(dev); struct gpio_desc *desc = data->desc; unsigned long flags; - ssize_t status; + ssize_t status = size; int i; for (i = 0; i < ARRAY_SIZE(trigger_types); i++) @@ -258,9 +253,14 @@ found: goto out_unlock; } - status = gpio_setup_irq(dev, flags); - if (!status) - status = size; + if (desc->flags & GPIO_TRIGGER_MASK) + gpio_sysfs_free_irq(dev); + + if (flags) { + status = gpio_sysfs_request_irq(dev, flags); + if (!status) + status = size; + } out_unlock: mutex_unlock(&sysfs_lock); @@ -288,8 +288,8 @@ static int sysfs_set_active_low(struct device *dev, int value) !!test_bit(FLAG_TRIG_FALL, &desc->flags)) { unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK; - gpio_setup_irq(dev, 0); - status = gpio_setup_irq(dev, trigger_flags); + gpio_sysfs_free_irq(dev); + status = gpio_sysfs_request_irq(dev, trigger_flags); } return status; @@ -699,7 +699,7 @@ void gpiod_unexport(struct gpio_desc *desc) * edge_store. */ if (desc->flags & GPIO_TRIGGER_MASK) - gpio_setup_irq(dev, 0); + gpio_sysfs_free_irq(dev); put_device(dev); kfree(data); } |