在linux内核中,有一些基本模块可以使用标准的接口函数来操作,比如GPIO、interrupt、clock,所谓的标准接口函数是指一些与硬件平台无关的、linux下做驱动通用的函数,
常用的有:
gpio_request();gpio_free();gpio_direction_output();gpio_direction_input();gpio_set_value();gpio_get_value()等;
函数分析:
1)GPIO申请:
int gpio_request(unsigned gpio, const char *label)
参数分析:
unsigned gpio:gpio端口号;
const char *label:给该gpio端口起的名字;
返回值:
成功返回0;失败返回负数的错误码;
不同平台的gpio端口号是不同的,比如在s5pv210平台上,在内核源码的arch/arm/mach-s5pv210/include/mach下有一个gpio.h的头文件,其中有:
/* S5PV210 GPIO number definitions */
#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr))
#define S5PV210_GPB(_nr) (S5PV210_GPIO_B_START + (_nr))
#define S5PV210_GPC0(_nr) (S5PV210_GPIO_C0_START + (_nr))
#define S5PV210_GPC1(_nr) (S5PV210_GPIO_C1_START + (_nr))
#define S5PV210_GPD0(_nr) (S5PV210_GPIO_D0_START + (_nr))
#define S5PV210_GPD1(_nr) (S5PV210_GPIO_D1_START + (_nr))
…..
例如端口GPJD0_1就对应宏定义的S5PV210_GPD0(1)。
2)GPIO的初始化
初始化为输出,并设置输出电平:
int gpio_direction_output(unsigned gpio, int value);
初始化为输入:
int gpio_direction_input(unsigned gpio);
3)GPIO的输出电平设置:
void gpio_set_value(unsigned gpio, int value);
4)得到GPIO的电平
int gpio_get_value(unsigned gpio);
5)释放GPIO
void gpio_free(unsigned gpio);
下面做一个简单的led驱动,实现对基于S5PV210平台的4盏LED灯控制,对应的GPIO口为GPJ2_0、GPJ2_0、GPJ2_0、GPJ2_0。
static int __init leddev_init(void)
{
int ret;
/*************led gpio request and initial**************/
int i;
for( i = 0; i < 4; i++)
{
ret = gpio_request(S5PV210_GPJ2(i), "led_gpio");
if(ret < 0)
{
printk("S5PV210_GPJ2(%d)_request error!\n", i);
goto err_gpio_request;
}
gpio_direction_output(S5PV210_GPJ2(i), 1);
}
printk("led initial success!\n");
if(cdev_Major) //初始值不为0,则手动分配设备号
{
cdev_num = MKDEV(cdev_Major, cdev_Minor);
ret= register_chrdev_region(cdev_num, 1, cdev_name);
}
else
{
ret = alloc_chrdev_region(&cdev_num, cdev_Minor, 1, cdev_name); //动态分配设备号
cdev_Major = MAJOR(cdev_num);
}
if(ret < 0)
{
printk(KERN_WARNING"can not get major %d\n", cdev_Major);
goto err_leddev_region;
}
cdev_init(&leddev, &leddev_fops);//建立字符设备与文件操作集的联系
gpiodev.owner = THIS_MODULE;
ret = cdev_add(&leddev, cdev_num, 1);
if(ret)
{
printk("error while register device!\n");
goto err_gpiodev_add;
}
/******************auto create device file****************/
class_ret = class_create(THIS_MODULE, "ledclass");
if(class_ret == NULL)
{
printk("class_create error!\n");
goto err_class_creat;
}
device_ret = device_create(class_ret, NULL, cdev_num, NULL, "leddev");
if(device_ret == NULL)
{
printk("device_create error!\n");
goto err_device_create;
}
return 0;
err_device_create:
class_destroy(class_ret);
err_class_creat:
err_leddev_add:
unregister_chrdev_region(MKDEV(cdev_Major, cdev_Minor), 1);
err_leddev_region:
err_gpio_request:
for( ; i > 0; i--)
{
gpio_free(S5PV210_GPJ2(i - 1));
}
return ret;
}
static void __exit leddev_exit(void)
{
int i;
printk("exit from leddev!\n");
for(i = 0 ; i < 4; i++)
{
gpio_free(S5PV210_GPJ2(i));
}
class_destroy(class_ret);
device_destroy(class_ret, cdev_num);
unregister_chrdev_region(MKDEV(cdev_Major, cdev_Minor), 1);
cdev_del(&leddev);
}
module_init(leddev_init);
module_exit(leddev_exit);
MODULE_AUTHOR("Mr.Huang");
MODULE_DESCRIPTION("This is a leddev for testing!");
MODULE_LICENSE("GPL");