Android led底层驱动

CPU:RK3288

系统:Android 5.1

功能:上层 app 控制 led 亮灭

开发板:Firefly RK3288

 

1、在dts文件中增加 led 设备

path:kernel/arch/arm/boot/dts/firefly-rk3288.dts

firefly-led{
    //匹配内容
    compatible = "firefly,led";
    //led引脚及有效电平
    led-work = <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
    status = "okay";
};

 

2、led 驱动

path:kernel/drivers/firefly/leds.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#define DEBUG

#ifdef DEBUG
#define LED_DBG(fmt,arg...)        do{\
                                    printk("<LED-DEBUG> [%d]"fmt"\n", __LINE__, ##arg);\
                                }while(0)
#else
#define LED_DBG(fmt,arg...)
#endif

struct led_data {
    int work_pin;        //led引脚
    int work_status;        //led状态
    int work_enable;    //led使能电平
};

struct led_data *led_info;


static int led_drv_open(struct inode *inode, struct file *filp)
{
    LED_DBG("--%s()--", __func__);
    return 0;
}

static int led_drv_release(struct inode *inode, struct file *filp)
{
    LED_DBG("--%s()--", __func__);
    return 0;
}

static ssize_t led_drv_read(struct file *filp, char __user *buf, size_t len, loff_t *pos)
{
    int ret;
    
    LED_DBG("--%s()--", __func__);
    ret = copy_to_user(buf, &(led_info->work_status), len);
    if(ret > 0)
    {
        LED_DBG("copy to user failed.");
        return ret;
    }
    
    return len;
}

static ssize_t led_drv_write(struct file *filp, const char __user *buf, size_t len, loff_t *pos)
{
    int on;
    int ret;
    
    LED_DBG("--%s()--", __func__);
    ret = copy_from_user(&on, buf, len);
    if(ret > 0)
    {
        LED_DBG("copy from user failed.");
        return ret;
    }
    
    gpio_direction_output(led_info->work_pin, !on);
    led_info->work_status = on;
    
    return ret;
}

//上层没添加此函数api
static long led_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    LED_DBG("--%s()--", __func__);
    return 0;
}

struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_drv_open,
    .release = led_drv_release,
    .write = led_drv_write,
    .read = led_drv_read,
    .unlocked_ioctl = led_drv_ioctl,
};

//注册为杂项设备
struct miscdevice led_dev =   
{  
    .minor  =   MISC_DYNAMIC_MINOR,  
    .fops   =   &led_fops,  
    .name   =   "firefly_leds",  
};  

static int led_drv_probe(struct platform_device *pdev)
{
    int ret = -1;
    enum of_gpio_flags work_flags;
    struct device_node *led_node = pdev->dev.of_node;
    
    LED_DBG("--%s()--", __func__);
    
    led_info = kzalloc(sizeof(struct led_data), GFP_KERNEL);
    if(led_info == NULL)
    {
        LED_DBG("Alloc GFP_KERNEL memory failed.");
        return -ENOMEM;
    }
    
    //从dts中获取led的引脚,和有效电平
    led_info->work_pin = of_get_named_gpio_flags(led_node, "led-work", 0, &work_flags);
    if(!gpio_is_valid(led_info->work_pin))
    {
        LED_DBG("Work pin is invaild.");
        ret = -ENODEV;
        goto dev_fail;
    }
    
    led_info->work_enable = (work_flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
    
    ret = gpio_request(led_info->work_pin, "work_led");
    if(ret < 0)
    {
        LED_DBG("Work led request failed.");
        goto dev_fail;
    }
    
    gpio_direction_output(led_info->work_pin, !(led_info->work_enable));
    led_info->work_status = 0;
    
    misc_register(&led_dev);
    
    return 0;
    
request_fail:
    gpio_free(led_info->work_pin);
dev_fail:
    kfree(led_info);
    
    return ret;
}

static int led_drv_remove(struct platform_device *pdev)
{
    misc_deregister(&led_dev);
    LED_DBG("--%s()--", __func__);
    gpio_free(led_info->work_pin);
    kfree(led_info);
}

int led_drv_suspend(struct device *dev)
{
    LED_DBG("--%s()--", __func__);
    return 0;
}

int led_drv_resume(struct device *dev)
{
    LED_DBG("--%s()--", __func__);
    return 0;
}

//suspend和resume暂时没调试成功
const struct dev_pm_ops led_pm_ops = {
    .suspend = led_drv_suspend,
    .resume = led_drv_resume,
};

static const struct of_device_id of_gpio_leds_match[] = {
    {.compatible = "firefly,led", },
    {},
};

static struct platform_driver led_drv = {
    .probe = led_drv_probe,
    .remove = led_drv_remove,
    .driver = {
        .name = "leds",
        .owner = THIS_MODULE,
        .pm = &led_pm_ops,
        .of_match_table = of_match_ptr(of_gpio_leds_match),
    },
};

module_platform_driver(led_drv);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("AaronLee");

 

3、Makefile

path:kernel/drivers/firefly/Makefile

obj-$(CONFIG_FIREFLY_RK3288_LEDS)                += leds.o

 

4.Kconfig

path:kernel/drivers/firefly/Kconfig

menu "Firefly Device Options"

config FIREFLY_RK3288_LEDS
    bool "select firefly rk3288 leds"
    default y

endmenu

 

5、defconfig文件中增加led

path:kernel/arch/arm/configs/firefly-rk3288_defconfig

CONFIG_FIREFLY_RK3288_LEDS=y

 

6、修改led节点的权限

path:device/rockchip/common/ueventd.rockchip.rc

/dev/firefly_leds         0666   system        system

 

版权声明:本文为lialong1st原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/lialong1st/p/8867754.html