在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. 【Flink入门修炼】2-3 Flink Checkpoint 原理机制

    如果让你来做一个有状态流式应用的故障恢复,你会如何来做呢? 单机和多机会遇到什么不同的问题? Flink Checkpoint 是做什么用的?原理是什么? 一.什么是 Checkpoint? Chec ...

  2. RK 平台安装 ubuntu 系统

    一.简介 之前有介绍到 ARM 平台移植 ubuntu 的操作流程,在 RK 系列的平台同样适用,所以这里就不介绍怎么一步步的去对 ubuntu 进行移植,而是怎么将移植的过程编写成脚本,这样便可以在 ...

  3. .Net 线程与锁

    一台服务器能运行多少个线程,大致取决于CPU的管理能力.CPU负责线程的创建.协调.切换.销毁.暂停.唤醒.运行等.一个应用程序中,必须有一个进程维持应用程序的运行环境,一个进程可同时有多个线程协作处 ...

  4. ssh秘钥对免密码登陆

    准备两台linux服务器 a和b , 在a上使用ssh命令登陆b服务器 , 并且不用 输入密码 1.在a服务器上,比如是root用户 ,进去/root/.ssh目录 ,没有就创建, 就是进入家目录的. ...

  5. postgresql 自动类型转换

    一.错误案例 1.赋值错误: ERROR druid.sql.Statement:149 - {conn-10005, pstmt-20005} execute error. UPDATE sys_p ...

  6. Git命令拾掇

    修改commit信息 git commit --amend -m 'The new message' 使用ssh替换https:// 设置某个仓库 git remote set-url origin ...

  7. C语言:ACLLIB图形库——如何搭建环境(附三个文件代码)

    看一下我配置完的运行结果: 1)首先创建一个项目. 2)选择win项目和C语言 3)然后找到你保存项目的文件夹里面拷贝两个.c和.h文件,两个文件代码我附在最后. 4)现在还不能用,找到项目属性 5) ...

  8. 一文带你读懂Arthas实现原理

    一. 前言 Arthas 相信大家已经不陌生了,肯定用过太多次了,平时说到 Arthas 的时候都知道是基于Java Agent的,那么他具体是怎么实现呢,今天就一起来看看. 首先 Arthas 是在 ...

  9. 鸿蒙HarmonyOS实战-Web组件(基本使用和属性)

    前言 Web是一种基于互联网的技术和资源的网络服务系统.它是指由许多互连的计算机组成的全球性计算机网络,使用户能够通过浏览器访问和交互式使用各种信息和资源,如网页.文档.图片.视频.音频等.通过Web ...

  10. 7.13晚考试总结(NOIP模拟14)[队长快跑·影魔·抛硬币]

    樱花满地集于我心,楪舞纷飞祈愿相随 前言 终于没有令人头疼的数学了,总感觉这次考试的题目比较良心. 尤其是对于部分分的明细就非常到位(不像上一场的凭感觉给出部分分). 这就令我这种靠部分分暴力的菜鸡选 ...