概述
gpio这些常见的外设,内核已经提供了函数接口,不需要一一设置寄存器
函数接口
int gpio_get_value(unsigned int gpio)
void gpio_set_value(unsigned int gpio, int value)
/*
* 功能:设置方向为输入
* 输入参数:unsigned int gpio: GPIO引脚
* 返回值:成功:0 失败:负数
*/
int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio, int value)
工程实例
static struct class *cls = NULL;
/{
fsled@4{
compatible = "fs4412,key";
gpx2_7 = <&gpx2 7 0>;
gpx1_0 = <&gpx1 0 0>;
gpf3_45 = <&gpf3 4 0>, <&gpf3 5 0>;
};
};
static int major = 0;
static int minor = 0;
const int count = 6;
static struct cdev *demop = NULL;
static atomic_t tv;
static int gpx2_7;
static int gpx1_0;
static int gpf3_4;
static int gpf3_5;
static void led_on(void)
{
gpio_set_value(gpx2_7, 1);//设置引脚状态为高电平
gpio_set_value(gpx1_0, 1);
gpio_set_value(gpf3_4, 1);
gpio_set_value(gpf3_5, 1);
}
static void led_off(void)
{
gpio_set_value(gpx2_7, 0);//设置引脚状态为低电平
gpio_set_value(gpx1_0, 0);
gpio_set_value(gpf3_4, 0);
gpio_set_value(gpf3_5, 0);
}
//打开设备
static int demo_open(struct inode *inode, struct file *filp)
{
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
if(!atomic_dec_and_test(&tv)){
atomic_inc(&tv);
return -EBUSY;
}
gpio_direction_output(gpx2_7, 0);//设置方向为输出
gpio_direction_output(gpx1_0, 0);
gpio_direction_output(gpf3_4, 0);
gpio_direction_output(gpf3_5, 0);
led_off();
return 0;
}
//关闭设备
static int demo_release(struct inode *inode, struct file *filp)
{
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
led_off();
atomic_inc(&tv);
return 0;
}
/*
* read/write param
* read status
* contrl device
*/
static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = filp->f_path.dentry->d_inode;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//get major and minor from inode
printk(KERN_INFO "(major=%d, minor=%dspinlock_t), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
switch(cmd){
case LEDON:
printk(KERN_INFO "LEDON: %s : %s : %d\n", __FILE__, __func__, __LINE__);
led_on();
break;
case LEDOFF:
printk(KERN_INFO "LEDOFF: %s : %s : %d\n", __FILE__, __func__, __LINE__);
led_off();
break;
default:
printk(KERN_INFO "inval cmd: %s : %s : %d\n", __FILE__, __func__, __LINE__);
return -EINVAL;
};
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = demo_open,
.release= demo_release,
.unlocked_ioctl = demo_ioctl,
};
static int __init demo_init(void)
{
dev_t devnum;
int ret, i;
struct device *devp = NULL;
struct device_node *np = NULL;
np = of_find_node_by_path("/fsled@4");//从设备树中找出LED设备节点
if(NULL == np){
return -EINVAL;
}
//根据名字从设备节点中筛选出gpio项
gpx2_7 = of_get_named_gpio(np, "gpx2_7", 0);//从np设备名字为"gpx2_7"的属性域中筛选出第0个项
if(0 > gpx2_7){
return -EINVAL;
}
gpx1_0 = of_get_named_gpio(np, "gpx1_0", 0);
if(0 > gpx1_0){
return -EINVAL;
}
gpf3_4 = of_get_named_gpio(np, "gpf3_45", 0);
if(0 > gpf3_4){
return -EINVAL;
}
gpf3_5 = of_get_named_gpio(np, "gpf3_45", 1);
if(0 > gpf3_5){
return -EINVAL;
}
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
//1. alloc cdev obj
demop = cdev_alloc();
if(NULL == demop){
return -ENOMEM;
}
//2. init cdev obj
cdev_init(demop, &fops);
ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
if(ret){
goto ERR_STEP;
}
major = MAJOR(devnum);
//3. register cdev obj
ret = cdev_add(demop, devnum, count);
if(ret){
goto ERR_STEP1;
}
cls = class_create(THIS_MODULE, DEVNAME);
if(IS_ERR(cls)){
ret = PTR_ERR(cls);
goto ERR_STEP1;
}
for(i = minor; i < (count+minor); i++){
devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
if(IS_ERR(devp)){
ret = PTR_ERR(devp);
goto ERR_STEP2;
}
}
// init atomic_t
atomic_set(&tv, 1);
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return 0;
ERR_STEP2:
for(--i; i >= minor; i--){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR_STEP1:
unregister_chrdev_region(devnum, count);
ERR_STEP:
cdev_del(demop);
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return ret;
}
static void __exit demo_exit(void)
{
int i;
//get command and pid
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
for(i=minor; i < (count+minor); i++){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
unregister_chrdev_region(MKDEV(major, minor), count);
cdev_del(demop);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");