From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/video/backlight/sprd_backlight.c | 740 +++++++++++++++++++++++++++++++ 1 file changed, 740 insertions(+) create mode 100644 drivers/video/backlight/sprd_backlight.c (limited to 'drivers/video/backlight/sprd_backlight.c') diff --git a/drivers/video/backlight/sprd_backlight.c b/drivers/video/backlight/sprd_backlight.c new file mode 100644 index 00000000..6d48eea6 --- /dev/null +++ b/drivers/video/backlight/sprd_backlight.c @@ -0,0 +1,740 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef CONFIG_64BIT +#include +#endif +#include +#include + +#include +#include + + +//#define SPRD_BACKLIGHT_DBG +//#ifdef SPRD_BACKLIGHT_DBG +#define ENTER printk(KERN_INFO "[SPRD_BACKLIGHT_DBG] func: %s line: %04d\n", __func__, __LINE__); +#define PRINT_DBG(x...) printk(KERN_INFO "[SPRD_BACKLIGHT_DBG] " x) +#define PRINT_INFO(x...) printk(KERN_INFO "[SPRD_BACKLIGHT_INFO] " x) +#define PRINT_WARN(x...) printk(KERN_INFO "[SPRD_BACKLIGHT_WARN] " x) +#define PRINT_ERR(format,x...) printk(KERN_ERR "[SPRD_BACKLIGHT_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_BACKLIGHT_INFO] " x) +#define PRINT_WARN(x...) printk(KERN_INFO "[SPRD_BACKLIGHT_WARN] " x) +#define PRINT_ERR(format,x...) printk(KERN_ERR "[SPRD_BACKLIGHT_ERR] func: %s line: %04d info: " format, __func__, __LINE__, ## x) +#endif*/ + +//#define CONFIG_THERMAL_BL +#ifdef CONFIG_THERMAL_BL +#include +#include +#endif + +#define DIMMING_PWD_BASE (SPRD_MISC_BASE + 0x8020) +#define PD_PWM_BASE DIMMING_PWD_BASE + +/* register definitions */ +#define PWM_PRESCALE (0x0000) +#define PWM_CNT (0x0004) +#define PWM_TONE_DIV (0x0008) +#define PWM_PAT_LOW (0x000C) +#define PWM_PAT_HIG (0x0010) + +#define PWM_ENABLE (1 << 8) +#define PWM_DUTY (1 << 8) +#define PWM_MOD 0 +#define PWM_DIV 0x190 +#define PWM_LOW 0xffff +#define PWM_HIG 0xffff +#ifdef CONFIG_ARCH_SCX15 +#define PWM_SCALE 0xd +#else +#define PWM_SCALE 1 +#endif +#define PWM2_SCALE 0x0 +#define PWM_REG_MSK 0xffff +#define PWM_MOD_MAX 0xff +#define PWM_DUTY_MAX 0x7f + +/***************************************** +* level mV step +* 0 ~ 63 0 mV ~ 189 mV 3 mV +* 64 ~ 95 192 mV ~ 378 mV 6 mV +* 96 ~ 127 384 mV ~ 756 mV 12 mV +******************************************/ +#define MAX_VOLTAGE_LEVEL 70 +#define MIN_VOLTAGE_LEVEL 4 + +/* sprdtrum backlight have two driven mode: + * 1) pwm mode //you need to define SPRD_BACKLIGHT_PWM + * 2) white led mode //you need to deifine SPRD_BACKLIGHT_WHITELED + * 2.1) series mode //whiteled driven by dimming PWM, + you need to define the DIMMING_PWD_BASE + * 2.2) parallel mode //whiteled driven by pd PWM, + * you need to define the PD_PWD_BASE + */ + +#ifdef CONFIG_BACKLIGHT_SPRD_PWM_MODE + /*if the backlight is driven by pwm, use this MACRO */ + #define SPRD_BACKLIGHT_PWM +#else + /*the backlight is driven by whiteled default */ + #define SPRD_BACKLIGHT_WHITELED + #define SPRD_DIM_PWM_MODE +#endif + +enum bl_pwm_mode { + normal_pwm, + dim_pwm, + pd_pwd, +}; + +struct sprd_bl_devdata { + enum bl_pwm_mode pwm_mode; + unsigned long pwm_index; + struct mutex mutex; + struct backlight_device *bldev; + int suspend; + struct clk *clk; + struct early_suspend sprd_early_suspend_desc; + int ctl_pin; + int ctl_pin_level; +}; + +#ifdef CONFIG_THERMAL_BL +u32 cooling_max_brightness = 170; + +struct bl_thermal_cooling_info_t { + struct thermal_cooling_device *cdev; + unsigned long cooling_state; + int max_state; +} bl_thermal_cooling_info = { + .cdev = NULL, + .cooling_state = 0, + .max_state = 4, +}; +#endif + +static struct sprd_bl_devdata sprdbl = { + .ctl_pin = -1, + .ctl_pin_level = -1, + }; +#if(defined(CONFIG_MACH_SP7715EA)||defined(CONFIG_MACH_SP7715EATRISIM)) +static int pwm_whiteled_both = 0; +static int sprd_bl_whiteled_update_status(struct backlight_device *bldev); +#endif + +static void bl_pwm_clk_en(int enable) +{ + unsigned long spin_lock_flags; + static int current_state = 0; + + if (1 == enable) { + if (0 == current_state) { + clk_prepare_enable(sprdbl.clk); + current_state = 1; + } + } else { + if (1 == current_state) { + clk_disable_unprepare(sprdbl.clk); + current_state = 0; + } + } + + return; +} + +static inline uint32_t pwm_read(unsigned long index, unsigned long reg) +{ + //this is the D-die PWM controller, here we use PWM2(index=3) for external backlight control. + return __raw_readl(SPRD_PWM_BASE + index * 0x20 + reg); +} + +static void pwm_write(unsigned long index, uint32_t value, unsigned long reg) +{ + //this is the D-die PWM controller, here we use PWM2(index=3) for external backlight control. + __raw_writel(value, SPRD_PWM_BASE + index * 0x20 + reg); +} + +//sprd used PWM2(mapped to gpio190) for external backlight control. +static int sprd_bl_pwm_update_status(struct backlight_device *bldev) +{ + u32 led_level; + + mutex_lock(&sprdbl.mutex); + + if ((bldev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) || + bldev->props.power != FB_BLANK_UNBLANK || + sprdbl.suspend || + bldev->props.brightness == 0) { + /* disable backlight */ + pwm_write(sprdbl.pwm_index, 0, PWM_PRESCALE); + bl_pwm_clk_en(0); + PRINT_INFO("[pwm] disabled\n"); + } else { + led_level = bldev->props.brightness & PWM_MOD_MAX; + PRINT_INFO("[pwm] brightness = %d\n", led_level); + //led_level = (led_level * (PWM_DUTY_MAX+1) / (PWM_MOD_MAX+1)) + 10; + if(led_level > 127) { + //led_level = led_level * 90 / 100; + led_level = 255 - (255 - led_level) * 14 / 10; + PRINT_INFO("[pwm] brightness = %d\n", led_level); + }else{ + led_level = led_level * 76 / 126; + } + led_level = led_level * 90 / 100; + if(led_level < 8) + led_level = 8; + #ifdef CONFIG_THERMAL_BL + if(led_level > cooling_max_brightness) led_level = cooling_max_brightness; + #endif + PRINT_INFO("[pwm] brightness = %d, led_level = %d\n", bldev->props.brightness, led_level); + bl_pwm_clk_en(1); + pwm_write(sprdbl.pwm_index, PWM2_SCALE, PWM_PRESCALE); + pwm_write(sprdbl.pwm_index, (led_level << 8) | PWM_MOD_MAX, PWM_CNT); + pwm_write(sprdbl.pwm_index, PWM_REG_MSK, PWM_PAT_LOW); + pwm_write(sprdbl.pwm_index, PWM_REG_MSK, PWM_PAT_HIG); + pwm_write(sprdbl.pwm_index, PWM_ENABLE, PWM_PRESCALE); + } + +#if(defined(CONFIG_MACH_SP7715EA)||defined(CONFIG_MACH_SP7715EATRISIM)) + if(1 == pwm_whiteled_both) + sprd_bl_whiteled_update_status(bldev); +#endif + mutex_unlock(&sprdbl.mutex); + + return 0; +} + +#ifdef CONFIG_THERMAL_BL +static int get_bl_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + int ret = 0; + + *state = bl_thermal_cooling_info.max_state; + + return ret; +} + +static int get_bl_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + int ret = 0; + + *state = bl_thermal_cooling_info.cooling_state; + + return ret; +} + +static int set_bl_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct bl_thermal_cooling_info_t *c_info = &bl_thermal_cooling_info; + + if (c_info->cooling_state == state){ + return 0; + }else{ + c_info->cooling_state = state; + } + if(c_info->cooling_state) + cooling_max_brightness = 85; + else + cooling_max_brightness = 170; + sprd_bl_pwm_update_status(sprdbl.bldev); + PRINT_INFO("thermal_brightness = %d,cur_state = %d\n", cooling_max_brightness,state); +} + +static struct thermal_cooling_device_ops sprd_backlight_cooling_ops = { + .get_max_state = get_bl_max_state, + .get_cur_state = get_bl_cur_state, + .set_cur_state = set_bl_cur_state, +}; +#endif + +static int sprd_bl_pwm_get_brightness(struct backlight_device *bldev) +{ + return (pwm_read(sprdbl.pwm_index, PWM_CNT) >> 8) & PWM_MOD_MAX; +} + +#ifdef CONFIG_ARCH_SCX15 +static void srpd_backlight_init(void) +{ + PRINT_INFO("srpd_backlight_init\n"); + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL1, BIT_PWM0_EN ); + + //this is the A-die PWM controller, it is used for white_led. + sci_adi_raw_write((unsigned long)PD_PWM_BASE+PWM_CNT, PWM_DUTY | PWM_MOD); + sci_adi_raw_write((unsigned long)PD_PWM_BASE+PWM_TONE_DIV, PWM_DIV); + sci_adi_raw_write((unsigned long)PD_PWM_BASE+PWM_PRESCALE, PWM_ENABLE | PWM_SCALE); + sci_adi_raw_write((unsigned long)PD_PWM_BASE+PWM_PAT_LOW, PWM_LOW); + sci_adi_raw_write((unsigned long)PD_PWM_BASE+PWM_PAT_HIG, PWM_HIG); + + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_SERIES_EN); + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_BOOST_EN); + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_PD); + + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL1, BIT_RTC_PWM0_EN); + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL1, BIT_PWM0_EN); +} +#endif + +static int sprd_bl_whiteled_update_status(struct backlight_device *bldev) +{ + u32 bl_brightness, led_level, pwm_level; + u32 reg_val; + + if ((bldev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) || + bldev->props.power != FB_BLANK_UNBLANK || + sprdbl.suspend || + bldev->props.brightness == 0) { + /* disable backlight */ + if (sprdbl.pwm_mode == dim_pwm) { + sci_adi_clr((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_BOOST_EN); + } else { + /*yes, 1 is disbale and 0 is enable*/ + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_PD); + } + PRINT_INFO("[white led] disabled\n"); + } else { + bl_brightness = bldev->props.brightness & PWM_MOD_MAX; + pwm_level = bl_brightness & 0x3; + /*duty ratio = 25% 50% 75% or 100%*/ + pwm_level = (PWM_MOD_MAX >> 2) * (pwm_level + 1) & PWM_MOD_MAX; + + if (sprdbl.pwm_mode == dim_pwm) { + /*series mode*/ + /*whiteled config*/ + led_level = (((MAX_VOLTAGE_LEVEL - MIN_VOLTAGE_LEVEL + 1) * bl_brightness) / (PWM_MOD_MAX + 1)) + MIN_VOLTAGE_LEVEL; + PRINT_INFO("[white led] brightness = %d, led_level = %d\n", bldev->props.brightness, led_level); + reg_val = sci_adi_read((unsigned long)ANA_REG_GLB_WHTLED_CTRL1); +#ifdef CONFIG_ARCH_SCX15 + reg_val &= ~(0x7f << 6); + reg_val |= led_level << 6; +#else + reg_val &= ~(0x7f << 5); + reg_val |= led_level << 5; +#endif + + sci_adi_raw_write((unsigned long)ANA_REG_GLB_WHTLED_CTRL1, reg_val); + #if 0 + /*dimming pwm config*/ + sci_adi_raw_write(DIMMING_PWD_BASE + PWM_SCALE, PWM_PRESCALE); + sci_adi_raw_write(DIMMING_PWD_BASE + PWM_CNT, + (pwm_level << 8) | PWM_MOD_MAX); + sci_adi_raw_write(DIMMING_PWD_BASE + PWM_SCALE, + PWM_SCALE | PWM_ENABLE); + #endif + /*enable the whiteled bootst output*/ + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_SERIES_EN); + sci_adi_set((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_BOOST_EN); + } else { + /*parallel mode*/ + led_level = (bl_brightness >> 2) & 0x3f; + reg_val = sci_adi_read((unsigned long)ANA_REG_GLB_WHTLED_CTRL0); + reg_val &= ~(0x3f << 1); + reg_val |= led_level << 1; + sci_adi_raw_write((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, reg_val); + + sci_adi_raw_write((unsigned long)(PD_PWM_BASE + PWM_SCALE), PWM_PRESCALE); + sci_adi_raw_write((unsigned long)(PD_PWM_BASE + PWM_CNT), + (pwm_level << 8) | PWM_MOD_MAX); + + sci_adi_raw_write((unsigned long)(PD_PWM_BASE + PWM_SCALE), + PWM_SCALE | PWM_ENABLE); + + sci_adi_clr((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_SERIES_EN); + sci_adi_clr((unsigned long)ANA_REG_GLB_WHTLED_CTRL0, BIT_WHTLED_PD); + } + } + + return 0; +} + +static int sprd_bl_whiteled_get_brightness(struct backlight_device *bldev) +{ + /*fixme*/ + return 0; +} + +static const struct backlight_ops sprd_backlight_pwm_ops = { + .update_status = sprd_bl_pwm_update_status, + .get_brightness = sprd_bl_pwm_get_brightness, +}; + +static const struct backlight_ops sprd_backlight_whiteled_ops = { + .update_status = sprd_bl_whiteled_update_status, + .get_brightness = sprd_bl_whiteled_get_brightness, +}; + +#ifdef CONFIG_EARLYSUSPEND +void set_ctl_pin_state(int on){ + static int ret = 0; + + if (sprdbl.ctl_pin == -1) + return; + on = on ? sprdbl.ctl_pin_level : !sprdbl.ctl_pin_level; + if (ret == 0) { + ret = gpio_request(sprdbl.ctl_pin, "backlight_ctl_pin"); + if (ret) { + printk("%s: request gpio error\n", __func__); + return -EIO; + } + gpio_direction_output(sprdbl.ctl_pin, on); + ret = 1; + } + gpio_set_value(sprdbl.ctl_pin,on); +} +static void sprd_backlight_earlysuspend(struct early_suspend *h) +{ + set_ctl_pin_state(0); + sprdbl.suspend = 1; + sprdbl.bldev->ops->update_status(sprdbl.bldev); + PRINT_INFO("early suspend\n"); +} + +static void sprd_backlight_lateresume(struct early_suspend *h) +{ + set_ctl_pin_state(1); + sprdbl.suspend = 0; + sprdbl.bldev->ops->update_status(sprdbl.bldev); + PRINT_INFO("late resume\n"); +} +#endif + +#ifdef CONFIG_OF +static struct resource *sprd_backlight_parse_dt(struct platform_device *pdev) +{ + int ret; + struct device_node *np = pdev->dev.of_node; + struct resource *pwm_res; + u32 tmp_val_u32; + pwm_res = kzalloc(sizeof(*pwm_res), GFP_KERNEL); + if (!pwm_res) { + dev_err(&pdev->dev, "sprd_backlight Could not allocate struct resource"); + return NULL; + } + ret = of_property_read_u32(np, "start", &tmp_val_u32); + if(ret){ + dev_err(&pdev->dev, "fail to get resource.start\n"); + goto fail; + } + pwm_res->start = tmp_val_u32; + ret = of_property_read_u32(np, "end", &tmp_val_u32); + if(ret){ + dev_err(&pdev->dev, "fail to get resource.end\n"); + goto fail; + } + pwm_res->end = tmp_val_u32; + ret = of_property_read_u32(np, "ctl_pin", &sprdbl.ctl_pin); + ret = of_property_read_u32(np, "ctl_pin_level", &sprdbl.ctl_pin_level); + ret = of_property_read_u32(np, "flags", &pwm_res->flags); + if(ret){ + dev_err(&pdev->dev, "fail to get resource.flags\n"); + goto fail; + } + return pwm_res; +fail: + kfree(pwm_res); + return NULL; +} +#endif + +static int sprd_backlight_probe(struct platform_device *pdev) +{ + struct backlight_properties props; + struct backlight_device *bldev; + int use_pwm = 0; +#ifdef CONFIG_THERMAL_BL + struct bl_thermal_cooling_info_t *c_info = &bl_thermal_cooling_info; +#endif + +#ifdef SPRD_BACKLIGHT_PWM + struct clk* ext_26m = NULL; + struct resource *pwm_res = NULL; + struct resource *pwm_res1 = NULL; + char pwm_clk_name[32]; + +#ifdef CONFIG_OF + struct device_node *np = pdev->dev.of_node; + if(np){ + pwm_res = sprd_backlight_parse_dt(pdev); + if (pwm_res){ + pdev->resource = pwm_res; + }else{ + printk("Can't get pwm resource"); + return -ENODEV; + } + }else{ + printk("dev.of_node is NULL"); + return -ENODEV; + } +#else + pwm_res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (IS_ERR(pwm_res)) { + printk("Can't get pwm resource"); + return -ENODEV; + } + pwm_res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (pwm_res1 != NULL) { + sprdbl.ctl_pin = pwm_res1->start; + sprdbl.ctl_pin_level = !!pwm_res1->end; + } +#endif + + sprdbl.pwm_index = pwm_res->start; + /*fixme, the pwm's clk name must like this:clk_pwmx*/ + sprintf(pwm_clk_name, "%s%d", "clk_pwm", (int)sprdbl.pwm_index); + sprdbl.clk = clk_get(&pdev->dev, pwm_clk_name); + if (IS_ERR(sprdbl.clk)) { + printk("Can't get pwm's clk"); + return -ENODEV; + } + + ext_26m = clk_get(NULL, "ext_26m"); + if (IS_ERR(ext_26m)) { + printk("Can't get pwm's ext_26m"); + return -ENODEV; + } + + clk_set_parent(sprdbl.clk,ext_26m); + + sprdbl.pwm_mode = normal_pwm; + use_pwm = 1; + PRINT_INFO("PWM%d is used for brightness control (external backlight controller)\n", (int)sprdbl.pwm_index); +#else + +#if(defined(CONFIG_MACH_SP7715EA)||defined(CONFIG_MACH_SP7715EATRISIM)) + struct clk* ext_26m = NULL; + struct resource *pwm_res = NULL; + char pwm_clk_name[32]; + int adie_chip_ver = 0; + + adie_chip_ver = sci_get_ana_chip_ver(); + PRINT_INFO("adie_chip_ver = 0x%08X\n", adie_chip_ver); + + //if(0x00000000 != adie_chip_ver) { + if(1) { +#ifdef CONFIG_OF + struct device_node *np = pdev->dev.of_node; + if(np){ + pwm_res = sprd_backlight_parse_dt(pdev); + if (pwm_res){ + pdev->resource = pwm_res; + }else{ + printk("Can't get pwm resource"); + return -ENODEV; + } + }else{ + printk("dev.of_node is NULL"); + return -ENODEV; + } +#else + pwm_res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (IS_ERR(pwm_res)) { + printk("Can't get pwm resource"); + return -ENODEV; + } +#endif + + sprdbl.pwm_index = pwm_res->start; + /*fixme, the pwm's clk name must like this:clk_pwmx*/ + sprintf(pwm_clk_name, "%s%d", "clk_pwm", (int)sprdbl.pwm_index); + sprdbl.clk = clk_get(&pdev->dev, pwm_clk_name); + if (IS_ERR(sprdbl.clk)) { + printk("Can't get pwm's clk"); + return -ENODEV; + } + + ext_26m = clk_get(NULL, "ext_26m"); + if (IS_ERR(ext_26m)) { + printk("Can't get pwm's ext_26m"); + return -ENODEV; + } + + clk_set_parent(sprdbl.clk,ext_26m); + + sprdbl.pwm_mode = normal_pwm; + PRINT_INFO("PWM%d is used for brightness control (external backlight controller)\n", (int)sprdbl.pwm_index); + use_pwm = 1; + goto pwm_7715ea; + } +#endif + +#ifdef SPRD_DIM_PWM_MODE + sprdbl.pwm_mode = dim_pwm; +#else + sprdbl.pwm_mode = pd_pwd; +#endif + +#ifdef CONFIG_ARCH_SCX15 + srpd_backlight_init(); +#endif +#endif + +pwm_7715ea: + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = PWM_MOD_MAX; + props.type = BACKLIGHT_RAW; + /*the default brightness = 1/2 max brightness */ + props.brightness = PWM_MOD_MAX >> 1; + props.power = FB_BLANK_UNBLANK; + + mutex_init(&sprdbl.mutex); + + if(1 == use_pwm) { + bldev = backlight_device_register( + pdev->name, &pdev->dev, + &sprdbl, &sprd_backlight_pwm_ops, &props); + if (IS_ERR(bldev)) { + printk(KERN_ERR "Failed to register backlight device\n"); + return -ENOMEM; + } +#ifdef CONFIG_THERMAL_BL + c_info->cdev = thermal_cooling_device_register("thermal-bl", 0, + &sprd_backlight_cooling_ops); + if (IS_ERR(c_info->cdev)){ + printk(KERN_ERR "Failed to register thermal_backlight device\n"); + return -ENOMEM; + } + PRINT_INFO("thermal_cooling_device_register successful!\n"); +#endif + #if(defined(CONFIG_MACH_SP7715EA)||defined(CONFIG_MACH_SP7715EATRISIM)) + if(0x00000000 == adie_chip_ver) { + pwm_whiteled_both = 1; + #ifdef SPRD_DIM_PWM_MODE + sprdbl.pwm_mode = dim_pwm; + #else + sprdbl.pwm_mode = pd_pwd; + #endif + #ifdef CONFIG_ARCH_SCX15 + srpd_backlight_init(); + #endif + } + #endif + } + else { + bldev = backlight_device_register( + pdev->name, &pdev->dev, + &sprdbl, &sprd_backlight_whiteled_ops, &props); + if (IS_ERR(bldev)) { + printk(KERN_ERR "Failed to register backlight device\n"); + return -ENOMEM; + } + } + + sprdbl.bldev = bldev; + platform_set_drvdata(pdev, bldev); + bldev->ops->update_status(bldev); + +#ifdef CONFIG_EARLYSUSPEND + sprdbl.sprd_early_suspend_desc.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + sprdbl.sprd_early_suspend_desc.suspend = sprd_backlight_earlysuspend; + sprdbl.sprd_early_suspend_desc.resume = sprd_backlight_lateresume; + register_early_suspend(&sprdbl.sprd_early_suspend_desc); +#endif + + return 0; +} + +static int sprd_backlight_remove(struct platform_device *pdev) +{ + struct backlight_device *bldev; + + bldev = platform_get_drvdata(pdev); + bldev->props.power = FB_BLANK_UNBLANK; + bldev->props.brightness = PWM_MOD_MAX; + + backlight_update_status(bldev); + + backlight_device_unregister(bldev); + + platform_set_drvdata(pdev, NULL); + +#ifdef CONFIG_EARLYSUSPEND + unregister_early_suspend(&sprdbl.sprd_early_suspend_desc); +#endif + return 0; +} + +static void sprd_backlight_shutdown(struct platform_device *pdev) +{ + struct backlight_device *bldev; + + bldev = platform_get_drvdata(pdev); + bldev->props.brightness = 0; + backlight_update_status(bldev); +} + + +#ifdef CONFIG_PM +static int sprd_backlight_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} + +static int sprd_backlight_resume(struct platform_device *pdev) +{ + return 0; +} +#else +#define sprd_backlight_suspend NULL +#define sprd_backlight_resume NULL +#endif + +static const struct of_device_id backlight_of_match[] = { + { .compatible = "sprd,sprd_backlight", }, + { } +}; +static struct platform_driver sprd_backlight_driver = { + .probe = sprd_backlight_probe, + .remove = sprd_backlight_remove, + .suspend = sprd_backlight_suspend, + .resume = sprd_backlight_resume, + .shutdown = sprd_backlight_shutdown, + .driver = { + .name = "sprd_backlight", + .owner = THIS_MODULE, + .of_match_table = backlight_of_match, + }, +}; + +static int __init sprd_backlight_init(void) +{ + return platform_driver_register(&sprd_backlight_driver); +} + +static void __exit sprd_backlight_exit(void) +{ + platform_driver_unregister(&sprd_backlight_driver); +} + +module_init(sprd_backlight_init); +module_exit(sprd_backlight_exit); + +MODULE_DESCRIPTION("Spreadtrum backlight Driver"); -- cgit v1.3.1