一、篇头
- 本章介绍LED子系统的使用。
- 使用LED子系统,可以轻松实现对LED,例如常见的闪烁和亮度控制功能。
- 简单起见,本章先使用GPIO实现,在不模拟PWM的情况下,只能实现点亮和灭灯的效果,重点是介绍GPIO、LED子系统的使用。
本文基于Amlogic T972 , Android 9.0, 内核版本 4.9.113
二、系列文章
第1篇:基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
第2篇:基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
第3篇:基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
第4篇:基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
第5篇:基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
三、准备工作
3.1 原理图:挑选测试用GPIO脚
(1) 红色LED: GPIOZ_6
(2) 绿色LED: GPIOZ_2
(3) 黄色LED: GPIOZ_1
(4) GND接地
3.2 LED模块
• 如下4个PIN脚,分别连接至开发板的4个引脚
四、源码解析
4.1 DTS设备树
aml_led_class{
status = "okay";
compatible = "szhou,aml_led_class";
/*
* (1) amlled-gpios 是使用新版GPIO子系统API的固定写法,必须以 -gpios 结尾
* (2) “&gpio” : 引用的GPIO控制器的名称
* (3) “GPIOZ_X ” :是一个宏定义,可转换成具体的gpio index
* (4) 最后的GPIO_ACTIVE_HIGH,代表此PIN脚物理上是高电平有效
*/
amlled-gpios = <&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>, //red_led
<&gpio GPIOZ_2 GPIO_ACTIVE_HIGH>, //green_led
<&gpio GPIOZ_1 GPIO_ACTIVE_HIGH>; //yellow_led
};
4.2 驱动源码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/leds.h>
#include <linux/gpio/consumer.h>
static char *name_red = "red";
static char *name_green = "green";
static char *name_yellow = "yellow";
//私有结构体
struct led_dev
{
struct gpio_desc *desc;
struct led_classdev cdev;
};
/*
* (1)对 /sys/class/leds/red/brightness 等LED属性进行控制时,会回调此函数
*/
static void led_control(struct led_classdev *led_cdev, enum led_brightness brightness)
{
struct led_dev *led = container_of(led_cdev, struct led_dev, cdev);
pr_info(" led_control led(0x%p)->desc=0x%p \n", led, led->desc);
if (brightness != LED_OFF) {
gpiod_set_value(led->desc , 1);
pr_info(" gpiod_set_value(led->desc , 1) \n");
}else{
gpiod_set_value(led->desc , 0);
pr_info(" gpiod_set_value(led->desc , 0) \n");
}
}
/*
* (1)在检测到DT中.compatible = "szhou,aml_led_class"的节点后,会自动调用此函数,实现初始化
*/
static int __init ledclass_plat_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int i, count, ret;
pr_info( "ledclass_plat_probe enter\n");
/* 获取amlled-gpios里面gpio的数量 */
count = gpiod_count(dev, "amlled");
if (count == -ENOENT)
return -ENOENT;
dev_info(dev, "gpiod_count = %d \n", count);
/* 填充每个gpio-led对象,并注册到LED子系统 */
for(i=0; i<count; i++){
struct led_dev *led_device;
led_device = devm_kzalloc(dev, sizeof(*led_device), GFP_KERNEL);
if (!led_device)
return -ENOMEM;
/* 初始化gpio对象,屏初始化为GPIOD_OUT_LOW,即设为输出脚、低电平 */
led_device->desc = gpiod_get_index(dev, "amlled", i, GPIOD_OUT_LOW);
switch(i){
case 0:
led_device->cdev.name = name_red;
break;
case 1:
led_device->cdev.name = name_green;
break;
case 2:
led_device->cdev.name = name_yellow;
break;
default:
pr_info( "zs, i=%d, default \n", i);
}
/* 初始化亮度值,以及LED的控制函数 */
led_device->cdev.brightness = LED_OFF;
led_device->cdev.brightness_set = led_control;
/* 注册到LED子系统 */
ret = devm_led_classdev_register(dev, &led_device->cdev);
if (ret) {
dev_err(dev, "failed to register the led %s\n", led_device->cdev.name);
return ret;
}
}
dev_info(dev, "ledclass_plat_probe exit\n");
return 0;
}
static int __exit ledclass_plat_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "leds_remove enter\n");
dev_info(&pdev->dev, "leds_remove exit\n");
return 0;
}
/*
* 设备树的匹配属性 .compatible ,需完全相同才会匹配
*/
static const struct of_device_id my_of_ids[] = {
{ .compatible = "szhou,aml_led_class"},
{},
};
MODULE_DEVICE_TABLE(of, my_of_ids);
/*
* led_platform_driver 结构体
*/
static struct platform_driver led_platform_driver = {
.probe = ledclass_plat_probe,
.remove = ledclass_plat_remove,
.driver = {
.name = "aml_class_leds",
.of_match_table = my_of_ids,
.owner = THIS_MODULE,
}
};
/*
* 注册 led_platform_driver 结构体到Platform子系统
*/
static int aml_GpioLedClass_plat_init(void)
{
int ret_val;
pr_info("aml_GpioLedClass_plat_init enter\n");
ret_val = platform_driver_register(&led_platform_driver);
if (ret_val !=0){
pr_err("platform value returned %d\n", ret_val);
return ret_val;
}
pr_info("aml_GpioLedClass_plat_init exit\n");
return 0;
}
/*
* 从Platform子系统注销 led_platform_driver 结构体
*/
static void aml_GpioLedClass_plat_exit(void)
{
pr_info("aml_GpioLedClass_plat_exit enter\n");
platform_driver_unregister(&led_platform_driver);
pr_info("aml_GpioLedClass_plat_exit exit\n");
}
module_init(aml_GpioLedClass_plat_init);
module_exit(aml_GpioLedClass_plat_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("szhou <66176468@qq.com>");
MODULE_DESCRIPTION("simple say[5]: misc device driver");
五、测试
(1)因为LED子系统自动为我们创建了用户接口,所以通过命令行就可以测试对LED的控制。
(2)编译、部署方法,参考之前的系列文章,不再赘述
5.1 加载KO
执行打印:
:/data # insmod aml_gpio_led_class_platform.ko
[ 1005.070654@1]- aml_GpioLedClass_plat_init enter
[ 1005.071134@1]- ledclass_plat_probe enter
[ 1005.071178@1]- aml_class_leds aml_led_class: gpiod_count = 3
[ 1005.071218@1]- ledclass_plat_probe led(0xe97f7b10)->desc=0xed96b860
[ 1005.071626@1]- zs, platform_probe devm_led_classdev_register [0], cdev->name=red
[ 1005.071667@1]- ledclass_plat_probe led(0xe97f7f10)->desc=0xed96b820
[ 1005.071975@1]- zs, platform_probe devm_led_classdev_register [1], cdev->name=green
[ 1005.072017@1]- ledclass_plat_probe led(0xe97f7c10)->desc=0xed96b810
[ 1005.072265@1]- zs, platform_probe devm_led_classdev_register [2], cdev->name=yellow
[ 1005.072274@1]- aml_class_leds aml_led_class: ledclass_plat_probe exit
[ 1005.075349@1]- aml_GpioLedClass_plat_init exit
图示如下:
5.2 查看设备
如下可见到在probe里面命名的3个LED灯,分别是red、green、yellow
执行打印:
x301:/ # cd /sys/class/leds/
x301:/sys/class/leds # ls -al
total 0
drwxr-xr-x 2 root root 0 2023-01-05 01:16 .
drwxr-xr-x 131 root root 0 2023-01-05 01:16 ..
lrwxrwxrwx 1 root root 0 2023-01-05 01:38 green -> ../../devices/platform/aml_led_class/leds/green
lrwxrwxrwx 1 root root 0 2023-01-05 01:38 pwm_e1 -> ../../devices/platform/pwmleds/leds/pwm_e1
lrwxrwxrwx 1 root root 0 2023-01-05 01:38 red -> ../../devices/platform/aml_led_class/leds/red
lrwxrwxrwx 1 root root 0 2023-01-05 01:38 yellow -> ../../devices/platform/aml_led_class/leds/yellow
x301:/sys/class/leds #
图示如下:
5.3 LED控制
(1)查看LED灯的属性,例如red
x301:/sys/class/leds # cd red/
x301:/sys/class/leds/red # ls -al
total 0
drwxr-xr-x 3 root root 0 2023-01-05 01:33 .
drwxr-xr-x 5 root root 0 2023-01-05 01:33 ..
-rw-r--r-- 1 root root 4096 2023-01-05 01:41 brightness
lrwxrwxrwx 1 root root 0 2023-01-05 01:41 device -> ../../../aml_led_class
-r--r--r-- 1 root root 4096 2023-01-05 01:41 max_brightness
drwxr-xr-x 2 root root 0 2023-01-05 01:41 power
lrwxrwxrwx 1 root root 0 2023-01-05 01:41 subsystem -> ../../../../../class/leds
-rw-r--r-- 1 root root 4096 2023-01-05 01:41 trigger
-rw-r--r-- 1 root root 4096 2023-01-05 01:41 uevent
(2)可见red默认为0,灯灭,符合设定
x301:/sys/class/leds/red # cat brightness
0
(3)点亮红灯
x301:/sys/class/leds/red # echo 1 > brightness
x301:/sys/class/leds/red # cd ..
(4)点亮绿灯
127|x301:/sys/class/leds # echo 1 > green/brightness
(5)点亮黄灯
x301:/sys/class/leds # echo 1 > yellow/brightness
x301:/sys/class/leds #
命令图示如下:
5.4 点灯效果
六、源码下载
- 地址:https://gitee.com/amizhou/amlogic_t972_android9_driver/tree/master/index_01_simpleSay_drivers/lesson_05
git clone git@gitee.com:amizhou/amlogic_t972_android9_driver.git
七、篇尾
保持持续学习, 欢迎交流。