fmql之Linux设备驱动框架

设备驱动框架

正点原子第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 <Skylar@33.com>");
MODULE_DESCRIPTION("FMQL LED Driver Framework");
MODULE_LICENSE("GPL");

代码解析

 

 内核自带的LED驱动

正点原子第40章内容

compatible属性一定要是“gpio-leds

驱动名称为“leds-gpio”        在/sys/bus/platform/drivers目录下

fmql自带的内核源码:

解析gpiogpios开头的属性

我自己改的dts如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值