ktd2801背光控制器支持两种调光方式:
1. 可通过控制引脚输入一组脉冲信号作为控制命令,来确定一个输出强度。
2. 同时也支持在该控制引脚输入一个持续的PWM脉冲来确定一个输出强度。
后者等同于其他类型的PWM调光控制方式:背光打开时必须要有一个持续的PWM输入信号;通过调整PWM的占空比来调整背光亮度。这种方式下的持续的PWM信号据说会造成其他设备的信号干扰。而ktd2801的第一种调光方式可解决这个问题。
在第一种调光方式中,只有亮度调整时才会向控制引脚输入一组脉冲作为控制命令,当ktd2801接到这个命令后便会改变背光强度。此后该控制引脚不需要维持脉冲信号。
通常,在该方式下,AP侧会用一个gpio引脚连接到ktd2801的控制端。软件会对该gpio进行输出高、低的操作来模拟出一组脉冲信号作为控制命令。命令协议很简单,可参考ktd2801的datasheet。
工作中出现的问题是:软件对该gpio进行输出高、底的操作时会出现偶尔的脉冲宽度不一致。也就是偶尔出现脉冲宽度比我们期望的要大很多,这会导致ktd2801解析出现错误,表现为对该命令不响应。
分析:
1. 首先必须明确,用gpio模拟一个信号时,维持高低电平的时间必须忙等,也就是必须用udelay之类的函数,绝对不能用msleep。这个原因很浅显。
2. 其次每个命令周期必须用自旋锁包裹起来,不能被打断。否则就会出现延时比你期望的要长,导致命令错误。
先前的代码对2使用的是:
spin_lock(&bl_ctrl_lock);
spin_unlock(&bl_ctrl_lock);
用了这个锁后,还是出现了延时比期望的要长,可能是有中断发生导致的。
因此,换为下面的锁,该锁会屏蔽中断,问题解决!
spin_lock_irqsave(&bl_ctrl_lock, flags);
spin_unlock_irqrestore(&bl_ctrl_lock, flags);
======================附上源码:修改前================================
/*************** maintained by customer ***************************************/ #define CONFIG_BACKLIGHT_AMAZING 1 /* * linux/drivers/video/backlight/s2c_bl.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /******************************************************************************* * Copyright 2010 Broadcom Corporation. All rights reserved. * * @file drivers/video/backlight/s2c_bl.c * * Unless you and Broadcom execute a separate written software license agreement * governing use of this software, this software is licensed to you under the * terms of the GNU General Public License version 2, available at * http://www.gnu.org/copyleft/gpl.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. *******************************************************************************/ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/fb.h> #include <linux/backlight.h> #include <linux/err.h> #include <linux/ktd2801_bl.h> #include <mach/gpio.h> #include <linux/delay.h> #include <linux/spinlock.h> #ifdef CONFIG_EARLYSUSPEND #include <linux/earlysuspend.h> #endif static DEFINE_SPINLOCK(bl_ctrl_lock); #define BACKLIGHT_DEBUG 1 #if BACKLIGHT_DEBUG #define BLDBG(fmt, args...) printk(fmt, ## args) #else #define BLDBG(fmt, args...) #endif #define EXPRESSWIRE_DIMMING #ifdef EXPRESSWIRE_DIMMING #define EW_DELAY 200 #define EW_DETECT 300 #define EW_WINDOW 900 #define DATA_START 40 #define LOW_BIT_L 40 #define LOW_BIT_H 10 #define HIGH_BIT_L 10 #define HIGH_BIT_H 40 #define END_DATA_L 10 #define END_DATA_H 400 #endif #define BACKLIGHT_DEV_NAME "sprd_backlight" int BL_brightness; int is_poweron = 1; int current_brightness; int wakeup_brightness; #ifdef CONFIG_MACH_NEVISTD #define GPIO_BL_CTRL 138 #else #define GPIO_BL_CTRL 190 #endif #ifdef CONFIG_MACH_NEVISTD #define MAX_BRIGHTNESS 255 #define MIN_BRIGHTNESS 20 #define DEFAULT_BRIGHTNESS 130 #define DEFAULT_PULSE 20 #define DIMMING_VALUE 31 #define MAX_BRIGHTNESS_IN_BLU 32 // backlight-IC MAX VALUE #else #define MAX_BRIGHTNESS 255 #define MIN_BRIGHTNESS 20 #define DEFAULT_BRIGHTNESS 122 #define DEFAULT_PULSE 20 #define DIMMING_VALUE 31 #define MAX_BRIGHTNESS_IN_BLU 32 // backlight-IC MAX VALUE #endif static int lcd_brightness = DEFAULT_PULSE; struct brt_value{ int level; // Platform setting values int tune_level; // Chip Setting values }; #ifdef CONFIG_HAS_EARLYSUSPEND struct early_suspend early_suspend_BL; #endif struct brt_value brt_table_ktd[] = { { 255, 0 }, /* Max */ { 250, 2 }, { 245, 3 }, { 240, 4 }, { 235, 5 }, { 230, 6 }, { 220, 7 }, { 210, 8 }, { 200, 9 }, { 190, 10 }, { 180, 11 }, { 170, 12 }, { 160, 13 }, { 150, 14 }, { 140, 15 }, { 130, 16 }, { 120, 17 }, /* default */ { 115, 18 }, { 110, 19 }, { 105, 20 }, { 100, 21 }, { 95, 22 }, { 90, 23 }, { 85, 24 }, { 80, 25 }, { 70, 26 }, /* Dimming */ { 60, 27 }, { 50, 28 }, { 40, 29 }, { 30, 30 }, { 20, 31 }, { 0, 31 }, /* Off */ }; #define NB_BRT_LEVEL (int)(sizeof(brt_table_ktd)/sizeof(struct brt_value)) #if defined(CONFIG_FB_SC8825) && defined(CONFIG_FB_LCD_NT35510_MIPI) extern bool is_first_frame_done; #endif #ifdef CONFIG_MACH_NEVISTD extern int spa_lpm_charging_mode_get(void); #endif #ifdef CONFIG_EARLYSUSPEND static void ktd253_backlight_early_suspend(struct early_suspend *h) { is_poweron = 0; ktd_backlight_set_brightness(0); #ifdef EXPRESSWIRE_DIMMING gpio_set_value(GPIO_BL_CTRL, 0); #endif return; } static void ktd253_backlight_late_resume(struct early_suspend *h) { int i = 0; #if defined(CONFIG_FB_SC8825) && defined(CONFIG_FB_LCD_NT35510_MIPI) while (i++ < 10 && !is_first_frame_done) { printk(KERN_INFO "[Backlight] wait first vsync_done, sleep 200msec\n", __func__); msleep(200); } #endif #ifdef EXPRESSWIRE_DIMMING spin_lock(&bl_ctrl_lock); gpio_set_value(GPIO_BL_CTRL, 1); udelay(200); gpio_set_value(GPIO_BL_CTRL, 0); udelay(300); gpio_set_value(GPIO_BL_CTRL, 1); udelay(400); spin_unlock(&bl_ctrl_lock); #endif ktd_backlight_set_brightness(wakeup_brightness); is_poweron = 1; } #endif #ifdef EXPRESSWIRE_DIMMING void ktd_backlight_set_brightness(int level) { int i = 0; unsigned char brightness; int bit_map[8]; brightness = level; printk("set_brightness : level(%d)\n", brightness); for(i = 0; i < 8; i++) { bit_map[i] = brightness & 0x01; brightness >>= 1; } spin_lock(&bl_ctrl_lock); #if 0 gpio_set_value(GPIO_BL_CTRL, 0); msleep(10); gpio_set_value(GPIO_BL_CTRL, 1); udelay(200); gpio_set_value(GPIO_BL_CTRL, 0); udelay(300); gpio_set_value(GPIO_BL_CTRL, 1); udelay(400); #endif gpio_set_value(GPIO_BL_CTRL, 1); udelay(DATA_START); for(i = 7; i >= 0; i--) { if(bit_map[i]) { gpio_set_value(GPIO_BL_CTRL, 0); udelay(HIGH_BIT_L); gpio_set_value(GPIO_BL_CTRL, 1); udelay(HIGH_BIT_H); } else { gpio_set_value(GPIO_BL_CTRL, 0); udelay(LOW_BIT_L); gpio_set_value(GPIO_BL_CTRL, 1); udelay(LOW_BIT_H); } } gpio_set_value(GPIO_BL_CTRL, 0); udelay(END_DATA_L); gpio_set_value(GPIO_BL_CTRL, 1); udelay(END_DATA_H); spin_unlock(&bl_ctrl_lock); return; } #else void ktd_backlight_set_brightness(int level) { int tune_level = 0; spin_lock(&bl_ctrl_lock); if (level > 0) { if (level < MIN_BRIGHTNESS) { tune_level = DIMMING_VALUE; /* DIMMING */ } else { int i; for (i = 0; i < NB_BRT_LEVEL; i++) { if (level <= brt_table_ktd[i].level && level > brt_table_ktd[i+1].level) { tune_level = brt_table_ktd[i].tune_level; break; } } } } /* BACKLIGHT is KTD model */ printk("set_brightness : level(%d) tune (%d)\n",level, tune_level); current_brightness = level; if (!level) { gpio_set_value(GPIO_BL_CTRL, 0); mdelay(3); lcd_brightness = tune_level; } else { int pulse; if (unlikely(lcd_brightness < 0)) { int val = gpio_get_value(GPIO_BL_CTRL); if (val) { lcd_brightness = 0; gpio_set_value(GPIO_BL_CTRL, 0); mdelay(3); printk(KERN_INFO "LCD Baklight init in boot time on kernel\n"); } } #ifdef CONFIG_MACH_NEVISTD if(spa_lpm_charging_mode_get()) msleep(500); #endif if (!lcd_brightness) { gpio_set_value(GPIO_BL_CTRL, 1); udelay(3); lcd_brightness = MAX_BRIGHTNESS_IN_BLU; } pulse = (tune_level - lcd_brightness + MAX_BRIGHTNESS_IN_BLU) % MAX_BRIGHTNESS_IN_BLU; for (; pulse > 0; pulse--) { gpio_set_value(GPIO_BL_CTRL, 0); udelay(3); gpio_set_value(GPIO_BL_CTRL, 1); udelay(3); } lcd_brightness = tune_level; } mdelay(1); spin_unlock(&bl_ctrl_lock); return; } #endif static int ktd_backlight_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; if (bl->props.fb_blank != FB_BLANK_UNBLANK) brightness = 0; wakeup_brightness = brightness; if (is_poweron == 1) ktd_backlight_set_brightness(brightness); else BLDBG("[BACKLIGHT] warning : ignore set brightness\n"); return 0; } static int ktd_backlight_get_brightness(struct backlight_device *bl) { BLDBG("[BACKLIGHT] ktd_backlight_get_brightness\n"); BL_brightness = bl->props.brightness; return BL_brightness; } static const struct backlight_ops ktd_backlight_ops = { .update_status = ktd_backlight_update_status, .get_brightness = ktd_backlight_get_brightness, }; static int ktd_backlight_probe(struct platform_device *pdev) { // struct platform_ktd253b_backlight_data *data = pdev->dev.platform_data; struct backlight_device *bl; struct backlight_properties props; printk("[BACKLIGHT] ktd253b_backlight_probe\n"); memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = MAX_BRIGHTNESS; props.type = BACKLIGHT_RAW; bl = backlight_device_register(BACKLIGHT_DEV_NAME, &pdev->dev, NULL, &ktd_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); } bl->props.max_brightness = MAX_BRIGHTNESS; bl->props.brightness = DEFAULT_BRIGHTNESS; platform_set_drvdata(pdev, bl); if(gpio_request(GPIO_BL_CTRL,"BL_CTRL")) printk(KERN_ERR "Request GPIO failed,""gpio: %d \n", GPIO_BL_CTRL); #ifdef EXPRESSWIRE_DIMMING spin_lock(&bl_ctrl_lock); gpio_set_value(GPIO_BL_CTRL, 0); udelay(1500); udelay(1500); gpio_set_value(GPIO_BL_CTRL, 1); udelay(200); gpio_set_value(GPIO_BL_CTRL, 0); udelay(300); gpio_set_value(GPIO_BL_CTRL, 1); udelay(400); spin_unlock(&bl_ctrl_lock); #endif #ifdef CONFIG_HAS_EARLYSUSPEND early_suspend_BL.suspend = ktd253_backlight_early_suspend; early_suspend_BL.resume = ktd253_backlight_late_resume; early_suspend_BL.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; register_early_suspend(&early_suspend_BL); #endif ktd_backlight_update_status(bl); return 0; out: return 1; } static int ktd_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); backlight_device_unregister(bl); gpio_direction_output(GPIO_BL_CTRL, 0); mdelay(3); return 0; } void ktd_backlight_shutdown(struct platform_device *pdev) { printk("[coko] %s\n",__FUNCTION__); gpio_direction_output(GPIO_BL_CTRL, 0); mdelay(5); } static struct platform_driver ktd_backlight_driver = { .driver = { .name = BACKLIGHT_DEV_NAME, .owner = THIS_MODULE, }, .probe = ktd_backlight_probe, .remove = ktd_backlight_remove, .shutdown = ktd_backlight_shutdown, }; static int __init ktd_backlight_init(void) { return platform_driver_register(&ktd_backlight_driver); } module_init(ktd_backlight_init); static void __exit ktd_backlight_exit(void) { platform_driver_unregister(&ktd_backlight_driver); } module_exit(ktd_backlight_exit); MODULE_DESCRIPTION("KTD based Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ktd-backlight");
======================附上源码:修改后================================
/*************** maintained by customer ***************************************/ #define CONFIG_BACKLIGHT_AMAZING 1 /* * linux/drivers/video/backlight/s2c_bl.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /******************************************************************************* * Copyright 2010 Broadcom Corporation. All rights reserved. * * @file drivers/video/backlight/s2c_bl.c * * Unless you and Broadcom execute a separate written software license agreement * governing use of this software, this software is licensed to you under the * terms of the GNU General Public License version 2, available at * http://www.gnu.org/copyleft/gpl.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. *******************************************************************************/ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/fb.h> #include <linux/backlight.h> #include <linux/err.h> #include <linux/ktd2801_bl.h> #include <mach/gpio.h> #include <linux/delay.h> #include <linux/spinlock.h> #ifdef CONFIG_EARLYSUSPEND #include <linux/earlysuspend.h> #endif static DEFINE_SPINLOCK(bl_ctrl_lock); #define BACKLIGHT_DEBUG 1 #if BACKLIGHT_DEBUG #define BLDBG(fmt, args...) printk(fmt, ## args) #else #define BLDBG(fmt, args...) #endif #define EXPRESSWIRE_DIMMING #ifdef EXPRESSWIRE_DIMMING #define EW_DELAY 200 #define EW_DETECT 300 #define EW_WINDOW 900 #define DATA_START 10 #define LOW_BIT_L 15 #define LOW_BIT_H 5 #define HIGH_BIT_L 5 #define HIGH_BIT_H 15 #define END_DATA_L 10 #define END_DATA_H 400 #endif #define BACKLIGHT_DEV_NAME "sprd_backlight" int BL_brightness; int is_poweron = 1; int current_brightness; int wakeup_brightness; #ifdef CONFIG_MACH_NEVISTD #define GPIO_BL_CTRL 138 #else #define GPIO_BL_CTRL 190 #endif #ifdef CONFIG_MACH_NEVISTD #define MAX_BRIGHTNESS 255 #define MIN_BRIGHTNESS 20 #define DEFAULT_BRIGHTNESS 130 #define DEFAULT_PULSE 20 #define DIMMING_VALUE 31 #define MAX_BRIGHTNESS_IN_BLU 32 // backlight-IC MAX VALUE #else #define MAX_BRIGHTNESS 255 #define MIN_BRIGHTNESS 20 #define DEFAULT_BRIGHTNESS 122 #define DEFAULT_PULSE 20 #define DIMMING_VALUE 31 #define MAX_BRIGHTNESS_IN_BLU 32 // backlight-IC MAX VALUE #endif static int lcd_brightness = DEFAULT_PULSE; struct brt_value{ int level; // Platform setting values int tune_level; // Chip Setting values }; #ifdef CONFIG_HAS_EARLYSUSPEND struct early_suspend early_suspend_BL; #endif struct brt_value brt_table_ktd[] = { { 255, 0 }, /* Max */ { 250, 2 }, { 245, 3 }, { 240, 4 }, { 235, 5 }, { 230, 6 }, { 220, 7 }, { 210, 8 }, { 200, 9 }, { 190, 10 }, { 180, 11 }, { 170, 12 }, { 160, 13 }, { 150, 14 }, { 140, 15 }, { 130, 16 }, { 120, 17 }, /* default */ { 115, 18 }, { 110, 19 }, { 105, 20 }, { 100, 21 }, { 95, 22 }, { 90, 23 }, { 85, 24 }, { 80, 25 }, { 70, 26 }, /* Dimming */ { 60, 27 }, { 50, 28 }, { 40, 29 }, { 30, 30 }, { 20, 31 }, { 0, 31 }, /* Off */ }; #define NB_BRT_LEVEL (int)(sizeof(brt_table_ktd)/sizeof(struct brt_value)) #if defined(CONFIG_FB_SC8825) && defined(CONFIG_FB_LCD_NT35510_MIPI) extern bool is_first_frame_done; #endif #ifdef CONFIG_MACH_NEVISTD extern int spa_lpm_charging_mode_get(void); #endif #ifdef CONFIG_EARLYSUSPEND static void ktd253_backlight_early_suspend(struct early_suspend *h) { is_poweron = 0; ktd_backlight_set_brightness(0); #ifdef EXPRESSWIRE_DIMMING gpio_set_value(GPIO_BL_CTRL, 0); #endif return; } static void ktd253_backlight_late_resume(struct early_suspend *h) { int i = 0; unsigned long flags; #if defined(CONFIG_FB_SC8825) && defined(CONFIG_FB_LCD_NT35510_MIPI) while (i++ < 10 && !is_first_frame_done) { printk(KERN_INFO "[Backlight] wait first vsync_done, sleep 200msec\n", __func__); msleep(200); } #endif #ifdef EXPRESSWIRE_DIMMING //spin_lock(&bl_ctrl_lock); spin_lock_irqsave(&bl_ctrl_lock, flags); gpio_set_value(GPIO_BL_CTRL, 1); udelay(200); gpio_set_value(GPIO_BL_CTRL, 0); udelay(300); gpio_set_value(GPIO_BL_CTRL, 1); udelay(400); //spin_unlock(&bl_ctrl_lock); spin_unlock_irqrestore(&bl_ctrl_lock, flags); #endif ktd_backlight_set_brightness(wakeup_brightness); is_poweron = 1; } #endif #ifdef EXPRESSWIRE_DIMMING void ktd_backlight_set_brightness(int level) { int i = 0; unsigned char brightness; int bit_map[8]; brightness = level; unsigned long flags; printk("set_brightness : level(%d)\n", brightness); for(i = 0; i < 8; i++) { bit_map[i] = brightness & 0x01; brightness >>= 1; } //spin_lock(&bl_ctrl_lock); spin_lock_irqsave(&bl_ctrl_lock, flags); #if 0 gpio_set_value(GPIO_BL_CTRL, 0); msleep(10); gpio_set_value(GPIO_BL_CTRL, 1); udelay(200); gpio_set_value(GPIO_BL_CTRL, 0); udelay(300); gpio_set_value(GPIO_BL_CTRL, 1); udelay(400); #endif gpio_set_value(GPIO_BL_CTRL, 1); udelay(DATA_START); for(i = 7; i >= 0; i--) { if(bit_map[i]) { gpio_set_value(GPIO_BL_CTRL, 0); udelay(HIGH_BIT_L); gpio_set_value(GPIO_BL_CTRL, 1); udelay(HIGH_BIT_H); } else { gpio_set_value(GPIO_BL_CTRL, 0); udelay(LOW_BIT_L); gpio_set_value(GPIO_BL_CTRL, 1); udelay(LOW_BIT_H); } } gpio_set_value(GPIO_BL_CTRL, 0); udelay(END_DATA_L); gpio_set_value(GPIO_BL_CTRL, 1); udelay(END_DATA_H); //spin_unlock(&bl_ctrl_lock); spin_unlock_irqrestore(&bl_ctrl_lock, flags); return; } #else void ktd_backlight_set_brightness(int level) { int tune_level = 0; spin_lock(&bl_ctrl_lock); if (level > 0) { if (level < MIN_BRIGHTNESS) { tune_level = DIMMING_VALUE; /* DIMMING */ } else { int i; for (i = 0; i < NB_BRT_LEVEL; i++) { if (level <= brt_table_ktd[i].level && level > brt_table_ktd[i+1].level) { tune_level = brt_table_ktd[i].tune_level; break; } } } } /* BACKLIGHT is KTD model */ printk("set_brightness : level(%d) tune (%d)\n",level, tune_level); current_brightness = level; if (!level) { gpio_set_value(GPIO_BL_CTRL, 0); mdelay(3); lcd_brightness = tune_level; } else { int pulse; if (unlikely(lcd_brightness < 0)) { int val = gpio_get_value(GPIO_BL_CTRL); if (val) { lcd_brightness = 0; gpio_set_value(GPIO_BL_CTRL, 0); mdelay(3); printk(KERN_INFO "LCD Baklight init in boot time on kernel\n"); } } #ifdef CONFIG_MACH_NEVISTD if(spa_lpm_charging_mode_get()) msleep(500); #endif if (!lcd_brightness) { gpio_set_value(GPIO_BL_CTRL, 1); udelay(3); lcd_brightness = MAX_BRIGHTNESS_IN_BLU; } pulse = (tune_level - lcd_brightness + MAX_BRIGHTNESS_IN_BLU) % MAX_BRIGHTNESS_IN_BLU; for (; pulse > 0; pulse--) { gpio_set_value(GPIO_BL_CTRL, 0); udelay(3); gpio_set_value(GPIO_BL_CTRL, 1); udelay(3); } lcd_brightness = tune_level; } mdelay(1); spin_unlock(&bl_ctrl_lock); return; } #endif static int ktd_backlight_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; if (bl->props.fb_blank != FB_BLANK_UNBLANK) brightness = 0; wakeup_brightness = brightness; if (is_poweron == 1) ktd_backlight_set_brightness(brightness); else BLDBG("[BACKLIGHT] warning : ignore set brightness\n"); return 0; } static int ktd_backlight_get_brightness(struct backlight_device *bl) { BLDBG("[BACKLIGHT] ktd_backlight_get_brightness\n"); BL_brightness = bl->props.brightness; return BL_brightness; } static const struct backlight_ops ktd_backlight_ops = { .update_status = ktd_backlight_update_status, .get_brightness = ktd_backlight_get_brightness, }; static int ktd_backlight_probe(struct platform_device *pdev) { // struct platform_ktd253b_backlight_data *data = pdev->dev.platform_data; struct backlight_device *bl; struct backlight_properties props; unsigned long flags; printk("[BACKLIGHT] ktd253b_backlight_probe\n"); memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = MAX_BRIGHTNESS; props.type = BACKLIGHT_RAW; bl = backlight_device_register(BACKLIGHT_DEV_NAME, &pdev->dev, NULL, &ktd_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); } bl->props.max_brightness = MAX_BRIGHTNESS; bl->props.brightness = DEFAULT_BRIGHTNESS; platform_set_drvdata(pdev, bl); if(gpio_request(GPIO_BL_CTRL,"BL_CTRL")) printk(KERN_ERR "Request GPIO failed,""gpio: %d \n", GPIO_BL_CTRL); #ifdef EXPRESSWIRE_DIMMING //spin_lock(&bl_ctrl_lock); spin_lock_irqsave(&bl_ctrl_lock, flags); gpio_set_value(GPIO_BL_CTRL, 0); udelay(1500); udelay(1500); gpio_set_value(GPIO_BL_CTRL, 1); udelay(200); gpio_set_value(GPIO_BL_CTRL, 0); udelay(300); gpio_set_value(GPIO_BL_CTRL, 1); udelay(400); //spin_unlock(&bl_ctrl_lock); spin_unlock_irqrestore(&bl_ctrl_lock, flags); #endif #ifdef CONFIG_HAS_EARLYSUSPEND early_suspend_BL.suspend = ktd253_backlight_early_suspend; early_suspend_BL.resume = ktd253_backlight_late_resume; early_suspend_BL.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; register_early_suspend(&early_suspend_BL); #endif ktd_backlight_update_status(bl); return 0; out: return 1; } static int ktd_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); backlight_device_unregister(bl); gpio_direction_output(GPIO_BL_CTRL, 0); mdelay(3); return 0; } void ktd_backlight_shutdown(struct platform_device *pdev) { printk("[coko] %s\n",__FUNCTION__); gpio_direction_output(GPIO_BL_CTRL, 0); mdelay(5); } static struct platform_driver ktd_backlight_driver = { .driver = { .name = BACKLIGHT_DEV_NAME, .owner = THIS_MODULE, }, .probe = ktd_backlight_probe, .remove = ktd_backlight_remove, .shutdown = ktd_backlight_shutdown, }; static int __init ktd_backlight_init(void) { return platform_driver_register(&ktd_backlight_driver); } module_init(ktd_backlight_init); static void __exit ktd_backlight_exit(void) { platform_driver_unregister(&ktd_backlight_driver); } module_exit(ktd_backlight_exit); MODULE_DESCRIPTION("KTD based Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ktd-backlight");