LED驱动可以说是hello world之后最简单的驱动模块了.如果自己写一个LED驱动那是很简单的,其实用linux内核中的leds子系统来做也是比较简单的,内核中的leds子系统是将led抽象成platform_device,并有leds_class.这样,在/sys/class/leds/目录下面就可以利用sysfs文件系统来实现LED的操作.其实,也可以在此基础上添加/dev访问的接口,甚至用不着包含mknod的脚本和udev等工具,在模块注册后就可以生成/dev下的设备文件. 一步一步的来,首先利用platform虚拟总线来实现sysfs文件系统下的LED操作. 在\linux-at91\arch\arm\mach-at91\leds.c中如下: [mw_shl_code=c,true]static struct platform_device at91_gpio_leds_device = {
.name = "leds-gpio",
.id = -1,
.dev.platform_data = &led_data,
};[/mw_shl_code] 对于SAMA5D3X的板子,linux-at91\arch\arm\boot\dts\sama5d3mb.dsti对应LED,所以这里的定义如下: [mw_shl_code=c,true]/* Added by MYIR, LEDs on main board */
leds {
compatible = "gpio-leds";
d6 {
label = "d6";
gpios = <&pioC 24 1>;/* Active low */
default-state = "off";
};
d16 {
label = "d16";
gpios = <&pioC 28 1>;/* Activie low */
linux,default-trigger = "heartbeat";
};
};[/mw_shl_code] 看完了platform_device再看下platform_driver是如何注册的: 在drivers/leds目录下的Makefile中有obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o 所以在make menuconfig的时候记得将其选为M. 这样,注册lleds-atmel-pwm.ko就会在/sys/class/leds中有 d6 d16两个个目录,进入d6目录,有 brightness device power trigger dev max_brightness subsystem uevent 执行echo 0 > brightness就可以关闭led,而echo 1 > brightness就可以打开led. 因为有leds_class,而在led-class.c中leds-init函数中有leds_class->dev_attrs = led_class_attrs; 其中,led_class_attrs定义如下 [mw_shl_code=c,true]static struct device_attribute led_class_attrs[] = {
__ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
__ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS
__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
#endif
__ATTR_NULL,
};[/mw_shl_code] 根据sysfs的属性文件,读写属性文件最终调用的就是show和store函数,在这里就是led_brightness_show和led_brightness_store函数. 顺着调用其实设置寄存器的动作是在leds.c中的at91_led_on实现的.从这里可以看出,LEDS这个子系统也做了抽象,与平台相关的放在一个文件中,而与平台无关的抽象出来放在led-class中. 到此,就可以通过sysfs文件系统来访问led设备了.
|