设备驱动框架
正点原子第39章---LED驱动框架
测试
成功:
贴代码
(不需要测试APP)
/***************************************************************Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.文件名 : leds-atk.c作者 : Skylar版本 : V1.0描述 : LED设备驱动框架其他 : 论坛 : www.openedv.com日志 : 初版V1.0 2024/10/8 创建***************************************************************/#include <linux/module.h>
#include <linux/of_gpio.h>
// #include <linux/cdev.h>
// #include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/leds.h>#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/kern_levels.h>#define MYLED_CNT 1
#define MYLED_NAME "myled"struct myled_data {
/* dev_t devid;struct cdev cdev;struct class *class;struct device *device;int led_gpio;
*/struct led_classdev cdev;int gpio;
};/* 静态内敛函数* @ 通过struct myled_data结构体中的cdev变量的地址,* 得到struct myled_data结构体变量的地址* @ led_cdev: struct myled_data结构体中的cdev变量的地址* @ 执行成功返回struct myled_data结构体变量的地址*/
static inline struct myled_data * cdev_to_led_data(struct led_classdev *led_cdev)
{return container_of(led_cdev, struct myled_data, cdev);
}/* LED相关初始化操作* @ pdev: struct platform_device指针* platform设备指针* @ 成功返回0,失败返回负数*/
static int myled_init(struct platform_device *pdev)
{struct myled_data *led_data = platform_get_drvdata(pdev);struct device *dev = &pdev->dev;int ret;led_data->gpio = of_get_named_gpio(dev->of_node, "led-gpio", 0);if(!gpio_is_valid(led_data->gpio)){dev_err(dev, "Failed t oget gpio");return -EINVAL;}ret = devm_gpio_request(dev, led_data->gpio, "fmql-led Gpio");if(ret){dev_err(dev, "Failde to request gpio");return ret;}gpio_direction_output(led_data->gpio, 0);return 0;
}/* 设置LED的亮度* @ 不可休眠* @ led_cdev: struct led_classdev类型的指针* @ 无返回值*/
static void myled_brightness_set(struct led_classdev *led_cdev,enum led_brightness value)
{struct myled_data *led_data = cdev_to_led_data(led_cdev);int level;if(value == LED_OFF)level = 0;elselevel = 1;gpio_set_value(led_data->gpio, level);
}/* 设置LED亮度* @ 可以休眠* @ led_cdev: struct led_classdev类型指针* @ value: 亮度值* @ 无返回值*/
static int myled_brightness_set_blocking(struct led_classdev *led_cdev,enum led_brightness value)
{myled_brightness_set(led_cdev, value);return 0;
}/* platform驱动的probe函数* @ 当驱动与设备匹配成功后此函数会执行* @ pdev: platforme设备指针* @ 成功返回0, 失败返回负值*/
static int myled_probe(struct platform_device *pdev)
{struct myled_data *led_data;struct led_classdev *led_cdev;int ret;dev_info(&pdev->dev, "Led driver and device have been matched\n");/* 为led_data指针分配内存 */led_data = devm_kzalloc(&pdev->dev, sizeof(struct myled_data), GFP_KERNEL);if(!led_data)return -ENOMEM;platform_set_drvdata(pdev, led_data);/* 初始化LED */ret = myled_init(pdev);if(ret){return ret;}/* 初始化led_cdev变量 */led_cdev = &led_data->cdev;led_cdev->name = "myled"; // 设备名字led_cdev->brightness = LED_OFF; // LED初始亮度led_cdev->max_brightness = LED_FULL; // LED最大亮度led_cdev->brightness_set = myled_brightness_set; // LED亮度设置函数-不可休眠led_cdev->brightness_set_blocking = myled_brightness_set_blocking; // LED亮度设置函数-可休眠/* 注册LED设备 */return led_classdev_register(&pdev->dev, led_cdev);
}/* platform驱动模块卸载时* 此函数i执行* @ dev: platform设备指针* @ 成功返回0, 失败返回负值*/
static int myled_remove(struct platform_device *pdev)
{struct myled_data *led_data = platform_get_drvdata(pdev);led_classdev_unregister(&led_data->cdev);dev_info(&pdev->dev, "LED driver was removed\n");return 0;
}/* 匹配列表 */
static const struct of_device_id led_of_match[] = {{.compatible = "fmql,led"},{/* Sentinel */}
};static struct platform_driver myled_driver = {.driver = {.name = "fmql-led3", /* platform_driver name*/.of_match_table = led_of_match,},.probe = myled_probe,.remove = myled_remove,
};module_platform_driver(myled_driver);MODULE_AUTHOR("Skylar <Skylar@33.com>");
MODULE_DESCRIPTION("FMQL LED Driver Framework");
MODULE_LICENSE("GPL");
代码解析
内核自带的LED驱动
正点原子第40章内容
compatible属性一定要是“gpio-leds”
驱动名称为“leds-gpio” 在/sys/bus/platform/drivers目录下
fmql自带的内核源码:
解析gpio和gpios开头的属性
我自己改的dts如下: