一、Rk3128 led 驱动
1、关于dts文件描述
瑞芯微平台上所有的gpio资源都是描述在dts 文件当中
dts 文件一般存放在kernel目录下 arch/arm/boot/dts/ 里面
全志平台的配置文件 一般为 sys_config.fex
存放路径lichee/brandy/pack/chips/sun8iw1p1/configs/android/
配置文件主要功能是用来统一管理cpu 平台资源,方便查看和修改
2、修改配置文件
cd /home/rk3128_4.4_tb01_new_v3/kernel/
vim arch/arm/boot/dts/rk3128-box.dts
新增gpio 管脚控制,描述如下,使用了 GPIO0_B0/GPIO0_D2/GPIO3_C5
work_led{
compatible = "WorkLed";
RED = <&gpio0 GPIO_B0 GPIO_ACTIVE_LOW>;
GREEN = <&gpio0 GPIO_D2 GPIO_ACTIVE_LOW>;
BULE = <&gpio3 GPIO_C5 GPIO_ACTIVE_LOW>;
status = "okay";
};
compatible 为驱动当中平台总线匹配的名字 “WorkLed”
RED = <&gpio0 GPIO_B0 GPIO_ACTIVE_LOW>;
描述的管脚名称为RED, 管脚IO 为: gpio 0组,B0这个管脚
status : 资源的状态状态,okay :表示使能 disable: 表示关闭
3、编写驱动代码
驱动探测函数当中匹配的名字为:WorkLed
static const struct of_device_id of_workled_match[] = {
{ .compatible = "WorkLed", },
{},
};
static struct platform_driver workled_driver = {
.probe = workled_probe,
.remove = workled_remove,
.driver = {
.name = "rk3128_led",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_workled_match),
},
};
4、采用平台总线进行注册获取IO资源
platform_driver_register(&workled_driver);
5、申请gpio 资源
探测到之后,在workled_probe 函数当中申请gpio 资源
通过如下函数进行申请管脚
unsigned int pin = of_get_named_gpio(pdev->dev.of_node, “RED”, 0);
devm_gpio_request(&pdev->dev,Led[i].pin, “RED”);
通过如下函数进行操作gpio 引脚
gpio_direction_output(pin,1); //设置管脚为输出模式,输出高电平
gpio_direction_input(pin); //设置管脚为输入模式
gpio_set_value(pin,1); //设置管脚输出高电平
int state = gpio_get_value(pin); //获取管脚电平状态
6、完整驱动代码如下
workled.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#define DEBUG 1
#ifdef DEBUG
#define dbg(x...) printk(x)
#else
#define dbg(x...) (void)(0)
#endif
#define RED_LED 0x01
#define GREEN_LED 0x02
#define BULE_LED 0x03
#define WORK_LED_SIZE (sizeof(Led)/sizeof(WorkLed))
typedef struct{
unsigned int pin;
char name[16];
}WorkLed;
static struct platform_device *getpdev=NULL;
WorkLed Led[3]={{0,"RED"},{0,"GREEN"},{0,"BULE"}};
static int workled_open(struct inode *inode, struct file *filp)
{
dbg("workled has been open!\n");
return -1;
}
static int workled_release(struct inode *inode, struct file *filp)
{
dbg("workled has not been open yet!\n");
return -1;
}
static ssize_t workled_read(struct file *filp, char *buf,
size_t count, loff_t fpos)
{
dbg("workled read!\n");
return 0;
}
static ssize_t workled_write(struct file *filp, char *buf,
size_t count, loff_t fpos)
{
dbg("workled write!\n");
return 0;
}
static void ctrl_workled(unsigned int pin,int state)
{
if(state)
{
if (gpio_is_valid(pin)&&pin!=0)
{
gpio_set_value(pin,0); //close led
}
}else{
if (gpio_is_valid(pin)&&pin!=0)
{
gpio_set_value(pin,1); // open led
}
}
}
int workled_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
dbg("cmd:%d arg:%d\n", cmd, arg);
switch(cmd)
{
case RED_LED:
ctrl_workled(Led[0].pin,arg);
break;
case GREEN_LED:
ctrl_workled(Led[1].pin,arg);
break;
case BULE_LED:
ctrl_workled(Led[2].pin,arg);
break;
default:
break;
}
return 0;
}
struct file_operations fops =
{
.owner = THIS_MODULE,
.open = workled_open,
.release = workled_release,
.write = workled_write,
.read = workled_read,
.unlocked_ioctl = workled_ioctl
};
static struct miscdevice dev =
{
.minor = MISC_DYNAMIC_MINOR,
.fops = &fops,
.name = "workled",
.nodename = "workled_node"
};
static void gpioFree(unsigned int pin)
{
if (gpio_is_valid(pin)&&pin!=0){
gpio_free(pin);
}
}
static int request_WorkLed(struct platform_device *pdev)
{
int i,free;
int err = 0;
for(i=0;i<WORK_LED_SIZE;i++)
{
Led[i].pin = of_get_named_gpio(pdev->dev.of_node, Led[i].name, 0);
if (!gpio_is_valid(Led[i].pin))
{
dbg("invalid Led[%d].pin: %d \n",i,Led[i].pin);
goto err1;
}
if (devm_gpio_request(&pdev->dev,Led[i].pin, Led[i].name))
{
dbg("devm_gpio_request Led[%d].pin 0x%2x request failed name =%s \n",i,Led[i].pin,Led[i].name);
goto err1;
}
}
gpio_direction_output(Led[0].pin,1);
gpio_direction_output(Led[1].pin,1);
dbg("gpio request ok .......\n");
return 0;
err1:
free=i;
//for(i=0;i<free;i++) //bug
for(i=0;i<WORK_LED_SIZE;i++)
{
gpioFree(Led[i].pin);
Led[i].pin=0;
}
return -1;
}
static void free_WorkLed(void)
{
int i=0;
for(i=0;i<WORK_LED_SIZE;i++)
{
dbg("free gpio Led[%d].pin = %d\n",i,Led[i].pin);
gpioFree(Led[i].pin);
}
}
static int workled_probe(struct platform_device *pdev)
{
getpdev = pdev;
request_WorkLed(pdev);
return misc_register(&dev);
}
static int workled_remove(struct platform_device *pdev)
{
dbg("key remove ok \n");
return 0;
}
static const struct of_device_id of_workled_match[] = {
{ .compatible = "WorkLed", },
{},
};
static struct platform_driver workled_driver = {
.probe = workled_probe,
.remove = workled_remove,
.driver = {
.name = "rk3128_led",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_workled_match),
},
};
static int __init workled_init(void)
{
dbg("workled init ! ... \n");
return platform_driver_register(&workled_driver);
}
static void __exit workled_exit(void)
{
platform_driver_unregister(&workled_driver);
//free_WorkLed();
misc_deregister(&dev);
dbg("workled exit ok!\n");
}
module_init(workled_init);
module_exit(workled_exit);
MODULE_LICENSE("Dual BSD/GPL");
7、Makefile 如下
CONFIG_CHARDEV ?=m
obj-$(CONFIG_CHARDEV) +=workled.o
KERN_DIR =/home/rk3128/rk3128_4.4_tb01_v3/kernel/
modules:
$(MAKE) -C $(KERN_DIR) M=$(PWD) modules
clean:
rm -rf chartest *.o *~core .depend. *.cmd *.ko *.mod.c .tmp_versions
8、将驱动上传到板子,进行调试
adb push *.ko /mnt/sdcard/
adb登录板子,转载驱动调试
adb shell