字符驱动:一个简单随意的LED

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/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值