diff options
Diffstat (limited to 'drivers/leds/leds-sprd-bltc-rgb.c')
| -rw-r--r-- | drivers/leds/leds-sprd-bltc-rgb.c | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/drivers/leds/leds-sprd-bltc-rgb.c b/drivers/leds/leds-sprd-bltc-rgb.c new file mode 100644 index 00000000..03abdb5a --- /dev/null +++ b/drivers/leds/leds-sprd-bltc-rgb.c @@ -0,0 +1,706 @@ +/* +* Copyright (C) 2012 Spreadtrum Communications Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <soc/sprd/hardware.h> +#include <soc/sprd/adi.h> +#include <soc/sprd/adc.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <soc/sprd/sci_glb_regs.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/leds-sprd-bltc-rgb.h> + +#define SPRD_BLTC_RGB_DBG +#ifdef SPRD_BLTC_RGB_DBG +#define ENTER printk(KERN_INFO "[SPRD_BLTC_RGB_DBG] func: %s line: %04d\n", __func__, __LINE__); +#define PRINT_DBG(x...) printk(KERN_INFO "[SPRD_BLTC_RGB_DBG] " x) +#define PRINT_INFO(x...) printk(KERN_INFO "[SPRD_BLTC_RGB_INFO] " x) +#define PRINT_WARN(x...) printk(KERN_INFO "[SPRD_BLTC_RGB_WARN] " x) +#define PRINT_ERR(format,x...) printk(KERN_ERR "[SPRD_BLTC_RGB_ERR] func: %s line: %04d info: " format, __func__, __LINE__, ## x) +#else +#define ENTER +#define PRINT_DBG(x...) +#define PRINT_INFO(x...) printk(KERN_INFO "[SPRD_BLTC_RGB_INFO] " x) +#define PRINT_WARN(x...) printk(KERN_INFO "[SPRD_BLTC_RGB_WARN] " x) +#define PRINT_ERR(format,x...) printk(KERN_ERR "[SPRD_BLTC_RGB_ERR] func: %s line: %04d info: " format, __func__, __LINE__, ## x) +#endif + +//#define SPRD_BLTC_BASE (SPRD_ADISLAVE_BASE+ 0x3C0) + +#define BLTC_CTRL 0x0000 +#define BLTC_R_PRESCL 0x0004 +#define BLTC_G_PRESCL 0x0014 +#define BLTC_B_PRESCL 0x0024 +#define BLTC_PRESCL_OFFSET 0x0004 +#define BLTC_DUTY_OFFSET 0x0004 +#define BLTC_CURVE0_OFFSET 0x0008 +#define BLTC_CURVE1_OFFSET 0x000C + +#define BLTC_STS 0x0034 +#if 0 +#define SPRD_SLP_RGB_PD_EN (SPRD_ADISLAVE_BASE + 0x800 + 0xA0) +#define RGB_V_SHIFT (8) +#define RGB_V_MSK (0x1F<<8) + +#define SPRD_ARM_MODULE_EN (SPRD_ADISLAVE_BASE + 0x800) +#define SPRD_CLK_EN (SPRD_ARM_MODULE_EN + 0x08) +#define SPRD_ARM_RST (SPRD_ARM_MODULE_EN + 0x0c) +#endif +#define PWM_MOD_COUNTER 0xFF +//liuhui add start +static struct mutex breathy_lock; +//static uint32_t is_charge_mode; +//static unsigned long *zoom_share_buf; +//extern void register_led_callback(int (*func)(int color, int mode)); +//static u32 charge_bltc_addr;//,bltc_addr_rf,bltc_addr_hl,bltc_addr_onoff; +//static u32 charge_sprd_bltc_base_addr,charge_sprd_arm_module_en_addr; +static struct sprd_leds_bltc_rgb *g_brgb_r = NULL; +static struct sprd_leds_bltc_rgb *g_brgb_g = NULL; +//liuhui add end +struct sprd_leds_bltc_rgb { + struct platform_device *dev; + struct mutex mutex; + struct work_struct work; + struct delayed_work work_bl; + struct workqueue_struct *work_bl_q; + spinlock_t value_lock; + enum led_brightness value; + struct led_classdev cdev; + u16 leds_flag; + u16 enable; + unsigned long bltc_addr,bltc_addr_rf,bltc_addr_hl,bltc_addr_onoff; + unsigned long sprd_bltc_base_addr,sprd_arm_module_en_addr; + u8 rising_time; + u8 falling_time; + u8 high_time; + u8 low_time; + u16 on_off; + int suspend; +}; + +enum sprd_leds_type { + SPRD_LED_TYPE_R = 0, + SPRD_LED_TYPE_G, + SPRD_LED_TYPE_B, + SPRD_LED_TYPE_R_BL, + SPRD_LED_TYPE_G_BL, + SPRD_LED_TYPE_B_BL, + SPRD_LED_TYPE_TOTAL +}; + +enum sprd_leds_bl_param { + R_TIME = 1, + F_TIME, + H_TIME, + L_TIME, + ONOFF +}; + +static char *sprd_leds_rgb_name[SPRD_LED_TYPE_TOTAL] = { + "red", + "green", + "blue", + "red_bl", + "green_bl", + "blue_bl", +}; + +#define to_sprd_bltc_rgb(led_cdev) \ + container_of(led_cdev, struct sprd_leds_bltc_rgb, cdev) +static void sprd_leds_bltc_rgb_disable(struct sprd_leds_bltc_rgb *brgb); +static inline uint32_t sprd_leds_bltc_rgb_read(unsigned long reg) +{ + return sci_adi_read(reg); +} + +static void sprd_leds_bltc_rgb_set_brightness(struct sprd_leds_bltc_rgb *brgb) +{ + unsigned long brightness = brgb->value; + unsigned long pwm_duty; + + pwm_duty = brightness; + if(pwm_duty > 255) + pwm_duty = 255; + sci_adi_write(brgb->bltc_addr, (pwm_duty<<8)|PWM_MOD_COUNTER,0xffff); + //PRINT_INFO("reg:0x%1LX set_val:0x%08X brightness:%ld brightness_level:%ld(0~15)\n", \ + // brgb->bltc_addr, sprd_leds_bltc_rgb_read(brgb->bltc_addr),brightness, pwm_duty); +} + +static void sprd_bltc_rgb_init(struct sprd_leds_bltc_rgb *brgb) +{ + sci_adi_set(brgb->sprd_arm_module_en_addr, (0x1<<10));//ARM_MODULE_EN-enable pclk + sci_adi_set(brgb->sprd_arm_module_en_addr + 0x08, (0x1<<8));//RTC_CLK_EN-enable rtc + sci_adi_set(brgb->sprd_arm_module_en_addr + 0x0c,0x1); + sci_adi_clr(brgb->sprd_arm_module_en_addr + 0x0c,0x1); + sci_adi_clr(brgb->sprd_arm_module_en_addr + 0xa0, (0x1<<2));//SW POWERDOWN DISABLE + sci_adi_set(brgb->sprd_arm_module_en_addr + 0xa0, (0x1<<8));//CURRENT CONTROL DEFAULT + + //sci_adi_set(brgb->sprd_arm_module_en_addr + 0xec, (0x8f0)); + //sci_adi_clr(brgb->sprd_arm_module_en_addr + 0xec, 0xf); + //sci_adi_set(brgb->sprd_bltc_base_addr, 0xf); +} + + +static void sprd_bltc_rgb_en(struct sprd_leds_bltc_rgb *brgb) +{ + sci_adi_set(brgb->sprd_arm_module_en_addr + 0xec, (0x800)); //brightness 4-8bit + sci_adi_clr(brgb->sprd_arm_module_en_addr + 0xec, 0xf); + sci_adi_set(brgb->sprd_bltc_base_addr, 0xf); +} +static void sprd_bltc_rgb_dis(struct sprd_leds_bltc_rgb *brgb) +{ + sci_adi_set(brgb->sprd_arm_module_en_addr + 0xec, (0xf)); + sci_adi_clr(brgb->sprd_arm_module_en_addr + 0xec, (0xf0)); + sci_adi_clr(brgb->sprd_bltc_base_addr, 0xf); +} + + +static void sprd_leds_bltc_rgb_enable(struct sprd_leds_bltc_rgb *brgb) +{ + //sprd_bltc_rgb_init(brgb); + if( strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0 || + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0 || + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0 + ) + { + if(brgb->value == 0) + { + sprd_leds_bltc_rgb_disable(brgb); + return; + } + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0) { + sci_adi_set(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<0)|(0x1<<1)); + brgb->bltc_addr = brgb->sprd_bltc_base_addr + BLTC_R_PRESCL + BLTC_DUTY_OFFSET; + sprd_leds_bltc_rgb_set_brightness(brgb); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0) { + sci_adi_set(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<4)|(0x1<<5)); + brgb->bltc_addr = brgb->sprd_bltc_base_addr + BLTC_G_PRESCL + BLTC_DUTY_OFFSET; + sprd_leds_bltc_rgb_set_brightness(brgb); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0) { + sci_adi_set(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<8)|(0x1<<9)); + brgb->bltc_addr = brgb->sprd_bltc_base_addr + BLTC_B_PRESCL + BLTC_DUTY_OFFSET; + sprd_leds_bltc_rgb_set_brightness(brgb); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R_BL]) == 0 || \ + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G_BL]) == 0 || \ + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B_BL]) == 0) { + PRINT_INFO("LEDFLAG:%1d\n",brgb->leds_flag); + PRINT_INFO("VALUE:%1d\n",brgb->value); + + if(brgb->leds_flag == R_TIME || brgb->leds_flag == F_TIME || brgb->leds_flag == H_TIME || \ + brgb->leds_flag == L_TIME) { + if(brgb->leds_flag == R_TIME) + brgb->rising_time = brgb->value; + if(brgb->leds_flag == F_TIME) + brgb->falling_time = brgb->value; + if(brgb->leds_flag == H_TIME) + brgb->high_time = brgb->value; + if(brgb->leds_flag == L_TIME) + brgb->low_time = brgb->value; + + brgb->leds_flag = 0; + } + + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R_BL]) == 0) { + brgb->bltc_addr_rf = brgb->sprd_bltc_base_addr + BLTC_R_PRESCL + BLTC_CURVE0_OFFSET; + brgb->bltc_addr_hl = brgb->sprd_bltc_base_addr + BLTC_R_PRESCL + BLTC_CURVE1_OFFSET; + brgb->bltc_addr_onoff = brgb->sprd_bltc_base_addr + BLTC_CTRL; + if(brgb->leds_flag == ONOFF) + brgb->on_off = (brgb->value << 0); + sci_adi_clr(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<0)|(0x1<<1)); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G_BL]) == 0) { + brgb->bltc_addr_rf = brgb->sprd_bltc_base_addr + BLTC_G_PRESCL + BLTC_CURVE0_OFFSET; + brgb->bltc_addr_hl = brgb->sprd_bltc_base_addr + BLTC_G_PRESCL + BLTC_CURVE1_OFFSET; + brgb->bltc_addr_onoff = brgb->sprd_bltc_base_addr + BLTC_CTRL; + if(brgb->leds_flag == ONOFF) + brgb->on_off = (brgb->value << 4); + sci_adi_clr(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<4)|(0x1<<5)); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B_BL]) == 0) { + brgb->bltc_addr_rf = brgb->sprd_bltc_base_addr + BLTC_B_PRESCL + BLTC_CURVE0_OFFSET; + brgb->bltc_addr_hl = brgb->sprd_bltc_base_addr + BLTC_B_PRESCL + BLTC_CURVE1_OFFSET; + brgb->bltc_addr_onoff = brgb->sprd_bltc_base_addr + BLTC_CTRL; + if(brgb->leds_flag == ONOFF) + brgb->on_off = (brgb->value << 8); + sci_adi_clr(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<8)|(0x1<<9)); + } + + sci_adi_write(brgb->bltc_addr_rf,(brgb->falling_time<<8)|brgb->rising_time,0xffff); + sci_adi_write(brgb->bltc_addr_hl,(brgb->low_time<<8)|brgb->high_time,0xffff); + sci_adi_set(brgb->bltc_addr_onoff,brgb->on_off); + } + //sprd_bltc_rgb_en(brgb); + PRINT_INFO("sprd_leds_bltc_rgb_enable\n"); + brgb->enable = 1; +} + +static void sprd_leds_bltc_rgb_disable(struct sprd_leds_bltc_rgb *brgb) +{ + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0 || \ + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R_BL]) == 0) { + sci_adi_clr(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<0)); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0 || \ + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G_BL]) == 0) { + sci_adi_clr(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<4)); + } + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0 || \ + strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B_BL]) == 0) { + sci_adi_clr(brgb->sprd_bltc_base_addr + BLTC_CTRL, (0x1<<8)); + } + PRINT_INFO("sprd_leds_bltc_rgb_disable\n"); + PRINT_INFO("reg:0x%08X set_val:0x%08X brightness:%1d\n", brgb->sprd_arm_module_en_addr + 0xa0, \ + sprd_leds_bltc_rgb_read(brgb->sprd_arm_module_en_addr + 0xa0),brgb->value); + + // sprd_bltc_rgb_dis(brgb); +} + +static void sprd_leds_rgb_work(struct work_struct *work) +{ + struct sprd_leds_bltc_rgb *brgb; + unsigned long flags; + + brgb = container_of(work, struct sprd_leds_bltc_rgb, work); + mutex_lock(&brgb->mutex); + spin_lock_irqsave(&brgb->value_lock, flags); + if (brgb->value == LED_OFF) { + spin_unlock_irqrestore(&brgb->value_lock, flags); + sprd_leds_bltc_rgb_set_brightness(brgb); + goto out; + } + spin_unlock_irqrestore(&brgb->value_lock, flags); + sprd_leds_bltc_rgb_enable(brgb); + PRINT_INFO("sprd_leds_bltc_rgb_work_for rgb!\n"); + +out: + mutex_unlock(&brgb->mutex); +} + +static void sprd_leds_bltc_work(struct work_struct *work) +{ + struct sprd_leds_bltc_rgb *brgb; + unsigned long flags; + + brgb = container_of(work, struct sprd_leds_bltc_rgb, work_bl.work); + mutex_lock(&brgb->mutex); +#if 1 + spin_lock_irqsave(&brgb->value_lock, flags); + if (brgb->value == LED_OFF) { + spin_unlock_irqrestore(&brgb->value_lock, flags); + if(brgb->leds_flag == ONOFF) + sprd_leds_bltc_rgb_disable(brgb); + goto out; + } + spin_unlock_irqrestore(&brgb->value_lock, flags); +#endif + sprd_leds_bltc_rgb_enable(brgb); + PRINT_INFO("sprd_leds_bltc_rgb_work for bltc!\n"); + +out: + mutex_unlock(&brgb->mutex); +} + +static void sprd_leds_bltc_rgb_set(struct led_classdev *bltc_rgb_cdev,enum led_brightness value) +{ + struct sprd_leds_bltc_rgb *brgb; + unsigned long flags; + + brgb = to_sprd_bltc_rgb(bltc_rgb_cdev); + spin_lock_irqsave(&brgb->value_lock, flags); + brgb->leds_flag = bltc_rgb_cdev->flags; + brgb->value = value; + spin_unlock_irqrestore(&brgb->value_lock, flags); + + //if (value > 0) + // sprd_leds_bltc_rgb_enable(brgb); + //else + //sprd_bltc_rgb_dis(brgb); + + + if(1 == brgb->suspend) { + PRINT_WARN("Do NOT change brightness in suspend mode\n"); + return; + } + //xiaotong + // if( strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0 || + // strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0 || + // strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0 + // ) + // schedule_work(&brgb->work); + // else + sprd_leds_bltc_rgb_enable(brgb); + //queue_delayed_work(brgb->work_bl_q, &brgb->work_bl, msecs_to_jiffies(500)); +//#endif +} + +#if 0 +static int sprd_leds_bltc_rgb_get(struct led_classdev *bltc_rgb_cdev) +{ + struct sprd_leds_bltc_rgb *brgb; + char i; + for(i = 0; i < 3; i++) { + brgb = to_sprd_bltc_rgb(bltc_rgb_cdev); + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_R]) == 0) + return brgb->value; + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_G]) == 0) + return brgb->value; + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[SPRD_LED_TYPE_B]) == 0) + return brgb->value; + ++brgb; + } +} +#endif +static void sprd_leds_bltc_rgb_shutdown(struct platform_device *dev) +{ + struct sprd_leds_bltc_rgb *brgb = platform_get_drvdata(dev); + + mutex_lock(&brgb->mutex); + sprd_leds_bltc_rgb_disable(brgb); + mutex_unlock(&brgb->mutex); +} + +static u16 r_value,f_value,h_value,l_value,onoff_value; + +static ssize_t show_rising_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", r_value); +} + +static ssize_t store_rising_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned long state; + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + PRINT_INFO("r_state_value:%1ld\n",state); + r_value = state; + led_cdev->flags = R_TIME; + sprd_leds_bltc_rgb_set(led_cdev,state); + return size; +} + +static ssize_t show_falling_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", f_value); +} + +static ssize_t store_falling_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned long state; + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + PRINT_INFO("f_state_value:%1ld\n",state); + f_value = state; + led_cdev->flags = F_TIME; + sprd_leds_bltc_rgb_set(led_cdev,state); + return size; +} + +static ssize_t show_high_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", h_value); +} + +static ssize_t store_high_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned long state; + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + PRINT_INFO("h_state_value:%1ld\n",state); + h_value = state; + led_cdev->flags = H_TIME; + sprd_leds_bltc_rgb_set(led_cdev,state); + return size; +} + +static ssize_t show_low_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", l_value); +} + +static ssize_t store_low_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned long state; + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + PRINT_INFO("l_state_value:%1ld\n",state); + l_value = state; + led_cdev->flags = L_TIME; + sprd_leds_bltc_rgb_set(led_cdev,state); + return size; +} + +static ssize_t show_on_off(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", onoff_value); +} + +static ssize_t store_on_off(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned long state; + ssize_t ret = -EINVAL; + + ret = kstrtoul(buf, 10, &state); + //PRINT_INFO("onoff_state_value:%1ld\n",state); + onoff_value = state; + led_cdev->flags = ONOFF; + sprd_leds_bltc_rgb_set(led_cdev,state); + return size; +} + +static DEVICE_ATTR(rising_time,0664,show_rising_time,store_rising_time); +static DEVICE_ATTR(falling_time,0664,show_falling_time,store_falling_time); +static DEVICE_ATTR(high_time,0664,show_high_time,store_high_time); +static DEVICE_ATTR(low_time,0664,show_low_time,store_low_time); +static DEVICE_ATTR(on_off,0664,show_on_off,store_on_off); +//liuhui add start + +int breathy_notifier_call(int color, int mode) +{ + PRINT_INFO("***********************\n"); + PRINT_INFO("%s liuhui charge led. color:%d,mode:%d\n", __func__, color, mode); + PRINT_INFO("***********************\n"); + unsigned long pwm_duty = 200; + mutex_lock(&breathy_lock); + + //is_charge_mode = 1; +if(mode ==2)//close charge led. +{ + sprd_leds_bltc_rgb_disable(g_brgb_r); +}else +{ + switch (color) + { + // 0% ~ 99%; red led always on + case 0: + { + g_brgb_r->value = 200; + sprd_leds_bltc_rgb_enable(g_brgb_r); + break; + } + + // 100%, full;green led always on + case 2: + { + g_brgb_g->value = 200; + sprd_leds_bltc_rgb_enable(g_brgb_g); + break; + } + default: + break; + } +} + mutex_unlock(&breathy_lock); + + return 0; +} + +//liuhui add end +static int sprd_leds_bltc_rgb_probe(struct platform_device *dev) +{ + struct sprd_leds_bltc_rgb *brgb; + int ret,i; + + PRINT_INFO("moonfu %s start", __func__); +#ifdef CONFIG_OF + mutex_init(&breathy_lock);//liuhui add. +/* + struct device_node *np = dev->dev.of_node; + struct resource res; + unsigned long base_addr0,base_addr1; + + ret = of_address_to_resource(np, 0, &res); + if(ret) { + PRINT_ERR("get dts data failed!\n"); + return -ENODEV; + } + base_addr0 = (unsigned long)ioremap_nocache(res.start,resource_size(&res)); + + ret = of_address_to_resource(np, 1, &res); + if(ret) { + PRINT_ERR("get dts data1 failed!\n"); + return -ENODEV; + } + base_addr1 = (unsigned long)ioremap_nocache(res.start,resource_size(&res)); +*/ +// PRINT_INFO("base_addr0:0x%1lx\n",base_addr0); /***0x40038440***/ +// PRINT_INFO("base_addr1:0x%1lx\n",base_addr1); /***0x40038800***/ +#else + struct sprd_leds_bltc_rgb_platform_data *pdata = NULL; + + pdata = dev->dev.platform_data; + if (!pdata) { + PRINT_ERR("No kpled_platform data!\n"); + return -ENODEV; + } +#endif + + for (i = 0; i < SPRD_LED_TYPE_TOTAL; i++) { + brgb = kzalloc(sizeof(struct sprd_leds_bltc_rgb), GFP_KERNEL); + + if (brgb == NULL) { + dev_err(&dev->dev, "No memory for bltc_device\n"); + ret = -ENOMEM; + goto err; + } + if((g_brgb_r == NULL) && (brgb != NULL)&& (i ==0))//liuhui add + g_brgb_r = brgb; + if((g_brgb_g == NULL) && (brgb != NULL)&& (i ==1))//liuhui add + g_brgb_g = brgb; + brgb->cdev.brightness_set = sprd_leds_bltc_rgb_set; + brgb->cdev.name = sprd_leds_rgb_name[i]; + brgb->cdev.brightness_get = NULL; + brgb->enable = 0; +#if CONFIG_OF + brgb->sprd_bltc_base_addr = SPRD_ADI_BASE + 0x83c0; //0x83c0; /***0x40038440***/ + brgb->sprd_arm_module_en_addr = SPRD_ADI_BASE + 0x8800; /***0x40038800***/ +#else + brgb->sprd_bltc_base_addr = pdata->sprd_base_addr + 0x440; /***0x40038440***/ + brgb->sprd_arm_module_en_addr = pdata->sprd_base_addr + 0x800; /***0x40038800***/ +#endif + spin_lock_init(&brgb->value_lock); + mutex_init(&brgb->mutex); + INIT_WORK(&brgb->work, sprd_leds_rgb_work); + INIT_DELAYED_WORK(&brgb->work_bl, sprd_leds_bltc_work); + brgb->work_bl_q = create_singlethread_workqueue("leds_bltc"); + if(brgb->work_bl_q == NULL) { + PRINT_ERR("create_singlethread_workqueue for leds_bltc failed!\n"); + goto failed_to_create_singlethread_workqueue_for_leds_bltc; + } + + brgb->value = LED_OFF; + platform_set_drvdata(dev, brgb); + ret = led_classdev_register(&dev->dev, &brgb->cdev); + if(strcmp(brgb->cdev.name,sprd_leds_rgb_name[i]) == 0) { + ret = device_create_file(brgb->cdev.dev,&dev_attr_rising_time); + ret = device_create_file(brgb->cdev.dev,&dev_attr_falling_time); + ret = device_create_file(brgb->cdev.dev,&dev_attr_high_time); + ret = device_create_file(brgb->cdev.dev,&dev_attr_low_time); + ret = device_create_file(brgb->cdev.dev,&dev_attr_on_off); + } + if (ret < 0) { + goto err; + } + brgb->value = 15;//set default brightness + brgb->suspend = 0; + sprd_bltc_rgb_init(brgb); + sci_adi_clr(brgb->sprd_arm_module_en_addr + 0x0c,(0x1<<13));//BLTC SOFT RESET + ++brgb; + } +//liuhui add. start + // Only for charge mode; + //register_led_callback(breathy_notifier_call); +//liuhui add. end + return 0; +err: + if (i) { + for (i = i-1; i >=0; i--) { + if (!brgb) + continue; + led_classdev_unregister(&brgb->cdev); + kfree(brgb); + brgb = NULL; + --brgb; + } + } +failed_to_create_singlethread_workqueue_for_leds_bltc: + cancel_delayed_work_sync(&brgb->work_bl); + destroy_workqueue(brgb->work_bl_q); + + return ret; +} + +static int sprd_leds_bltc_rgb_remove(struct platform_device *dev) +{ + struct sprd_leds_bltc_rgb *brgb = platform_get_drvdata(dev); + mutex_destroy(&breathy_lock);//liuhui add + led_classdev_unregister(&brgb->cdev); + flush_scheduled_work(); + brgb->value = LED_OFF; + brgb->enable = 1; + sprd_leds_bltc_rgb_disable(brgb); + kfree(brgb); + + return 0; +} + +static const struct of_device_id sprd_leds_bltc_rgb_of_match[] = { + { .compatible = "sprd,sprd-leds-bltc-rgb", }, + { } +}; + +static struct platform_driver sprd_leds_bltc_rgb_driver = { + .driver = { + .name = "sprd-leds-bltc-rgb", + .owner = THIS_MODULE, + .of_match_table = sprd_leds_bltc_rgb_of_match, + }, + .probe = sprd_leds_bltc_rgb_probe, + .remove = sprd_leds_bltc_rgb_remove, + .shutdown = sprd_leds_bltc_rgb_shutdown, +}; + +static int __init sprd_leds_bltc_rgb_init(void) +{ + PRINT_INFO("Locate in sprd_leds_bltc_rgb_init!\n"); + + return platform_driver_register(&sprd_leds_bltc_rgb_driver); +} + +static void sprd_leds_bltc_rgb_exit(void) +{ + platform_driver_unregister(&sprd_leds_bltc_rgb_driver); +} + +module_init(sprd_leds_bltc_rgb_init); +module_exit(sprd_leds_bltc_rgb_exit); + +MODULE_AUTHOR("ya huang <ya.huang@spreadtrum.com>"); +MODULE_DESCRIPTION("Sprd leds bltc rgb driver for 7731ea"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sprd_leds_bltc_rgb_7731ea"); + + + + |
