|
@@ -128,7 +128,7 @@ static ssize_t gpio_value_store(struct device *dev,
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
-static const DEVICE_ATTR(value, 0644,
|
|
|
|
|
|
+static DEVICE_ATTR(value, 0644,
|
|
gpio_value_show, gpio_value_store);
|
|
gpio_value_show, gpio_value_store);
|
|
|
|
|
|
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
|
|
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
|
|
@@ -353,17 +353,46 @@ static ssize_t gpio_active_low_store(struct device *dev,
|
|
return status ? : size;
|
|
return status ? : size;
|
|
}
|
|
}
|
|
|
|
|
|
-static const DEVICE_ATTR(active_low, 0644,
|
|
|
|
|
|
+static DEVICE_ATTR(active_low, 0644,
|
|
gpio_active_low_show, gpio_active_low_store);
|
|
gpio_active_low_show, gpio_active_low_store);
|
|
|
|
|
|
-static const struct attribute *gpio_attrs[] = {
|
|
|
|
|
|
+static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
|
|
|
|
+ int n)
|
|
|
|
+{
|
|
|
|
+ struct device *dev = container_of(kobj, struct device, kobj);
|
|
|
|
+ struct gpio_desc *desc = dev_get_drvdata(dev);
|
|
|
|
+ umode_t mode = attr->mode;
|
|
|
|
+ bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
|
|
|
|
+
|
|
|
|
+ if (attr == &dev_attr_direction.attr) {
|
|
|
|
+ if (!show_direction)
|
|
|
|
+ mode = 0;
|
|
|
|
+ } else if (attr == &dev_attr_edge.attr) {
|
|
|
|
+ if (gpiod_to_irq(desc) < 0)
|
|
|
|
+ mode = 0;
|
|
|
|
+ if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
|
|
|
|
+ mode = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return mode;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct attribute *gpio_attrs[] = {
|
|
|
|
+ &dev_attr_direction.attr,
|
|
|
|
+ &dev_attr_edge.attr,
|
|
&dev_attr_value.attr,
|
|
&dev_attr_value.attr,
|
|
&dev_attr_active_low.attr,
|
|
&dev_attr_active_low.attr,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
};
|
|
|
|
|
|
-static const struct attribute_group gpio_attr_group = {
|
|
|
|
- .attrs = (struct attribute **) gpio_attrs,
|
|
|
|
|
|
+static const struct attribute_group gpio_group = {
|
|
|
|
+ .attrs = gpio_attrs,
|
|
|
|
+ .is_visible = gpio_is_visible,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct attribute_group *gpio_groups[] = {
|
|
|
|
+ &gpio_group,
|
|
|
|
+ NULL
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -400,16 +429,13 @@ static ssize_t chip_ngpio_show(struct device *dev,
|
|
}
|
|
}
|
|
static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
|
|
static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
|
|
|
|
|
|
-static const struct attribute *gpiochip_attrs[] = {
|
|
|
|
|
|
+static struct attribute *gpiochip_attrs[] = {
|
|
&dev_attr_base.attr,
|
|
&dev_attr_base.attr,
|
|
&dev_attr_label.attr,
|
|
&dev_attr_label.attr,
|
|
&dev_attr_ngpio.attr,
|
|
&dev_attr_ngpio.attr,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
};
|
|
-
|
|
|
|
-static const struct attribute_group gpiochip_attr_group = {
|
|
|
|
- .attrs = (struct attribute **) gpiochip_attrs,
|
|
|
|
-};
|
|
|
|
|
|
+ATTRIBUTE_GROUPS(gpiochip);
|
|
|
|
|
|
/*
|
|
/*
|
|
* /sys/class/gpio/export ... write-only
|
|
* /sys/class/gpio/export ... write-only
|
|
@@ -556,45 +582,30 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
|
goto fail_unlock;
|
|
goto fail_unlock;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!desc->chip->direction_input || !desc->chip->direction_output)
|
|
|
|
- direction_may_change = false;
|
|
|
|
|
|
+ if (desc->chip->direction_input && desc->chip->direction_output &&
|
|
|
|
+ direction_may_change) {
|
|
|
|
+ set_bit(FLAG_SYSFS_DIR, &desc->flags);
|
|
|
|
+ }
|
|
|
|
+
|
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
|
|
|
|
|
offset = gpio_chip_hwgpio(desc);
|
|
offset = gpio_chip_hwgpio(desc);
|
|
if (desc->chip->names && desc->chip->names[offset])
|
|
if (desc->chip->names && desc->chip->names[offset])
|
|
ioname = desc->chip->names[offset];
|
|
ioname = desc->chip->names[offset];
|
|
|
|
|
|
- dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
|
|
|
|
- desc, ioname ? ioname : "gpio%u",
|
|
|
|
- desc_to_gpio(desc));
|
|
|
|
|
|
+ dev = device_create_with_groups(&gpio_class, desc->chip->dev,
|
|
|
|
+ MKDEV(0, 0), desc, gpio_groups,
|
|
|
|
+ ioname ? ioname : "gpio%u",
|
|
|
|
+ desc_to_gpio(desc));
|
|
if (IS_ERR(dev)) {
|
|
if (IS_ERR(dev)) {
|
|
status = PTR_ERR(dev);
|
|
status = PTR_ERR(dev);
|
|
goto fail_unlock;
|
|
goto fail_unlock;
|
|
}
|
|
}
|
|
|
|
|
|
- status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
|
|
|
|
- if (status)
|
|
|
|
- goto fail_unregister_device;
|
|
|
|
-
|
|
|
|
- if (direction_may_change) {
|
|
|
|
- status = device_create_file(dev, &dev_attr_direction);
|
|
|
|
- if (status)
|
|
|
|
- goto fail_unregister_device;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
|
|
|
|
- !test_bit(FLAG_IS_OUT, &desc->flags))) {
|
|
|
|
- status = device_create_file(dev, &dev_attr_edge);
|
|
|
|
- if (status)
|
|
|
|
- goto fail_unregister_device;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
set_bit(FLAG_EXPORT, &desc->flags);
|
|
set_bit(FLAG_EXPORT, &desc->flags);
|
|
mutex_unlock(&sysfs_lock);
|
|
mutex_unlock(&sysfs_lock);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
-fail_unregister_device:
|
|
|
|
- device_unregister(dev);
|
|
|
|
fail_unlock:
|
|
fail_unlock:
|
|
mutex_unlock(&sysfs_lock);
|
|
mutex_unlock(&sysfs_lock);
|
|
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
|
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
|
@@ -718,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc)
|
|
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
|
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
|
if (dev) {
|
|
if (dev) {
|
|
gpio_setup_irq(desc, dev, 0);
|
|
gpio_setup_irq(desc, dev, 0);
|
|
|
|
+ clear_bit(FLAG_SYSFS_DIR, &desc->flags);
|
|
clear_bit(FLAG_EXPORT, &desc->flags);
|
|
clear_bit(FLAG_EXPORT, &desc->flags);
|
|
} else
|
|
} else
|
|
status = -ENODEV;
|
|
status = -ENODEV;
|
|
@@ -750,13 +762,13 @@ int gpiochip_export(struct gpio_chip *chip)
|
|
|
|
|
|
/* use chip->base for the ID; it's already known to be unique */
|
|
/* use chip->base for the ID; it's already known to be unique */
|
|
mutex_lock(&sysfs_lock);
|
|
mutex_lock(&sysfs_lock);
|
|
- dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
|
|
|
|
- "gpiochip%d", chip->base);
|
|
|
|
- if (!IS_ERR(dev)) {
|
|
|
|
- status = sysfs_create_group(&dev->kobj,
|
|
|
|
- &gpiochip_attr_group);
|
|
|
|
- } else
|
|
|
|
|
|
+ dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
|
|
|
|
+ chip, gpiochip_groups,
|
|
|
|
+ "gpiochip%d", chip->base);
|
|
|
|
+ if (IS_ERR(dev))
|
|
status = PTR_ERR(dev);
|
|
status = PTR_ERR(dev);
|
|
|
|
+ else
|
|
|
|
+ status = 0;
|
|
chip->exported = (status == 0);
|
|
chip->exported = (status == 0);
|
|
mutex_unlock(&sysfs_lock);
|
|
mutex_unlock(&sysfs_lock);
|
|
|
|
|