ITOP-4412 LED驱动实现

来源:互联网 发布:淘宝双11营业额直播 编辑:程序博客网 时间:2024/05/21 10:57

开发环境:ubuntu12.04  内核版本:ITOP提供的Kernel_3.0

一直想学学驱动,最近买了一块ITOP-4412开发板,资料相对比较全,比较适合现在的学习。Itop-4412的核心板有两种,一种是POP核心板,另一种是SCP核心板。本次试验所用的是SCP板,该板主频1.4GHz,1G内存。底板有两个LED灯,本次使用就是实现对这两个LED灯对应GPIO的控制。LED引脚连接如下如:

 

KP_COL0对应引脚GPL2_0,VDD50_EN对应引脚GPK1_1,分别如下图所示:

 


首先实现对单个led的控制,然后实现两个led控制,具体流程如下:

1、注册设备

A、在内核源码中,找到drivers/char/Kconfig,仿照led写一个GPIO的设备控制配置,如下:

 

B、arch/arm/mach-exynos/mach-itop4412.c文件中,仿照led添加一个gpio设备,具体如下:

此处需要特别注意结构体中的.name,它是设备名字,改名字将在后面的驱动注册中使用到,需要对应才可。

同样在该文件中,还需要在另一处加载设备注册函数(搜索led相关即可),操作如下:

 

至此,注册设备完毕,重新编译内核,烧写至开发板。

2、注册驱动

在该部分中,主要相关的是对platform_driver结构体的使用,该结构体在:include/linux/platform_device.h,结构体定义如下:

 

Platform_driver_register函数是注册驱动,platform_driver_unregsiter函数是卸载驱动。对该结构体使用如下:

 

注意,.name = DRIVER_NAMEDRIVER_NAME必须是第一注册设备时的“gpios_ctl”。然后分别编写函数实现led_probe,led_remove,led_shutdown等函数,具体实现见后面的代码。

调用platform_driver_register(&led_driver)注册驱动,该函数在led_init()中调用,platform_driver_unregister(&led_driver)led_exit()中调用。

3、注册杂项设备,生成设备节点

杂项设备引入主要是节省主设备号,是驱动写起来更简单。

杂项设备主要涉及file_operations结构体的使用,该结构体在Include/linux/fs.h定义

杂项设备涉及头文件在include/linux/miscdevice.h

该步骤中主要是注册杂项设备和关闭杂项设备,分别使用misc_registermisc_deregister函数,而这两个函数又和file_operations结构体关联,该结构主要是包含文件的打开、关闭、控制等函数实现。

 


然后实现file_operations的相关操作函数即可,见后面代码。至此,led的驱动实现。

4、应用程序

该步骤就是编写应用程序,对led进行操作,控制led亮灭。

驱动代码如下:

/**
 * @brief      
 * @file     leds.c
 * @author   cc
 * @version  
 * @date     Sat 09 Dec 2017 21:48:16 CST
 * @mail     13568859409@163.com 
 * @note     
 */

/*包含模块初始化宏定义的头文件,module_init、moudle_exit在此文件中定义*/
#include <linux/init.h>
/*包含初始化加载模块的头文件,MODULE_LICENSE在此头文件中定义*/
#include <linux/module.h>
/*驱动注册头文件,包含驱动的结构体和注册、卸载函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的头文件结构体*/
#include <linux/fs.h>

/*Linux中申请GPIO的头文件*/
#include <linux/gpio.h>
/*三星平台的GPIO配置函数头文件*/
/*三星平台EXYNOS平台GPIO配置头文件*/
#include <plat/gpio-cfg.h>
#include <mach/gpio.h>
/*三星平台4412GPIO宏定义头文件*/
#include <mach/gpio-exynos4.h>


#define DRIVER_NAME "gpios_ctl"
#define DEVICE_NAME "gpios_ctl_dev"

/*声明开源*/
MODULE_LICENSE("Dual BSD/GPL");
/*作者声明*/
MODULE_AUTHOR("CC");

/**
 *@brief 设备文件打开
 *@return 成功:0   失败:-1
 */
static int led_open(struct inode *inode,struct file *fnode)
{
printk(KERN_EMERG "led open\n");
return 0;
}

/**
 *@brief 设备文件关闭
 *@return 成功:0   失败:-1
 */
static int led_release(struct inode *inode,struct file *fnode)
{
printk(KERN_EMERG "led release\n");
return 0;
}
/**
 *@brief 设备文件关闭
 *@return 成功:0   失败:-1
 */
static long led_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
printk(KERN_EMERG "cmd is %d,arg is %ld\n",cmd,arg);


if(cmd > 1)
{
printk(KERN_EMERG "cmd is 0 or 1\n");
}
if(arg > 1)
{
printk(KERN_EMERG "arg is 0 or 1\n");
}
//设置GPL2引脚电平
gpio_set_value(EXYNOS4_GPL2(0),cmd);


return 0;
}

/**
 *@brief 杂项设备节点
 *@note 该结构体在 include/linux/fs.h
 */
static struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = led_open,//打开文件函数
.release = led_release,//关闭文件函数
.unlocked_ioctl = led_ioctl,//控制文件函数
};


/**
 *@brief 杂项设备结构体变量
 *@note 该结构体在 include/linux/miscdevice.h
 */
static struct miscdevice led_dev = {
.minor = MISC_DYNAMIC_MINOR,//自动分配设备号  include/linux/miscdevice.h
.name = DEVICE_NAME,//设备节点名称
.fops = &led_ops,//设备节点文件
};


/**
 *@brief 驱动初始化
 *@return 成功:0   失败:-1
 */
static int led_probe(struct platform_device *pdv)
{
int ret;
printk(KERN_EMERG "\tinitialized\n");


//Linux GPIO申请
ret = gpio_request(EXYNOS4_GPL2(0),"LEDS");
if(ret < 0)
{
printk(KERN_EMERG "gpio_request EXYNOS_GPL(2) failed\n");
return ret;
}
//三星平台4412GPIO配置,设置为输出功能
s3c_gpio_cfgpin(EXYNOS4_GPL2(0),S3C_GPIO_OUTPUT);
//设置EXYNOS4_GPL2(0)引脚初始电平为0
gpio_set_value(EXYNOS4_GPL2(0),0);


misc_register(&led_dev);//杂项设备注册
return 0;
}

/**
 *@brief 驱动移除
 *@return 成功:0   失败:-1
 */
static int led_remove(struct platform_device *pdv)
{
printk(KERN_EMERG "\tremove\n");
misc_deregister(&led_dev);//杂项设备关闭
return 0;
}

/**
 *@brief 驱动关闭
 *@return 无
 */
static void led_shutdown(struct platform_device *pdv)
{
}

/**
 *@brief 驱动休眠
 *@return 成功:0   失败:-1
 */
static int led_suspend(struct platform_device *pdv,pm_message_t pmt)
{
return 0;
}

/**
 *@brief 驱动恢复
 *@return 成功:0   失败:-1
 */
static int led_resume(struct platform_device *pdv)
{
return 0;
}

/**
 *@brief 定义驱动结构体变量
 *@note 该结构体在include/linux/platform_device.h
 */
struct platform_driver led_driver = {
.probe = led_probe,//初始化
.remove = led_remove,//移除
.shutdown = led_shutdown,//关闭
.suspend = led_suspend,//挂起
.resume = led_resume,//恢复
.driver = {
.name = DRIVER_NAME,//该name必须和注册设备时使用的一样
.owner = THIS_MODULE,
}
};

/**
 *@brief 模块初始化函数
 *@return 成功:0   失败:-1
 */
static int led_init(void)
{
int DriverState;


printk(KERN_EMERG "Led Init\n");


DriverState = platform_driver_register(&led_driver);//驱动注册
printk(KERN_EMERG "\tDriverState is %d \n",DriverState);
return 0;
}

/**
 *@brief 模块卸载函数
 *@return 无
 */
static void led_exit(void)
{
printk(KERN_EMERG "Led Exit\n");
platform_driver_unregister(&led_driver);//驱动注销
}

/*模块初始化函数*/
module_init(led_init);
/*模块卸载函数*/
module_exit(led_exit);


测试代码如下:

/**
 * @brief      
 * @file     led-test.c
 * @author   cc
 * @version  
 * @date     Sat 09 Dec 2017 22:16:34 CST
 * @mail     13568859409@163.com 
 * @note     
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main(int argc,char **argv)
{
int fd;
char *hello_node = "/dev/gpios_ctl_dev";
if((fd = open(hello_node,O_RDWR|O_NDELAY))<0)
{
printf("open %s error",hello_node);
return -1;
}
else
{
printf("open %s ok",hello_node);
ioctl(fd,1,1);
sleep(2);
ioctl(fd,0,1);
sleep(2);
ioctl(fd,1,1);
}
close(fd);
return 0;
}



原创粉丝点击