struct gpiod_data {
struct gpio_desc *desc;
struct kernfs_node *value_kn;
+ int irq;
};
/* lock protects against unexport_gpio() being called while
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))
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
*/
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;
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++)
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);
!!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;
* edge_store.
*/
if (desc->flags & GPIO_TRIGGER_MASK)
- gpio_setup_irq(dev, 0);
+ gpio_sysfs_free_irq(dev);
put_device(dev);
kfree(data);
}