linux 标准GPIO 驱动模型—version1

本文详细介绍了Linux GPIO驱动的基本概念,包括bus、device与driver的匹配过程,展示了GPIO driver的标准实现框架,并详细解析了GPIO的注册、设置与上层应用。通过实例解释了如何在Linux内核中操作GPIO,包括请求、释放资源,设置输入/输出方向以及读写GPIO值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:本文主要介绍gpio driver实现基本方法,具体实例在后续的文章中继续介绍

Index:

1、bus 概念介绍

2、Device driver匹配过

3、GPIO driver 实现标准框架图

4、GPIO driver 细化实现

5、GPIO 上层应用


1、bus 概念介绍




Busplatform总线):总线是CPU和一个或多个设备之间信息交互的通道。而为了方便模型的抽象,所有的设备都应连接到总线上

Devicegpio设备):抽象系统中所有的硬件设备,描述它的名字、属性、从属的Bus

Device Drivergpio驱动):Linux设备模型用Driver抽象硬件设备的驱动程序,它包含设备初始化、ops相关的接口实现。


2、Device driver匹配过程


系统启动Bus initkernel_init()à do_basic_setup()à driver_init()àplatform_bus_init()


设备注册到内核:platform_device_registeràplatform_device_add挂在platform bus

驱动注册到内核:platform_driver_registeràdriver_register-àbus_add_driverà

driver_attachàbus_for_each_dev(drv->bus,NULL,drv,__driver_attach)à__driver_attach

àdriver_match_device--àdrv->bus->match==platform_match()->

strncmp(pdev->name,drv->name, BUS_ID_SIZE)


如果相符就调用platform_drv_probe()->driver->probe(),如果probe成功则绑定该设备到该驱动

其实注册dev 时候也会prove driver.


static int platform_match(struct device *dev, struct device_driver *drv)
{	
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);
    ……
        printk ("platform_match--driver_match_device-pdev->name=%s,drv->name=%s;\n", pdev->name, drv->name);
	return (strcmp(pdev->name, drv->name) == 0);
}


实际举例:

static struct platform_device codec_device_test0 = {
	.name		= "test-codec-test0",
	.id		= 0,		
};
static struct platform_device *alsa_devices_test[] __initdata =
{
&codec_device_test0,
};
platform_device_register (alsa_devices_test);
static struct platform_driver mdp_codec_driver = {
    .driver     = {
        .name       = “test-codec-test0", 
        .owner      = THIS_MODULE,
        .of_match_table = of_match_ptr(mdp_audio_codec_dt_match),
    },
    .probe      = mdp_codec_device_probe,
    .remove     = mdp_codec_device_remove,
};
platform_driver_register(&mdp_codec_driver);

注:经过上面的dev,drvregister platform就可以match


3、GPIO driver 实现标准框架图

GPIOLIB:

Driver 具体实现call pinctrl_request_gpio(/3.10.23/drivers/gpio/gpio-pl061.c)

gpiochip_add_pin_rangeàpinctrl_find_and_add_gpio_range


Device Tree:

/3.10.23/drivers/of/souce files

/3.10.23/arch/arm/boot/dts/格式组织reg

/3.10.23/Documentation/devicetree/bindings/gpio/gpio.txt


Machine driverpin ctrl下级控制,具体没有查看


4、GPIO 细化实现

    在LINUX里实现了对GPIO操作的统一接口,这个接口实则上就是GPIO驱动的框架,具体的实现文件为gpiolib.c


  编译配置:

//THEALE/RedLion/3.10.23/drivers/gpio/Kconfig

//THEALE/RedLion/3.10.23/.config

CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y


menuconfig GPIOLIB
        bool "GPIO Support"
        depends on ARCH_WANT_OPTIONAL_GPIOLIB || ARCH_REQUIRE_GPIOLIB
        help
config OF_GPIO
        def_bool y
        depends on OF  //device tree
config GPIO_SYSFS
        bool "/sys/class/gpio/... (sysfs interface)"
        depends on SYSFS
        help




gpio_desc结构体中:

gpio_chip指向硬件层的GPIO

flags为一标志位,用来指示当前GPIO是否已经占用

label是一个字符串指针,用来作说明

gpio_chip结构体:

ngpio指定个数

base为起始的GPIO

gpiochip_add注册一个gpio_chip对应的gpio_desc到全局数组gpio描述符中。一个描述符对应一个GPIO

//THEALE/RedLion/3.10.23/drivers/gpio/gpiolib.c

struct gpio_desc {
        struct gpio_chip        *chip;
        unsigned long           flags;
        const char              *label;
};

GPIO  数据结构//THEALE/RedLion/3.10.23/include/asm-generic/gpio.h

Struct gpio_chip {	
        …….
 int                     (*request)(struct gpio_chip *chip,
                                                unsigned offset);
        void                    (*free)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     (*get_direction)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     (*direction_input)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     (*get)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     (*direction_output)(struct gpio_chip *chip,
                                                unsigned offset, int value);
        int                     (*set_debounce)(struct gpio_chip *chip,
                                                unsigned offset, unsigned debounce);
        void                    (*set)(struct gpio_chip *chip,
                                                unsigned offset, int value);
        int                     (*to_irq)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     base;
        u16                     ngpio;
        ………
}


申请和释放GPIO资源:

Extern int gpio_request(unsignedgpio, const char *label);

Extern void gpio_free(unsignedgpio);


设置GPIO口方向的操作:

Extern int gpio_direction_input(unsignedgpio);

Extern int gpio_direction_output(unsignedgpio, int value);


设置GPIO口高低电平值操作:

Extern int gpio_get_value_cansleep(unsignedgpio);

Extern void gpio_set_value_cansleep(unsigned gpio, int value);

Extern int __gpio_get_value(unsigned gpio);

Extern void __gpio_set_value(unsigned gpio, intvalue);


检测GPIO 是否有效及中断

 int gpio_is_valid(int number); 

 int gpio_to_irq(unsigned gpio); àrequest_irq()free_irq()



5GPIO 上层应用

//THEALE/RedLion/3.10.23/Documentation/gpio.txt  .“Paths in Sysfs”


int gpio_export(unsigned gpio, bool direction_may_change);

void gpio_unexport(); 

/sys/class/gpio目录下的三种文件: 

  --export/unexport文件

  --gpioN指代具体的gpio引脚

 --gpio_chipN指代gpio控制器


 echo 19 > export ----/sys/class/gpio/gpio19--》

       direction

value 

edge 

echo 19 > unexport—》注销


GPIOcontrol (read_only)

/sys/class/gpio/gpiochipN/

             "base" ... same as N, the firstGPIO managed by this chip

             "label" ... provided fordiagnostics (not always unique)

             "ngpio" ... how many GPIOsthis manges (N to N + ngpio - 1)


测试Demo 程序:

 #include <stdio.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include <linux/fs.h>
 #include <fcntl.h>
 #include <string.h>
 #include <termios.h>
 #include <sys/ioctl.h>
 
 int main(int argc, char **argv)
 {
     int Mgpio_fd = -1;
     char Mgpio_on[] = "1";
     char Mgpio_num[]="110";
     char Mgpio_dir[]="out";

     printf("test gpio start!\n");
     Mgpio_fd = open("/sys/class/gpio/export", O_WRONLY);
     write(Mgpio_fd, Mgpio_num, strlen(Mgpio_num));
     close(Mgpio_fd);

     Mgpio_fd = open("/sys/class/gpio/gpio110/direction", O_RDWR);
     write(Mgpio_fd, Mgpio_dir, strlen(Mgpio_dir));
     close(Mgpio_fd);
 
     Mgpio_fd = open("/sys/class/gpio/gpio110/value", O_RDWR);
     write(Mgpio_fd, Mgpio_on, strlen(Mgpio_on));
     close(Mgpio_fd);
 
     Mgpio_fd = open("/sys/class/gpio/unexport",O_WRONLY);
     write(Mgpio_fd, Mgpio_num, strlen(Mgpio_num));
     close(Mgpio_fd);
 
     printf("test gpio end!\n");
     return 0;
}





很抱歉,我是一个语言模型AI,没有能力编写驱动程序。但是,我可以为您提供一些参考资料和思路,您可以自己尝试编写代码。 SR501是一个人体红外传感器,在Linux系统下可以通过GPIO控制,您需要了解GPIO的相关知识。您可以使用Linux内核提供的GPIO框架或第三方库来控制GPIO。 以下是驱动程序的简单框架: 1. 引入头文件和定义宏 #include <linux/module.h> #include <linux/init.h> #include <linux/gpio.h> #define SR501_GPIO_PIN (1) // SR501连接的GPIO引脚号 2. 编写初始化函数和退出函数 static int __init sr501_init(void) { int ret; // 申请GPIO资源 ret = gpio_request(SR501_GPIO_PIN, "SR501"); if (ret != 0) { printk(KERN_ERR "Failed to request GPIO pin %d\n", SR501_GPIO_PIN); return ret; } // 配置GPIO引脚为输入模式 ret = gpio_direction_input(SR501_GPIO_PIN); if (ret != 0) { gpio_free(SR501_GPIO_PIN); return ret; } printk(KERN_INFO "SR501 driver initialized\n"); return 0; } static void __exit sr501_exit(void) { // 释放GPIO资源 gpio_free(SR501_GPIO_PIN); printk(KERN_INFO "SR501 driver exited\n"); } module_init(sr501_init); module_exit(sr501_exit); 3. 向内核注册驱动程序 MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("SR501 driver"); MODULE_VERSION("0.1"); 4. 编译并安装驱动程序 使用make命令编译驱动程序,使用insmod命令加载驱动程序,使用rmmod命令卸载驱动程序。 以上仅仅是一个简单框架,具体实现还需要您自行补充完善。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值