From: 钟勇汪 Date: Tue, 18 May 2010 14:32:33 +0000 (+0000) Subject: add backlight X-Git-Tag: firefly_0821_release~11508 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b54180c799b5a64a2ba69e0665742437303900aa;p=firefly-linux-kernel-4.4.55.git add backlight --- diff --git a/.config b/.config index 52be336db86e..65ea64e1f0f6 100644 --- 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 diff --git a/arch/arm/mach-rk2818/board-midsdk.c b/arch/arm/mach-rk2818/board-midsdk.c index 1269251d2001..85cab9c90bc8 100644 --- a/arch/arm/mach-rk2818/board-midsdk.c +++ b/arch/arm/mach-rk2818/board-midsdk.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/arch/arm/mach-rk2818/devices.c b/arch/arm/mach-rk2818/devices.c index 6b7b49e8c819..f9ed143361a8 100644 --- a/arch/arm/mach-rk2818/devices.c +++ b/arch/arm/mach-rk2818/devices.c @@ -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[] = { diff --git a/arch/arm/mach-rk2818/devices.h b/arch/arm/mach-rk2818/devices.h index 22e8f6c9f549..1e4c78f559f1 100644 --- a/arch/arm/mach-rk2818/devices.h +++ b/arch/arm/mach-rk2818/devices.h @@ -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 index 000000000000..f139178d48ee --- /dev/null +++ b/arch/arm/mach-rk2818/include/mach/rk2818_backlight.h @@ -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 + +///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 */ diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 09bfa9662e4d..9061330841aa 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -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. diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 9a405548874c..1739ab2b389a 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -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 index 000000000000..55ec77bd361f --- /dev/null +++ b/drivers/video/backlight/rk2818_backlight.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ANDROID_POWER +#include +#endif +#include +//#include +#include +#include +#include +#include + +//#define RK28_PRINT +//#include + +/* + * 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);