add backlight
author钟勇汪 <zyw@rock-chips.com>
Tue, 18 May 2010 14:32:33 +0000 (14:32 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:35:12 +0000 (13:35 +0800)
.config
arch/arm/mach-rk2818/board-midsdk.c
arch/arm/mach-rk2818/devices.c
arch/arm/mach-rk2818/devices.h
arch/arm/mach-rk2818/include/mach/rk2818_backlight.h [new file with mode: 0755]
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/rk2818_backlight.c [new file with mode: 0644]

diff --git a/.config b/.config
index 52be336db86e0a3846699e2f47aa0cf430e41b8c..65ea64e1f0f6222343235a58fe2771267d27d5d9 100644 (file)
--- a/.config
+++ b/.config
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.32.9
-# Tue May 18 17:32:48 2010
+# Tue May 18 22:11:51 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -656,8 +656,8 @@ CONFIG_KEYBOARD_RK28ADC=y
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_ADS7846 is not set
 # CONFIG_TOUCHSCREEN_AD7877 is not set
-# CONFIG_TOUCHSCREEN_RK2818_SPI_XPT2046 is not set
-# CONFIG_TOUCHSCREEN_RK2818_SPI_XPT2046_CBN is not set
+CONFIG_TOUCHSCREEN_XPT2046_SPI=y
+# CONFIG_TOUCHSCREEN_XPT2046_CBN_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879_I2C is not set
 # CONFIG_TOUCHSCREEN_AD7879_SPI is not set
 # CONFIG_TOUCHSCREEN_AD7879 is not set
@@ -913,7 +913,17 @@ CONFIG_FB_RK2818=y
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
 # CONFIG_FB_BROADSHEET is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_RK2818_BL=y
 
 #
 # Display device support
index 1269251d20019aec83832097ef7004e43ba000f5..85cab9c90bc8ffff5c83e9fd9a4d4762d88c6d19 100644 (file)
@@ -33,6 +33,7 @@
 #include <mach/rk2818_iomap.h>
 #include <mach/iomux.h>
 #include <mach/gpio.h>
+#include <mach/rk2818_backlight.h>
 
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -271,6 +272,12 @@ struct rk2818_fb_mach_info rk2818_fb_mach_info = {
     .iomux = &rk2818_fb_iomux_info,
 };
 
+struct rk2818bl_info rk2818_bl_info = {
+        .pwm_id   = 0,
+        .pw_pin   = GPIO_HIGH | (RK2818_PIN_PF1 << 8) ,
+        .bl_ref   = 0,
+};
+
 static struct platform_device *devices[] __initdata = {
        &rk2818_device_uart1,
        &rk2818_device_dm9k,
@@ -284,7 +291,8 @@ static struct platform_device *devices[] __initdata = {
        &rk2818_device_pmem,
        &rk2818_device_adc,
        &rk2818_device_adckey,
-    &rk2818_device_fb,    
+  &rk2818_device_fb,    
+    &rk2818_device_backlight,
 };
 
 extern struct sys_timer rk2818_timer;
index 6b7b49e8c819ec8b2f515d0caab58b9c95991448..f9ed143361a847da62a3337cf8ec5291640d33c5 100644 (file)
@@ -195,6 +195,22 @@ struct platform_device rk2818_device_fb = {
                .platform_data  = &rk2818_fb_mach_info,
        }
 };
+
+/***********************************************************
+*        backlight
+*      author :nzy zhongyw
+*      data:2010-05-18
+***************************************************************/
+extern struct rk2818bl_info rk2818_bl_info;
+
+struct platform_device rk2818_device_backlight = {
+               .name   = "rk2818_backlight",
+               .id     = -1,
+        .dev    = {
+           .platform_data  = &rk2818_bl_info,
+        }
+};
+
 //net device
 /* DM9000 */
 static struct resource dm9k_resource[] = {
index 22e8f6c9f549454ae260d8f6a3073981acec21b4..1e4c78f559f1f7e3fa12df978bcf6fb4f965b0a5 100644 (file)
@@ -30,4 +30,5 @@ extern struct platform_device rk2818_device_pmem;
 extern struct platform_device rk2818_device_fb;
 extern struct platform_device rk2818_device_adc;
 extern struct platform_device rk2818_device_adckey;
+extern struct platform_device rk2818_device_backlight;
 #endif
diff --git a/arch/arm/mach-rk2818/include/mach/rk2818_backlight.h b/arch/arm/mach-rk2818/include/mach/rk2818_backlight.h
new file mode 100755 (executable)
index 0000000..f139178
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  linux/include/asm-arm/arch-rockchip/pwm.h
+ *
+ */
+
+#ifndef __ASM_ARCH_RK2818_BACKLIGHT_H
+#define __ASM_ARCH_RK2818_BACKLIGHT_H
+#include <linux/timer.h>
+
+///PWM_CTRL
+#define PWM_DIV2            (0<<9)
+#define PWM_DIV4            (1<<9)
+#define PWM_DIV8            (2<<9)
+#define PWM_DIV16           (3<<9)
+#define PWM_DIV32           (4<<9)
+#define PWM_DIV64           (5<<9)
+#define PWM_DIV128          (6<<9)
+#define PWM_DIV256          (7<<9)
+#define PWM_DIV512          (8<<9)
+#define PWM_DIV1024         (9<<9)
+
+#define PWM_CAPTURE         (1<<8)
+#define PWM_RESET           (1<<7)
+#define PWM_INTCLR          (1<<6)
+#define PWM_INTEN           (1<<5)
+#define PWM_SINGLE          (1<<6)
+
+#define PWM_ENABLE          (1<<3)
+#define PWM_TIME_EN         (1)
+
+
+#define PWM_REG_CNTR         0x00
+#define PWM_REG_HRC          0x04 
+#define PWM_REG_LRC          0x08
+#define PWM_REG_CTRL         0x0c
+
+
+#define PWM_DIV              PWM_DIV2
+#define PWM_APB_PRE_DIV      1000
+#define BL_STEP              255
+
+
+struct rk2818bl_info{
+    u32 pwm_id;
+    u32 pw_pin;
+    u32 bl_ref;
+    struct timer_list timer;  
+    struct notifier_block freq_transition;
+};
+
+
+#endif /* __ASM_ARCH_RK2818_BACKLIGHT_H */
index 09bfa9662e4d9fd8cf032e0f30d2cca19cc20b2b..9061330841aaef6f5ed0dd271802f15ffc753717 100644 (file)
@@ -262,3 +262,9 @@ config BACKLIGHT_ADP5520
          To compile this driver as a module, choose M here: the module will
          be called adp5520_bl.
 
+config BACKLIGHT_RK2818_BL
+        bool "rk2818 backlight driver"
+       depends on BACKLIGHT_CLASS_DEVICE
+       default y
+       help
+         rk2818 backlight support.
index 9a405548874c74e5f7ede64283c4764fb3512758..1739ab2b389a317207a31e1b0398c53681c789df 100644 (file)
@@ -28,4 +28,5 @@ obj-$(CONFIG_BACKLIGHT_SAHARA)        += kb3886_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
 obj-$(CONFIG_BACKLIGHT_ADX)    += adx_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP5520)        += adp5520_bl.o
+obj-$(CONFIG_BACKLIGHT_RK2818_BL) += rk2818_backlight.o
 
diff --git a/drivers/video/backlight/rk2818_backlight.c b/drivers/video/backlight/rk2818_backlight.c
new file mode 100644 (file)
index 0000000..55ec77b
--- /dev/null
@@ -0,0 +1,404 @@
+/* arch/arm/mach-rockchip/rk28_backlight.c
+ *
+ * Copyright (C) 2009 Rockchip Corporation.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+
+#ifdef CONFIG_ANDROID_POWER
+#include <linux/android_power.h>
+#endif
+#include <asm/io.h>
+//#include <mach/typedef.h>
+#include <mach/iomux.h>
+#include <mach/gpio.h>
+#include <mach/rk2818_backlight.h>
+#include <mach/rk2818_iomap.h>
+
+//#define RK28_PRINT 
+//#include <mach/rk2818_debug.h>
+
+/*
+ * Debug
+ */
+#if 0
+#define DBG(x...)      printk(KERN_INFO x)
+#else
+#define DBG(x...)
+#endif
+
+
+#define write_pwm_reg(id, addr, val)        __raw_writel(val, addr+(RK2818_PWM_BASE+id*0x10)) 
+#define read_pwm_reg(id, addr)              __raw_readl(addr+(RK2818_PWM_BASE+id*0x10))    
+#define mask_pwm_reg(id, addr, msk, val)    write_dma_reg(id, addr, (val)|((~(msk))&read_dma_reg(id, addr)))
+
+
+static struct backlight_device *rk2818_bl = NULL;
+static int suspend_flag = 0;
+#define BACKLIGHT_SEE_MINVALUE 52
+
+static s32 rk2818_bl_update_status(struct backlight_device *bl)
+{
+    u32 divh,div_total;
+    struct rk2818bl_info *rk2818_bl_info = bl->dev.parent->platform_data;
+    u32 id = rk2818_bl_info->pwm_id;
+    u32 ref = rk2818_bl_info->bl_ref;
+
+    if (suspend_flag)
+        return 0;
+    
+    div_total = read_pwm_reg(id, PWM_REG_LRC);
+    if (ref) {
+        DBG(">>>%s-->%d   bl->props.brightness == %d\n",__FUNCTION__,__LINE__,bl->props.brightness);
+        divh = div_total*(bl->props.brightness)/BL_STEP;
+    } else {
+        DBG(">>>%s-->%d   bl->props.brightness == %d\n",__FUNCTION__,__LINE__,bl->props.brightness);
+        if(bl->props.brightness < BACKLIGHT_SEE_MINVALUE)      /*avoid can't view screen when close backlight*/
+               bl->props.brightness = BACKLIGHT_SEE_MINVALUE;
+        divh = div_total*(BL_STEP-bl->props.brightness)/BL_STEP;
+    }
+    write_pwm_reg(id, PWM_REG_HRC, divh);
+    DBG("%s::========================================\n",__func__);
+    return 0;
+}
+
+static s32 rk2818_bl_get_brightness(struct backlight_device *bl)
+{
+    u32 divh,div_total;
+    struct rk2818bl_info *rk2818_bl_info = bl->dev.parent->platform_data;
+    u32 id = rk2818_bl_info->pwm_id;
+    u32 ref = rk2818_bl_info->bl_ref;
+    
+    div_total = read_pwm_reg(id, PWM_REG_LRC);
+    divh = read_pwm_reg(id, PWM_REG_HRC);
+
+       DBG("%s::========================================\n",__func__);
+
+    if (ref) {
+        return BL_STEP*divh/div_total;
+    } else {
+        return BL_STEP-(BL_STEP*divh/div_total);
+    }
+}
+
+static struct backlight_ops rk2818_bl_ops = {
+       .update_status = rk2818_bl_update_status,
+       .get_brightness = rk2818_bl_get_brightness,
+};
+
+
+static int rk2818_bl_change_clk(struct notifier_block *nb, unsigned long val, void *data)
+{
+    struct rk2818bl_info *rk2818_bl_info;
+    u32 id;
+    u32 divl, divh, tmp;
+    u32 div_total;
+    struct clk* pclk; 
+
+    if (!rk2818_bl)
+    {
+        DBG(KERN_CRIT "%s: backlight device does not exist \n",
+               __func__); 
+               return -ENODEV;         
+    }
+    
+    switch (val) 
+    {
+    case CPUFREQ_PRECHANGE:        
+         break;
+    case CPUFREQ_POSTCHANGE:
+         rk2818_bl_info = rk2818_bl->dev.parent->platform_data;
+         id = rk2818_bl_info->pwm_id;
+     
+         pclk = clk_get(NULL, "arm_pclk");
+         if (!pclk || IS_ERR(pclk)) 
+         {
+               printk(KERN_ERR "%s, %s, failed to get lcd clock source\n",__FILE__, __FUNCTION__);
+               return -ENODEV; 
+         }
+         
+         divl = read_pwm_reg(id, PWM_REG_LRC);
+         divh = read_pwm_reg(id, PWM_REG_HRC);
+     
+         tmp = clk_get_rate(pclk)/PWM_APB_PRE_DIV;
+         tmp >>= (1 + (PWM_DIV >> 9));
+
+         clk_put(pclk);
+         
+         div_total = (tmp) ? tmp : 1;
+         tmp = div_total*divh/divl;
+         
+         write_pwm_reg(id, PWM_REG_LRC, div_total);
+         write_pwm_reg(id, PWM_REG_HRC, tmp);    
+         write_pwm_reg(id, PWM_REG_CNTR, 0);  
+         break;
+    }
+   
+    return 0;
+}   
+static void rk2818_delaybacklight_timer(unsigned long data)
+{
+       struct rk2818bl_info *rk2818_bl_info = (struct rk2818bl_info *)data;
+       u32 id, brightness;
+       u32 div_total, divh;
+       id = rk2818_bl_info->pwm_id;
+    brightness = rk2818_bl->props.brightness;
+    div_total = read_pwm_reg(id, PWM_REG_LRC);
+    if (rk2818_bl_info->bl_ref) {
+        divh = div_total*(brightness)/BL_STEP;
+    } else {
+        divh = div_total*(BL_STEP-brightness)/BL_STEP;
+    }
+    write_pwm_reg(id, PWM_REG_HRC, divh);
+    suspend_flag = 0;
+    DBG("%s: ======================== \n",__func__); 
+}
+
+#ifdef CONFIG_ANDROID_POWER
+static void rk2818_bl_suspend(android_early_suspend_t *h)
+{
+    struct rk2818bl_info *rk2818_bl_info;
+    u32 id;
+    u32 div_total, divh;
+    
+    rk2818_bl_info = rk2818_bl->dev.parent->platform_data;
+
+    id = rk2818_bl_info->pwm_id;
+
+    div_total = read_pwm_reg(id, PWM_REG_LRC);
+    
+    if(rk2818_bl_info->bl_ref) {
+        divh = 0;
+    } else {
+        divh = div_total;
+    }
+
+    write_pwm_reg(id, PWM_REG_HRC, divh);
+
+    suspend_flag = 1;
+    
+    DBG("%s: ========================= \n",__func__); 
+}
+
+
+static void rk2818_bl_resume(android_early_suspend_t *h)
+{
+    struct rk2818bl_info *rk2818_bl_info;
+   // u32 id, brightness;
+    //u32 div_total, divh;
+    DBG(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+    rk2818_bl_info = rk2818_bl->dev.parent->platform_data;
+       
+       rk2818_bl_info->timer.expires  = jiffies + 30;
+       add_timer(&rk2818_bl_info->timer);
+       #if 0
+    id = rk28_bl_info->pwm_id;
+    brightness = rk28_bl->props.brightness;
+    
+    div_total = read_pwm_reg(id, PWM_REG_LRC);
+    if (rk28_bl_info->bl_ref) {
+        divh = div_total*(brightness)/BL_STEP;
+    } else {
+        divh = div_total*(BL_STEP-brightness)/BL_STEP;
+    }
+    //mdelay(100);
+    write_pwm_reg(id, PWM_REG_HRC, divh);
+
+    suspend_flag = 0;
+
+    rk28printk("%s: ======================== \n",__func__); 
+       #endif 
+}
+
+static android_early_suspend_t bl_early_suspend;
+#endif
+
+static char *pwm_iomux[] = {
+     GPIOF2_APWM0_SEL_NAME,
+     GPIOF3_APWM1_MMC0DETN_NAME,
+     GPIOF4_APWM2_MMC0WPT_NAME,
+     GPIOF5_APWM3_DPWM3_NAME,
+};
+
+static int rk2818_backlight_probe(struct platform_device *pdev)
+{              
+    int ret = 0;
+    struct rk2818bl_info *rk2818_bl_info = pdev->dev.platform_data;
+    u32 pin =  (rk2818_bl_info->pw_pin >> 8) & 0xff;
+    u32 lev =  rk2818_bl_info->pw_pin & 0xf;
+    u32 id  =  rk2818_bl_info->pwm_id;
+    u32 divh, div_total;
+    struct clk* arm_pclk; 
+
+    DBG("%s::========================================\n",__func__);
+
+       if (rk2818_bl) {
+        DBG(KERN_CRIT "%s: backlight device register has existed \n",
+               __func__); 
+               return -EEXIST;         
+    }
+    
+       rk2818_bl = backlight_device_register("rk2818_bl", &pdev->dev, NULL, &rk2818_bl_ops);
+       if (!rk2818_bl) {
+        DBG(KERN_CRIT "%s: backlight device register error\n",
+               __func__); 
+               return -ENODEV;         
+       }
+
+    arm_pclk = clk_get(NULL, "arm_pclk");
+    if (!arm_pclk || IS_ERR(arm_pclk)) 
+    {
+               printk(KERN_ERR "failed to get lcd clock source\n");
+               return -ENODEV; 
+       }
+    div_total = clk_get_rate(arm_pclk)/PWM_APB_PRE_DIV;
+    clk_put(arm_pclk);
+    
+    div_total >>= (1 + (PWM_DIV >> 9));
+    div_total = (div_total) ? div_total : 1;
+    
+    if(rk2818_bl_info->bl_ref) {
+        divh = 0;
+    } else {
+        divh = div_total / 2;
+    }
+
+    /*init timer to dispose workqueue */
+    setup_timer(&rk2818_bl_info->timer, rk2818_delaybacklight_timer, (unsigned long)rk2818_bl_info);
+
+    rk2818_bl_info->freq_transition.notifier_call = rk2818_bl_change_clk;   
+    cpufreq_register_notifier(&rk2818_bl_info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+        
+    write_pwm_reg(id, PWM_REG_CTRL, PWM_DIV|PWM_RESET);
+    write_pwm_reg(id, PWM_REG_LRC, div_total);
+    write_pwm_reg(id, PWM_REG_HRC, divh);
+    write_pwm_reg(id, PWM_REG_CNTR, 0x0);
+    write_pwm_reg(id, PWM_REG_CTRL, PWM_DIV|PWM_ENABLE|PWM_TIME_EN);
+   
+       rk2818_bl->props.power = FB_BLANK_UNBLANK;
+       rk2818_bl->props.fb_blank = FB_BLANK_UNBLANK;
+       rk2818_bl->props.max_brightness = BL_STEP;
+       rk2818_bl->props.brightness = rk2818_bl_get_brightness(rk2818_bl);
+
+#ifdef CONFIG_ANDROID_POWER
+    bl_early_suspend.suspend = rk2818_bl_suspend;
+    bl_early_suspend.resume = rk2818_bl_resume;
+    bl_early_suspend.level = ~0x0;
+    android_register_early_suspend(&bl_early_suspend);
+#endif
+
+    rk2818_mux_api_set(pwm_iomux[id], 1);
+
+    ret = gpio_request(pin, NULL); 
+    if(ret != 0)
+    {
+        gpio_free(pin);
+        printk(KERN_ERR ">>>>>> lcd_cs gpio_request err \n ");        
+    }
+    
+    gpio_direction_output(pin, 0);
+    gpio_set_value(pin, lev);
+
+    return 0;
+}
+
+static int rk2818_backlight_remove(struct platform_device *pdev)
+{              
+    struct rk2818bl_info *rk2818_bl_info = pdev->dev.platform_data;
+    u32 pin =  (rk2818_bl_info->pw_pin >> 8) & 0xff;
+    
+       if (rk2818_bl) {
+               backlight_device_unregister(rk2818_bl);
+#ifdef CONFIG_ANDROID_POWER
+        android_unregister_early_suspend(&bl_early_suspend);
+#endif       
+        cpufreq_unregister_notifier(&rk2818_bl_info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+        gpio_free(pin); 
+        return 0;
+    } else {
+        DBG(KERN_CRIT "%s: no backlight device has registered\n",
+               __func__); 
+        return -ENODEV;      
+    }
+}
+static void rk2818_backlight_shutdown(struct platform_device *pdev)
+{
+
+   u32 divh,div_total;
+    struct rk2818bl_info *rk2818_bl_info = pdev->dev.platform_data;
+    u32 id = rk2818_bl_info->pwm_id;
+    u32 pin=rk2818_bl_info->pw_pin;
+    u32  brightness;
+    u8 lev;
+       brightness = rk2818_bl->props.brightness; 
+       brightness/=2;
+       div_total = read_pwm_reg(id, PWM_REG_LRC);   
+       if (rk2818_bl_info->bl_ref) {
+                       divh = div_total*(brightness)/BL_STEP;
+       } else {
+                       divh = div_total*(BL_STEP-brightness)/BL_STEP;
+       }
+       write_pwm_reg(id, PWM_REG_HRC, divh);
+       //printk("divh=%d\n",divh);
+        mdelay(100);
+       brightness/=2;
+       if (rk2818_bl_info->bl_ref) {
+       divh = div_total*(brightness)/BL_STEP;
+       } else {
+       divh = div_total*(BL_STEP-brightness)/BL_STEP;
+       }
+       //printk("------------rk28_backlight_shutdown  mdelay----------------------------\n");
+       write_pwm_reg(id, PWM_REG_HRC, divh); 
+    mdelay(100);
+       /*set  PF1=1 PF2=1 for close backlight*/        
+
+    if(rk2818_bl_info->bl_ref) {
+        lev = GPIO_LOW;
+    } else {
+        lev = GPIO_HIGH;
+    }
+    gpio_set_value(pin, lev);
+  
+}
+
+static struct platform_driver rk2818_backlight_driver = {
+       .probe  = rk2818_backlight_probe,
+       .remove = rk2818_backlight_remove,
+       .driver = {
+               .name   = "rk2818_backlight",
+               .owner  = THIS_MODULE,
+       },
+       .shutdown=rk2818_backlight_shutdown,
+};
+
+
+static int __init rk2818_backlight_init(void)
+{
+       DBG("%s::========================================\n",__func__);
+       platform_driver_register(&rk2818_backlight_driver);
+       return 0;
+}
+rootfs_initcall(rk2818_backlight_init);
+
+//late_initcall(rk28_backlight_init);
+//module_init(rk28_backlight_init);