Linux内核LED子系统、请务必看
前言
AW9110 LED驱动芯片
LED trigger 的理解
微信扫描二维码,关注我的公众号
LED子系统你要是说很难嘛,但是它就是控制一些简单的GPIO口,但是你要是说它很简单嘛,但是我也不见得一个初学者很快就能掌握,你如果是刚入门这部分的话,我觉得你还是要去仔细研究下这些驱动。前两天在网上看到一句话,初学者喜欢研究语法,大牛喜欢研究数据结构,Linux下的数据结构非常多,把这些东西搞明白对你非常有帮助。
简单说下LED子系统- 应用的话不是很想解释,应用就是调用驱动的接口,打开、关闭、设置等等操作。
- 核心是为驱动和效果和应用服务的,所以我们很多东西都依赖于核心,所以会有一些基本的数据结构,注册、卸载等函数。
- 驱动的用法很简单,但是在简单的用法后面蕴藏着巨大的秘密,Linux下的很多驱动都是如此,填充好一些数据结构,然后调用register函数注册,这样之后,就能把驱动注册起来。
- trigger指的是一种效果,比如亮、灭、是一个效果,驱动里面就做成了default-on的效果,还有闪烁、呼吸等,都是不同的效果。
AW9110 LED驱动芯片
我们分析下这个芯片的硬件连接吧,先分析下硬件有啥特点。
这是一款I2C接口的LED驱动IC,默认的驱动电流大小是37mA,有256个驱动等级,读到这里我们应该可以知道,我们可以用这个IC做呼吸的功能。
我吹几句
我们写程序的时候,需要注意的是在dts里面可以设置什么,这个应该是关键,如果这个是一个LED灯驱动,那么,在dts里面就需要设置LED的属性,比如这个LED灯有什么效果,默认效果是什么。
还有就是要注意led_classdev,因为register注册的时候就是把这个结构体填充的东西给注册起来的。
dts
+ aw9110b: aw9110b@5b {
+ compatible = "aw9110b-leds";
+ gpio_out_drv = ;
+ shdn-gpio = <&pio 19 GPIO_ACTIVE_HIGH>;
+ reg = <0x5b>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ led1: led@1 {
+ label = "led_cam1";
+ reg = <1>;
+ flags = ;
+ led-max-microamp = <10000>;
+ linux,default-trigger = "default-on";
+ };
}
led_classdev 结构体
struct led_classdev {
const char *name;
enum led_brightness brightness;
enum led_brightness max_brightness;
int flags;
/* Lower 16 bits reflect status */
#define LED_SUSPENDED (1 << 0)
/* Upper 16 bits reflect control information */
#define LED_CORE_SUSPENDRESUME (1 << 16)
#define LED_BLINK_ONESHOT (1 << 17)
#define LED_BLINK_ONESHOT_STOP (1 << 18)
#define LED_BLINK_INVERT (1 << 19)
#define LED_SYSFS_DISABLE (1 << 20)
#define SET_BRIGHTNESS_ASYNC (1 << 21)
#define SET_BRIGHTNESS_SYNC (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
/* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
/*
* Set LED brightness level immediately - it can block the caller for
* the time required for accessing a LED device register.
*/
int (*brightness_set_sync)(struct led_classdev *led_cdev,
enum led_brightness brightness);
/* Get LED brightness level */
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
/*
* Activate hardware accelerated blink, delays are in milliseconds
* and if both are zero then a sensible default should be chosen.
* The call should adjust the timings in that case and if it can't
* match the values specified exactly.
* Deactivate blinking again when the brightness is set to a fixed
* value via the brightness_set() callback.
*/
int (*blink_set)(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off);
struct device *dev;
const struct attribute_group **groups;
struct list_head node; /* LED Device list */
const char *default_trigger; /* Trigger to use */
unsigned long blink_delay_on, blink_delay_off;
struct timer_list blink_timer;
int blink_brightness;
void (*flash_resume)(struct led_classdev *led_cdev);
struct work_struct set_brightness_work;
int delayed_set_value;
#ifdef CONFIG_LEDS_TRIGGERS
/* Protects the trigger data below */
struct rw_semaphore trigger_lock;
struct led_trigger *trigger;
struct list_head trig_list;
void *trigger_data;
/* true if activated - deactivate routine uses it to do cleanup */
bool activated;
#endif
/* Ensures consistent access to the LED Flash Class device */
struct mutex led_access;
};
LED trigger 的理解
我这里打开的是呼吸的trigger,这个trigger是用来实现呼吸效果的,但是我们这个IC没有自主呼吸的功能,所以我们需要实现呼吸的话,肯定是离不开定时器的,我们使用一个定时器在一个时间段内不断的改变输出的电流,以此来改变输出的亮度。这样让用户就看到呼吸的效果了。
我简单的说下这个呼吸曲线,因为人眼对亮度的观察并不是线性的,举个例子,理想的做法是,我们的曲线在一个时间内递增一样大小的电流,这样输出看到的亮度也是曲线增加的,但是因为我们人眼对亮度观察并不是理想的,所以我们可能看到的是突然变亮,变灭的过程也会极其尴尬。
赠送一段不健全的呼吸曲线
static const uint8_t s_breath_effect[] = {
0, 0, 0, 0, 1, 2, 3, 4, 6, 8,
10, 12, 14, 16, 19, 22, 25, 28, 32, 36,
40, 44, 48, 52, 57, 62, 67, 72, 78, 84,
90, 96, 102, 108, 115, 122, 129, 136, 144, 152,
160, 168, 176, 184, 193, 202, 211, 220, 230, 240,
250, 240, 230, 220, 211, 202, 193, 184, 176, 168,
160, 152, 144, 136, 129, 122, 115, 108, 102, 96,
90, 84, 78, 72, 67, 62, 57, 52, 48, 44,
40, 36, 32, 28, 25, 22, 19, 16, 14, 12,
10, 8, 6, 4, 3, 2, 1, 0, 0, 0,
};
LED sys节点节点
android:/sys/class/leds # ls
blue led_cam_b led_key1
属性
android:/sys/class/leds/led_key1 # ls
brightness device max_brightness power subsystem trigger uevent
trigger
android:/sys/class/leds/led_key1 # cat trigger
[none] rc-feedback nand-disk mmc0 timer oneshot heartbeat breath
微信扫描二维码,关注我的公众号
评论