1.dts:gpio节点与pin-ctrl
@@ -117,6 +117,15 @@
};
};
+ gyan_led {
+ compatible = "gyan,led";
+ red-gpios = <&gpio4 RK_PD3 GPIO_ACTIVE_HIGH>;
+ green-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc_led_ctrl>;
+ status = "okay";
+ };
+
@@ -960,6 +969,7 @@
led {
vcc_led_ctrl: vcc-led-ctrl {
rockchip,pins =
+ <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_down>,
<1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>;
};
};
2.添加对应驱动文件led_gyan.c
#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init __exit 宏定义声明
#include <linux/kernel.h> //内核printf打印模拟声明
#include <linux/gpio.h>
#include <linux/of_gpio.h> //内核gpio控制相关声明
#include <linux/init.h> //包含module_init/module_exit函数声明
#include <linux/platform_device.h> //包含平台设备相关结构体声明
#include <linux/err.h> //包含返回错误码声明
#include <linux/uaccess.h> //包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include <linux/delay.h> //内核层延时函数声明
#include <linux/cdev.h> //设备初始化相关函数声明
#include <linux/ioctl.h> //设备控制相关函数声明
#include <linux/workqueue.h> //工作队列相关声明、定义
/*led设备信息描述结构体*/
struct led_context {
struct platform_device *pdev; //平台设备指针
struct delayed_work led_blink; //闪灯延时工作函数
struct gpio_desc *red_gpio; //红灯gpio口结构体指针
int green_gpio; //绿灯gpio口号
};
struct led_context *g_led;//全局变量,保留led设备信息做副本
/*******************************************************
* Function name : led_parse_dt
* Description : led gpio口解析申请
* Parameter :
* *led led设备结构体指针
* Return : 返回return code
**********************************************************/
static int led_parse_dt(struct led_context *led)
{
struct platform_device *pdev =led->pdev;
struct device_node *np = pdev->dev.of_node;
enum of_gpio_flags flags;
int ret = 0;
/*使用devm_gpiod_get_optional申请red gpio,gpiod申请后不进行free也没有什么问题
*devm_gpiod_get_optional只是对gpiod_get_index的包装而已,
*gpiod_get_index()本质上和gpio_request()一样是申请gpio的,只是它是从device tree去查找节点。
*/
led->red_gpio = devm_gpiod_get_optional(&pdev->dev, "red", 0);
if (IS_ERR(led->red_gpio)) {
ret = PTR_ERR(led->red_gpio);
dev_err(&pdev->dev, "failed to request red GPIO: %d\n", ret);
return ret;
}
if(led->red_gpio) {
printk("succeed to request red-gpios!\n");
}
/*旧有的gpio申请方式,先解析再申请,gpio用完有free,否则可能会有问题*/
led->green_gpio = of_get_named_gpio_flags(np,"green-gpios",0,&flags);
if(gpio_is_valid(led->green_gpio)) {
ret = devm_gpio_request_one(&pdev->dev,led->green_gpio,GPIOF_DIR_OUT,NULL);
if(ret) {
dev_err(&pdev->dev, "failed to request green-gpios: %d\n", ret);
return ret;
}
printk("succeed to request green-gpios!\n");
}
return ret;
}
/*亮红灯*/
void led_red_on(struct led_context *led)
{
if(led->red_gpio) {
gpiod_direction_output(led->red_gpio, 1);
}
if(gpio_is_valid(led->green_gpio)) {
gpio_set_value(led->green_gpio,0);
}
}
/*亮绿灯*/
void led_green_on(struct led_context *led)
{
if(led->red_gpio) {
gpiod_direction_output(led->red_gpio, 0);
}
if(gpio_is_valid(led->green_gpio)) {
gpio_set_value(led->green_gpio,1);
}
}
/*红绿灯交替工作函数*/
static void led_blink(struct work_struct *work)
{
int i = 0;
for(i = 0; i < 10; i++) {
led_red_on(g_led);
mdelay(400);
led_green_on(g_led);
mdelay(400);
}
}
/*led驱动的probe函数,类似main函数*/
static int led_probe(struct platform_device *pdev)
{
struct led_context *led;
int ret = 0;
led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
g_led = led;
led->pdev = pdev;
ret = led_parse_dt(led);
if (ret) {
dev_err(&pdev->dev, "failed to parse device tree for led!\n");
return ret;
}
INIT_DELAYED_WORK(&led->led_blink,led_blink); //初始化闪灯延时工作队列
schedule_delayed_work(&led->led_blink,msecs_to_jiffies(1200));//延时1200ms开始闪灯
printk("====================gyan %s %d\n",__func__,__LINE__);
return 0;
};
/*led设备移除,是否gpio口资源*/
static int led_remove(struct platform_device *pdev)
{
if(g_led->red_gpio) {
gpiod_put(g_led->red_gpio);
}
if(gpio_is_valid(g_led->green_gpio)) {
gpio_free(g_led->green_gpio);
}
printk("====================gyan %s %d",__func__,__LINE__);
return 0;
};
static struct of_device_id of_leds_match[] = {
{ .compatible = "gyan,led"},//dts节点匹配字段
{ } //此处需保留这个空括号
};
MODULE_DEVICE_TABLE(of,of_leds_match);
/*平台驱动结构体信息对应到具体驱动*/
static struct platform_driver led_driver = {
.driver = {
.name = "gyan_led",
.of_match_table = of_leds_match,
},
.probe = led_probe, //对应到led的probe函数
.remove = led_remove,//对应到led的remove函数
};
module_platform_driver(led_driver);
/*驱动版权信息*/
MODULE_AUTHOR("Gyan <wja_well@163.com>");
MODULE_DESCRIPTION("Gyan LED driver");
MODULE_LICENSE("GPL");
3.配置Kconfig与Makefile
drivers/led/Kconfig
comment "LED Triggers"
config LEDS_GYAN
tristate "LED Support by Gyan"
help
LED Support by Gyan,Just for Fun.
drivers/led/Makefile
obj-$(CONFIG_LEDS_GYAN) += led_gyan.o
驱动上级目录drivers/下的Kconfig与Makefile
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c7a3c412bce1..4c2a001a24b1 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -208,4 +208,6 @@ source "drivers/rk_nand/Kconfig"
source "drivers/headset_observe/Kconfig"
+source "drivers/led/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 082c6f0c158d..d36065428fc1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -179,3 +179,4 @@ obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_RK_NAND) += rk_nand/
obj-$(CONFIG_RK_HEADSET) += headset_observe/
obj-$(CONFIG_RK_FLASH) += rkflash/
+obj-$(CONFIG_LEDS_GYAN) += led/