在Linux驱动中使用LED子系统

原文:https://blog.csdn.net/hanp_linux/article/details/79037684

前提配置device driver下面的LED Support和它下面的LED class support及相应的trigger打开。

步骤

编写设备树(可选)

类似高通平台的方案。

    qcom,gpio-leds {
compatible = "gpio-leds";
led-blue{
label = "red";
default-state = "off";
linux,default-trigger = "none";//没有默认的触发源,也可以写为timer
gpios = <&msm_gpio 17 0x00>;
};
led-green{
label = "green";
default-state = "on";
gpios = <&msm_gpio 34 0x00>;
};
};

分配led_classdev实例以及初始化

一般在init或者probe中实现这个。

     static struct led_classdev *led_devs;
led_devs = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
if (led_devs == NULL)
{
printk("alex.han %s:%d led_devs alloc error\n", __func__, __LINE__);
return -1;
} //设置led的最大亮度 LED_FULL在leds.h中定义,为255(有些led是可以通过控制电流来控制亮度的,)
led_devs->max_brightness = LED_FULL;
//设置led的默认亮度,LED_HALF在leds.h中定义,为127,如果不设置默认为0
led_devs->brightness = LED_HALF;
led_devs->flags = LED_CORE_SUSPENDRESUME;
//这个led设备的名字,注册后将会在/sys/class/leds/目录下创建xxx设备目录
led_devs->name = "xxx";
//设置默认的trigger,如果不设置则默认trigger为0, 如果不需要trigger,这个地方可以不设置
led_devs->default_trigger = "timer"; //默认trigger为timer
//设置亮度的函数,当我们通过sys文件系统来调节led亮度的时候,会调用这个函数,当我们设置了trigger,对应的trigger也会调用这个函数
led_devs->brightness_set = my_brightness_set;
//delay_on和delay_off表示默认led闪烁的频率,只有在使用timer这个trigger的时候才有效,表示led亮的时间和灭的时间,从而来控制闪烁频率,单位是ms
led_devs->blink_delay_on = 1000;
led_devs->blink_delay_off = 2000;
//设置闪烁时led的亮度
led_devs->blink_brightness = 100;

实现亮度调节函数

static void my_brightness_set(struct led_classdev * led_cdev, enum led_brightness brightness)
{
struct led_device * dev = (struct led_device *)led_cdev;
led_cdev->brightness = brightness; printk("alex.han %s %d brightness = %d gpio = %d\n", __func__, __LINE__, brightness, dev->gpio);
/*
这个地方要实现你自己的的led设备的亮和灭或者是设置亮度操作
比如:
如果你的led设备是用一个gpio进行简单控制,那么这个地方对你来说brightness就是亮和灭的开个,brightness=0就设置灯亮,否则就设置led灭
如果你的led设备使用一个中间芯片来控制的(比如lp5523,可以通过iic控制lp5523芯片从而来控制led的亮度),同时又是通过控制电流来控制亮度,那么就需要调用i2c_write将需要设置的内容写到对应的芯片中,
*/
}

注册这个结构体

//调用led_class.c中的注册函数,将初始化的led_classdev结构体注册到led子系统中,创建对应的设备节点
led_classdev_register(NULL, led_devs);

测试

将上述框架添加到一个模块中,编译到kernel中,并make menuconfig打开相应的宏,重新烧写image。

进入/sys/class/目录会发现有leds目录,进入leds目录会发现我们注册的xxx设备,进入xxx目录会发现有brightness max_brightness trigger等属性

cat brightness #会打印出我们设置的默认的brightness值,
echo 100 > brightness #根据log会发现我们驱动的my_brightness_set函数被调用,

关于 trigger,如果你在make menuconfig去将相应的trigger添加的话,cat trigger 会发现打印出很多的触发器。此时,对应触发器前面如果有[]代表当前使用的trigger。

如果在none的这个触发器上加了[],表示我们当前没有添加触发器,

这时如果你echo timer > trigger然后cat trigger会发现[]加在了timer上面,表示当前的触发器是timer,并且在当前目录下生成了delay_on和delay_off两个文件。

分别cat会发现打印的值和我们设置的值一样,同时看log会发现我们的my_brightness_set函数被不断的调用。

最后附上我自己的实例代码,虚拟了4个led:

/*************************************************************************
> File Name: led-test.c
> Author:
> Mail:
> Created Time: 2018年01月02日 星期二 18时37分17秒
************************************************************************/ #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/leds.h> struct led_desc {
int gpio;
char * name;
}; /* 虚拟了4个led */
static struct led_desc led_gpios[] = {
{1, "led1"},
{2, "led2"},
{3, "led3"},
}; struct led_device {
struct led_classdev cdev;
int gpio;
}; static struct led_device * led_devs = NULL; static void my_brightness_set(struct led_classdev * led_cdev, enum led_brightness brightness)
{
struct led_device * dev = (struct led_device *)led_cdev;
led_cdev->brightness = brightness; printk("alex.han %s %d brightness = %d gpio = %d\n", __func__, __LINE__, brightness, dev->gpio);
} static int myled_init(void)
{
int i;
int ret;
printk("alex.han %s %d\n", __func__, __LINE__); led_devs = kzalloc(sizeof(struct led_device) * sizeof(led_gpios) / sizeof(led_gpios[0]), GFP_KERNEL);
if (led_devs == NULL)
{
printk("alex.han %s:%d led_devs alloc error\n", __func__, __LINE__);
return -1;
} for (i = 0; i < (sizeof(led_gpios) / sizeof(led_gpios[0])); i++)
{
led_devs[i].cdev.max_brightness = LED_FULL;
led_devs[i].cdev.brightness = LED_HALF;
led_devs[i].cdev.flags = LED_CORE_SUSPENDRESUME;
led_devs[i].cdev.name = led_gpios[i].name;
led_devs[i].cdev.default_trigger = "timer"; //默认trigger为timer
led_devs[i].gpio = led_gpios[i].gpio; // gpio端口号
led_devs[i].cdev.brightness_set = my_brightness_set;
led_devs[i].cdev.blink_delay_on = 1000;
led_devs[i].cdev.blink_delay_off = 2000;
led_devs[i].cdev.blink_brightness = 100; ret = led_classdev_register(NULL, &led_devs[i].cdev);
if (ret < 0)
{
i--;
while (i >= 0)
{
i--; printk("alex.han %s %d register err\n", __func__, __LINE__);
led_classdev_unregister(&led_devs[i].cdev);
}
kfree(led_devs); return -1;
}
} return 0;
} static void myled_exit(void)
{
int i;
for (i = 0; i < (sizeof(led_gpios) / sizeof(led_gpios[0])); i++)
{
led_classdev_unregister(&led_devs[i].cdev);
} kfree(led_devs);
} module_init(myled_init);
module_exit(myled_exit);

在Linux驱动中使用LED子系统的更多相关文章

  1. Linux内核中SPI/I2c子系统剖析

    Linux内核中,SPI和I2C两个子系统的软件架构是一致的,且Linux内核的驱动模型都以bus,driver,device三种抽象对象为基本元素构建起来.下文的分析将主要用这三种抽象对象的创建过程 ...

  2. 【Linux驱动】TQ2440 LED驱动程序

    ★整体介绍 LED驱动程序主要实现了TQ2440开发板上的4个LED灯的硬件驱动,实现了对引脚GPIOB5.GPIOB6.GPIOB7.GPIOB8的高低电平设置(common-smdk.c中已经实现 ...

  3. 树莓派linux驱动学习之LED控制

    前面我们编写了hello world的程序,接下来继续研究GPIO功能,通过GPIO来控制LED的亮灭,这在单片机中应该算是十分简单的一个程序了,但是在Linux系统中控制GPIO没有那么简单,难点就 ...

  4. Linux 驱动——Button8(输入子系统)

    输入子系统由驱动层.输入子系统核心.事件处理层三部分组成.一个输入事件,如鼠标移动.键盘按下等通过Driver->Inputcore->Event handler->userspac ...

  5. 超简单易用的 “在 pcduino 开发板上写 Linux 驱动控制板载 LED 的闪烁”

    版权声明:本文为博主原创文章,未经博主同意不得转载.转载联系 QQ 30952589,加好友请注明来意. https://blog.csdn.net/sleks/article/details/251 ...

  6. Linux驱动架构之pinctrl子系统分析(一)

    1.前言在嵌入式系统中,许多SoC的内部都包含了pin控制器,通过芯片内部的pin控制器,我们可以配置一个或者一组引脚的状态和功能特性,Linux内核为了统一各SoC厂商的引脚管理,提供了pinctr ...

  7. Linux驱动开发之LED驱动

    首先讲下字符设备控制技术 : 大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力.比如: 改变波特率. 在用户空间,使用ioctl系统调用来控制设备,原型如下:int ioctl(i ...

  8. Linux驱动中的EPROBE_DEFER是个啥

    ​Linux kernel 驱动中,有不少驱动会引用到 EPROBE_DEFER 这个错误号.比如下面这个例子,对 devm_gpiod_get 的返回值进行判断,如果有错误且错误号不是 -EPRBO ...

  9. linux驱动中printk的使用注意事项

    今天在按键驱动中增加printk(KERN_INFO "gpio_keys_gpio_isr()\n");在驱动加载阶段可以输出调试信息,但驱动加载起来后的信息,在串口端看不到输出 ...

  10. Linux驱动中completion接口浅析(wait_for_complete例子,很好)【转】

    转自:http://blog.csdn.net/batoom/article/details/6298267 completion是一种轻量级的机制,它允许一个线程告诉另一个线程工作已经完成.可以利用 ...

随机推荐

  1. VSCode+VUE+ESLint以达到保存自动格式化

    首先打开VSCode在.eslintrc.js中加入以下代码(不知道怎么找可以ctrl+shift+p进行搜索),添加 vscode 终端启动服务 // 添加⾃定义规则 'prettier/prett ...

  2. Canvas简历编辑器-我的剪贴板里究竟有什么数据

    Canvas图形编辑器-我的剪贴板里究竟有什么数据 在这里我们先来聊聊我们究竟应该如何操作剪贴板,也就是我们在浏览器的复制粘贴事件,并且在此基础上聊聊我们在Canvas图形编辑器中应该如何控制焦点以及 ...

  3. nim 7. nimble--制作包

    1. nim的包管理工具: nimble nim的包管理工具,是nimble. 在安装nim的时候,已经自带了nimble. nible通常需要使用git服务器存储包,因此,本地需要git命令的支持. ...

  4. 🔥httpsok-v1.11.0支持CDN证书自动部署

    httpsok-v1.11.0支持CDN证书自动部署 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具,专为 Nginx .OpenResty 服务器设计.已服务众多中小企业,稳定.安 ...

  5. npm包离线安装

    npm包离线安装 npm包的安装,在Internet联网机器上通过npm install轻松搞定的事情,在离线或者纯内网环境下就变得异常艰难,本文就来讲一讲离线安装npm包的方法. 通过 npm in ...

  6. 我们小公司,哪像华为一样,用得上IPD(集成产品开发)?

    在一些咨询或活动现场,我们经常听到有朋友说:我们是小公司,IPD(集成产品开发)太厚重了,不适合我们.但--到底哪里不合适? 提及IPD,成功的案例多以大公司为主:20世纪90年代,IBM在激烈的市场 ...

  7. 配置Ingress支持HTTPS访问(二):使用cert-manager申请证书

    目录 一.系统环境 二.前言 三.Let's Encrypt和cert-manager简介 四.部署cert-manager 4.1 安装cert-manager 4.2 创建clusterissue ...

  8. 多线程池Flask实战应用

    多线程池Flask实战应用 import json import time import flask from concurrent.futures import ThreadPoolExecutor ...

  9. StackExchange.Redis跑起来,为什么这么溜?

    StackExchange.Redis 是一个高性能的 Redis 客户端库,主要用于 .NET 环境下与 Redis 服务器进行通信,大名鼎鼎的stackoverflow 网站就使用它.它使用异步编 ...

  10. Django模板templates

    1.模板文件的路径配置 2.模板中变量替换 3.变量渲染之深度查询 4.内置过滤器 过滤器的语法: {{obj|过滤器名称:过滤器参数}} 内置过滤器: 过滤器例子: 5.注释 6.多行注释 7.if ...