转载地址:http://blog.csdn.net/xuefeng_apple/article/details/48230885
前言:本文主要介绍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 = "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 intgpio_request(unsignedgpio, const char *label);
Extern voidgpio_free(unsignedgpio);
设置GPIO口方向的操作:
Extern intgpio_direction_input(unsignedgpio);
Extern intgpio_direction_output(unsignedgpio, int value);
设置GPIO口高低电平值操作:
Extern intgpio_get_value_cansleep(unsignedgpio);
Extern voidgpio_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;