前言:本文主要介绍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 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;
}