内核里的gpiolib除了提供如gpio_request, gpio_direction_input/output, gpio_set_value等操作函数外,还提供了在终端上用直接操作gpio口的功能.
首先确认内核里是否已选择上gpiolib的sysfs接口功能(默认是已选择上的)
make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Device Drivers --->
*- GPIO Support --->
[*] /sys/class/gpio/... (sysfs interface)
然后确认在linux内核源码里gpio口对应的序号,这个是由芯片厂家自定义的,通常在”arch/arm/mach-xxx/include/mach/gpio.h”里.
h3的gpio口定义在”arch/arm/mach-sunxi/include/mach/gpio.h”
#define SUNXI_BANK_SIZE 32
#define SUNXI_PA_BASE 0
#define SUNXI_PB_BASE 32
#define SUNXI_PC_BASE 64
#define SUNXI_PD_BASE 96
#define SUNXI_PE_BASE 128
#define SUNXI_PF_BASE 160
#define SUNXI_PG_BASE 192
#define SUNXI_PH_BASE 224
#define SUNXI_PI_BASE 256
#define SUNXI_PJ_BASE 288
#define SUNXI_PK_BASE 320
#define SUNXI_PL_BASE 352
#define SUNXI_PM_BASE 384
#define SUNXI_PN_BASE 416
#define SUNXI_PO_BASE 448
#define AXP_PIN_BASE 1024
#define SUNXI_PIN_NAME_MAX_LEN 8
/* sunxi gpio name space */
#define GPIOA(n) (SUNXI_PA_BASE + (n))
#define GPIOB(n) (SUNXI_PB_BASE + (n))
#define GPIOC(n) (SUNXI_PC_BASE + (n))
#define GPIOD(n) (SUNXI_PD_BASE + (n))
#define GPIOE(n) (SUNXI_PE_BASE + (n))
#define GPIOF(n) (SUNXI_PF_BASE + (n))
#define GPIOG(n) (SUNXI_PG_BASE + (n))
#define GPIOH(n) (SUNXI_PH_BASE + (n))
#define GPIOI(n) (SUNXI_PI_BASE + (n))
#define GPIOJ(n) (SUNXI_PJ_BASE + (n))
#define GPIOK(n) (SUNXI_PK_BASE + (n))
#define GPIOL(n) (SUNXI_PL_BASE + (n))
#define GPIOM(n) (SUNXI_PM_BASE + (n))
#define GPION(n) (SUNXI_PN_BASE + (n))
#define GPIOO(n) (SUNXI_PO_BASE + (n))
#define GPIO_AXP(n) (AXP_PIN_BASE + (n))
gpio口的操作过程,如控制status-led(接在PA15)的亮灭.
1 让gpiolib导出PA15的控制文件. 可根据上面检出PA15引脚对应的gpio口序号为15
echo 15 > /sys/class/gpio/export
操作完成后,应会在/sys/class/gpio/目录下生成一个gpio15的子目录.
2 在/sys/class/gpio/gpio15目录有文件:
/mnt/kernel_coding # ls /sys/class/gpio/gpio15/
active_low direction edge value
//通过direction文件可控制gpio口是作输入或输出功能
// echo "high" > /sys/class/gpio/gpio15/direction 是让gpio口作输出,并输出高电平
// echo "out" > /sys/class/gpio/gpio15/direction 是作输出功能,并输出低电平
// echo "in" > /sys/class/gpio/gpio15/direction 是作输入功能
//通过value文件可以获取和控制gpio口的电平(当gpio口作输出时,可以通过写操作改变电平。当作输入时,可以通过读操作获取电平)
// echo "1" > /sys/class/gpio/gpio15/value 让gpio口输出高电平
// echo "0" > /sys/class/gpio/gpio15/value 让gpio口输出低电平
//通过edge文件, 可以指定gpio作中断功能,并指定它的触发电平和获取. 触发电平方式有("none", "falling", "rising", "both")
//通过active_low文件,可以指定往value文件写1时为有效电平.
如: echo "1" > /sys/calss/gpio/gpio15/value时是输出高电平的
当echo "1" > /sys/calss/gpio/gpio15/active_low后, 再往value写1是就是输出低电平了.
工作原理可参考https://blog.csdn.net/jklinux/article/details/73896459
702 static struct class_attribute gpio_class_attrs[] = {
703 __ATTR(export, 0200, NULL, export_store), // 当对/sys/class/gpio/export进行写操作时,会触发调用export_store函数
704 __ATTR(unexport, 0200, NULL, unexport_store),
705 __ATTR_NULL,
706 };
707
708 static struct class gpio_class = {
709 .name = "gpio",
710 .owner = THIS_MODULE,
711
712 .class_attrs = gpio_class_attrs, //指定了属性文件. (/sys/class/gpio/export, /sys/class/gpio/unexport)
713 };
997 static int __init gpiolib_sysfs_init(void)
998 {
...
1003 status = class_register(&gpio_class); //注册class后就会生成/sys/class/gpio目录,并在目录下生成gpio_class的属性文件
...
1029 }
1030 postcore_initcall(gpiolib_sysfs_init); //系统初始化时会调用
//当对"echo gpio口对应的序号 > /sys/class/gpio/export"进行写操作时,会触发调用export_store函数
637 static ssize_t export_store(struct class *class,
638 struct class_attribute *attr,
639 const char *buf, size_t len)
640 {
641 long gpio;
642 int status;
643
644 status = strict_strtol(buf, 0, &gpio); //把字符串buf里描述的gpio口序号转成long类型变量gpio
...
653 status = gpio_request(gpio, "sysfs"); //请求gpio口
...
659 status = gpio_export(gpio, true); //再调用gpio_export函数来处理请求的gpio口
...
669 }
731 int gpio_export(unsigned gpio, bool direction_may_change)
732 {
...
774 dev = device_create_with_groups(&gpio_class, desc->chip->dev,
775 MKDEV(0, 0), desc, gpio_groups,
776 ioname ? ioname : "gpio%u", gpio); //会在/sys/class/gpio/目录下生成一个名为"gpio"+gpio口序号的子目录(请gpio口为15, 则子目录名为"gpio15"), 并在子目录生成"direction, edge,value, active_low"等属性文件
...
790 }
791 EXPORT_SYMBOL_GPL(gpio_export);
571 static struct attribute *gpio_attrs[] = {
572 &dev_attr_direction.attr,
573 &dev_attr_edge.attr,
574 &dev_attr_value.attr,
575 &dev_attr_active_low.attr,
576 NULL,
577 };
578
579 static const struct attribute_group gpio_group = {
580 .attrs = gpio_attrs,
581 .is_visible = gpio_is_visible,
582 };
583
584 static const struct attribute_group *gpio_groups[] = {
585 &gpio_group,
586 NULL
587 };
///////////////////////////////////
242 static ssize_t gpio_direction_store(struct device *dev,
243 struct device_attribute *attr, const char *buf, size_t size)
244 {
245 const struct gpio_desc *desc = dev_get_drvdata(dev);
246 unsigned gpio = desc - gpio_desc;
247 ssize_t status;
248
249 mutex_lock(&sysfs_lock);
250
251 if (!test_bit(FLAG_EXPORT, &desc->flags))
252 status = -EIO;
253 else if (sysfs_streq(buf, "high"))
254 status = gpio_direction_output(gpio, 1);
255 else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
256 status = gpio_direction_output(gpio, 0);
257 else if (sysfs_streq(buf, "in"))
258 status = gpio_direction_input(gpio);
259 else
260 status = -EINVAL;
261
262 mutex_unlock(&sysfs_lock);
263 return status ? : size;
264 }
265
266 static DEVICE_ATTR(direction, 0644,
267 gpio_direction_show, gpio_direction_store); // 当对direction属性文件写操作时,触发调用gpio_direction_store. 如写"out"则把gpio口作为输出,并输出低电平. 同样的原理,可以通过value属性文件操作gpio口的电平状态.
|