对于Linux 内核中的gpio操作,想必大家都很清楚,一般的做法是通过 gpio 的 sysfs文件系统
cd /sys/class/gpio
echo 11 > export
cd gpio11
xxxxxxxxx......
这种方法,可以直接操作GPIO口,但是当我们需要将类似刚刚例子里面的gpio11替换为我们使用引脚的具体定义时,如PWR_EN,这样的方法就行不通了,
所以这里我们要重写 Linux 的gpio_export为 gpio_export_with_name
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index d9fa7985..3d539600 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -604,6 +604,111 @@ fail_unlock:
}
EXPORT_SYMBOL_GPL(gpiod_export);
+/**
+ * gpiod_export_with_name - export a GPIO through sysfs
+ * @gpio: gpio to make available, already requested
+ * @direction_may_change: true if userspace may change gpio direction
+ * @name: gpio name
+ * Context: arch_initcall or later
+ *
+ * When drivers want to make a GPIO accessible to userspace after they
+ * have requested it -- perhaps while debugging, or as part of their
+ * public interface -- they may use this routine. If the GPIO can
+ * change direction (some can't) and the caller allows it, userspace
+ * will see "direction" sysfs attribute which may be used to change
+ * the gpio's direction. A "value" attribute will always be provided.
+ *
+ * Returns zero on success, else an error.
+ */
+int gpiod_export_with_name(struct gpio_desc *desc, bool direction_may_change,
+ const char *name)
+{
+ struct gpio_chip *chip;
+ unsigned long flags;
+ int status;
+ const char *ioname = NULL;
+ struct device *dev;
+ int offset;
+
+ /* can't export until sysfs is available ... */
+ if (!gpio_class.p) {
+ pr_debug("%s: called too early!\n", __func__);
+ return -ENOENT;
+ }
+
+ if (!desc) {
+ pr_debug("%s: invalid gpio descriptor\n", __func__);
+ return -EINVAL;
+ }
+
+ chip = desc->chip;
+
+ mutex_lock(&sysfs_lock);
+
+ /* check if chip is being removed */
+ if (!chip || !chip->exported) {
+ status = -ENODEV;
+ goto fail_unlock;
+ }
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
+ test_bit(FLAG_EXPORT, &desc->flags)) {
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
+ __func__,
+ test_bit(FLAG_REQUESTED, &desc->flags),
+ test_bit(FLAG_EXPORT, &desc->flags));
+ status = -EPERM;
+ goto fail_unlock;
+ }
+
+ if (!desc->chip->direction_input || !desc->chip->direction_output)
+ direction_may_change = false;
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ offset = gpio_chip_hwgpio(desc);
+ //if (desc->chip->names && desc->chip->names[offset])
+ // ioname = desc->chip->names[offset];
+ ioname = name; //这里最关键
+
+ 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)) {
+ status = PTR_ERR(dev);
+ goto fail_unlock;
+ }
+
+ 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_remove_attr_direction;
+ }
+
+ set_bit(FLAG_EXPORT, &desc->flags);
+ mutex_unlock(&sysfs_lock);
+ return 0;
+
+fail_remove_attr_direction:
+ device_remove_file(dev, &dev_attr_direction);
+fail_unregister_device:
+ device_unregister(dev);
+fail_unlock:
+ mutex_unlock(&sysfs_lock);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+ return status;
+}
+EXPORT_SYMBOL_GPL(gpiod_export_with_name);
+
static int match_export(struct device *dev, const void *data)
{
return dev_get_drvdata(dev) == data;
头文件相关
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d38a2948..ccdbe493 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -113,7 +113,8 @@ static inline int __gpio_to_irq(unsigned gpio)
extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
extern int gpio_request_array(const struct gpio *array, size_t num);
extern void gpio_free_array(const struct gpio *array, size_t num);
-
+extern int gpiod_export_with_name(struct gpio_desc *desc, bool direction_may_change,
+ const char *name);
/*
* A sysfs interface can be exported by individual drivers if they want,
* but more typically is configured entirely from userspace.
@@ -123,6 +124,12 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change,
+ const char *name)
+{
+ return gpiod_export_with_name(gpio_to_desc(gpio), direction_may_change, name);
+}
+
static inline int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
{
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 85aa5d0b..a43c7e6b 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -188,6 +188,14 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
return -EINVAL;
}
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change,
+ const char *name)
+{
+ /* GPIO can never have been requested or set as {in,out}put */
+ WARN_ON(1);
+ return -EINVAL;
+}
+
static inline int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
{