以上就是创建设备节点,然后通过节点操作【read/write】GPIO的上下电实现led的亮灭的简单实现代码,串口或者adb工具操作对应节点文件gpio_led控制gpio电平:
rk3288:/ # su
rk3288:/ # echo 0 > sys/devices/platform/led_ctrl/gpio_led //往***
rk3288:/ # cat sys/devices/platform/led_ctrl/gpio_led // cat查看一下gpio电平
0
rk3288:/ # echo 1 > sys/devices/platform/led_ctrl/gpio_led //往节点写入1,亮红灯
rk3288:/ # cat sys/devices/platform/led_ctrl/gpio_led // cat查看一下gpio电平
1
rk3288:/ #
注意:在安卓开发过程需要给节点的权限:
可以创建个脚本(*.sh文件)运行,然后在脚本里添加节点的权限:
例如apk/system/bin/lowmem_manage.sh文件中添加以下语句:
chmod 666 sys/devices/platform/led_ctrl/gpio_led
或者在init*.rc文件当中添加赋权限的语句。
为了实现闪灯效果,我这里使用了工作队列来实现,具体逻辑:创建一个工作队列,然后在工作队列去操作GPIO的上下电,并且在工作队列函数中加入定时器,时间一到,又重新开始执行工作队列里面的操作,如此循环,实现led闪灯效果。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //添加需要用到的头文件
static int gpio_led; //定义一个GPIO变量,用gpio_led表示
static int rb_switch_value = 0;//定义一个GPIO电平变量值
static struct delayed_work gpioled_event; //定义一个delay_work
static void gpioled_event_workq(struct work_struct *work) //定义你要延时执行的工作队列函数
{
printk("#%s#: led color blue or red,rb_switch_value=%dn", __func__, rb_switch_value);
gpio_direction_output(gpio_led, rb_switch_value); //设置GPIO电平
rb_switch_value = !rb_switch_value; //设置rb_switch_value取反,以此实现高低电平切换设置
schedule_delayed_work(&gpioled_event, msecs_to_jiffies(1000)); //添加这句之后每隔1秒执行一次
}
static ssize_t gpio_led_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%dn", gpio_get_value(gpio_led)); //获取GPIO的电平,1为高电平,0为低电平
}
static ssize_t gpio_led_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
int val;
int ret;
ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数
if (ret) {
printk("%s: kstrtoint error return %dn", __func__, ret);
return -1;
}
if (val== 1) { //如果echo 1 到节点则调用
printk("-czd-: _%s_ :gpio pull upn", __func__);
gpio_direction_output(gpio_led, val); //设置GPIO电平为高电平
} else if (val == 0) { //如果echo 0 到节点则调用
printk("-czd-: _%s_ :gpio pull downn", __func__);
gpio_direction_output(gpio_led, val); //设置GPIO电平为低电平
} else {
printk("I only support 0 or 1 to ctrl ledn");
}
return size;
}
static DEVICE_ATTR(gpio_led, 0664, gpio_led_show, gpio_led_store); //调用DEVICE_ATTR创建设备节点
static int led_ctrl_probe(struct platform_device *pdev) //compatible的属性和dts的compatible一致,就会调用probe函数
{
struct device_node *led_ctrl_node = pdev->dev.of_node;
enum of_gpio_flags flags;
int gpio_value;
printk("[%d] enter %s start..n", __LINE__, __func__); //printk打印,kernel一般调用这个函数打印log
gpio_led = of_get_named_gpio_flags(led_ctrl_node, "gpio_led", 0, &flags); //解析dts的gpio
printk("gpio_led is %d --n", gpio_led);
gpio_value = (flags == GPIO_ACTIVE_HIGH)? 1:0;
if (!gpio_is_valid(gpio_led)) { //判断GPIO是否合法能用
printk("gpio_led: %d is invalidn", gpio_led);
return -ENODEV;
}
if (gpio_request(gpio_led, "gpio_led")) { //申请GPIO口资源
printk("gpio_led: %d request failed!n", gpio_led);
gpio_free(gpio_led); //如果申请失败,要释放GPIO的占用
return -ENODEV;
}
gpio_direction_output(gpio_led, !gpio_value); //设置GPIO初始电平为低电平
printk("gpio_led pin level is %dn", !gpio_value); //这里gpio_value取反!gpio_value,是低电平
device_create_file(&pdev->dev, &dev_attr_gpio_led);
INIT_DELAYED_WORK(&gpioled_event, gpioled_event_workq); //初始化工作队列
schedule_delayed_work(&gpioled_event, msecs_to_jiffies(2000)); //添加到延时工作队列,这里延时2秒
printk("[%d]: ___%s___ sucess!n", __LINE__, __func__);
return 0;
}
static int led_ctrl_remove(struct platform_device *pdv)
{
printk("___%s___n", __func__);
return 0;
}
static struct of_device_id led_ctrl_match_table[] = {
{ .compatible = "led_ctrl",},
{},
};
static struct platform_driver led_ctrl_driver = {
.driver = {
.name = "led_ctrl",
.owner = THIS_MODULE,
.of_match_table = led_ctrl_match_table,
},
.probe = led_ctrl_probe,
.remove = led_ctrl_remove,
};
static int led_ctrl_init(void)
{
printk("#led_ctrl#: ___%s___n", __func__);
platform_driver_register(&led_ctrl_driver);
return 0;
}
static void led_ctrl_exit(void)
{
printk("#led_ctrl#: ___%s___,n", __func__);
cancel_delayed_work_sync(&gpioled_event); //取消延时工作队列
platform_driver_unregister(&led_ctrl_driver);
}
module_init(led_ctrl_init); //模块加载函数
module_exit(led_ctrl_exit); //模块卸载函数
MODULE_AUTHOR("czd,");
MODULE_DESCRIPTION("Driver for control sysled");
MODULE_LICENSE("GPL"); //许可声明, 描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到kernel tainted的警告。
以上就是创建设备节点,然后通过节点操作【read/write】GPIO的上下电实现led的亮灭的简单实现代码,串口或者adb工具操作对应节点文件gpio_led控制gpio电平:
rk3288:/ # su
rk3288:/ # echo 0 > sys/devices/platform/led_ctrl/gpio_led //往***
rk3288:/ # cat sys/devices/platform/led_ctrl/gpio_led // cat查看一下gpio电平
0
rk3288:/ # echo 1 > sys/devices/platform/led_ctrl/gpio_led //往节点写入1,亮红灯
rk3288:/ # cat sys/devices/platform/led_ctrl/gpio_led // cat查看一下gpio电平
1
rk3288:/ #
注意:在安卓开发过程需要给节点的权限:
可以创建个脚本(*.sh文件)运行,然后在脚本里添加节点的权限:
例如apk/system/bin/lowmem_manage.sh文件中添加以下语句:
chmod 666 sys/devices/platform/led_ctrl/gpio_led
或者在init*.rc文件当中添加赋权限的语句。
为了实现闪灯效果,我这里使用了工作队列来实现,具体逻辑:创建一个工作队列,然后在工作队列去操作GPIO的上下电,并且在工作队列函数中加入定时器,时间一到,又重新开始执行工作队列里面的操作,如此循环,实现led闪灯效果。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //添加需要用到的头文件
static int gpio_led; //定义一个GPIO变量,用gpio_led表示
static int rb_switch_value = 0;//定义一个GPIO电平变量值
static struct delayed_work gpioled_event; //定义一个delay_work
static void gpioled_event_workq(struct work_struct *work) //定义你要延时执行的工作队列函数
{
printk("#%s#: led color blue or red,rb_switch_value=%dn", __func__, rb_switch_value);
gpio_direction_output(gpio_led, rb_switch_value); //设置GPIO电平
rb_switch_value = !rb_switch_value; //设置rb_switch_value取反,以此实现高低电平切换设置
schedule_delayed_work(&gpioled_event, msecs_to_jiffies(1000)); //添加这句之后每隔1秒执行一次
}
static ssize_t gpio_led_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%dn", gpio_get_value(gpio_led)); //获取GPIO的电平,1为高电平,0为低电平
}
static ssize_t gpio_led_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
int val;
int ret;
ret = kstrtoint(buf, 10, &val); //输入一个字符然后转换成10进制整形数
if (ret) {
printk("%s: kstrtoint error return %dn", __func__, ret);
return -1;
}
if (val== 1) { //如果echo 1 到节点则调用
printk("-czd-: _%s_ :gpio pull upn", __func__);
gpio_direction_output(gpio_led, val); //设置GPIO电平为高电平
} else if (val == 0) { //如果echo 0 到节点则调用
printk("-czd-: _%s_ :gpio pull downn", __func__);
gpio_direction_output(gpio_led, val); //设置GPIO电平为低电平
} else {
printk("I only support 0 or 1 to ctrl ledn");
}
return size;
}
static DEVICE_ATTR(gpio_led, 0664, gpio_led_show, gpio_led_store); //调用DEVICE_ATTR创建设备节点
static int led_ctrl_probe(struct platform_device *pdev) //compatible的属性和dts的compatible一致,就会调用probe函数
{
struct device_node *led_ctrl_node = pdev->dev.of_node;
enum of_gpio_flags flags;
int gpio_value;
printk("[%d] enter %s start..n", __LINE__, __func__); //printk打印,kernel一般调用这个函数打印log
gpio_led = of_get_named_gpio_flags(led_ctrl_node, "gpio_led", 0, &flags); //解析dts的gpio
printk("gpio_led is %d --n", gpio_led);
gpio_value = (flags == GPIO_ACTIVE_HIGH)? 1:0;
if (!gpio_is_valid(gpio_led)) { //判断GPIO是否合法能用
printk("gpio_led: %d is invalidn", gpio_led);
return -ENODEV;
}
if (gpio_request(gpio_led, "gpio_led")) { //申请GPIO口资源
printk("gpio_led: %d request failed!n", gpio_led);
gpio_free(gpio_led); //如果申请失败,要释放GPIO的占用
return -ENODEV;
}
gpio_direction_output(gpio_led, !gpio_value); //设置GPIO初始电平为低电平
printk("gpio_led pin level is %dn", !gpio_value); //这里gpio_value取反!gpio_value,是低电平
device_create_file(&pdev->dev, &dev_attr_gpio_led);
INIT_DELAYED_WORK(&gpioled_event, gpioled_event_workq); //初始化工作队列
schedule_delayed_work(&gpioled_event, msecs_to_jiffies(2000)); //添加到延时工作队列,这里延时2秒
printk("[%d]: ___%s___ sucess!n", __LINE__, __func__);
return 0;
}
static int led_ctrl_remove(struct platform_device *pdv)
{
printk("___%s___n", __func__);
return 0;
}
static struct of_device_id led_ctrl_match_table[] = {
{ .compatible = "led_ctrl",},
{},
};
static struct platform_driver led_ctrl_driver = {
.driver = {
.name = "led_ctrl",
.owner = THIS_MODULE,
.of_match_table = led_ctrl_match_table,
},
.probe = led_ctrl_probe,
.remove = led_ctrl_remove,
};
static int led_ctrl_init(void)
{
printk("#led_ctrl#: ___%s___n", __func__);
platform_driver_register(&led_ctrl_driver);
return 0;
}
static void led_ctrl_exit(void)
{
printk("#led_ctrl#: ___%s___,n", __func__);
cancel_delayed_work_sync(&gpioled_event); //取消延时工作队列
platform_driver_unregister(&led_ctrl_driver);
}
module_init(led_ctrl_init); //模块加载函数
module_exit(led_ctrl_exit); //模块卸载函数
MODULE_AUTHOR("czd,");
MODULE_DESCRIPTION("Driver for control sysled");
MODULE_LICENSE("GPL"); //许可声明, 描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到kernel tainted的警告。
举报