您的位置:首页 > 运维架构 > Linux

linux 标准GPIO 驱动模型—version1

2015-09-05 22:28 701 查看
前言:本文主要介绍gpio
driver实现基本方法,具体实例在后续的文章中继续介绍

Index:

1、bus 概念介绍

2、Device 与driver匹配过

3、GPIO driver 实现标准框架图

4、GPIO driver 细化实现

5、GPIO 上层应用

1、bus
概念介绍






Bus(platform总线):总线是CPU和一个或多个设备之间信息交互的通道。而为了方便模型的抽象,所有的设备都应连接到总线上
Device(gpio设备):抽象系统中所有的硬件设备,描述它的名字、属性、从属的Bus。

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

2、Device 与driver匹配过程

系统启动Bus init:kernel_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
101eb
= "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 driver:pin 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()

5、GPIO
上层应用

//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;
}





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 驱动