diff options
Diffstat (limited to 'drivers/video/samsung_duallcd/mdnie.c')
-rw-r--r-- | drivers/video/samsung_duallcd/mdnie.c | 916 |
1 files changed, 916 insertions, 0 deletions
diff --git a/drivers/video/samsung_duallcd/mdnie.c b/drivers/video/samsung_duallcd/mdnie.c new file mode 100644 index 0000000..6ef64e8 --- /dev/null +++ b/drivers/video/samsung_duallcd/mdnie.c @@ -0,0 +1,916 @@ +/* linux/drivers/video/samsung/mdnie.c + * + * Register interface file for Samsung mDNIe driver + * + * Copyright (c) 2009 Samsung Electronics + * http://www.samsungsemi.com/ + * + * 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. +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/mm.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> +#include <linux/mdnie.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <mach/gpio.h> +#include <linux/delay.h> +#include <linux/lcd.h> + +#include "s3cfb.h" +#include "s3cfb_mdnie.h" + +#if defined(CONFIG_CPU_EXYNOS4210) +#if defined(CONFIG_FB_S5P_LD9040) || defined(CONFIG_FB_S5P_NT35560) +#include "mdnie_table_u1.h" +#elif defined(CONFIG_FB_S5P_S6E8AA0) +#include "mdnie_table_q1.h" +#elif defined(CONFIG_FB_S5P_S6E8AB0) +#include "mdnie_table_p8.h" +#elif defined(CONFIG_FB_S5P_S6F1202A) +#include "mdnie_table.h" +#include "mdnie_table_p2_boe.h" +#include "mdnie_table_p2_hydis.h" +#include "mdnie_table_p2_sec.h" +#elif defined(CONFIG_FB_S5P_S6C1372) +#include "mdnie_table_p4.h" +#endif +#include "mdnie_color_tone_4210.h" +#else /* CONFIG_CPU_EXYNOS4210 */ +#if defined(CONFIG_FB_S5P_S6E8AA0) +#include "mdnie_table_c1m0.h" +#elif defined(CONFIG_FB_S5P_S6E63M0) +#include "mdnie_table_c1m0.h" +#elif defined(CONFIG_FB_S5P_S6C1372) +#include "mdnie_table_p4note.h" +#elif defined(CONFIG_FB_S5P_S6D6AA1) +#include "mdnie_table_gc1.h" +#else +#include "mdnie_table_4412.h" +#endif +#include "mdnie_color_tone.h" /* sholud be added for 4212, 4412 */ +#endif + +#if defined(CONFIG_TDMB) || defined(CONFIG_TARGET_LOCALE_NTT) +#include "mdnie_dmb.h" +#endif + +#if defined(CONFIG_FB_MDNIE_PWM) +#define MIN_BRIGHTNESS 0 +#define DEFAULT_BRIGHTNESS 150 +#if defined(CONFIG_FB_S5P_S6F1202A) +#define MAX_BACKLIGHT_VALUE 1424 /* 1504(94%) -> 1424(89%) */ +#define MID_BACKLIGHT_VALUE 544 /* 784(49%) -> 544(34%) */ +#define LOW_BACKLIGHT_VALUE 16 +#define DIM_BACKLIGHT_VALUE 16 +#define CABC_CUTOFF_BACKLIGHT_VALUE 40 /* 2.5% */ +#elif defined(CONFIG_FB_S5P_S6C1372) +#define MAX_BACKLIGHT_VALUE 1441 //90% +#define MID_BACKLIGHT_VALUE 784 +#define LOW_BACKLIGHT_VALUE 16 +#define DIM_BACKLIGHT_VALUE 16 +#define CABC_CUTOFF_BACKLIGHT_VALUE 40 /* 2.5% */ +#endif +#define MAX_BRIGHTNESS_LEVEL 255 +#define MID_BRIGHTNESS_LEVEL 150 +#define LOW_BRIGHTNESS_LEVEL 30 +#define DIM_BRIGHTNESS_LEVEL 20 +#endif + +#define SCENARIO_IS_COLOR(scenario) \ + ((scenario >= COLOR_TONE_1) && (scenario < COLOR_TONE_MAX)) + +#if defined(CONFIG_TDMB) || defined(CONFIG_TARGET_LOCALE_NTT) +#define SCENARIO_IS_DMB(scenario) \ + ((scenario >= DMB_NORMAL_MODE) && (scenario < DMB_MODE_MAX)) +#define SCENARIO_IS_VALID(scenario) \ + ((SCENARIO_IS_COLOR(scenario)) || SCENARIO_IS_DMB(scenario) || \ + (scenario < SCENARIO_MAX)) +#else +#define SCENARIO_IS_VALID(scenario) \ + ((SCENARIO_IS_COLOR(scenario)) || (scenario < SCENARIO_MAX)) +#endif + +static char tuning_file_name[50]; + +struct class *mdnie_class; + +struct mdnie_info *g_mdnie; + +#ifdef CONFIG_MACH_P4NOTE +static struct mdnie_backlight_value b_value; +#endif + +int mdnie_send_sequence(struct mdnie_info *mdnie, const unsigned short *seq) +{ + int ret = 0, i = 0; + const unsigned short *wbuf; + + if (IS_ERR_OR_NULL(seq)) { + dev_err(mdnie->dev, "mdnie sequence is null\n"); + return -EPERM; + } + + mutex_lock(&mdnie->dev_lock); + + wbuf = seq; + + s3c_mdnie_mask(); + + while (wbuf[i] != END_SEQ) { + mdnie_write(wbuf[i], wbuf[i+1]); + i += 2; + } + + s3c_mdnie_unmask(); + + mutex_unlock(&mdnie->dev_lock); + + return ret; +} + +void set_mdnie_value(struct mdnie_info *mdnie, u8 force) +{ + u8 idx; + + if ((!mdnie->enable) && (!force)) { + dev_err(mdnie->dev, "mdnie states is off\n"); + return; + } + + if (mdnie->scenario == VIDEO_WARM_MODE) + mdnie->tone = TONE_WARM; + else if (mdnie->scenario == VIDEO_COLD_MODE) + mdnie->tone = TONE_COLD; + else + mdnie->tone = TONE_NORMAL; + + if (mdnie->tunning) { + dev_info(mdnie->dev, "mdnie tunning mode is enabled\n"); + return; + } + + mutex_lock(&mdnie->lock); + + if (mdnie->negative == NEGATIVE_ON) { + dev_info(mdnie->dev, "NEGATIVE_ON\n"); + mdnie_send_sequence(mdnie, tune_negative[mdnie->cabc].seq); + goto exit; + } + +#if defined(CONFIG_TDMB) || defined(CONFIG_TARGET_LOCALE_NTT) + if (SCENARIO_IS_DMB(mdnie->scenario)) { + idx = mdnie->scenario - DMB_NORMAL_MODE; + mdnie_send_sequence(mdnie, tune_dmb[mdnie->mode].seq); + dev_info(mdnie->dev, "mode=%d, scenario=%d, outdoor=%d, cabc=%d, %s\n", + mdnie->mode, mdnie->scenario, mdnie->outdoor, + mdnie->cabc, tune_dmb[mdnie->mode].name); + goto etc; + } +#endif + + if (SCENARIO_IS_COLOR(mdnie->scenario)) { + idx = mdnie->scenario - COLOR_TONE_1; + mdnie_send_sequence(mdnie, tune_color_tone[idx].seq); + dev_info(mdnie->dev, "mode=%d, scenario=%d, outdoor=%d, cabc=%d, %s\n", + mdnie->mode, mdnie->scenario, mdnie->outdoor, mdnie->cabc, + tune_color_tone[idx].name); + + goto exit; + } else if ((mdnie->scenario == CAMERA_MODE) && (mdnie->outdoor == OUTDOOR_OFF)) { + mdnie_send_sequence(mdnie, tune_camera); + dev_info(mdnie->dev, "%s\n", "CAMERA"); + + goto exit; + } else if ((mdnie->scenario == CAMERA_MODE) && (mdnie->outdoor == OUTDOOR_ON)) { + mdnie_send_sequence(mdnie, tune_camera_outdoor); + dev_info(mdnie->dev, "%s\n", "CAMERA_OUTDOOR"); + + goto exit; + } else { + mdnie_send_sequence(mdnie, tunning_table[mdnie->cabc][mdnie->mode][mdnie->scenario].seq); + dev_info(mdnie->dev, "mode=%d, scenario=%d, outdoor=%d, cabc=%d, %s\n", + mdnie->mode, mdnie->scenario, mdnie->outdoor, mdnie->cabc, + tunning_table[mdnie->cabc][mdnie->mode][mdnie->scenario].name); + } + +#if defined(CONFIG_TDMB) || defined(CONFIG_TARGET_LOCALE_NTT) +etc: +#endif + if (!IS_ERR_OR_NULL(etc_table[mdnie->cabc][mdnie->outdoor][mdnie->tone].seq)) { + mdnie_send_sequence(mdnie, etc_table[mdnie->cabc][mdnie->outdoor][mdnie->tone].seq); + dev_info(mdnie->dev, "%s\n", etc_table[mdnie->cabc][mdnie->outdoor][mdnie->tone].name); + } + +exit: + mutex_unlock(&mdnie->lock); + + return; +} + +#if defined(CONFIG_FB_MDNIE_PWM) +#ifdef CONFIG_MACH_P4NOTE +static int get_backlight_level_from_brightness(unsigned int brightness) +{ + unsigned int value; + + /* brightness tuning*/ + if (brightness >= MID_BRIGHTNESS_LEVEL) + value = (brightness - MID_BRIGHTNESS_LEVEL) * (b_value.max-b_value.mid) / (MAX_BRIGHTNESS_LEVEL-MID_BRIGHTNESS_LEVEL) + b_value.mid; + else if (brightness >= LOW_BRIGHTNESS_LEVEL) + value = (brightness - LOW_BRIGHTNESS_LEVEL) * (b_value.mid-b_value.low) / (MID_BRIGHTNESS_LEVEL-LOW_BRIGHTNESS_LEVEL) + b_value.low; + else if (brightness >= DIM_BRIGHTNESS_LEVEL) + value = (brightness - DIM_BRIGHTNESS_LEVEL) * (b_value.low-b_value.dim) / (LOW_BRIGHTNESS_LEVEL-DIM_BRIGHTNESS_LEVEL) + b_value.dim; + else if (brightness > 0) + value = b_value.dim; + else + return 0; + + if (value > 1600) + value = 1600; + + if (value < 16) + value = 1; + else + value = value >> 4; + + return value; +} +#else +static int get_backlight_level_from_brightness(unsigned int brightness) +{ + unsigned int value; + + /* brightness tuning*/ + if (brightness >= MID_BRIGHTNESS_LEVEL) + value = (brightness - MID_BRIGHTNESS_LEVEL) * (MAX_BACKLIGHT_VALUE-MID_BACKLIGHT_VALUE) / (MAX_BRIGHTNESS_LEVEL-MID_BRIGHTNESS_LEVEL) + MID_BACKLIGHT_VALUE; + else if (brightness >= LOW_BRIGHTNESS_LEVEL) + value = (brightness - LOW_BRIGHTNESS_LEVEL) * (MID_BACKLIGHT_VALUE-LOW_BACKLIGHT_VALUE) / (MID_BRIGHTNESS_LEVEL-LOW_BRIGHTNESS_LEVEL) + LOW_BACKLIGHT_VALUE; + else if (brightness >= DIM_BRIGHTNESS_LEVEL) + value = (brightness - DIM_BRIGHTNESS_LEVEL) * (LOW_BACKLIGHT_VALUE-DIM_BACKLIGHT_VALUE) / (LOW_BRIGHTNESS_LEVEL-DIM_BRIGHTNESS_LEVEL) + DIM_BACKLIGHT_VALUE; + else if (brightness > 0) + value = DIM_BACKLIGHT_VALUE; + else + return 0; + + if (value > 1600) + value = 1600; + + if (value < 16) + value = 1; + else + value = value >> 4; + + return value; +} +#endif + +#if defined(CONFIG_CPU_EXYNOS4210) +static void mdnie_pwm_control(struct mdnie_info *mdnie, int value) +{ + mutex_lock(&mdnie->dev_lock); + mdnie_write(0x00, 0x0000); + mdnie_write(0xB4, 0xC000 | value); + mdnie_write(0x28, 0x0000); + mutex_unlock(&mdnie->dev_lock); +} + +static void mdnie_pwm_control_cabc(struct mdnie_info *mdnie, int value) +{ + int reg; + const unsigned char *p_plut; + u16 min_duty; + unsigned idx; + + mutex_lock(&mdnie->dev_lock); + + idx = tunning_table[mdnie->cabc][mdnie->mode][mdnie->scenario].idx_lut; + p_plut = power_lut[idx]; + min_duty = p_plut[7] * value / 100; + + mdnie_write(0x00, 0x0000); + + if (min_duty < 4) + reg = 0xC000 | (max(1, (value * p_plut[3] / 100))); + else { + /*PowerLUT*/ + mdnie_write(0x76, (p_plut[0] * value / 100) << 8 | (p_plut[1] * value / 100)); + mdnie_write(0x77, (p_plut[2] * value / 100) << 8 | (p_plut[3] * value / 100)); + mdnie_write(0x78, (p_plut[4] * value / 100) << 8 | (p_plut[5] * value / 100)); + mdnie_write(0x79, (p_plut[6] * value / 100) << 8 | (p_plut[7] * value / 100)); + mdnie_write(0x7a, (p_plut[8] * value / 100) << 8); + + reg = 0x5000 | (value << 4); + } + + mdnie_write(0xB4, reg); + mdnie_write(0x28, 0x0000); + + mutex_unlock(&mdnie->dev_lock); +} +#elif defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) +static void mdnie_pwm_control(struct mdnie_info *mdnie, int value) +{ + mutex_lock(&mdnie->dev_lock); + mdnie_write(0x00, 0x0001); + mdnie_write(0xB6, 0xC000 | value); + mdnie_write(0xff, 0x0000); + mutex_unlock(&mdnie->dev_lock); +} + +static void mdnie_pwm_control_cabc(struct mdnie_info *mdnie, int value) +{ + int reg; + const unsigned char *p_plut; + u16 min_duty; + unsigned idx; + + mutex_lock(&mdnie->dev_lock); + + idx = tunning_table[mdnie->cabc][mdnie->mode][mdnie->scenario].idx_lut; + p_plut = power_lut[idx]; + min_duty = p_plut[7] * value / 100; + + mdnie_write(0x00, 0x0001); + + if (min_duty < 4) + reg = 0xC000 | (max(1, (value * p_plut[3] / 100))); + else { + /*PowerLUT*/ + mdnie_write(0x79, (p_plut[0] * value / 100) << 8 | (p_plut[1] * value / 100)); + mdnie_write(0x7a, (p_plut[2] * value / 100) << 8 | (p_plut[3] * value / 100)); + mdnie_write(0x7b, (p_plut[4] * value / 100) << 8 | (p_plut[5] * value / 100)); + mdnie_write(0x7c, (p_plut[6] * value / 100) << 8 | (p_plut[7] * value / 100)); + mdnie_write(0x7d, (p_plut[8] * value / 100) << 8); + + reg = 0x5000 | (value << 4); + } + + mdnie_write(0xB6, reg); + mdnie_write(0xff, 0x0000); + + mutex_unlock(&mdnie->dev_lock); +} +#endif + +void set_mdnie_pwm_value(struct mdnie_info *mdnie, int value) +{ + mdnie_pwm_control(mdnie, value); +} + +static int update_brightness(struct mdnie_info *mdnie) +{ + unsigned int value; + unsigned int brightness = mdnie->bd->props.brightness; + + value = get_backlight_level_from_brightness(brightness); + + if (!mdnie->enable) { + dev_err(mdnie->dev, "WTH! do not configure mDNIe after LCD/mDNIe power off\n"); + return 0; + } + if (brightness <= CABC_CUTOFF_BACKLIGHT_VALUE) { + mdnie_pwm_control(mdnie, value); + } else { + if ((mdnie->cabc) && (mdnie->scenario != CAMERA_MODE) && !(mdnie->tunning)) + mdnie_pwm_control_cabc(mdnie, value); + else + mdnie_pwm_control(mdnie, value); + } + return 0; +} + +static int mdnie_set_brightness(struct backlight_device *bd) +{ + struct mdnie_info *mdnie = bl_get_data(bd); + int ret = 0; + unsigned int brightness = bd->props.brightness; + + if (brightness < MIN_BRIGHTNESS || + brightness > bd->props.max_brightness) { + dev_err(&bd->dev, "lcd brightness should be %d to %d. now %d\n", + MIN_BRIGHTNESS, bd->props.max_brightness, brightness); + brightness = bd->props.max_brightness; + } + + if ((mdnie->enable) && (mdnie->bd_enable)) { + ret = update_brightness(mdnie); + dev_info(&bd->dev, "brightness=%d\n", bd->props.brightness); + if (ret < 0) + return -EINVAL; + } + + return ret; +} + +static int mdnie_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static const struct backlight_ops mdnie_backlight_ops = { + .get_brightness = mdnie_get_brightness, + .update_status = mdnie_set_brightness, +}; +#endif + +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", mdnie->mode); +} + +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = strict_strtoul(buf, 0, (unsigned long *)&value); + + dev_info(dev, "%s :: value=%d\n", __func__, value); + + if (value >= MODE_MAX) { + value = STANDARD; + return -EINVAL; + } + + mutex_lock(&mdnie->lock); + mdnie->mode = value; + mutex_unlock(&mdnie->lock); + + set_mdnie_value(mdnie, 0); +#if defined(CONFIG_FB_MDNIE_PWM) + if ((mdnie->enable) && (mdnie->bd_enable)) + update_brightness(mdnie); +#endif + + return count; +} + + +static ssize_t scenario_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", mdnie->scenario); +} + +static ssize_t scenario_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = strict_strtoul(buf, 0, (unsigned long *)&value); + + dev_info(dev, "%s :: value=%d\n", __func__, value); + + if (!SCENARIO_IS_VALID(value)) + value = UI_MODE; + +#if defined(CONFIG_FB_MDNIE_PWM) + if (value >= SCENARIO_MAX) + value = UI_MODE; +#endif + + mutex_lock(&mdnie->lock); + mdnie->scenario = value; + mutex_unlock(&mdnie->lock); + + set_mdnie_value(mdnie, 0); +#if defined(CONFIG_FB_MDNIE_PWM) + if ((mdnie->enable) && (mdnie->bd_enable)) + update_brightness(mdnie); +#endif + + return count; +} + + +static ssize_t outdoor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", mdnie->outdoor); +} + +static ssize_t outdoor_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = strict_strtoul(buf, 0, (unsigned long *)&value); + + dev_info(dev, "%s :: value=%d\n", __func__, value); + + if (value >= OUTDOOR_MAX) + value = OUTDOOR_OFF; + + value = (value) ? OUTDOOR_ON : OUTDOOR_OFF; + + mutex_lock(&mdnie->lock); + mdnie->outdoor = value; + mutex_unlock(&mdnie->lock); + + set_mdnie_value(mdnie, 0); + + return count; +} + + +#if defined(CONFIG_FB_MDNIE_PWM) +static ssize_t cabc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", mdnie->cabc); +} + +static ssize_t cabc_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = strict_strtoul(buf, 0, (unsigned long *)&value); + + dev_info(dev, "%s :: value=%d\n", __func__, value); + + if (value >= CABC_MAX) + value = CABC_OFF; + + value = (value) ? CABC_ON : CABC_OFF; + + mutex_lock(&mdnie->lock); + mdnie->cabc = value; + mutex_unlock(&mdnie->lock); + + set_mdnie_value(mdnie, 0); + if ((mdnie->enable) && (mdnie->bd_enable)) + update_brightness(mdnie); + + return count; +} +#endif + +static ssize_t tunning_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char temp[128]; + + sprintf(temp, "%s\n", tuning_file_name); + strcat(buf, temp); + + return strlen(buf); +} + +static ssize_t tunning_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + + if (!strncmp(buf, "0", 1)) { + mdnie->tunning = FALSE; + dev_info(dev, "%s :: tunning is disabled.\n", __func__); + } else if (!strncmp(buf, "1", 1)) { + mdnie->tunning = TRUE; + dev_info(dev, "%s :: tunning is enabled.\n", __func__); + } else { + if (!mdnie->tunning) + return count; + memset(tuning_file_name, 0, sizeof(tuning_file_name)); + strcpy(tuning_file_name, "/sdcard/mdnie/"); + strncat(tuning_file_name, buf, count-1); + + mdnie_txtbuf_to_parsing(tuning_file_name); + + dev_info(dev, "%s :: %s\n", __func__, tuning_file_name); + } + + return count; +} + +static ssize_t negative_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + char temp[3]; + + sprintf(temp, "%d\n", mdnie->negative); + strcpy(buf, temp); + + return strlen(buf); +} + +static ssize_t negative_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mdnie_info *mdnie = dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret = strict_strtoul(buf, 0, (unsigned long *)&value); + dev_info(dev, "%s :: value=%d\n", __func__, value); + + if (ret < 0) + return ret; + else { + if (mdnie->negative == value) + return count; + + if (value >= NEGATIVE_MAX) + value = NEGATIVE_OFF; + + value = (value) ? NEGATIVE_ON : NEGATIVE_OFF; + + mutex_lock(&mdnie->lock); + mdnie->negative = value; + mutex_unlock(&mdnie->lock); + + set_mdnie_value(mdnie, 0); + } + return count; +} + +static struct device_attribute mdnie_attributes[] = { + __ATTR(mode, 0664, mode_show, mode_store), + __ATTR(scenario, 0664, scenario_show, scenario_store), + __ATTR(outdoor, 0664, outdoor_show, outdoor_store), +#if defined(CONFIG_FB_MDNIE_PWM) + __ATTR(cabc, 0664, cabc_show, cabc_store), +#endif + __ATTR(tunning, 0664, tunning_show, tunning_store), + __ATTR(negative, 0664, negative_show, negative_store), + __ATTR_NULL, +}; + +#ifdef CONFIG_PM +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_FB_MDNIE_PWM) +void mdnie_early_suspend(struct early_suspend *h) +{ + struct mdnie_info *mdnie = container_of(h, struct mdnie_info, early_suspend); + struct lcd_platform_data *pd = NULL; + pd = mdnie->lcd_pd; + + dev_info(mdnie->dev, "+%s\n", __func__); + + mdnie->bd_enable = FALSE; + + if (mdnie->enable) + mdnie_pwm_control(mdnie, 0); + + if (!pd) + dev_info(&mdnie->bd->dev, "platform data is NULL.\n"); + + if (!pd->power_on) + dev_info(&mdnie->bd->dev, "power_on is NULL.\n"); + else + pd->power_on(NULL, 0); + + dev_info(mdnie->dev, "-%s\n", __func__); + + return ; +} + +void mdnie_late_resume(struct early_suspend *h) +{ + struct mdnie_info *mdnie = container_of(h, struct mdnie_info, early_suspend); + struct lcd_platform_data *pd = NULL; + + dev_info(mdnie->dev, "+%s\n", __func__); + pd = mdnie->lcd_pd; + + if (mdnie->enable) + mdnie_pwm_control(mdnie, 0); + + if (!pd) + dev_info(&mdnie->bd->dev, "platform data is NULL.\n"); + + if (!pd->power_on) + dev_info(&mdnie->bd->dev, "power_on is NULL.\n"); + else + pd->power_on(NULL, 1); + + if (mdnie->enable) { + dev_info(&mdnie->bd->dev, "brightness=%d\n", mdnie->bd->props.brightness); + update_brightness(mdnie); + } + + mdnie->bd_enable = TRUE; + dev_info(mdnie->dev, "-%s\n", __func__); + + return ; +} +#endif +#endif + +static int mdnie_probe(struct platform_device *pdev) +{ +#if defined(CONFIG_FB_MDNIE_PWM) + struct platform_mdnie_data *pdata = pdev->dev.platform_data; +#endif + struct mdnie_info *mdnie; + int ret = 0; + + mdnie_class = class_create(THIS_MODULE, dev_name(&pdev->dev)); + if (IS_ERR_OR_NULL(mdnie_class)) { + pr_err("failed to create mdnie class\n"); + ret = -EINVAL; + goto error0; + } + + mdnie_class->dev_attrs = mdnie_attributes; + + mdnie = kzalloc(sizeof(struct mdnie_info), GFP_KERNEL); + if (!mdnie) { + pr_err("failed to allocate mdnie\n"); + ret = -ENOMEM; + goto error1; + } + + mdnie->dev = device_create(mdnie_class, &pdev->dev, 0, &mdnie, "mdnie"); + if (IS_ERR_OR_NULL(mdnie->dev)) { + pr_err("failed to create mdnie device\n"); + ret = -EINVAL; + goto error2; + } + +#if defined(CONFIG_FB_MDNIE_PWM) + mdnie->bd = backlight_device_register("panel", mdnie->dev, + mdnie, &mdnie_backlight_ops, NULL); + mdnie->bd->props.max_brightness = MAX_BRIGHTNESS_LEVEL; + mdnie->bd->props.brightness = DEFAULT_BRIGHTNESS; + mdnie->bd_enable = TRUE; + mdnie->lcd_pd = pdata->lcd_pd; +#endif + + mdnie->scenario = UI_MODE; + mdnie->mode = STANDARD; + mdnie->tone = TONE_NORMAL; + mdnie->outdoor = OUTDOOR_OFF; +#if defined(CONFIG_FB_MDNIE_PWM) + mdnie->cabc = CABC_ON; +#else + mdnie->cabc = CABC_OFF; +#endif + mdnie->enable = TRUE; + mdnie->tunning = FALSE; + mdnie->negative = NEGATIVE_OFF; + + mutex_init(&mdnie->lock); + mutex_init(&mdnie->dev_lock); + + platform_set_drvdata(pdev, mdnie); + dev_set_drvdata(mdnie->dev, mdnie); + +#ifdef CONFIG_HAS_WAKELOCK +#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_FB_MDNIE_PWM) + mdnie->early_suspend.suspend = mdnie_early_suspend; + mdnie->early_suspend.resume = mdnie_late_resume; + mdnie->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + register_early_suspend(&mdnie->early_suspend); +#endif +#endif +#endif + +#if defined(CONFIG_FB_S5P_S6C1372) + check_lcd_type(); + dev_info(mdnie->dev, "lcdtype = %d\n", pdata->display_type); + if (pdata->display_type == 1) { + b_value.max = 1441; + b_value.mid = 784; + b_value.low = 16; + b_value.dim = 16; + } else { + b_value.max = 1216; /* 76% */ + b_value.mid = 679; /* 39% */ + b_value.low = 16; /* 1% */ + b_value.dim = 16; /* 1% */ + } +#endif + +#if defined(CONFIG_FB_S5P_S6F1202A) + if (pdata->display_type == 0) { + memcpy(tunning_table, tunning_table_hy, sizeof(tunning_table)); + memcpy(etc_table, etc_table_hy, sizeof(etc_table)); + tune_camera = tune_camera_hy; + tune_camera_outdoor = tune_camera_outdoor_hy; + } else if (pdata->display_type == 1) { + memcpy(tunning_table, tunning_table_sec, sizeof(tunning_table)); + memcpy(etc_table, etc_table_sec, sizeof(etc_table)); + tune_camera = tune_camera_sec; + tune_camera_outdoor = tune_camera_outdoor_sec; + } else if (pdata->display_type == 2) { + memcpy(tunning_table, tunning_table_bo, sizeof(tunning_table)); + memcpy(etc_table, etc_table_bo, sizeof(etc_table)); + tune_camera = tune_camera_bo; + tune_camera_outdoor = tune_camera_outdoor_bo; + } +#endif + + g_mdnie = mdnie; + + set_mdnie_value(mdnie, 0); + + dev_info(mdnie->dev, "registered successfully\n"); + + return 0; + +error2: + kfree(mdnie); +error1: + class_destroy(mdnie_class); +error0: + return ret; +} + +static int mdnie_remove(struct platform_device *pdev) +{ + struct mdnie_info *mdnie = dev_get_drvdata(&pdev->dev); + +#if defined(CONFIG_FB_MDNIE_PWM) + backlight_device_unregister(mdnie->bd); +#endif + class_destroy(mdnie_class); + kfree(mdnie); + + return 0; +} + +static void mdnie_shutdown(struct platform_device *pdev) +{ +#if defined(CONFIG_FB_MDNIE_PWM) + struct mdnie_info *mdnie = dev_get_drvdata(&pdev->dev); + struct lcd_platform_data *pd = NULL; + pd = mdnie->lcd_pd; + + dev_info(mdnie->dev, "+%s\n", __func__); + + mdnie->bd_enable = FALSE; + + if (mdnie->enable) + mdnie_pwm_control(mdnie, 0); + + if (!pd) + dev_info(&mdnie->bd->dev, "platform data is NULL.\n"); + + if (!pd->power_on) + dev_info(&mdnie->bd->dev, "power_on is NULL.\n"); + else + pd->power_on(NULL, 0); + + dev_info(mdnie->dev, "-%s\n", __func__); +#endif +} + + +static struct platform_driver mdnie_driver = { + .driver = { + .name = "mdnie", + .owner = THIS_MODULE, + }, + .probe = mdnie_probe, + .remove = mdnie_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = mdnie_suspend, + .resume = mdnie_resume, +#endif + .shutdown = mdnie_shutdown, +}; + +static int __init mdnie_init(void) +{ + return platform_driver_register(&mdnie_driver); +} +module_init(mdnie_init); + +static void __exit mdnie_exit(void) +{ + platform_driver_unregister(&mdnie_driver); +} +module_exit(mdnie_exit); + +MODULE_DESCRIPTION("mDNIe Driver"); +MODULE_LICENSE("GPL"); + |