LED驱动

作者: Wood木木 | 来源:发表于2022-12-11 09:33 被阅读0次

LED驱动

添加节点

/*
 * drivers/amlogic/led/led_sys.c
 *
 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#define pr_fmt(fmt) "rc_led: " fmt

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/delay.h>


#define AML_DEV_NAME        "rc_led"
#define AML_LED_NAME        "led-rc"

enum {
    LED_GPIO_STATE_OFF = 0,
    LED_GPIO_STATE_ON,
};

struct aml_led_gpio {
    const char *name;
    unsigned int pin;
    unsigned int active_low;
    unsigned int state;
};


struct aml_rcled_dev {
    struct aml_led_gpio d;
    struct led_classdev cdev;
    enum led_brightness new_brightness;

    unsigned int status;
    struct work_struct work;
    struct mutex lock;
};

static struct class *rcled_class;
struct aml_rcled_dev *rcled_dev;

static void aml_rcled_output_setup(struct aml_rcled_dev *ldev,
                enum led_brightness value)
{
    unsigned int level = !!value;

    if (ldev->d.active_low)
        level = !level;
    gpio_direction_output(ldev->d.pin, level);
}

static void aml_rcled_work(struct work_struct *work)
{
    char led_blink = 0,d_blink = 0;
    struct aml_rcled_dev *ldev;

    ldev = container_of(work, struct aml_rcled_dev, work);
    led_blink = !gpio_get_value(ldev->d.pin);
    //0 LED灯灭,1 LED灯常亮。2,LED灯慢闪。3,LED灯快闪。4,LED灯间闪
    switch(rcled_dev->status){
            case 0:
                mutex_lock(&ldev->lock);
                aml_rcled_output_setup(ldev, 0);
                mutex_unlock(&ldev->lock);
            break;
            case 1:
                mutex_lock(&ldev->lock);
                aml_rcled_output_setup(ldev, 1);
                mutex_unlock(&ldev->lock);
            break;
            // default:
                // mutex_lock(&ldev->lock);
                // aml_rcled_output_setup(ldev, ldev->new_brightness);
                // mutex_unlock(&ldev->lock);
            // break;
    }
    while(rcled_dev->status > 1){  //快闪,慢闪,间闪需要无限循环。
        switch(rcled_dev->status){
            case 2:
                mutex_lock(&ldev->lock);
                aml_rcled_output_setup(ldev, led_blink);
                led_blink = !led_blink;
                mutex_unlock(&ldev->lock);
                msleep(500);
            break;
            case 3:
                mutex_lock(&ldev->lock);
                aml_rcled_output_setup(ldev, led_blink);
                led_blink = !led_blink;
                mutex_unlock(&ldev->lock);
                msleep(100);
            break;
            case 4:
                mutex_lock(&ldev->lock);
                aml_rcled_output_setup(ldev, led_blink);
                led_blink = !led_blink;
                mutex_unlock(&ldev->lock);
                msleep(200);
                d_blink++;
                if(d_blink % 10 == 0)
                    msleep(2000);
            break;
        }
    }
}


static void aml_rcled_brightness_set(struct led_classdev *cdev,
    enum led_brightness value)
{
    struct aml_rcled_dev *ldev;
    struct platform_device *pdev;

    pdev = to_platform_device(cdev->dev->parent);
    ldev = platform_get_drvdata(pdev);
    ldev->new_brightness = value;
    ldev->status = 1;
    schedule_work(&ldev->work);
}


static int aml_rcled_dt_parse(struct platform_device *pdev)
{
    struct device_node *node;
    struct aml_rcled_dev *ldev;
    int led_gpio;
    enum of_gpio_flags flags;

    ldev = platform_get_drvdata(pdev);
    node = pdev->dev.of_node;
    if (!node) {
        pr_err("failed to find node for %s\n", AML_DEV_NAME);
        return -ENODEV;
    }

    led_gpio = of_get_named_gpio_flags(node, "led_gpio", 0, &flags);
    if (!gpio_is_valid(led_gpio)) {
        pr_err("gpio %d is not valid\n", led_gpio);
        return -EINVAL;
    }

    ldev->d.pin = led_gpio;
    ldev->d.active_low = flags & OF_GPIO_ACTIVE_LOW;
    gpio_request(ldev->d.pin, AML_DEV_NAME);
//  gpio_direction_output(ldev->d.pin, 0);

    return 0;
}



static const struct of_device_id aml_rcled_dt_match[] = {
    {
        .compatible = "ruichi, rcled",
    },
    {},
};

static ssize_t led_status_show(struct class *class,
                                struct class_attribute *attr, char *buf)
{
    return sprintf(buf, "%d\n", rcled_dev->status);
}
static ssize_t led_status_store(struct class *class,
                                 struct class_attribute *attr, const char *buf, size_t count)
{
    unsigned int val;
    int ret;
    ret = sscanf(buf, "%d", &val);
    if (ret == 1) { //success
        rcled_dev->status = val;
        rcled_dev->new_brightness = 1;
        schedule_work(&rcled_dev->work);
    } else {
        pr_info("invalid data\n");
            return -EINVAL;
    }
    return count;
}

void led_status_set(int status){
    rcled_dev->status = status;
    rcled_dev->new_brightness = 1;
    schedule_work(&rcled_dev->work);
}
EXPORT_SYMBOL(led_status_set);

static struct class_attribute rcled_class_attrs[] =
{
    __ATTR(status,   0644,
           led_status_show, led_status_store),
};


static int creat_rcled_class(void)
{
    int i;

    rcled_class = class_create(THIS_MODULE, "rcled");
    if (IS_ERR(rcled_class))    {
        pr_info("create debug class failed\n");
        return -1;
    }

    for (i = 0; i < ARRAY_SIZE(rcled_class_attrs); i++)    {
        if (class_create_file(rcled_class,
                              &rcled_class_attrs[i]))        {
            pr_info("create debug attribute %s failed\n",
                    rcled_class_attrs[i].attr.name);
        }
    }

    return 0;
}

static int remove_rcled_class(void)
{
    int i;

    for (i = 0; i < ARRAY_SIZE(rcled_class_attrs); i++)
        class_remove_file(rcled_class, &rcled_class_attrs[i]);

    class_destroy(rcled_class);
    rcled_class = NULL;

    return 0;
}

static int aml_rcled_probe(struct platform_device *pdev)
{
    struct aml_rcled_dev *ldev;
    int ret;

    ldev = kzalloc(sizeof(struct aml_rcled_dev), GFP_KERNEL);

    /* set driver data */
    platform_set_drvdata(pdev, ldev);

    /* parse dt param */
    ret = aml_rcled_dt_parse(pdev);
    if (ret)
        return ret;

    /* register led class device */
    ldev->cdev.name = AML_LED_NAME;
    ldev->cdev.brightness_set = aml_rcled_brightness_set;
    rcled_dev = ldev;
    mutex_init(&ldev->lock);
    INIT_WORK(&ldev->work, aml_rcled_work);
    ret = led_classdev_register(&pdev->dev, &ldev->cdev);
    if (ret < 0) {
        kfree(ldev);
        return ret;
    }

    /* set led default on */
    //aml_rcled_output_setup(ldev, 0);
    creat_rcled_class();
    led_status_set(2);
    pr_info("rcled: module probed ok\n");
    return 0;
}


static int __exit aml_rcled_remove(struct platform_device *pdev)
{
    struct aml_rcled_dev *ldev = platform_get_drvdata(pdev);
    remove_rcled_class();
    led_classdev_unregister(&ldev->cdev);
    cancel_work_sync(&ldev->work);
    gpio_free(ldev->d.pin);
    platform_set_drvdata(pdev, NULL);
    kfree(ldev);
    pr_info("module removed ok\n");
    return 0;
}


static void aml_rcled_shutdown(struct platform_device *pdev)
{
    struct aml_rcled_dev *ldev = platform_get_drvdata(pdev);
    /* set led off*/
    aml_rcled_output_setup(ldev, 0);
    pr_info("module shutdown ok\n");
}


#ifdef CONFIG_PM
static int aml_rcled_suspend(struct platform_device *pdev, pm_message_t state)
{
    struct aml_rcled_dev *ldev = platform_get_drvdata(pdev);
    /* set led off */
    aml_rcled_output_setup(ldev, 0);
    pr_info("module suspend ok\n");
    return 0;
}

static int aml_rcled_resume(struct platform_device *pdev)
{
    struct aml_rcled_dev *ldev = platform_get_drvdata(pdev);
    /* set led on */
    aml_rcled_output_setup(ldev, 1);
    pr_info("module resume ok\n");
    return 0;
}
#endif


static struct platform_driver aml_rcled_driver = {
    .driver = {
        .name = AML_DEV_NAME,
        .owner = THIS_MODULE,
        .of_match_table = aml_rcled_dt_match,
    },
    .probe = aml_rcled_probe,
    .remove = __exit_p(aml_rcled_remove),
    .shutdown = aml_rcled_shutdown,
#ifdef  CONFIG_PM
    .suspend = aml_rcled_suspend,
    .resume = aml_rcled_resume,
#endif
};


static int __init aml_rcled_init(void)
{
    if (platform_driver_register(&aml_rcled_driver)) {
        pr_err("failed to register driver\n");
        return -ENODEV;
    }

    return 0;
}


static void __exit aml_rcled_exit(void)
{
    pr_info("module exit\n");
    platform_driver_unregister(&aml_rcled_driver);
}


subsys_initcall(aml_rcled_init);
module_exit(aml_rcled_exit);

MODULE_DESCRIPTION("ruichi led driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("rubin  zhanghb@ruichi-group.com");

相关文章

  • linux驱动:[1]LED驱动/dev/led

    linux驱动:[1]LED驱动/dev/led LED Linux驱动程序 测试平台: Xunlong Oran...

  • 电子元器件LED驱动电源小常识

    1、什么是LED驱动电源 LED驱动电源把电源供应转化为特定的电压电流以驱动LED发光的电压转化器,作为电子元器件...

  • LED驱动

    LED驱动 添加节点

  • (a40i)嵌入式Linux LED驱动

    简介 Linux内核已经集成LED灯驱动。Linux内核的LED灯驱动采用platform框架,因此我们只...

  • 迅为IMX6ULL开发板Linux蜂鸣器实验

    在上一章讲解了添加LED灯驱动的整个流程和测试结果,这一章在来看一下蜂鸣器的驱动,蜂鸣器和 LED 灯的驱动其实是...

  • LED驱动IC的特点

    LED驱动IC(AL5802-7)主要有以下几个特点: 1.高效率:LED是节能产品,驱动电源的效率要高。 2.保...

  • LED驱动测试

    1.测试设备需求 30V 3A实验室电源 万用表 示波器 2.测试项目 2.1.输出电压测试 测试LED+的Vou...

  • 何为体育照明?

    中国LED渗率不断提升,驱动市场高速发展,国家政策和节能需求不断推动LED替换传统照明。伴着LED照明产业进入深化...

  • 避免命令宏冲突无法使用

    12-25 linux内核加入控制四个led状态的驱动程序是要注意两点: 1.关闭原有的led驱动程序 2.通过#...

  • 6.Led的驱动(iTOP4412)

    上边的注册依旧要做 led驱动,说白了就是单个io口驱动,驱动步骤如下 1.设备注册2.驱动注册 3.生成设备节点...

网友评论

      本文标题:LED驱动

      本文链接:https://www.haomeiwen.com/subject/kdkfqdtx.html