LED子系统和驱动简介
enum led_brightness brightness);
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
int
(*blink_set)(struct led_classdev *led_cdev,
unsignedu ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子嵌入式-ARM 工控机
1.1.3 LED 设备的实现 1. 关键的数据结构 LED 子系统的每个 LED 设备都是用 led_classdev 结构体描述。该结构体定义在
{
gpio_direction_output(LED_GPIO, !value);
}
在模块的初始化函数中,需要为 ERR LED 注册 LED 设备和申请 GPIO,其实现函数为 led_init()。该函数的实现代码如程序清单 1.5 所示。
程序清单 1.5led_init()函数的实现代码
static int __init led_init(void) {
/* 默认使用 none 触发器
*/
};
ERR LED 的点亮/熄灭的实现函数为 mxs_led_brightness_set(),如程序清单 1.4 所示。当 该函数被调用时,根据传入的亮度参数直接设置到 ERR LED 即可。
程序清单 1.4mxs_led_brightness_set()函数的实现
核心模块的代码文件为<drivers/leds/led-class.c>。核心模块的任务有: 维护 LED 子系统的所有触发器,为触发器的注册/注销提供操作函数; 维护 LED 子系统的所有 LED 设备,并为每个 LED 设备在/sys/class/leds/目录下实
现操作接口;为 LED 设备的注册/注销提供操作函数。
int led_classdev_register(struct device *parent,struct led_classdev *led_cdev);
在该函数中,parent 可取值为 NULL。led_classdev_register()函数调用成功后,将返回 0 值;否则返回非 0 值。
在模块的移除函数中,需要为 ERR LED 注销 LED 设备和释放 GPIO,其实现函数为 led_ext()。该函数的实现代码为程序清单 1.6 所示。
程序清单 1.6 led_exit()函数的实现
static void __exit led_exit(void)
{ led_classdev_unregister(&led_dev); gpio_free(LED_GPIO);
unsigned long *delay_off);
struct device
*dev;
struct list_head
node;
const char
*default_trigger;
struct rw_semaphore trigger_lock;
struct led_trigger *trigger;
/* 注册 LED 设备
*/
u ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
3
广州致远电子有限公司
嵌入式-ARM 工控机
return 0; } module_init(led_init);
在 leds-mxs.c 文件实现了一个名字为“mxs-leds”的平台驱动(platform_driver 对象)。 若系统中注册了名字也为“mxs-leds”的平台设备(platform_deivce 的对象),将被这个平台 驱动探测到。该平台驱动将在新注册的平台设备的私有数据中,获取所有 LED 设备信息, 然后根据每个 LED 设备信息都生成一个 led_classdev 对象并注册。
LED 子系统的可以分为三部分:触发器、LED 设备和核心模块,如图 1.1 所示。
图 1.1 LED 子系统的分层结构
LED 设备可设置的各种触发方式都是由 LED 子系统里各触发器实现的。触发器的代码 文件为<drivers/leds/>目录下的 ledtrig-*.c,例如 ledtrig-heartbeat.c 文件是心跳触发器的代码 文件。这些触发器的代码文件的主要任务是初始化各自的触发器,然后注册到核心模块。
内核源码为 i.MX28 系列处理器定义了 mxs_led 结构体用于描述 LED 设备信息,其定义 如程序清单 1.7 所示。
程序清单 1.7 mxs_led 结构体的定义
struct mxs_led { struct led_classdev dev; const char *name; char *default_trigger; unsigned index;
#define LED_GPIO MXS_PIN_TO_GPIO(PINID_LCD_D23)
/* ERR LED 的 GPIO
*/
static void mxs_led_brightness_set(struct led_classdev *pled,enum led_brightness value)
default_trigger 该成员表示 LED 设备u ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
2
广州致远电子有限公司
嵌入式-ARM 工控机
当 LED 设备的 led_classdev 结构体初始化完成后,就可以调用 led_classdev_register()函 数注册:
int ret = 0;
ret = led_classdev_register(NULL, &led_dev); if (ret) {
printk("register led device faile \n"); return -1; } gpio_request(LED_GPIO, "led");
程序清单 1.3 为 ERR LED 实现 LED 设备代码
struct led_classdev led_dev = { .name = "led-example",
/* 设备名称为 led-example
*/
.brightness_set = mxs_led_brightness_set, .default_trigger = "none",
调用 led_classdev_unregister()函数可以注销已经注册的 LED 设备:
void led_classdev_unregister(struct led_classdev *led_cdev);
2. LED 设备实现示例 这里以 EasyARM-i.MX283A 开发套件的 ERR LED 为例,说明如何在 LED 子系统实现 一个 LED 设备。该实现示例程序文件为 leds-test.c。 在 leds-test.c 模块文件中,需要为 ERR LED 实现一个 LED u ZHIYUAN Electronics Stock Co., Ltd. 文章源自广州致远电子有限公司,转载或引用请注明出处
4
广州致远电子有限公司
嵌入式-ARM 工控机
int (*led_set) (unsigned pinid, int value); };
下面介绍 mxs_led 结构体的部分成员: name 该成员表示 LED 设备的名字。 default_trigger 该成员表示 LED 设备默认设置的触发器字符串。 index 该成员表示 LED 设备的索引值。 led_set 该成员是实现 LED 点亮/熄灭的函数的指针。 内核源码定义了 mxs_leds_plat_data 结构体用于描述 mxs_led 数组的信息,其定义如程 序清单 1.8 所示。
图 1.2 新添加的 LED 目录
至于 LED 子系统的设备接口的操作方法,请参考前面的“EasyARM-i.MX283A 入门实 操”章节的“LED 使用”小节中,这里不再多述。
1.1.4 i.MX28 平台的 LED 设备
实际上相当一部分的处理器平台在<drivers/leds/>目录下提供了自己的 LED 设备模块代 码文件,并不需要程序员编写,仅需要程序员提供 LED 硬件信息即可。<drivers/leds/leds-mxs.c> 文件是为 i.MX28 处理器实现 LED 设备的模块文件。
程序清单 1.2 LED 的亮度取值
enum led_brightness {
LED_OFF
= 0,
LED_HALF = 127,
LED_FULL = 255,
/* LED 关闭
*/
/* LED 半亮
*/
/* LED 全亮
*/
};
max_brightness 该成员表示 LED 的最高亮度值。
brightness_set 该成员是设置 LED 点亮/熄灭的方法。当 LED 设备的 LED 点亮/熄灭的 实现函数被调用时,会传入 LED 设备参数和需要设置的亮度参数。在实现函数中,需要根 据这些参数把指定的 LED 设置到指定的亮度。
LED 子系统为每个 LED 设备都在/sys/class/leds/目录提供了操作接口。LED 设备可以通过设 置不同的触发方式而具有不同的功能。
通过 LED 子系统,程序员可以通过很简便的方法添加/删减 LED 设备。这些 LED 设备 在使用过程中,用户可以随意设置 LED 设备的功能。
1.1.2 LED 子系统的分层结构