diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/video/backlight/wmt_bl.c')
-rwxr-xr-x | ANDROID_3.4.5/drivers/video/backlight/wmt_bl.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/video/backlight/wmt_bl.c b/ANDROID_3.4.5/drivers/video/backlight/wmt_bl.c new file mode 100755 index 00000000..97087216 --- /dev/null +++ b/ANDROID_3.4.5/drivers/video/backlight/wmt_bl.c @@ -0,0 +1,191 @@ +/* + * for backlight control on wmt platform, base on pwm_bl.c + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/pwm_backlight.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/leds.h> + +#include <mach/wmt_env.h> +#include "wmt_bl.h" + +#define LTH_BRIGHTNESS 0 +#define DFT_BRIGHTNESS 180 +#define DFT_PWM0_FREQ 4 /* kHz */ + +static struct { + int gpio; + int active; +} power = { -1, 0, }; + +static int backlight_delay = 0; + +static struct led_trigger *logo_led; +static BLOCKING_NOTIFIER_HEAD(bl_chain_head); + +int register_bl_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&bl_chain_head, nb); +} +EXPORT_SYMBOL_GPL(register_bl_notifier); + +int unregister_bl_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&bl_chain_head, nb); +} +EXPORT_SYMBOL_GPL(unregister_bl_notifier); + +static inline int bl_notifier_call_chain(unsigned long val) +{ + int ret = blocking_notifier_call_chain(&bl_chain_head, val, NULL); + return notifier_to_errno(ret); +} + +static void backlight_on(bool on) +{ + static int old_state = -1; + + if (!gpio_is_valid(power.gpio)) + return; + + if (old_state != on) { + if (old_state == false) { + /* delay 100 ms between 'lcd power on' and 'backlight + * power on' at resume sequence. */ + msleep(100); + /* wmt.backlight.delay */ + msleep(backlight_delay); + } + gpio_direction_output(power.gpio, on ? power.active : !power.active); + led_trigger_event(logo_led, on ? LED_FULL : LED_OFF); + + if (!on) { + /* + * delay 100 ms between 'backlight power off' and 'lcd power off' + * at suspend sequence to avoid to lcd flicker + */ + msleep(100); + } + + old_state = on; + bl_notifier_call_chain(on ? BL_OPEN : BL_CLOSE); + } +} + +static int wmt_bl_notify(struct device *dev, int brightness) +{ + return brightness; +} + +static void wmt_bl_notify_after(struct device *dev, int brightness) +{ + backlight_on(brightness != 0); +} + +#define KHZ2PICOS(hz) (1000000000/(hz)) +static struct platform_pwm_backlight_data wm8880_pwmbl_data = { + .pwm_id = 0, + .invert = 1, + .lth_brightness = LTH_BRIGHTNESS, /* low threshold */ + .hth_brightness = 256, /* high threshold */ + .max_brightness = 256, + .dft_brightness = DFT_BRIGHTNESS, + .pwm_period_ns = KHZ2PICOS(DFT_PWM0_FREQ*1000), /* revisit when clocks are implemented */ + .notify = wmt_bl_notify, + .notify_after = wmt_bl_notify_after, +}; + +struct platform_device wm8880_device_pwmbl = { + .name = "pwm-backlight", + .id = 0, + .dev = { + .platform_data = &wm8880_pwmbl_data, + }, +}; + +static int parse_backlight_param(void) +{ + static char env[] = "wmt.backlight.param"; + struct platform_pwm_backlight_data *pdata = &wm8880_pwmbl_data; + uint8_t buf[64]; + size_t l = sizeof(buf); + int pwm_freq = DFT_PWM0_FREQ; + int rc; + + if (wmt_getsyspara(env, buf, &l)) { + pr_err("please set %s\n", env); + return -EINVAL; + } + + /* wmt.backlight.param + * <pwmid>:<invert>:<gpio>:<active>: + * <lth_brightness>:<hth_brightness>:<pwm0freq>:<dft_brightness> + */ + rc = sscanf(buf, "%d:%d:%d:%d:%d:%d:%d:%d", + &pdata->pwm_id, + &pdata->invert, + &power.gpio, &power.active, + &pdata->lth_brightness, + &pdata->hth_brightness, + &pwm_freq, + &pdata->dft_brightness); + + if ((rc < 4)) { + pr_err("bad env %s %s\n", env, buf); + return -EINVAL; + } + if ((pdata->hth_brightness > pdata->max_brightness) || + (pdata->lth_brightness > pdata->hth_brightness)) + pdata->hth_brightness = pdata->max_brightness; + + pdata->pwm_period_ns = KHZ2PICOS(pwm_freq * 1000); + + pr_info("backlight param: pwm%d(%dkHz), invert %d, brightness %d(%d~%d) ", + pdata->pwm_id, pwm_freq, pdata->invert, pdata->dft_brightness, + pdata->lth_brightness, pdata->hth_brightness); + + if (gpio_is_valid(power.gpio)) { + if (gpio_request(power.gpio, "pwm_bl switch")) { + pr_warning("gpio request %d failed\n", power.gpio); + power.gpio = -1; + } + pr_info("gpio%d (active %d)\n", power.gpio, power.active); + } else + pr_info("no gpio control\n"); + + /* parse wmt.backlight.delay */ + l = sizeof(buf); + if (wmt_getsyspara("wmt.backlight.delay", buf, &l) == 0) { + sscanf(buf, "%d", &backlight_delay); + } + pr_info("backlight delay: %dms\n", backlight_delay); + + return 0; +} + +static int __init wmt_bl_init(void) +{ + int rc; + + rc = parse_backlight_param(); + if (rc) + return rc; + + led_trigger_register_simple("logoled", &logo_led); + + return platform_device_register(&wm8880_device_pwmbl); +} + +static void __exit wmt_bl_exit(void) +{ + led_trigger_unregister_simple(logo_led); + platform_device_unregister(&wm8880_device_pwmbl); +} + +module_init(wmt_bl_init); +module_exit(wmt_bl_exit); + |