692 lines
14 KiB
C
Executable File
692 lines
14 KiB
C
Executable File
#include <linux/kernel.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/err.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/module.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/syslog.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/io.h>
|
|
#include <linux/pwm.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
|
|
|
|
/*red led gpio PE1*/
|
|
#define RLED_NUM 129
|
|
#define ENABLE 1
|
|
#define DISABLE 0
|
|
#define MAX 100
|
|
#define LED_DEFAULT_STATE 9
|
|
#define LED_DEFAULT_DELAY (HZ / 20)
|
|
//#define DEBUG_PWM
|
|
|
|
#ifdef DEBUG_PWM
|
|
#define pwm_printf pr_info
|
|
#else
|
|
#define pwm_printf pr_debug
|
|
#endif
|
|
|
|
|
|
static unsigned int duty_ns = 8000000; /*占空,高电平 u32*/
|
|
static unsigned long long period_ns = 10000000; /*周期__u64*/
|
|
static struct mutex pwm_muter;
|
|
static struct delayed_work blue_led_delay_work;
|
|
static struct delayed_work green_led_delay_work;
|
|
|
|
struct pwm_green_led {
|
|
struct pwm_device *pwm0_dev;
|
|
int pwm_id; /*0:green;1:blue*/
|
|
unsigned long green_status;
|
|
int time_delay;
|
|
};
|
|
|
|
struct pwm_blue_led {
|
|
struct pwm_device *pwm1_dev;
|
|
int pwm_id; /*0:green;1:blue*/
|
|
unsigned long blue_status;
|
|
int time_delay;
|
|
};
|
|
|
|
struct pwm_red_led {
|
|
unsigned long red_status;
|
|
u32 rled_gpio;
|
|
};
|
|
|
|
static struct pwm_green_led *t_pwm_green_led;
|
|
static struct pwm_blue_led *t_pwm_blue_led;
|
|
static struct pwm_red_led *t_pwm_red_led;
|
|
|
|
|
|
static void set_pwm(int pwm_id, int level)
|
|
{
|
|
unsigned int ret = 0;
|
|
unsigned duty_ns, period_ns ;
|
|
|
|
mutex_lock(&pwm_muter);
|
|
period_ns = 100000; /*1000000000/10000 freq=10KHz, 1s=1000000000ns*/
|
|
duty_ns = (period_ns * level)/MAX ;
|
|
if (pwm_id == 0) {
|
|
ret = pwm_config(t_pwm_green_led->pwm0_dev, duty_ns, period_ns);
|
|
ret = pwm_enable(t_pwm_green_led->pwm0_dev);
|
|
} else if (pwm_id == 1) {
|
|
ret = pwm_config(t_pwm_blue_led->pwm1_dev, duty_ns, period_ns);
|
|
ret = pwm_enable(t_pwm_blue_led->pwm1_dev);
|
|
}
|
|
pwm_printf("[pwm_leds] pwm_config pwm%d:<%d | %d>, ret = %d\n",
|
|
pwm_id, duty_ns, period_ns, ret);
|
|
mutex_unlock(&pwm_muter);
|
|
}
|
|
|
|
|
|
static ssize_t get_blue_func(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", (int)t_pwm_blue_led->blue_status);
|
|
}
|
|
|
|
static ssize_t set_blue_func(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
int ret;
|
|
|
|
ret = kstrtoul(buf, 10, &t_pwm_blue_led->blue_status);
|
|
|
|
if (t_pwm_blue_led->time_delay != 0)
|
|
cancel_delayed_work_sync(&blue_led_delay_work);
|
|
|
|
pwm_printf("id = %d, status= %d\n",
|
|
t_pwm_blue_led->pwm_id, t_pwm_blue_led->blue_status);
|
|
switch (t_pwm_blue_led->blue_status) {
|
|
case 0: /*LOW_BRIGHT*/
|
|
t_pwm_blue_led->time_delay = 0;
|
|
set_pwm(t_pwm_blue_led->pwm_id, 90);
|
|
break;
|
|
case 1: /*MIDIUM_BRIGHT*/
|
|
t_pwm_blue_led->time_delay = 0;
|
|
set_pwm(t_pwm_blue_led->pwm_id, 50);
|
|
break;
|
|
case 2: /*HIGHT_BRIGHT*/
|
|
t_pwm_blue_led->time_delay = 0;
|
|
set_pwm(t_pwm_blue_led->pwm_id, 10);
|
|
break;
|
|
case 4: /*DISABLE*/
|
|
t_pwm_blue_led->time_delay = 0;
|
|
pwm_disable(t_pwm_blue_led->pwm1_dev);
|
|
break;
|
|
case 6: /*ADJEST_BRGHT*/
|
|
t_pwm_blue_led->time_delay = HZ / 2;
|
|
break;
|
|
default:
|
|
t_pwm_blue_led->time_delay = 0;
|
|
pr_err("inval cmd\n");
|
|
break;
|
|
}
|
|
|
|
if (t_pwm_blue_led->time_delay)
|
|
schedule_delayed_work(&blue_led_delay_work,
|
|
t_pwm_blue_led->time_delay);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t get_green_func(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", (int)t_pwm_green_led->green_status);
|
|
}
|
|
|
|
static ssize_t set_green_func(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
int ret;
|
|
|
|
ret = kstrtoul(buf, 10, &t_pwm_green_led->green_status);
|
|
if (t_pwm_green_led->time_delay != 0)
|
|
cancel_delayed_work_sync(&green_led_delay_work);
|
|
pwm_printf("pwm_id = %d, status= %d\n",
|
|
t_pwm_green_led->pwm_id,
|
|
t_pwm_green_led->green_status);
|
|
switch (t_pwm_green_led->green_status) {
|
|
case 0: /*LOW_BRIGHT*/
|
|
t_pwm_green_led->time_delay = 0;
|
|
set_pwm(t_pwm_green_led->pwm_id, 90);
|
|
break;
|
|
case 1: /*MIDIUM_BRIGHT*/
|
|
t_pwm_green_led->time_delay = 0;
|
|
set_pwm(t_pwm_green_led->pwm_id, 50);
|
|
break;
|
|
case 2: /*HIGHT_BRIGHT*/
|
|
t_pwm_green_led->time_delay = 0;
|
|
set_pwm(t_pwm_green_led->pwm_id, 10);
|
|
break;
|
|
case 4: /*DISABLE*/
|
|
t_pwm_green_led->time_delay = 0;
|
|
pwm_disable(t_pwm_green_led->pwm0_dev);
|
|
break;
|
|
case 6: /*ADJEST_BRGHT*/
|
|
t_pwm_green_led->time_delay = HZ / 20;
|
|
break;
|
|
default:
|
|
t_pwm_green_led->time_delay = 0;
|
|
pr_err("inval cmd\n");
|
|
break;
|
|
}
|
|
|
|
if (t_pwm_green_led->time_delay)
|
|
schedule_delayed_work(&green_led_delay_work,
|
|
t_pwm_green_led->time_delay);
|
|
|
|
#if 0
|
|
/*int pwm_id = 0;*/
|
|
switch (green_status) {
|
|
case 1: /*MIDIUM_BRIGHT*/
|
|
set_pwm0(0, 30);
|
|
break;
|
|
case 4: /*DISABLE*/
|
|
pwm_disable(pwm0_dev);
|
|
break;
|
|
default:
|
|
pr_err("inval cmd\n");
|
|
break;
|
|
}
|
|
#endif
|
|
return size;
|
|
}
|
|
static ssize_t set_red_func(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t size)
|
|
{
|
|
int ret;
|
|
|
|
ret = kstrtoul(buf, 10, &t_pwm_red_led->red_status);
|
|
pwm_printf("red_status= %d\n", t_pwm_red_led->red_status);
|
|
switch (t_pwm_red_led->red_status) {
|
|
case 0:
|
|
case 1: /*MIDIUM_BRIGHT*/
|
|
case 2:
|
|
gpio_set_value(t_pwm_red_led->rled_gpio, 1);
|
|
break;
|
|
case 4: /*DISABLE*/
|
|
gpio_set_value(t_pwm_red_led->rled_gpio, 0);
|
|
break;
|
|
default:
|
|
pr_err("inval cmd\n");
|
|
break;
|
|
}
|
|
return size;
|
|
}
|
|
static ssize_t get_red_func(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", (int)t_pwm_red_led->red_status);
|
|
}
|
|
|
|
|
|
static DEVICE_ATTR(blue_func, 0664,
|
|
get_blue_func, set_blue_func);
|
|
static DEVICE_ATTR(green_func, 0664,
|
|
get_green_func, set_green_func);
|
|
static DEVICE_ATTR(red_func, 0664,
|
|
get_red_func, set_red_func);
|
|
|
|
|
|
static struct attribute *sunxi_pwmleds_attributes[] = {
|
|
&dev_attr_blue_func.attr,
|
|
&dev_attr_green_func.attr,
|
|
&dev_attr_red_func.attr,
|
|
NULL
|
|
};
|
|
|
|
static struct attribute_group sunxi_pwmleds_attribute_group = {
|
|
.name = "pwm_leds",
|
|
.attrs = sunxi_pwmleds_attributes
|
|
};
|
|
|
|
static struct miscdevice sunxi_pwmleds_dev = {
|
|
.minor = MISC_DYNAMIC_MINOR,
|
|
.name = "misc_dev",
|
|
};
|
|
static void pwm_blue_led_delay_work(struct work_struct *work)
|
|
{
|
|
static int level;
|
|
static int pol;
|
|
|
|
pwm_printf(">>>led_timer_func level= %d, pol=%d+++\n", level, pol);
|
|
int pwm_id = t_pwm_blue_led->pwm_id;
|
|
|
|
switch (level) {
|
|
#if 1
|
|
case 0:
|
|
set_pwm(pwm_id, 99);
|
|
break;
|
|
case 1:
|
|
set_pwm(pwm_id, 96);
|
|
break;
|
|
case 2:
|
|
set_pwm(pwm_id, 92);
|
|
break;
|
|
case 3:
|
|
set_pwm(pwm_id, 88);
|
|
break;
|
|
case 4:
|
|
set_pwm(pwm_id, 84);
|
|
break;
|
|
case 5:
|
|
set_pwm(pwm_id, 80);
|
|
break;
|
|
case 6:
|
|
set_pwm(pwm_id, 76);
|
|
break;
|
|
case 7:
|
|
set_pwm(pwm_id, 72);
|
|
break;
|
|
case 8:
|
|
set_pwm(pwm_id, 68);
|
|
break;
|
|
case 9:
|
|
set_pwm(pwm_id, 64);
|
|
break;
|
|
case 10:
|
|
set_pwm(pwm_id, 60);
|
|
break;
|
|
case 11:
|
|
set_pwm(pwm_id, 56);
|
|
break;
|
|
case 12:
|
|
set_pwm(pwm_id, 52);
|
|
break;
|
|
case 13:
|
|
set_pwm(pwm_id, 48);
|
|
break;
|
|
case 14:
|
|
set_pwm(pwm_id, 44);
|
|
break;
|
|
case 15:
|
|
set_pwm(pwm_id, 40);
|
|
break;
|
|
case 16:
|
|
set_pwm(pwm_id, 36);
|
|
break;
|
|
case 17:
|
|
set_pwm(pwm_id, 32);
|
|
break;
|
|
case 18:
|
|
set_pwm(pwm_id, 28);
|
|
break;
|
|
case 19:
|
|
set_pwm(pwm_id, 24);
|
|
break;
|
|
case 20:
|
|
set_pwm(pwm_id, 20);
|
|
break;
|
|
case 21:
|
|
set_pwm(pwm_id, 16);
|
|
break;
|
|
case 22:
|
|
set_pwm(pwm_id, 12);
|
|
break;
|
|
case 23:
|
|
set_pwm(pwm_id, 8);
|
|
break;
|
|
case 24:
|
|
set_pwm(pwm_id, 4);
|
|
break;
|
|
#else
|
|
case 0:
|
|
set_pwm(pwm_id, 100);
|
|
break;
|
|
/* case 1: set_pwm(pwm_id, 96); break;*/
|
|
case 2:
|
|
set_pwm(pwm_id, 92);
|
|
break;
|
|
/* case 3: set_pwm(pwm_id, 88); break;*/
|
|
case 4:
|
|
set_pwm(pwm_id, 84);
|
|
break;
|
|
/* case 5: set_pwm(pwm_id, 80); break;*/
|
|
case 6:
|
|
set_pwm(pwm_id, 76);
|
|
break;
|
|
/* case 7: set_pwm(pwm_id, 72); break;*/
|
|
case 8:
|
|
set_pwm(pwm_id, 68);
|
|
break;
|
|
/* case 9: set_pwm(pwm_id, 64); break;*/
|
|
case 10:
|
|
set_pwm(pwm_id, 60);
|
|
break;
|
|
/* case 11: set_pwm(pwm_id, 56); break;*/
|
|
case 12:
|
|
set_pwm(pwm_id, 52);
|
|
break;
|
|
/* case 13: set_pwm(pwm_id, 48); break;*/
|
|
case 14:
|
|
set_pwm(pwm_id, 44);
|
|
break;
|
|
/* case 15: set_pwm(pwm_id, 40); break;*/
|
|
case 16:
|
|
set_pwm(pwm_id, 36);
|
|
break;
|
|
/* case 17: set_pwm(pwm_id, 32); break;*/
|
|
case 18:
|
|
set_pwm(pwm_id, 28);
|
|
break;
|
|
/* case 19: set_pwm(pwm_id, 24); break;*/
|
|
case 20:
|
|
set_pwm(pwm_id, 20);
|
|
break;
|
|
/* case 21: set_pwm(pwm_id, 16); break;*/
|
|
case 22:
|
|
set_pwm(pwm_id, 12);
|
|
break;
|
|
/* case 23: set_pwm(pwm_id, 8); break;*/
|
|
case 24:
|
|
set_pwm(pwm_id, 4);
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pol == 1) {
|
|
level = level + 1;
|
|
if (level >= 24) {
|
|
level = 24;
|
|
pol = 0;
|
|
}
|
|
} else {
|
|
level = level - 1;
|
|
if (level <= 0) {
|
|
level = 0;
|
|
pol = 1;
|
|
}
|
|
}
|
|
|
|
if (level == 24)
|
|
schedule_delayed_work(&blue_led_delay_work, HZ/1);
|
|
else if (level == 0)
|
|
schedule_delayed_work(&blue_led_delay_work, HZ/2);
|
|
else
|
|
schedule_delayed_work(&blue_led_delay_work, HZ/(level+4));
|
|
}
|
|
|
|
static void pwm_green_led_delay_work(struct work_struct *work)
|
|
{
|
|
static int level;
|
|
static int pol;
|
|
int pwm_id = t_pwm_green_led->pwm_id;
|
|
|
|
pwm_printf(">>>led_timer_func level= %d, pol=%d+++\n", level, pol);
|
|
|
|
switch (level) {
|
|
#if 1
|
|
case 0:
|
|
set_pwm(pwm_id, 99);
|
|
break;
|
|
case 1:
|
|
set_pwm(pwm_id, 96);
|
|
break;
|
|
case 2:
|
|
set_pwm(pwm_id, 92);
|
|
break;
|
|
case 3:
|
|
set_pwm(pwm_id, 88);
|
|
break;
|
|
case 4:
|
|
set_pwm(pwm_id, 84);
|
|
break;
|
|
case 5:
|
|
set_pwm(pwm_id, 80);
|
|
break;
|
|
case 6:
|
|
set_pwm(pwm_id, 76);
|
|
break;
|
|
case 7:
|
|
set_pwm(pwm_id, 72);
|
|
break;
|
|
case 8:
|
|
set_pwm(pwm_id, 68);
|
|
break;
|
|
case 9:
|
|
set_pwm(pwm_id, 64);
|
|
break;
|
|
case 10:
|
|
set_pwm(pwm_id, 60);
|
|
break;
|
|
case 11:
|
|
set_pwm(pwm_id, 56);
|
|
break;
|
|
case 12:
|
|
set_pwm(pwm_id, 52);
|
|
break;
|
|
case 13:
|
|
set_pwm(pwm_id, 48);
|
|
break;
|
|
case 14:
|
|
set_pwm(pwm_id, 44);
|
|
break;
|
|
case 15:
|
|
set_pwm(pwm_id, 40);
|
|
break;
|
|
case 16:
|
|
set_pwm(pwm_id, 36);
|
|
break;
|
|
case 17:
|
|
set_pwm(pwm_id, 32);
|
|
break;
|
|
case 18:
|
|
set_pwm(pwm_id, 28);
|
|
break;
|
|
case 19:
|
|
set_pwm(pwm_id, 24);
|
|
break;
|
|
case 20:
|
|
set_pwm(pwm_id, 20);
|
|
break;
|
|
case 21:
|
|
set_pwm(pwm_id, 16);
|
|
break;
|
|
case 22:
|
|
set_pwm(pwm_id, 12);
|
|
break;
|
|
case 23:
|
|
set_pwm(pwm_id, 8);
|
|
break;
|
|
case 24:
|
|
set_pwm(pwm_id, 4);
|
|
break;
|
|
#else
|
|
case 0:
|
|
set_pwm(pwm_id, 100);
|
|
break;
|
|
/* case 1: set_pwm(pwm_id, 96); break;*/
|
|
case 2:
|
|
set_pwm(pwm_id, 92);
|
|
break;
|
|
/* case 3: set_pwm(pwm_id, 88); break;*/
|
|
case 4:
|
|
set_pwm(pwm_id, 84);
|
|
break;
|
|
/* case 5: set_pwm(pwm_id, 80); break;*/
|
|
case 6:
|
|
set_pwm(pwm_id, 76);
|
|
break;
|
|
/* case 7: set_pwm(pwm_id, 72); break;*/
|
|
case 8:
|
|
set_pwm(pwm_id, 68);
|
|
break;
|
|
/* case 9: set_pwm(pwm_id, 64); break;*/
|
|
case 10:
|
|
set_pwm(pwm_id, 60);
|
|
break;
|
|
/* case 11: set_pwm(pwm_id, 56); break;*/
|
|
case 12:
|
|
set_pwm(pwm_id, 52);
|
|
break;
|
|
/* case 13: set_pwm(pwm_id, 48); break;*/
|
|
case 14:
|
|
set_pwm(pwm_id, 44);
|
|
break;
|
|
/* case 15: set_pwm(pwm_id, 40); break;*/
|
|
case 16:
|
|
set_pwm(pwm_id, 36);
|
|
break;
|
|
/* case 17: set_pwm(pwm_id, 32); break;*/
|
|
case 18:
|
|
set_pwm(pwm_id, 28);
|
|
break;
|
|
/* case 19: set_pwm(pwm_id, 24); break;*/
|
|
case 20:
|
|
set_pwm(pwm_id, 20);
|
|
break;
|
|
/* case 21: set_pwm(pwm_id, 16); break;*/
|
|
case 22:
|
|
set_pwm(pwm_id, 12);
|
|
break;
|
|
/* case 23: set_pwm(pwm_id, 8); break;*/
|
|
case 24:
|
|
set_pwm(pwm_id, 4);
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pol == 1) {
|
|
level = level + 1;
|
|
if (level >= 24) {
|
|
level = 24;
|
|
pol = 0;
|
|
}
|
|
} else {
|
|
level = level - 1;
|
|
if (level <= 0) {
|
|
level = 0;
|
|
pol = 1;
|
|
}
|
|
}
|
|
|
|
if (level == 24)
|
|
schedule_delayed_work(&green_led_delay_work, HZ/1);
|
|
else if (level == 0)
|
|
schedule_delayed_work(&green_led_delay_work, HZ/2);
|
|
else
|
|
schedule_delayed_work(&green_led_delay_work, HZ/(level+4));
|
|
}
|
|
|
|
static int pwm_leds_ctrl_init(void)
|
|
{
|
|
int ret = 0;
|
|
int pwm_id = 0; /*pwm0_para used*/
|
|
pwm_printf("[pwm_leds]: %s: %d===into\n", __func__, __LINE__);
|
|
t_pwm_green_led = kzalloc(sizeof(struct pwm_green_led), GFP_KERNEL);
|
|
t_pwm_blue_led = kzalloc(sizeof(struct pwm_blue_led), GFP_KERNEL);
|
|
t_pwm_red_led = kzalloc(sizeof(struct pwm_red_led), GFP_KERNEL);
|
|
|
|
if (!t_pwm_green_led || !t_pwm_blue_led || !t_pwm_red_led) {
|
|
pr_err("[pwm_leds] request memory fail!\n");
|
|
return -1;
|
|
}
|
|
|
|
t_pwm_green_led->pwm0_dev = pwm_request(0, "led_green");
|
|
if (t_pwm_green_led->pwm0_dev == NULL ||
|
|
IS_ERR(t_pwm_green_led->pwm0_dev)) {
|
|
pr_err("[pwm_leds] pwm_request pwm0 fail!\n");
|
|
return -1;
|
|
}
|
|
t_pwm_green_led->green_status = LED_DEFAULT_STATE;
|
|
t_pwm_green_led->pwm_id = 0;
|
|
t_pwm_green_led->time_delay = LED_DEFAULT_DELAY;
|
|
|
|
pwm_printf("[pwm_leds] pwm_request pwm0 success!\n");
|
|
|
|
t_pwm_blue_led->pwm1_dev = pwm_request(1, "led_blue");
|
|
if (t_pwm_blue_led->pwm1_dev == NULL ||
|
|
IS_ERR(t_pwm_blue_led->pwm1_dev)) {
|
|
pr_err("[pwm_leds] pwm_request pwm1 fail!\n");
|
|
return -1;
|
|
}
|
|
t_pwm_blue_led->blue_status = LED_DEFAULT_STATE;
|
|
t_pwm_blue_led->pwm_id = 1;
|
|
t_pwm_blue_led->time_delay = LED_DEFAULT_DELAY;
|
|
|
|
pwm_printf("[pwm_leds] pwm_request pwm1 success!\n");
|
|
|
|
t_pwm_red_led->rled_gpio = RLED_NUM;
|
|
t_pwm_red_led->red_status = LED_DEFAULT_STATE;
|
|
|
|
if (!gpio_is_valid(t_pwm_red_led->rled_gpio)) {
|
|
pr_err("failed to get gpio\n");
|
|
return -EINVAL;
|
|
}
|
|
ret = gpio_request(t_pwm_red_led->rled_gpio, "rled_gpio");
|
|
if (ret) {
|
|
pr_err("failed to request rled gpio\n");
|
|
return -EINVAL;
|
|
}
|
|
gpio_direction_output(t_pwm_red_led->rled_gpio, 1);
|
|
gpio_set_value(t_pwm_red_led->rled_gpio, 0);
|
|
|
|
|
|
mutex_init(&pwm_muter);
|
|
INIT_DELAYED_WORK(&blue_led_delay_work, pwm_blue_led_delay_work);
|
|
INIT_DELAYED_WORK(&green_led_delay_work, pwm_green_led_delay_work);
|
|
return ret;
|
|
}
|
|
|
|
static int __init pwm_leds_init(void)
|
|
{
|
|
int ret, err, pwmleds_used;
|
|
|
|
pwm_printf("pwmleds debug gpio driver init\n");
|
|
|
|
ret = pwm_leds_ctrl_init();
|
|
if (ret == 0)
|
|
pwm_printf("pwm_leds_init is ok==============\n");
|
|
else
|
|
pwm_printf("pwm_leds_init is err==============\n");
|
|
|
|
err = misc_register(&sunxi_pwmleds_dev);
|
|
if (err) {
|
|
pwm_printf("%s led register as misc device error\n", __func__);
|
|
goto exit;
|
|
}
|
|
err = sysfs_create_group(&sunxi_pwmleds_dev.this_device->kobj,
|
|
&sunxi_pwmleds_attribute_group);
|
|
if (err)
|
|
pwm_printf("%s sysfs_create_group error\n", __func__);
|
|
|
|
return 0;
|
|
exit:
|
|
return -1;
|
|
}
|
|
|
|
static void __exit pwm_leds_exit(void)
|
|
{
|
|
pwm_printf("Bye, pwm_leds exit\n");
|
|
gpio_set_value(t_pwm_red_led->rled_gpio, 0);
|
|
gpio_free(t_pwm_red_led->rled_gpio);
|
|
pwm_disable(t_pwm_green_led->pwm0_dev);
|
|
pwm_disable(t_pwm_blue_led->pwm1_dev);
|
|
cancel_delayed_work_sync(&blue_led_delay_work);
|
|
cancel_delayed_work_sync(&green_led_delay_work);
|
|
pwm_free(t_pwm_green_led->pwm0_dev);
|
|
pwm_free(t_pwm_blue_led->pwm1_dev);
|
|
kfree(t_pwm_green_led);
|
|
kfree(t_pwm_blue_led);
|
|
kfree(t_pwm_red_led);
|
|
sysfs_remove_group(&sunxi_pwmleds_dev.this_device->kobj,
|
|
&sunxi_pwmleds_attribute_group);
|
|
misc_deregister(&sunxi_pwmleds_dev);
|
|
}
|
|
|
|
module_init(pwm_leds_init);
|
|
module_exit(pwm_leds_exit);
|
|
|
|
MODULE_DESCRIPTION("a simple pwmleds driver");
|
|
MODULE_AUTHOR("yanu");
|
|
MODULE_LICENSE("GPL");
|