设备驱动框架
正点原子第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;
else
level = 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 <[email protected]>");
MODULE_DESCRIPTION("FMQL LED Driver Framework");
MODULE_LICENSE("GPL");
代码解析
内核自带的LED驱动
正点原子第40章内容
compatible属性一定要是“gpio-leds”
驱动名称为“leds-gpio” 在/sys/bus/platform/drivers目录下
fmql自带的内核源码:
解析gpio和gpios开头的属性
标签:led,struct,框架,fmql,cdev,Linux,myled,include,data From: https://blog.csdn.net/qq_41656020/article/details/142762077我自己改的dts如下: