/*
* LEDs driver for GPIOs
*
* Copyright (C) 2007 8D Technologies inc.
* Raphael Assenat <raph@8d.com>
* Copyright (C) 2008 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/leds.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/rk_fb.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/err.h>
#define TAG "ROCKCHIP_LEDS_GPIO"
#if 0
#define D(fmt, arg...) printk("D>>> %s->%s(%d): " fmt, TAG, __FUNCTION__, __LINE__, ##arg)
#else
#define D(fmt, arg...)
#endif
#define E(fmt, arg...) printk("E>>> %s->%s(%d): " fmt, TAG, __FUNCTION__, __LINE__, ##arg)
#define I(fmt, arg...) printk("I>>> %s->%s(%d): " fmt, TAG, __FUNCTION__, __LINE__, ##arg)
#define GPIO_LOW 0
#define GPIO_HIGH 1
#define LED_ON 0
#define LED_OFF 1
struct rk_gpio_leds_ctl_io {
unsigned int power_green;
unsigned int power_red;
unsigned int ir_red;
};
struct rk_gpio_leds_priv {
struct rk_gpio_leds_ctl_io leds;
struct timer_list led_timer;
unsigned int ir_red_status;
unsigned int ir_red_first_resume;
unsigned int suspend_state;
};
struct rk_gpio_leds_priv *g_privdata = NULL;
static ssize_t led_store(struct device *dev, struct device_attribute *attr, const char *cmd, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk_gpio_leds_priv *priv = platform_get_drvdata(pdev);
// I("led_store(): cmd = %s \n", cmd);
if (true == priv->suspend_state)
{
return count;
}
if(0 == strcmp("IR_LED_ON", cmd))
{
gpio_set_value(priv->leds.ir_red, GPIO_HIGH);
}
else if(0 == strcmp("IR_LED_OFF", cmd))
{
gpio_set_value(priv->leds.ir_red, GPIO_LOW);
}
return count;
}
static ssize_t led_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return 0;
}
static DEVICE_ATTR(led_ctl, 0777, led_show, led_store);
static void rk_gpio_led_early_suspend(void)
{
struct rk_gpio_leds_priv *priv = g_privdata;
if (priv)
{
//POWER_LED_RED
gpio_set_value(priv->leds.power_green, GPIO_LOW);
gpio_set_value(priv->leds.power_red, GPIO_HIGH);
}
return;
}
static void rk_gpio_led_early_resume(void)
{
struct rk_gpio_leds_priv *priv = g_privdata;
if (priv)
{
//POWER_LED_GREEN
gpio_set_value(priv->leds.power_green, GPIO_HIGH);
gpio_set_value(priv->leds.power_red, GPIO_LOW);
// IR_LED
if (false == priv->ir_red_first_resume) // 开机时,系统会调用 rk_gpio_led_early_resume ,此时红外灯不应该闪烁。
{
mod_timer(&priv->led_timer, jiffies + msecs_to_jiffies(50));
}
else
{
priv->ir_red_first_resume = false;
}
}
return;
}
static int rk_gpio_led_event_notify(struct notifier_block *self,
unsigned long action, void *data)
{
struct fb_event *event = data;
int blank_mode = *((int *)event->data);
if (action == FB_EARLY_EVENT_BLANK) {
switch (blank_mode) {
case FB_BLANK_UNBLANK:
break;
default:
rk_gpio_led_early_suspend();
break;
}
} else if (action == FB_EVENT_BLANK) {
switch (blank_mode) {
case FB_BLANK_UNBLANK:
rk_gpio_led_early_resume();
break;
default:
break;
}
}
return NOTIFY_OK;
}
static struct notifier_block rk_gpio_led_notifier = {
.notifier_call = rk_gpio_led_event_notify,
};
static void rk_gpio_led_timer(unsigned long _data)
{
struct rk_gpio_leds_priv *priv;
priv = (struct rk_gpio_leds_priv *)_data;
if (LED_OFF == priv->ir_red_status) // turn on
{
priv->ir_red_status = LED_ON;
gpio_set_value(priv->leds.ir_red, GPIO_HIGH);
mod_timer(&priv->led_timer, jiffies + msecs_to_jiffies(300));
}
else // turn off
{
priv->ir_red_status = LED_OFF;
gpio_set_value(priv->leds.ir_red, GPIO_LOW);
}
}
static int rk_gpio_led_probe(struct platform_device *pdev)
{
struct rk_gpio_leds_priv *priv;
struct device_node *np = pdev->dev.of_node;
int ret;
I ("rk_gpio_led v1.0 init");
priv = devm_kzalloc(&pdev->dev, sizeof(struct rk_gpio_leds_priv),
GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
}
g_privdata = priv;
priv->leds.power_green = of_get_named_gpio(np,"led-gpios", 0);
priv->leds.power_red = of_get_named_gpio(np,"led-gpios", 1);
// priv->leds.ir_red = of_get_named_gpio(np,"led-gpios", 2);
if(priv->leds.power_green)
{
ret = gpio_request(priv->leds.power_green, "power_green");
if (!ret)
{
gpio_direction_output(priv->leds.power_green, GPIO_HIGH);
}
else
{
I("power_green request gpio fail!");
}
}
if(priv->leds.power_red)
{
ret = gpio_request(priv->leds.power_red, "power_red");
if (!ret)
{
gpio_direction_output(priv->leds.power_red, GPIO_LOW);
}
else
{
I("power_red request gpio fail!");
}
}
if(priv->leds.ir_red)
{
ret = gpio_request(priv->leds.ir_red, "ir_red");
if (!ret)
{
gpio_direction_output(priv->leds.ir_red, GPIO_LOW);
}
else
{
I("ir_red request gpio fail!");
}
}
priv->ir_red_status = LED_OFF;
priv->ir_red_first_resume = true;
priv->suspend_state = false;
setup_timer(&priv->led_timer, rk_gpio_led_timer, (unsigned long)priv);
ret = device_create_file(&pdev->dev, &dev_attr_led_ctl);
if (ret) {
return ret;
}
fb_register_client(&rk_gpio_led_notifier);
platform_set_drvdata(pdev, priv);
return 0;
}
static int rk_gpio_led_remove(struct platform_device *pdev)
{
D("Enter function! \n");
platform_set_drvdata(pdev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int rk_gpio_led_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk_gpio_leds_priv *priv = platform_get_drvdata(pdev);
priv->suspend_state = true;
return 0;
}
static int rk_gpio_led_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rk_gpio_leds_priv *priv = platform_get_drvdata(pdev);
priv->suspend_state = false;
return 0;
}
static const struct dev_pm_ops rk_gpio_led_pm_ops = {
.suspend_late = rk_gpio_led_suspend,
.resume_early = rk_gpio_led_resume,
};
#endif
static const struct of_device_id of_gpio_leds_match[] = {
{ .compatible = "rockchip-leds-gpio", },
{},
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
static struct platform_driver gpio_led_driver = {
.probe = rk_gpio_led_probe,
.remove = rk_gpio_led_remove,
.driver = {
.name = "rockchip-leds-gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_gpio_leds_match),
#ifdef CONFIG_PM
.pm = &rk_gpio_led_pm_ops,
#endif
},
};
module_platform_driver(gpio_led_driver);
MODULE_AUTHOR("Fengminxi <fmx@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip GPIO LED driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:rockchip-leds-gpio");
rockchip-leds-gpio.c 注释
最新推荐文章于 2024-03-29 07:19:44 发布