aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/backlight
diff options
context:
space:
mode:
authorcodeworkx <codeworkx@cyanogenmod.com>2012-09-22 09:48:20 +0200
committercodeworkx <codeworkx@cyanogenmod.com>2012-09-22 14:02:16 +0200
commit2489007e7d740ccbc3e0a202914e243ad5178787 (patch)
treeb8e6380ea7b1da63474ad68a5dba997e01146043 /drivers/video/backlight
parent5f67568eb31e3a813c7c52461dcf66ade15fc2e7 (diff)
downloadkernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.zip
kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.tar.gz
kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.tar.bz2
merge opensource jb u5
Change-Id: I1aaec157aa196f3448eff8636134fce89a814cf2
Diffstat (limited to 'drivers/video/backlight')
-rw-r--r--drivers/video/backlight/Kconfig25
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/ea8061.c899
-rw-r--r--drivers/video/backlight/ea8061.h21
-rw-r--r--drivers/video/backlight/ea8061_gamma.h250
-rw-r--r--drivers/video/backlight/s6d6aa1.c976
-rw-r--r--drivers/video/backlight/s6d6aa1.h21
-rw-r--r--drivers/video/backlight/s6e8aa0.c339
-rw-r--r--drivers/video/backlight/s6e8aa0.h9
-rw-r--r--drivers/video/backlight/smart_dimming.c11
-rw-r--r--drivers/video/backlight/smart_dimming.h2
12 files changed, 2462 insertions, 95 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 80f42e6..29c581f 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -174,12 +174,33 @@ config LCD_LTE480WV
config LCD_S6E8AA0
tristate "S6E8AA0 MIPI AMOLED LCD Driver"
depends on S5P_MIPI_DSI2 && BACKLIGHT_CLASS_DEVICE && \
- (MACH_SLP_MIDAS || MACH_SLP_PQ_LTE || MACH_SLP_PQ)
+ (MACH_SLP_MIDAS || MACH_SLP_PQ_LTE || MACH_SLP_PQ || MACH_TRATS)
default n
help
If you have an S6E8AA0 MIPI AMOLED LCD Panel, say Y to enable its
LCD control driver.
+config LCD_EA8061
+ tristate "EA8061 MIPI AMOLED LCD Driver"
+ depends on S5P_MIPI_DSI2 && BACKLIGHT_CLASS_DEVICE && \
+ (MACH_SLP_T0_LTE)
+ default n
+ help
+ If you have an S6E8AA0 MIPI AMOLED LCD Panel, say Y to enable its
+ LCD control driver. this driver supported S-Strip Portrait.
+ It support MIPI interface for transmitting video data to LCD.
+ please find quality about display.
+
+config LCD_S6D6AA1
+ tristate "S6D6AA1 MIPI TFT-LCD Driver"
+ depends on S5P_MIPI_DSI2 && BACKLIGHT_CLASS_DEVICE && \
+ (MACH_REDWOOD)
+ help
+ If you have an S6D6AA1 MIPI TFT-LCD Panel, say Y to enable its
+ LCD control driver. this driver supported white maic sony ip.
+ improve power consumtion and outdoor mode using white pixel.
+ please find advantage about this driver.
+
config LCD_S6E39A0X02
tristate "S6E39A0X02 MIPI AMOLED LCD Driver"
depends on S5P_MIPI_DSI2 && BACKLIGHT_CLASS_DEVICE
@@ -399,7 +420,7 @@ config BACKLIGHT_PCF50633
config BACKLIGHT_SMART_DIMMING
bool "SLP Backlight driver feature for smart dimming"
- depends on (MACH_SLP_MIDAS || MACH_SLP_PQ_LTE || MACH_SLP_PQ)
+ depends on (MACH_SLP_MIDAS || MACH_SLP_T0_LTE || MACH_SLP_PQ_LTE || MACH_SLP_PQ || MACH_TRATS)
help
Say Y to enable the Smart Dimming Feature.
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 16737d6..9d8d82f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_LCD_MIPI_TC358764) += tc358764_mipi_lcd.o
obj-$(CONFIG_LCD_LD9040) += ld9040.o
obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o
obj-$(CONFIG_LCD_S6E8AA0) += s6e8aa0.o
+obj-$(CONFIG_LCD_EA8061) += ea8061.o
+obj-$(CONFIG_LCD_S6D6AA1) += s6d6aa1.o
obj-$(CONFIG_LCD_S6E39A0X02) += s6e39a0x02.o
obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 1a6fe06..2086dd1 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -211,7 +211,7 @@ static ssize_t backlight_store_brightness(struct device *dev,
}
mutex_unlock(&bd->ops_lock);
- backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);
+ /* backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS); */
return rc;
}
diff --git a/drivers/video/backlight/ea8061.c b/drivers/video/backlight/ea8061.c
new file mode 100644
index 0000000..b8da952
--- /dev/null
+++ b/drivers/video/backlight/ea8061.c
@@ -0,0 +1,899 @@
+/* linux/drivers/video/backlight/ea8061.c
+ *
+ * MIPI-DSI based ea8061 AMOLED lcd 5.55 inch panel driver.
+ *
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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/wait.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/lcd.h>
+#include <linux/lcd-property.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <video/mipi_display.h>
+
+#ifdef CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ
+#include <linux/devfreq/exynos4_display.h>
+#endif
+
+#include <plat/mipi_dsim2.h>
+#include "ea8061.h"
+
+#include "ea8061_gamma.h"
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+#include "smart_dimming.h"
+#endif
+
+#define VER_161 (0xA1) /* MACH_SLP_T0_LTE */
+#define LDI_FW_PATH "ea8061/reg_%s.bin"
+#define MAX_STR 255
+#define LDI_MTP_LENGTH 24
+#define MAX_READ_LENGTH 64
+#define MIN_BRIGHTNESS (0)
+#define MAX_BRIGHTNESS (24)
+
+#define POWER_IS_ON(pwr) ((pwr) == FB_BLANK_UNBLANK)
+#define POWER_IS_OFF(pwr) ((pwr) == FB_BLANK_POWERDOWN)
+#define POWER_IS_NRM(pwr) ((pwr) == FB_BLANK_NORMAL)
+
+#define lcd_to_master(a) (a->dsim_dev->master)
+#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
+
+struct panel_model {
+ int ver;
+ char *name;
+};
+
+struct ea8061 {
+ struct device *dev;
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+ struct mipi_dsim_lcd_device *dsim_dev;
+ struct lcd_platform_data *ddi_pd;
+ struct lcd_property *property;
+
+ struct regulator *reg_vdd3;
+ struct regulator *reg_vci;
+
+#ifdef CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ
+ struct notifier_block nb_disp;
+#endif
+ struct mutex lock;
+
+ unsigned int id;
+ unsigned int aid;
+ unsigned int ver;
+ unsigned int power;
+ unsigned int acl_enable;
+ unsigned int cur_addr;
+
+ const struct panel_model *model;
+ unsigned int model_count;
+
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+ unsigned int support_elvss;
+ struct str_smart_dim smart_dim;
+#endif
+};
+
+static void ea8061_delay(unsigned int msecs)
+{
+ /* refer from documentation/timers/timers-howto.txt */
+ if (msecs < 20)
+ usleep_range(msecs*1000, (msecs+1)*1000);
+ else
+ msleep(msecs);
+}
+
+static void ea8061_sleep_in(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x10, 0x00);
+}
+
+static void ea8061_sleep_out(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x11, 0x00);
+}
+
+static void ea8061_apply_level_1_key(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF0, 0x5A, 0x5A
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void ea8061_apply_level_2_key(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xFC, 0x5A, 0x5A
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void ea8061_acl_on(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ /* FIXME: off, 33%, 40%, 50% */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x55, 0x03);
+}
+
+static void ea8061_acl_off(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ /* FIXME: off, 33%, 40%, 50% */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x55, 0x00);
+}
+
+static void ea8061_enable_mtp_register(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF1, 0x5A, 0x5A
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void ea8061_disable_mtp_register(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF1, 0xA5, 0xA5
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void ea8061_read_id(struct ea8061 *lcd, u8 *mtp_id)
+{
+ unsigned int ret;
+ unsigned int addr = 0xD1; /* MTP ID */
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ret = ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ addr, 3, mtp_id);
+}
+
+static unsigned int ea8061_read_mtp(struct ea8061 *lcd, u8 *mtp_data)
+{
+ unsigned int ret;
+ unsigned int addr = 0xD3; /* MTP addr */
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ea8061_enable_mtp_register(lcd);
+
+ ret = ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ addr, LDI_MTP_LENGTH, mtp_data);
+
+ ea8061_disable_mtp_register(lcd);
+
+ return ret;
+}
+
+static void ea8061_disp_cond(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x36, 0x02);
+}
+
+static void ea8061_panel_cond(struct ea8061 *lcd, int high_freq)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xc4, 0x4E, 0xBD, 0x00, 0x00, 0x58, 0xA7, 0x0B, 0x34,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x92, 0x0B, 0x92,
+ 0x08, 0x08, 0x07, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x04, 0x04
+ };
+
+ /* ToDo : Low requency control */
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+unsigned int convert_brightness_to_gamma(int brightness)
+{
+ const unsigned int gamma_table[] = {
+ 30, 30, 50, 70, 80, 90, 100, 120, 130, 140,
+ 150, 160, 170, 180, 190, 200, 210, 220, 230,
+ 240, 250, 260, 270, 280, 300
+ };
+
+ return gamma_table[brightness] - 1;
+}
+
+static int ea8061_gamma_ctrl(struct ea8061 *lcd, int brightness)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+ unsigned int gamma;
+ unsigned char gamma_set[GAMMA_TABLE_COUNT] = {0,};
+ gamma = convert_brightness_to_gamma(brightness);
+
+ gamma_set[0] = 0xfa;
+ gamma_set[1] = 0x01;
+
+ calc_gamma_table(&lcd->smart_dim, gamma, gamma_set + 2);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)gamma_set,
+ GAMMA_TABLE_COUNT);
+#else
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)ea8061_gamma22_table[brightness],
+ GAMMA_TABLE_COUNT);
+#endif
+
+ /* update gamma table. */
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ 0xf7, 0x03);
+
+ ea8061_acl_on(lcd);
+
+ return 0;
+}
+
+static void ea8061_elvss_nvm_set(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[] = {
+ 0xB2, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x0B, 0x0C, 0x0E, 0x10, 0x12,
+ 0x13, 0x15, 0x17, 0x18, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B,
+ 0x1C, 0x1C, 0x1C, 0xB4, 0xA0, 0x00, 0x00, 0x00, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void ea8061_slew_ctl(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[] = {
+ 0xB4, 0x33, 0x0D, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static int ea8061_panel_init(struct ea8061 *lcd)
+{
+ struct backlight_device *bd = lcd->bd;
+ int brightness = bd->props.brightness;
+
+ ea8061_delay(5);
+ ea8061_apply_level_1_key(lcd);
+ ea8061_apply_level_2_key(lcd);
+
+ ea8061_panel_cond(lcd, 1);
+ ea8061_disp_cond(lcd);
+ ea8061_gamma_ctrl(lcd, brightness);
+ ea8061_elvss_nvm_set(lcd);
+ ea8061_acl_on(lcd);
+ ea8061_slew_ctl(lcd);
+
+ ea8061_sleep_out(lcd);
+
+ /* wait more than 120ms */
+ ea8061_delay(lcd->ddi_pd->power_on_delay);
+ dev_info(lcd->dev, "panel init sequence done.\n");
+
+ return 0;
+}
+
+static void ea8061_display_on(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x29, 0x00);
+}
+
+static void ea8061_display_off(struct ea8061 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x28, 0x00);
+}
+
+static int ea8061_early_set_power(struct lcd_device *ld, int power)
+{
+ struct ea8061 *lcd = lcd_get_data(ld);
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ int ret = 0;
+
+ if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+ power != FB_BLANK_NORMAL) {
+ dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+ return -EINVAL;
+ }
+
+ if (lcd->power == power) {
+ dev_err(lcd->dev, "power mode is same as previous one.\n");
+ return -EINVAL;
+ }
+
+ if (ops->set_early_blank_mode) {
+ /* LCD power off */
+ if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power))
+ || (POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
+ ret = ops->set_early_blank_mode(lcd_to_master(lcd),
+ power);
+ if (!ret && lcd->power != power)
+ lcd->power = power;
+ }
+ }
+
+ return ret;
+}
+
+static int ea8061_set_power(struct lcd_device *ld, int power)
+{
+ struct ea8061 *lcd = lcd_get_data(ld);
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ int ret = 0;
+
+ if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+ power != FB_BLANK_NORMAL) {
+ dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+ return -EINVAL;
+ }
+
+ if (lcd->power == power) {
+ dev_err(lcd->dev, "power mode is same as previous one.\n");
+ return -EINVAL;
+ }
+
+ if (ops->set_blank_mode) {
+ ret = ops->set_blank_mode(lcd_to_master(lcd), power);
+ if (!ret && lcd->power != power)
+ lcd->power = power;
+ }
+
+ return ret;
+}
+
+static int ea8061_get_power(struct lcd_device *ld)
+{
+ struct ea8061 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static struct lcd_ops ea8061_lcd_ops = {
+ .early_set_power = ea8061_early_set_power,
+ .set_power = ea8061_set_power,
+ .get_power = ea8061_get_power,
+};
+
+static int ea8061_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int ea8061_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0, brightness = bd->props.brightness;
+ struct ea8061 *lcd = bl_get_data(bd);
+
+ if (lcd->power == FB_BLANK_POWERDOWN) {
+ dev_err(lcd->dev,
+ "lcd off: brightness set failed.\n");
+ return -EINVAL;
+ }
+
+ if (brightness < MIN_BRIGHTNESS ||
+ brightness > bd->props.max_brightness) {
+ dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ ret = ea8061_gamma_ctrl(lcd, brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static const struct backlight_ops ea8061_backlight_ops = {
+ .get_brightness = ea8061_get_brightness,
+ .update_status = ea8061_set_brightness,
+};
+
+static ssize_t acl_control_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct ea8061 *lcd = dev_get_drvdata(dev);
+ char temp[3];
+
+ sprintf(temp, "%d\n", lcd->acl_enable);
+ strcpy(buf, temp);
+
+ return strlen(buf);
+}
+
+static ssize_t acl_control_store(struct device *dev, struct
+ device_attribute * attr, const char *buf, size_t size)
+{
+ struct ea8061 *lcd = dev_get_drvdata(dev);
+ unsigned int value;
+ int rc;
+
+ rc = strict_strtoul(buf, (unsigned int)0, (unsigned long *)&value);
+ if (rc < 0)
+ return rc;
+
+ if (lcd->acl_enable != value) {
+ dev_info(dev, "acl control changed from %d to %d\n",
+ lcd->acl_enable, value);
+ lcd->acl_enable = value;
+ if (lcd->acl_enable)
+ ea8061_acl_on(lcd);
+ else
+ ea8061_acl_off(lcd);
+ }
+ return size;
+}
+
+static ssize_t lcd_type_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct ea8061 *lcd = dev_get_drvdata(dev);
+ char temp[32];
+ int i;
+
+ for (i = 0; i < lcd->model_count; i++) {
+ if (lcd->ver == lcd->model[i].ver)
+ break;
+ }
+
+ if (i == lcd->model_count)
+ return -EINVAL;
+
+ sprintf(temp, "%s\n", lcd->model[i].name);
+ strcpy(buf, temp);
+
+ return strlen(buf);
+}
+
+static int ea8061_read_reg(struct ea8061 *lcd, unsigned int addr, char *buf)
+{
+ unsigned char data[MAX_READ_LENGTH];
+ unsigned int size;
+ int i;
+ int pos = 0;
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ memset(data, 0x0, ARRAY_SIZE(data));
+ size = ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ addr, MAX_READ_LENGTH, data);
+ if (!size) {
+ dev_err(lcd->dev, "failed to read 0x%.2x register.\n", addr);
+ return size;
+ }
+
+ pos += sprintf(buf, "0x%.2x, ", addr);
+ for (i = 1; i < size+1; i++) {
+ if (i % 9 == 0)
+ pos += sprintf(buf+pos, "\n");
+ pos += sprintf(buf+pos, "0x%.2x, ", data[i-1]);
+ }
+ pos += sprintf(buf+pos, "\n");
+
+ return pos;
+}
+
+static int ea8061_write_reg(struct ea8061 *lcd, char *name)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const struct firmware *fw;
+ char fw_path[MAX_STR+1];
+ int ret = 0;
+
+ mutex_lock(&lcd->lock);
+ snprintf(fw_path, MAX_STR, LDI_FW_PATH, name);
+
+ ret = request_firmware(&fw, fw_path, lcd->dev);
+ if (ret) {
+ dev_err(lcd->dev, "failed to request firmware.\n");
+ mutex_unlock(&lcd->lock);
+ return ret;
+ }
+
+ if (fw->size == 1)
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ (unsigned int)fw->data[0], 0);
+ else if (fw->size == 2)
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ (unsigned int)fw->data[0], fw->data[1]);
+ else
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)fw->data, fw->size);
+ if (ret)
+ dev_err(lcd->dev, "failed to write 0x%.2x register and %d error.\n",
+ fw->data[0], ret);
+
+ release_firmware(fw);
+ mutex_unlock(&lcd->lock);
+
+ return ret;
+}
+
+static ssize_t read_reg_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct ea8061 *lcd = dev_get_drvdata(dev);
+
+ if (lcd->cur_addr == 0) {
+ dev_err(dev, "failed to set current lcd register.\n");
+ return -EINVAL;
+ }
+
+ return ea8061_read_reg(lcd, lcd->cur_addr, buf);
+}
+
+static ssize_t read_reg_store(struct device *dev, struct
+ device_attribute * attr, const char *buf, size_t size)
+{
+ struct ea8061 *lcd = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = sscanf(buf, "0x%x", &value);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "success to set 0x%x address.\n", value);
+ lcd->cur_addr = value;
+
+ return size;
+}
+
+static ssize_t write_reg_store(struct device *dev, struct
+ device_attribute * attr, const char *buf, size_t size)
+{
+ struct ea8061 *lcd = dev_get_drvdata(dev);
+ char name[32];
+ int ret;
+
+ ret = sscanf(buf, "%s", name);
+ if (ret < 0)
+ return ret;
+
+ ret = ea8061_write_reg(lcd, name);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "success to set %s address.\n", name);
+
+ return size;
+}
+
+static struct device_attribute device_attrs[] = {
+ __ATTR(acl_control, S_IRUGO|S_IWUSR|S_IWGRP,
+ acl_control_show, acl_control_store),
+ __ATTR(lcd_type, S_IRUGO,
+ lcd_type_show, NULL),
+ __ATTR(read_reg, S_IRUGO|S_IWUSR|S_IWGRP,
+ read_reg_show, read_reg_store),
+ __ATTR(write_reg, S_IWUSR|S_IWGRP,
+ NULL, write_reg_store),
+};
+
+static struct panel_model ea8061_model[] = {
+ {
+ .ver = VER_161, /* MACH_SLP_T0_LTE */
+ .name = "SMD_AMS555HBxx-0",
+ }
+};
+
+#ifdef CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ
+static int ea8061_notifier_callback(struct notifier_block *this,
+ unsigned long event, void *_data)
+{
+ struct ea8061 *lcd = container_of(this, struct ea8061, nb_disp);
+
+ if (lcd->power == FB_BLANK_POWERDOWN)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case EXYNOS4_DISPLAY_LV_HF:
+ ea8061_panel_cond(lcd, 1);
+ break;
+ case EXYNOS4_DISPLAY_LV_LF:
+ ea8061_panel_cond(lcd, 0);
+ break;
+ default:
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_DONE;
+}
+#endif
+
+static void ea8061_regulator_ctl(struct ea8061 *lcd, bool enable)
+{
+ mutex_lock(&lcd->lock);
+
+ if (enable) {
+ if (lcd->reg_vdd3)
+ regulator_enable(lcd->reg_vdd3);
+
+ if (lcd->reg_vci)
+ regulator_enable(lcd->reg_vci);
+ } else {
+ if (lcd->reg_vci)
+ regulator_disable(lcd->reg_vci);
+
+ if (lcd->reg_vdd3)
+ regulator_disable(lcd->reg_vdd3);
+ }
+
+ mutex_unlock(&lcd->lock);
+}
+
+static void ea8061_power_on(struct mipi_dsim_lcd_device *dsim_dev,
+ unsigned int enable)
+{
+ struct ea8061 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ dev_dbg(lcd->dev, "%s:enable[%d]\n", __func__, enable);
+
+ if (enable) {
+ /* lcd power on */
+ ea8061_regulator_ctl(lcd, true);
+
+ ea8061_delay(lcd->ddi_pd->reset_delay);
+
+ /* lcd reset high */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+
+ /* wait more than 5ms */
+ ea8061_delay(5);
+ } else {
+ /* lcd reset low */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+
+ /* lcd power off */
+ ea8061_regulator_ctl(lcd, false);
+ }
+}
+
+static int ea8061_check_mtp(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ /* FIXME:! read id mtp failed */
+ return 0;
+}
+
+static void ea8061_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct ea8061 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ ea8061_panel_init(lcd);
+ ea8061_display_on(lcd);
+}
+
+static int ea8061_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct ea8061 *lcd;
+ int ret;
+ int i;
+
+ lcd = kzalloc(sizeof(struct ea8061), GFP_KERNEL);
+ if (!lcd) {
+ dev_err(&dsim_dev->dev, "failed to allocate ea8061 structure.\n");
+ return -ENOMEM;
+ }
+
+ lcd->dsim_dev = dsim_dev;
+ lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
+ lcd->dev = &dsim_dev->dev;
+
+ mutex_init(&lcd->lock);
+
+ lcd->reg_vdd3 = regulator_get(lcd->dev, "VDD3");
+ if (IS_ERR(lcd->reg_vdd3)) {
+ ret = PTR_ERR(lcd->reg_vdd3);
+ dev_err(lcd->dev, "failed to get %s regulator (%d)\n",
+ "VDD3", ret);
+ lcd->reg_vdd3 = NULL;
+ }
+
+ lcd->reg_vci = regulator_get(lcd->dev, "VCI");
+ if (IS_ERR(lcd->reg_vci)) {
+ ret = PTR_ERR(lcd->reg_vci);
+ dev_err(lcd->dev, "failed to get %s regulator (%d)\n",
+ "VCI", ret);
+ lcd->reg_vci = NULL;
+ }
+
+ lcd->ld = lcd_device_register("ea8061", lcd->dev, lcd,
+ &ea8061_lcd_ops);
+ if (IS_ERR(lcd->ld)) {
+ dev_err(lcd->dev, "failed to register lcd ops.\n");
+ ret = PTR_ERR(lcd->ld);
+ goto err_regulator;
+ }
+
+ lcd->bd = backlight_device_register("ea8061-bl", lcd->dev, lcd,
+ &ea8061_backlight_ops, NULL);
+ if (IS_ERR(lcd->bd)) {
+ dev_err(lcd->dev, "failed to register backlight ops.\n");
+ ret = PTR_ERR(lcd->bd);
+ goto err_unregister_lcd;
+ }
+
+ ea8061_regulator_ctl(lcd, true);
+
+ if (lcd->ddi_pd)
+ lcd->property = lcd->ddi_pd->pdata;
+
+#ifdef CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ
+ if (lcd->property && lcd->property->dynamic_refresh) {
+ lcd->nb_disp.notifier_call = ea8061_notifier_callback;
+ ret = exynos4_display_register_client(&lcd->nb_disp);
+ if (ret < 0)
+ dev_warn(&lcd->ld->dev, "failed to register exynos-display notifier\n");
+ }
+#endif
+
+ lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
+ lcd->bd->props.brightness = MAX_BRIGHTNESS;
+ lcd->power = FB_BLANK_UNBLANK;
+ lcd->model = ea8061_model;
+ lcd->model_count = ARRAY_SIZE(ea8061_model);
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+ ret = device_create_file(&lcd->ld->dev,
+ &device_attrs[i]);
+ if (ret < 0) {
+ dev_err(&lcd->ld->dev, "failed to add sysfs entries\n");
+ break;
+ }
+ }
+
+ dev_set_drvdata(&dsim_dev->dev, lcd);
+ dev_info(lcd->dev, "probed ea8061 panel driver(%s).\n",
+ dev_name(&lcd->ld->dev));
+
+ return 0;
+
+err_unregister_lcd:
+ lcd_device_unregister(lcd->ld);
+
+err_regulator:
+ regulator_put(lcd->reg_vci);
+ regulator_put(lcd->reg_vdd3);
+
+ kfree(lcd);
+
+ return ret;
+}
+
+static void ea8061_remove(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct ea8061 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ backlight_device_unregister(lcd->bd);
+ lcd_device_unregister(lcd->ld);
+
+ regulator_put(lcd->reg_vci);
+ regulator_put(lcd->reg_vdd3);
+
+#ifdef CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ
+ if (lcd->property && lcd->property->dynamic_refresh)
+ exynos4_display_unregister_client(&lcd->nb_disp);
+#endif
+ kfree(lcd);
+}
+
+#ifdef CONFIG_PM
+static int ea8061_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct ea8061 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ ea8061_display_off(lcd);
+ ea8061_sleep_in(lcd);
+ ea8061_delay(lcd->ddi_pd->power_off_delay);
+
+ return 0;
+}
+
+static int ea8061_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct ea8061 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ ea8061_sleep_out(lcd);
+ ea8061_delay(lcd->ddi_pd->power_on_delay);
+
+ return 0;
+}
+#else
+#define ea8061_suspend NULL
+#define ea8061_resume NULL
+#endif
+
+static struct mipi_dsim_lcd_driver ea8061_dsim_ddi_driver = {
+ .name = "ea8061",
+ .id = -1,
+
+ .power_on = ea8061_power_on,
+ .check_mtp = ea8061_check_mtp,
+ .set_sequence = ea8061_set_sequence,
+ .probe = ea8061_probe,
+ .remove = ea8061_remove,
+ .suspend = ea8061_suspend,
+ .resume = ea8061_resume,
+};
+
+static int ea8061_init(void)
+{
+ s5p_mipi_dsi_register_lcd_driver(&ea8061_dsim_ddi_driver);
+
+ return 0;
+}
+
+static void ea8061_exit(void)
+{
+ return;
+}
+
+module_init(ea8061_init);
+module_exit(ea8061_exit);
+
+
+MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
+MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based ea8061 AMOLED Panel Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/backlight/ea8061.h b/drivers/video/backlight/ea8061.h
new file mode 100644
index 0000000..d283d06
--- /dev/null
+++ b/drivers/video/backlight/ea8061.h
@@ -0,0 +1,21 @@
+/* linux/drivers/video/backlight/ea8061.h
+ *
+ * MIPI-DSI based ea8061 AMOLED lcd 5.55 inch panel driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics
+ *
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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.
+*/
+
+#ifndef _EA8061_H
+#define _EA8061_H
+
+/* ToDo */
+
+#endif
+
diff --git a/drivers/video/backlight/ea8061_gamma.h b/drivers/video/backlight/ea8061_gamma.h
new file mode 100644
index 0000000..2a9e6a4
--- /dev/null
+++ b/drivers/video/backlight/ea8061_gamma.h
@@ -0,0 +1,250 @@
+/* linux/drivers/video/backlight/ea8061_gamma.h
+ *
+ * Brightness level definition.
+ *
+ * Copyright (c) 2012 Samsung Electronics
+ *
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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.
+*/
+
+#ifndef _EA8061_GAMMA_H
+#define _EA8061_GAMMA_H
+
+#define MAX_GAMMA_LEVEL 25
+#define GAMMA_TABLE_COUNT 26
+
+static const unsigned char ea8061_gamma22_20[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_30[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_40[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_50[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_60[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_70[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEA, 0xC9, 0xEA, 0xD6,
+ 0xD2, 0xD2, 0xDF, 0xE1, 0xE3, 0xC2, 0xC1, 0xC0, 0xD1,
+ 0xD0, 0xCE, 0x00, 0x84, 0x00, 0x84, 0x00, 0x96
+};
+
+static const unsigned char ea8061_gamma22_80[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEB, 0xCC, 0xE9, 0xD5,
+ 0xD4, 0xD3, 0xDE, 0xE1, 0xE2, 0xC2, 0xBF, 0xBF, 0xCF,
+ 0xCF, 0xCC, 0x00, 0x89, 0x00, 0x89, 0x00, 0x9C
+};
+
+static const unsigned char ea8061_gamma22_90[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_100[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_110[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_120[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_130[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_140[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_150[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_160[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_170[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_180[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_190[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_200[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_210[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_220[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_230[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_240[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_250[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_260[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_270[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_280[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_290[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char ea8061_gamma22_300[] = {
+ 0xCA, 0x00, 0xE8, 0x00, 0xF7, 0x01, 0x03, 0xDB, 0xDB,
+ 0xDC, 0xD9, 0xD8, 0xDA, 0xCB, 0xC8, 0xCB, 0xD4, 0xD3,
+ 0xD7, 0xE6, 0xE6, 0xEA, 0xE2, 0xE4, 0xE5, 0xCE, 0xC3,
+ 0xCF, 0xB9, 0x9D, 0xDE, 0x11, 0x00
+};
+
+static const unsigned char *ea8061_gamma22_table[MAX_GAMMA_LEVEL] = {
+ ea8061_gamma22_30,
+ ea8061_gamma22_50,
+ ea8061_gamma22_60,
+ ea8061_gamma22_70,
+ ea8061_gamma22_80,
+ ea8061_gamma22_90,
+ ea8061_gamma22_100,
+ ea8061_gamma22_110,
+ ea8061_gamma22_120,
+ ea8061_gamma22_130,
+ ea8061_gamma22_140,
+ ea8061_gamma22_150,
+ ea8061_gamma22_160,
+ ea8061_gamma22_170,
+ ea8061_gamma22_180,
+ ea8061_gamma22_190,
+ ea8061_gamma22_200,
+ ea8061_gamma22_210,
+ ea8061_gamma22_220,
+ ea8061_gamma22_230,
+ ea8061_gamma22_240,
+ ea8061_gamma22_270,
+ ea8061_gamma22_280,
+ ea8061_gamma22_290,
+ ea8061_gamma22_300
+};
+
+#endif /* _EA8061_GAMMA_H */
diff --git a/drivers/video/backlight/s6d6aa1.c b/drivers/video/backlight/s6d6aa1.c
new file mode 100644
index 0000000..15a0b63
--- /dev/null
+++ b/drivers/video/backlight/s6d6aa1.c
@@ -0,0 +1,976 @@
+/* linux/drivers/video/backlight/s6d6aa1.c
+ *
+ * MIPI-DSI based s6d6aa1 TFT-LCD 4.77 inch panel driver.
+ *
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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/wait.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/lcd.h>
+#include <linux/lcd-property.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <video/mipi_display.h>
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+#include <linux/devfreq/exynos4_display.h>
+#endif
+
+#include <plat/mipi_dsim2.h>
+#include "s6d6aa1.h"
+
+#define VER_16 (0x10) /* MACH_SLP_REDWOORD */
+#define LDI_FW_PATH "s6d6aa1/reg_%s.bin"
+#define MAX_STR 255
+#define MAX_READ_LENGTH 64
+#define MIN_BRIGHTNESS (0)
+#define MAX_BRIGHTNESS (0xff)
+#define DSCTL_VFLIP (1 << 7)
+#define DSCTL_HFLIP (1 << 6)
+
+/*
+ * FIXME:!!simple init vs full init
+ * If lcd don't working simple sequence,
+ * we use full initialization sequence
+ */
+#define SIMPLE_INIT
+
+#define POWER_IS_ON(pwr) ((pwr) == FB_BLANK_UNBLANK)
+#define POWER_IS_OFF(pwr) ((pwr) == FB_BLANK_POWERDOWN)
+#define POWER_IS_NRM(pwr) ((pwr) == FB_BLANK_NORMAL)
+
+#define lcd_to_master(a) (a->dsim_dev->master)
+#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
+
+/* white magic mode */
+enum wm_mode {
+ WM_MODE_MIN = 0x00,
+ WM_MODE_NORMAL = WM_MODE_MIN,
+ WM_MODE_CONSERVATIVE,
+ WM_MODE_MEDIUM,
+ WM_MODE_AGGRESSIVE,
+ WM_MODE_OUTDOOR,
+ WM_MODE_MAX = WM_MODE_OUTDOOR
+};
+
+struct panel_model {
+ int ver;
+ char *name;
+};
+
+struct s6d6aa1 {
+ struct device *dev;
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+ struct mipi_dsim_lcd_device *dsim_dev;
+ struct lcd_platform_data *ddi_pd;
+ struct lcd_property *property;
+
+ struct regulator *reg_vddi;
+ struct regulator *reg_vdd;
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+ struct notifier_block nb_disp;
+#endif
+ struct mutex lock;
+
+ unsigned int ver;
+ unsigned int power;
+ enum wm_mode wm_mode;
+ unsigned int cur_addr;
+
+ const struct panel_model *model;
+ unsigned int model_count;
+};
+
+static void s6d6aa1_delay(unsigned int msecs)
+{
+ /* refer from documentation/timers/timers-howto.txt */
+ if (msecs < 20)
+ usleep_range(msecs*1000, (msecs+1)*1000);
+ else
+ msleep(msecs);
+}
+
+static void s6d6aa1_sleep_in(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x10, 0x00);
+}
+
+static void s6d6aa1_sleep_out(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x11, 0x00);
+}
+
+static void s6d6aa1_apply_level_1_key(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF0, 0x5A, 0x5A
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_apply_level_2_key(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF1, 0x5A, 0x5A
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_read_id(struct s6d6aa1 *lcd, u8 *mtp_id)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ 0xDA, 1, &mtp_id[0]);
+ ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ 0xDB, 1, &mtp_id[1]);
+ ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ 0xDC, 1, &mtp_id[2]);
+}
+
+static void s6d6aa1_write_ddb(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xB4, 0x59, 0x10, 0x10, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_bcm_mode(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xC1, 0x03);
+}
+
+static void s6d6aa1_wrbl_ctl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xC3, 0x7C, 0x00, 0x22
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_sony_ip_setting(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send1[] = {
+ 0xC4, 0x72, 0xFF, 0x72, 0xFF, 0x72, 0xFF, 0x72, 0x72,
+ 0x05, 0x0F, 0x1F, 0x01, 0x00, 0x00
+ };
+ const unsigned char data_to_send2[] = {
+ 0xC5, 0x80, 0x80, 0x80, 0x60, 0x4E, 0x36, 0x83, 0x85,
+ 0x01, 0xFF, 0x20, 0x40, 0x50
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send1, ARRAY_SIZE(data_to_send1));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send2, ARRAY_SIZE(data_to_send2));
+}
+
+/*
+ * FIXME:!!simple init vs full init
+ * If lcd don't working simple sequence,
+ * we use full initialization sequence
+ */
+#ifdef SIMPLE_INIT
+static void s6d6aa1_disp_ctl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ struct lcd_property *property = lcd->property;
+ unsigned char cfg = 0;
+
+ if (property) {
+ if (property->flip & LCD_PROPERTY_FLIP_VERTICAL)
+ cfg |= DSCTL_VFLIP;
+
+ if (property->flip & LCD_PROPERTY_FLIP_HORIZONTAL)
+ cfg |= DSCTL_HFLIP;
+ }
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x36, cfg);
+}
+#else
+static void s6d6aa1_disp_ctl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xEF, 0x02);
+}
+#endif
+
+static void s6d6aa1_source_ctl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF2, 0x03, 0x03, 0x91, 0x85
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_pwr_ctl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF4, 0x04, 0x0B, 0x07, 0x07, 0x10, 0x14, 0x0D, 0x0C,
+ 0xAD, 0x00, 0x33, 0x33
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_panel_ctl(struct s6d6aa1 *lcd, int high_freq)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xF6, 0x0B, 0x11, 0x0F, 0x25, 0x0A, 0x00, 0x13, 0x22,
+ 0x1B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03,
+ 0x12, 0x32, 0x51
+ };
+
+ /* ToDo : Low requency control */
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6d6aa1_mount_ctl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xF7, 0x00);
+}
+
+static int s6d6aa1_gamma_ctrl(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send1[] = {
+ 0xFA, 0x1C, 0x3F, 0x20, 0xDF, 0xEB, 0xEB, 0xE3, 0x61,
+ 0x61, 0xDB, 0x94, 0x15, 0xD9, 0xD8, 0xDB, 0xE1, 0xE4,
+ 0xE6, 0xE3, 0xA2, 0x49, 0xDC, 0x7F, 0x5E, 0xDD, 0x6B,
+ 0x6A, 0xA3, 0xE1, 0xE2, 0x9B, 0x55, 0xD6, 0x99, 0x59,
+ 0x9C, 0xA1, 0xA4, 0x64, 0xA0, 0x9F, 0x06, 0x80, 0xBF,
+ 0xB0, 0xB1, 0xFB, 0xFA, 0xF4, 0x31, 0x72, 0xEC, 0x25,
+ 0xA5, 0xA7, 0xE9, 0x6B, 0xAE, 0xB1, 0xB4, 0x35, 0xF8,
+ 0x9F
+ };
+
+ const unsigned char data_to_send2[] = {
+ 0xFB, 0x1C, 0x3F, 0x20, 0xDF, 0xEB, 0xEB, 0xE3, 0x61,
+ 0x61, 0xDB, 0x94, 0x15, 0xD9, 0xD8, 0xDB, 0xE1, 0xE4,
+ 0xE6, 0xE3, 0xA2, 0x49, 0xDC, 0x7F, 0x5E, 0xDD, 0x6B,
+ 0x6A, 0xA3, 0xE1, 0xE2, 0x9B, 0x55, 0xD6, 0x99, 0x59,
+ 0x9C, 0xA1, 0xA4, 0x64, 0xA0, 0x9F, 0x06, 0x80, 0xBF,
+ 0xB0, 0xB1, 0xFB, 0xFA, 0xF4, 0x31, 0x72, 0xEC, 0x25,
+ 0xA5, 0xA7, 0xE9, 0x6B, 0xAE, 0xB1, 0xB4, 0x35, 0xF8,
+ 0x9F
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send1, ARRAY_SIZE(data_to_send1));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send2, ARRAY_SIZE(data_to_send2));
+
+ return 0;
+}
+
+static int s6d6aa1_panel_init(struct s6d6aa1 *lcd)
+{
+ s6d6aa1_sleep_out(lcd);
+ s6d6aa1_delay(140);
+/*
+ * FIXME:!!simple init vs full init
+ * If lcd don't working simple sequence,
+ * we use full initialization sequence
+ */
+#ifdef SIMPLE_INIT
+ s6d6aa1_disp_ctl(lcd);
+#else
+ s6d6aa1_apply_level_1_key(lcd);
+ s6d6aa1_apply_level_2_key(lcd);
+
+ s6d6aa1_write_ddb(lcd);
+ s6d6aa1_bcm_mode(lcd);
+ s6d6aa1_wrbl_ctl(lcd);
+ s6d6aa1_sony_ip_setting(lcd);
+ s6d6aa1_disp_ctl(lcd);
+ s6d6aa1_source_ctl(lcd);
+ s6d6aa1_pwr_ctl(lcd);
+ s6d6aa1_panel_ctl(lcd, 1);
+ s6d6aa1_mount_ctl(lcd);
+
+ s6d6aa1_gamma_ctrl(lcd);
+
+ /* wait more than 10ms */
+ s6d6aa1_delay(lcd->ddi_pd->power_on_delay);
+#endif
+
+ return 0;
+}
+
+static void s6d6aa1_write_disbv(struct s6d6aa1 *lcd,
+ unsigned int brightness)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x51, brightness);
+}
+
+static void s6d6aa1_write_ctrld(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x53, 0x2C);
+}
+
+static void s6d6aa1_write_cabc(struct s6d6aa1 *lcd,
+ enum wm_mode wm_mode)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0x55, wm_mode);
+}
+
+static void s6d6aa1_display_on(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x29, 0x00);
+}
+
+static void s6d6aa1_display_off(struct s6d6aa1 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x28, 0x00);
+}
+
+static int s6d6aa1_early_set_power(struct lcd_device *ld, int power)
+{
+ struct s6d6aa1 *lcd = lcd_get_data(ld);
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ int ret = 0;
+
+ if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+ power != FB_BLANK_NORMAL) {
+ dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+ return -EINVAL;
+ }
+
+ if (lcd->power == power) {
+ dev_err(lcd->dev, "power mode is same as previous one.\n");
+ return -EINVAL;
+ }
+
+ if (ops->set_early_blank_mode) {
+ /* LCD power off */
+ if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power))
+ || (POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
+ ret = ops->set_early_blank_mode(lcd_to_master(lcd),
+ power);
+ if (!ret && lcd->power != power)
+ lcd->power = power;
+ }
+ }
+
+ return ret;
+}
+
+static int s6d6aa1_set_power(struct lcd_device *ld, int power)
+{
+ struct s6d6aa1 *lcd = lcd_get_data(ld);
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ int ret = 0;
+
+ if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+ power != FB_BLANK_NORMAL) {
+ dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+ return -EINVAL;
+ }
+
+ if (lcd->power == power) {
+ dev_err(lcd->dev, "power mode is same as previous one.\n");
+ return -EINVAL;
+ }
+
+ if (ops->set_blank_mode) {
+ ret = ops->set_blank_mode(lcd_to_master(lcd), power);
+ if (!ret && lcd->power != power)
+ lcd->power = power;
+ }
+
+ return ret;
+}
+
+static int s6d6aa1_get_power(struct lcd_device *ld)
+{
+ struct s6d6aa1 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static struct lcd_ops s6d6aa1_lcd_ops = {
+ .early_set_power = s6d6aa1_early_set_power,
+ .set_power = s6d6aa1_set_power,
+ .get_power = s6d6aa1_get_power,
+};
+
+static int s6d6aa1_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int s6d6aa1_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0, brightness = bd->props.brightness;
+ struct s6d6aa1 *lcd = bl_get_data(bd);
+
+ if (lcd->power == FB_BLANK_POWERDOWN) {
+ dev_err(lcd->dev,
+ "lcd off: brightness set failed.\n");
+ return -EINVAL;
+ }
+
+ if (brightness < MIN_BRIGHTNESS ||
+ brightness > bd->props.max_brightness) {
+ dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ s6d6aa1_write_disbv(lcd, brightness);
+ return ret;
+}
+
+static const struct backlight_ops s6d6aa1_backlight_ops = {
+ .get_brightness = s6d6aa1_get_brightness,
+ .update_status = s6d6aa1_set_brightness,
+};
+
+static ssize_t wm_mode_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(dev);
+ char temp[3];
+
+ sprintf(temp, "%d\n", lcd->wm_mode);
+ strcpy(buf, temp);
+
+ return strlen(buf);
+}
+
+static ssize_t wm_mode_store(struct device *dev, struct
+ device_attribute * attr, const char *buf, size_t size)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(dev);
+ unsigned int value;
+ int rc;
+
+ rc = strict_strtoul(buf, (unsigned int)0, (unsigned long *)&value);
+ if (rc < 0)
+ return rc;
+
+ if (value < WM_MODE_MIN || value > WM_MODE_MAX) {
+ dev_info(dev, "failed to set white magic mode to %d\n",
+ value);
+ return -EINVAL;
+ }
+
+ if (lcd->wm_mode != value) {
+ dev_info(dev, "wm mode changed from %d to %d\n",
+ lcd->wm_mode, value);
+ lcd->wm_mode = value;
+ s6d6aa1_write_cabc(lcd, lcd->wm_mode);
+ }
+ return size;
+}
+
+static ssize_t lcd_type_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(dev);
+ char temp[32];
+ int i;
+
+ for (i = 0; i < lcd->model_count; i++) {
+ if (lcd->ver == lcd->model[i].ver)
+ break;
+ }
+
+ if (i == lcd->model_count)
+ return -EINVAL;
+
+ sprintf(temp, "%s\n", lcd->model[i].name);
+ strcpy(buf, temp);
+
+ return strlen(buf);
+}
+
+static int s6d6aa1_read_reg(struct s6d6aa1 *lcd, unsigned int addr, char *buf)
+{
+ unsigned char data[MAX_READ_LENGTH];
+ unsigned int size;
+ int i;
+ int pos = 0;
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ memset(data, 0x0, ARRAY_SIZE(data));
+ size = ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ addr, MAX_READ_LENGTH, data);
+ if (!size) {
+ dev_err(lcd->dev, "failed to read 0x%.2x register.\n", addr);
+ return size;
+ }
+
+ pos += sprintf(buf, "0x%.2x, ", addr);
+ for (i = 1; i < size+1; i++) {
+ if (i % 9 == 0)
+ pos += sprintf(buf+pos, "\n");
+ pos += sprintf(buf+pos, "0x%.2x, ", data[i-1]);
+ }
+ pos += sprintf(buf+pos, "\n");
+
+ return pos;
+}
+
+static int s6d6aa1_write_reg(struct s6d6aa1 *lcd, char *name)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const struct firmware *fw;
+ char fw_path[MAX_STR+1];
+ int ret = 0;
+
+ mutex_lock(&lcd->lock);
+ snprintf(fw_path, MAX_STR, LDI_FW_PATH, name);
+
+ ret = request_firmware(&fw, fw_path, lcd->dev);
+ if (ret) {
+ dev_err(lcd->dev, "failed to request firmware.\n");
+ mutex_unlock(&lcd->lock);
+ return ret;
+ }
+
+ if (fw->size == 1)
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ (unsigned int)fw->data[0], 0);
+ else if (fw->size == 2)
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ (unsigned int)fw->data[0], fw->data[1]);
+ else
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)fw->data, fw->size);
+ if (ret)
+ dev_err(lcd->dev, "failed to write 0x%.2x register and %d error.\n",
+ fw->data[0], ret);
+
+ release_firmware(fw);
+ mutex_unlock(&lcd->lock);
+
+ return ret;
+}
+
+static ssize_t read_reg_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(dev);
+
+ if (lcd->cur_addr == 0) {
+ dev_err(dev, "failed to set current lcd register.\n");
+ return -EINVAL;
+ }
+
+ return s6d6aa1_read_reg(lcd, lcd->cur_addr, buf);
+}
+
+static ssize_t read_reg_store(struct device *dev, struct
+ device_attribute * attr, const char *buf, size_t size)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = sscanf(buf, "0x%x", &value);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "success to set 0x%x address.\n", value);
+ lcd->cur_addr = value;
+
+ return size;
+}
+
+static ssize_t write_reg_store(struct device *dev, struct
+ device_attribute * attr, const char *buf, size_t size)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(dev);
+ char name[32];
+ int ret;
+
+ ret = sscanf(buf, "%s", name);
+ if (ret < 0)
+ return ret;
+
+ ret = s6d6aa1_write_reg(lcd, name);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "success to set %s address.\n", name);
+
+ return size;
+}
+
+static struct device_attribute device_attrs[] = {
+ __ATTR(wm_mode, S_IRUGO|S_IWUSR|S_IWGRP,
+ wm_mode_show, wm_mode_store),
+ __ATTR(lcd_type, S_IRUGO,
+ lcd_type_show, NULL),
+ __ATTR(read_reg, S_IRUGO|S_IWUSR|S_IWGRP,
+ read_reg_show, read_reg_store),
+ __ATTR(write_reg, S_IWUSR|S_IWGRP,
+ NULL, write_reg_store),
+};
+
+static struct panel_model s6d6aa1_model[] = {
+ {
+ .ver = VER_16, /* MACH_SLP_REDWOORD */
+ .name = "SMD_ACX445AKM",
+ }
+};
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+static int s6d6aa1_notifier_callback(struct notifier_block *this,
+ unsigned long event, void *_data)
+{
+ struct s6d6aa1 *lcd = container_of(this, struct s6d6aa1, nb_disp);
+
+ if (lcd->power == FB_BLANK_POWERDOWN)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case EXYNOS4_DISPLAY_LV_HF:
+ s6d6aa1_panel_ctl(lcd, 1);
+ break;
+ case EXYNOS4_DISPLAY_LV_LF:
+ s6d6aa1_panel_ctl(lcd, 0);
+ break;
+ default:
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_DONE;
+}
+#endif
+
+static void s6d6aa1_regulator_ctl(struct s6d6aa1 *lcd, bool enable)
+{
+ mutex_lock(&lcd->lock);
+
+ if (enable) {
+ if (lcd->reg_vddi)
+ regulator_enable(lcd->reg_vddi);
+
+ if (lcd->reg_vdd)
+ regulator_enable(lcd->reg_vdd);
+ } else {
+ if (lcd->reg_vdd)
+ regulator_disable(lcd->reg_vdd);
+
+ if (lcd->reg_vddi)
+ regulator_disable(lcd->reg_vddi);
+ }
+
+ mutex_unlock(&lcd->lock);
+}
+
+static void s6d6aa1_power_on(struct mipi_dsim_lcd_device *dsim_dev,
+ unsigned int enable)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ dev_dbg(lcd->dev, "%s:enable[%d]\n", __func__, enable);
+
+ if (enable) {
+ /* lcd power on */
+ s6d6aa1_regulator_ctl(lcd, true);
+
+ s6d6aa1_delay(lcd->ddi_pd->reset_delay);
+
+ /* lcd reset high */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+
+ /* wait more than 10ms */
+ s6d6aa1_delay(10);
+ } else {
+ /* lcd reset low */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+
+ /* lcd power off */
+ s6d6aa1_regulator_ctl(lcd, false);
+ }
+}
+
+static int s6d6aa1_check_mtp(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ u8 mtp_id[3] = {0, };
+
+ s6d6aa1_read_id(lcd, mtp_id);
+ if (mtp_id[0] == 0x00) {
+ dev_err(lcd->dev, "read id failed\n");
+ return -EIO;
+ }
+
+ lcd->ver = mtp_id[1];
+ dev_info(lcd->dev,
+ "Read ID : %x, %x, %x\n", mtp_id[0], mtp_id[1], mtp_id[2]);
+
+ return 0;
+}
+
+static void s6d6aa1_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ struct backlight_device *bd = lcd->bd;
+
+ s6d6aa1_panel_init(lcd);
+
+ s6d6aa1_write_disbv(lcd, bd->props.brightness);
+ s6d6aa1_write_ctrld(lcd);
+ s6d6aa1_write_cabc(lcd, lcd->wm_mode);
+ s6d6aa1_display_on(lcd);
+}
+
+static int s6d6aa1_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6d6aa1 *lcd;
+ int ret;
+ int i;
+
+ lcd = kzalloc(sizeof(struct s6d6aa1), GFP_KERNEL);
+ if (!lcd) {
+ dev_err(&dsim_dev->dev, "failed to allocate s6d6aa1 structure.\n");
+ return -ENOMEM;
+ }
+
+ lcd->dsim_dev = dsim_dev;
+ lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
+ lcd->dev = &dsim_dev->dev;
+
+ mutex_init(&lcd->lock);
+
+ lcd->reg_vddi = regulator_get(lcd->dev, "VDDI");
+ if (IS_ERR(lcd->reg_vddi)) {
+ ret = PTR_ERR(lcd->reg_vddi);
+ dev_err(lcd->dev, "failed to get %s regulator (%d)\n",
+ "VDDI", ret);
+ lcd->reg_vddi = NULL;
+ }
+
+ lcd->reg_vdd = regulator_get(lcd->dev, "VDD");
+ if (IS_ERR(lcd->reg_vdd)) {
+ ret = PTR_ERR(lcd->reg_vdd);
+ dev_err(lcd->dev, "failed to get %s regulator (%d)\n",
+ "VDD", ret);
+ lcd->reg_vdd = NULL;
+ }
+
+ lcd->ld = lcd_device_register("s6d6aa1", lcd->dev, lcd,
+ &s6d6aa1_lcd_ops);
+ if (IS_ERR(lcd->ld)) {
+ dev_err(lcd->dev, "failed to register lcd ops.\n");
+ ret = PTR_ERR(lcd->ld);
+ goto err_regulator;
+ }
+
+ lcd->bd = backlight_device_register("s6d6aa1-bl", lcd->dev, lcd,
+ &s6d6aa1_backlight_ops, NULL);
+ if (IS_ERR(lcd->bd)) {
+ dev_err(lcd->dev, "failed to register backlight ops.\n");
+ ret = PTR_ERR(lcd->bd);
+ goto err_unregister_lcd;
+ }
+
+ s6d6aa1_regulator_ctl(lcd, true);
+
+ if (lcd->ddi_pd)
+ lcd->property = lcd->ddi_pd->pdata;
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+ if (lcd->property && lcd->property->dynamic_refresh) {
+ lcd->nb_disp.notifier_call = s6d6aa1_notifier_callback;
+ ret = exynos4_display_register_client(&lcd->nb_disp);
+ if (ret < 0)
+ dev_warn(&lcd->ld->dev, "failed to register exynos-display notifier\n");
+ }
+#endif
+
+ lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
+ lcd->bd->props.brightness = MAX_BRIGHTNESS;
+ lcd->power = FB_BLANK_UNBLANK;
+ lcd->wm_mode = WM_MODE_CONSERVATIVE;
+ lcd->model = s6d6aa1_model;
+ lcd->model_count = ARRAY_SIZE(s6d6aa1_model);
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+ ret = device_create_file(&lcd->ld->dev,
+ &device_attrs[i]);
+ if (ret < 0) {
+ dev_err(&lcd->ld->dev, "failed to add sysfs entries\n");
+ break;
+ }
+ }
+
+ dev_set_drvdata(&dsim_dev->dev, lcd);
+ dev_info(lcd->dev, "probed s6d6aa1 panel driver(%s).\n",
+ dev_name(&lcd->ld->dev));
+
+ return 0;
+
+err_unregister_lcd:
+ lcd_device_unregister(lcd->ld);
+
+err_regulator:
+ regulator_put(lcd->reg_vdd);
+ regulator_put(lcd->reg_vddi);
+
+ kfree(lcd);
+
+ return ret;
+}
+
+static void s6d6aa1_remove(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ backlight_device_unregister(lcd->bd);
+ lcd_device_unregister(lcd->ld);
+
+ regulator_put(lcd->reg_vdd);
+ regulator_put(lcd->reg_vddi);
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+ if (lcd->property && lcd->property->dynamic_refresh)
+ exynos4_display_unregister_client(&lcd->nb_disp);
+#endif
+ kfree(lcd);
+}
+
+#ifdef CONFIG_PM
+static int s6d6aa1_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6d6aa1_display_off(lcd);
+ s6d6aa1_sleep_in(lcd);
+ s6d6aa1_delay(lcd->ddi_pd->power_off_delay);
+
+ return 0;
+}
+
+static int s6d6aa1_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6d6aa1 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6d6aa1_sleep_out(lcd);
+ s6d6aa1_delay(lcd->ddi_pd->power_on_delay);
+
+ return 0;
+}
+#else
+#define s6d6aa1_suspend NULL
+#define s6d6aa1_resume NULL
+#endif
+
+static struct mipi_dsim_lcd_driver s6d6aa1_dsim_ddi_driver = {
+ .name = "s6d6aa1",
+ .id = -1,
+
+ .power_on = s6d6aa1_power_on,
+ .check_mtp = s6d6aa1_check_mtp,
+ .set_sequence = s6d6aa1_set_sequence,
+ .probe = s6d6aa1_probe,
+ .remove = s6d6aa1_remove,
+ .suspend = s6d6aa1_suspend,
+ .resume = s6d6aa1_resume,
+};
+
+static int s6d6aa1_init(void)
+{
+ s5p_mipi_dsi_register_lcd_driver(&s6d6aa1_dsim_ddi_driver);
+
+ return 0;
+}
+
+static void s6d6aa1_exit(void)
+{
+ return;
+}
+
+module_init(s6d6aa1_init);
+module_exit(s6d6aa1_exit);
+
+
+MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
+MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6d6aa1 TFT-LCD Panel Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/backlight/s6d6aa1.h b/drivers/video/backlight/s6d6aa1.h
new file mode 100644
index 0000000..aaf8446a
--- /dev/null
+++ b/drivers/video/backlight/s6d6aa1.h
@@ -0,0 +1,21 @@
+/* linux/drivers/video/backlight/s6d6aa1.h
+ *
+ * MIPI-DSI based s6d6aa1 TFT-LCD 4.77 inch panel driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics
+ *
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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.
+*/
+
+#ifndef _S6D6AA1_H
+#define _S6D6AA1_H
+
+/* ToDo */
+
+#endif
+
diff --git a/drivers/video/backlight/s6e8aa0.c b/drivers/video/backlight/s6e8aa0.c
index c9b1184..2cc5466 100644
--- a/drivers/video/backlight/s6e8aa0.c
+++ b/drivers/video/backlight/s6e8aa0.c
@@ -4,6 +4,8 @@
*
* Inki Dae, <inki.dae@samsung.com>
* Donghwa Lee, <dh09.lee@samsung.com>
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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
@@ -21,6 +23,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/lcd.h>
+#include <linux/lcd-property.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/regulator/consumer.h>
@@ -28,8 +31,13 @@
#include <video/mipi_display.h>
+#include <plat/cpu.h>
#include <plat/mipi_dsim2.h>
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+#include <linux/devfreq/exynos4_display.h>
+#endif
+
#include "s6e8aa0_gamma.h"
#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
#include "smart_dimming.h"
@@ -43,10 +51,62 @@
#define MIN_BRIGHTNESS (0)
#define MAX_BRIGHTNESS (24)
+/* 1 */
+#define PANELCTL_SS_MASK (1 << 5)
+#define PANELCTL_SS_1_800 (0 << 5)
+#define PANELCTL_SS_800_1 (1 << 5)
+#define PANELCTL_GTCON_MASK (7 << 2)
+#define PANELCTL_GTCON_110 (6 << 2)
+#define PANELCTL_GTCON_111 (7 << 2)
+/* LTPS */
+/* 30 */
+#define PANELCTL_CLK1_CON_MASK (7 << 3)
+#define PANELCTL_CLK1_000 (0 << 3)
+#define PANELCTL_CLK1_001 (1 << 3)
+#define PANELCTL_CLK2_CON_MASK (7 << 0)
+#define PANELCTL_CLK2_000 (0 << 0)
+#define PANELCTL_CLK2_001 (1 << 0)
+/* 31 */
+#define PANELCTL_INT1_CON_MASK (7 << 3)
+#define PANELCTL_INT1_000 (0 << 3)
+#define PANELCTL_INT1_001 (1 << 3)
+#define PANELCTL_INT2_CON_MASK (7 << 0)
+#define PANELCTL_INT2_000 (0 << 0)
+#define PANELCTL_INT2_001 (1 << 0)
+/* 32 */
+#define PANELCTL_BICTL_CON_MASK (7 << 3)
+#define PANELCTL_BICTL_000 (0 << 3)
+#define PANELCTL_BICTL_001 (1 << 3)
+#define PANELCTL_BICTLB_CON_MASK (7 << 0)
+#define PANELCTL_BICTLB_000 (0 << 0)
+#define PANELCTL_BICTLB_001 (1 << 0)
+/* 36 */
+#define PANELCTL_EM_CLK1_CON_MASK (7 << 3)
+#define PANELCTL_EM_CLK1_110 (6 << 3)
+#define PANELCTL_EM_CLK1_111 (7 << 3)
+#define PANELCTL_EM_CLK1B_CON_MASK (7 << 0)
+#define PANELCTL_EM_CLK1B_110 (6 << 0)
+#define PANELCTL_EM_CLK1B_111 (7 << 0)
+/* 37 */
+#define PANELCTL_EM_CLK2_CON_MASK (7 << 3)
+#define PANELCTL_EM_CLK2_110 (6 << 3)
+#define PANELCTL_EM_CLK2_111 (7 << 3)
+#define PANELCTL_EM_CLK2B_CON_MASK (7 << 0)
+#define PANELCTL_EM_CLK2B_110 (6 << 0)
+#define PANELCTL_EM_CLK2B_111 (7 << 0)
+/* 38 */
+#define PANELCTL_EM_INT1_CON_MASK (7 << 3)
+#define PANELCTL_EM_INT1_000 (0 << 3)
+#define PANELCTL_EM_INT1_001 (1 << 3)
+#define PANELCTL_EM_INT2_CON_MASK (7 << 0)
+#define PANELCTL_EM_INT2_000 (0 << 0)
+#define PANELCTL_EM_INT2_001 (1 << 0)
+
#define VER_142 (0x8e) /* MACH_SLP_PQ */
#define VER_174 (0xae) /* MACH_SLP_PQ Dali */
#define VER_42 (0x2a) /* MACH_SLP_PQ_LTE */
#define VER_32 (0x20) /* MACH_SLP_PQ M0 B-Type */
+#define VER_96 (0x60) /* MACH_SLP_PQ Galaxy S3 */
#define VER_210 (0xd2) /* MACH_SLP_PQ M0 A-Type */
#define AID_DISABLE (0x4)
@@ -61,87 +121,64 @@
#define lcd_to_master(a) (a->dsim_dev->master)
#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
-struct str_elvss {
- u8 reference;
- u8 limit;
-};
-
struct panel_model {
int ver;
char *name;
};
-enum {
- DSIM_NONE_STATE = 0,
- DSIM_RESUME_COMPLETE = 1,
- DSIM_FRAME_DONE = 2,
-};
-
struct s6e8aa0 {
struct device *dev;
- unsigned int id;
- unsigned int aid;
- unsigned int ver;
- unsigned int power;
- unsigned int current_brightness;
- unsigned int updated;
- unsigned int brightness;
- unsigned int resume_complete;
- unsigned int acl_enable;
- unsigned int cur_acl;
- unsigned int cur_addr;
-
- struct lcd_device *ld;
- struct backlight_device *bd;
-
+ struct lcd_device *ld;
+ struct backlight_device *bd;
struct mipi_dsim_lcd_device *dsim_dev;
struct lcd_platform_data *ddi_pd;
+ struct lcd_property *property;
- struct mutex lock;
- struct regulator *reg_vdd3;
- struct regulator *reg_vci;
+ struct regulator *reg_vdd3;
+ struct regulator *reg_vci;
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+ struct notifier_block nb_disp;
+#endif
+ struct mutex lock;
+
+ unsigned int id;
+ unsigned int aid;
+ unsigned int ver;
+ unsigned int power;
+ unsigned int acl_enable;
+ unsigned int cur_acl;
+ unsigned int cur_addr;
const struct panel_model *model;
- unsigned int model_count;
+ unsigned int model_count;
- bool enabled;
#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
- unsigned int support_elvss;
- struct str_smart_dim smart_dim;
- struct str_elvss elvss;
- struct mutex bl_lock;
+ unsigned int support_elvss;
+ struct str_smart_dim smart_dim;
#endif
};
-struct s6e8aa0 *lcd_global;
-
-static void s6e8aa0_regulator_enable(struct s6e8aa0 *lcd)
+static void s6e8aa0_regulator_ctl(struct s6e8aa0 *lcd, bool enable)
{
+ dev_dbg(lcd->dev, "%s:enable[%d]\n", __func__, enable);
+
mutex_lock(&lcd->lock);
- if (!lcd->enabled) {
+
+ if (enable) {
if (lcd->reg_vdd3)
regulator_enable(lcd->reg_vdd3);
if (lcd->reg_vci)
regulator_enable(lcd->reg_vci);
-
- lcd->enabled = true;
- }
- mutex_unlock(&lcd->lock);
-}
-
-static void s6e8aa0_regulator_disable(struct s6e8aa0 *lcd)
-{
- mutex_lock(&lcd->lock);
- if (lcd->enabled) {
+ } else {
if (lcd->reg_vci)
regulator_disable(lcd->reg_vci);
if (lcd->reg_vdd3)
regulator_disable(lcd->reg_vdd3);
-
- lcd->enabled = false;
}
+
mutex_unlock(&lcd->lock);
}
@@ -178,9 +215,8 @@ static unsigned char s6e8aa0_apply_aid_panel_cond(unsigned int aid)
return ret;
}
-void s6e8aa0_panel_cond(int high_freq)
+static void s6e8aa0_panel_cond(struct s6e8aa0 *lcd, int high_freq)
{
- struct s6e8aa0 *lcd = lcd_global;
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
unsigned char data_to_send_v42[] = {
0xf8, 0x01, 0x34, 0x00, 0x00, 0x00, 0x95, 0x00, 0x3c,
@@ -204,6 +240,13 @@ void s6e8aa0_panel_cond(int high_freq)
0x23, 0x6e, 0xc0, 0xc1, 0x01, 0x81, 0xc1, 0x00, 0xc3,
0xf6, 0xf6, 0xc1
};
+ unsigned char data_to_send_v96[] = {
+ 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x94, 0x00, 0x3c,
+ 0x7d, 0x10, 0x27, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+ 0x23, 0x37, 0xc0, 0xc1, 0x01, 0x81, 0xc1, 0x00, 0xc3,
+ 0xf6, 0xf6, 0xc1
+ };
unsigned char data_to_send_v210[] = {
0xf8, 0x3d, 0x32, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x39,
0x78, 0x08, 0x26, 0x78, 0x3c, 0x00, 0x00, 0x00, 0x20,
@@ -213,17 +256,92 @@ void s6e8aa0_panel_cond(int high_freq)
};
unsigned char *data_to_send;
unsigned int size;
+ struct lcd_property *property = lcd->property;
+ unsigned char cfg;
if (lcd->ver == VER_42) {
data_to_send = data_to_send_v42;
size = ARRAY_SIZE(data_to_send_v42);
- } else if (lcd->ver == VER_142 || lcd->ver == VER_174) {
+ } else if (lcd->ver == VER_142) {
+ data_to_send_v142[18] = s6e8aa0_apply_aid_panel_cond(lcd->aid);
+ data_to_send = data_to_send_v142;
+ if (property) {
+ if (property->flip & LCD_PROPERTY_FLIP_VERTICAL) {
+ /* GTCON */
+ cfg = data_to_send[1];
+ cfg &= ~(PANELCTL_GTCON_MASK);
+ cfg |= (PANELCTL_GTCON_110);
+ data_to_send[1] = cfg;
+ }
+
+ if (property->flip & LCD_PROPERTY_FLIP_HORIZONTAL) {
+ /* SS */
+ cfg = data_to_send[1];
+ cfg &= ~(PANELCTL_SS_MASK);
+ cfg |= (PANELCTL_SS_1_800);
+ data_to_send[1] = cfg;
+ }
+
+ if (property->flip & (LCD_PROPERTY_FLIP_VERTICAL |
+ LCD_PROPERTY_FLIP_HORIZONTAL)) {
+ /* CLK1,2_CON */
+ cfg = data_to_send[30];
+ cfg &= ~(PANELCTL_CLK1_CON_MASK |
+ PANELCTL_CLK2_CON_MASK);
+ cfg |= (PANELCTL_CLK1_000 | PANELCTL_CLK2_001);
+ data_to_send[30] = cfg;
+
+ /* INT1,2_CON */
+ cfg = data_to_send[31];
+ cfg &= ~(PANELCTL_INT1_CON_MASK |
+ PANELCTL_INT2_CON_MASK);
+ cfg |= (PANELCTL_INT1_000 | PANELCTL_INT2_001);
+ data_to_send[31] = cfg;
+
+ /* BICTL,B_CON */
+ cfg = data_to_send[32];
+ cfg &= ~(PANELCTL_BICTL_CON_MASK |
+ PANELCTL_BICTLB_CON_MASK);
+ cfg |= (PANELCTL_BICTL_000 |
+ PANELCTL_BICTLB_001);
+ data_to_send[32] = cfg;
+
+ /* EM_CLK1,1B_CON */
+ cfg = data_to_send[36];
+ cfg &= ~(PANELCTL_EM_CLK1_CON_MASK |
+ PANELCTL_EM_CLK1B_CON_MASK);
+ cfg |= (PANELCTL_EM_CLK1_110 |
+ PANELCTL_EM_CLK1B_110);
+ data_to_send[36] = cfg;
+
+ /* EM_CLK2,2B_CON */
+ cfg = data_to_send[37];
+ cfg &= ~(PANELCTL_EM_CLK2_CON_MASK |
+ PANELCTL_EM_CLK2B_CON_MASK);
+ cfg |= (PANELCTL_EM_CLK2_110 |
+ PANELCTL_EM_CLK2B_110);
+ data_to_send[37] = cfg;
+
+ /* EM_INT1,2_CON */
+ cfg = data_to_send[38];
+ cfg &= ~(PANELCTL_EM_INT1_CON_MASK |
+ PANELCTL_EM_INT2_CON_MASK);
+ cfg |= (PANELCTL_EM_INT1_000 |
+ PANELCTL_EM_INT2_001);
+ data_to_send[38] = cfg;
+ }
+ }
+ size = ARRAY_SIZE(data_to_send_v142);
+ } else if (lcd->ver == VER_174) {
data_to_send_v142[18] = s6e8aa0_apply_aid_panel_cond(lcd->aid);
data_to_send = data_to_send_v142;
size = ARRAY_SIZE(data_to_send_v142);
} else if (lcd->ver == VER_32) {
data_to_send = data_to_send_v32;
size = ARRAY_SIZE(data_to_send_v32);
+ } else if (lcd->ver == VER_96) {
+ data_to_send = data_to_send_v96;
+ size = ARRAY_SIZE(data_to_send_v96);
} else if (lcd->ver == VER_210) {
data_to_send = data_to_send_v210;
size = ARRAY_SIZE(data_to_send_v210);
@@ -270,7 +388,7 @@ static void s6e8aa0_etc_pentile_control(struct s6e8aa0 *lcd)
0x00
};
- if (lcd->ver == VER_32)
+ if (lcd->ver == VER_32 || lcd->ver == VER_96)
data_to_send[5] = 0xc0;
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
@@ -306,7 +424,7 @@ static void s6e8aa0_etc_power_control(struct s6e8aa0 *lcd)
0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02
};
- if (lcd->ver == VER_32) {
+ if (lcd->ver == VER_32 || lcd->ver == VER_96) {
data_to_send[3] = 0x15;
data_to_send[5] = 0x19;
}
@@ -349,6 +467,8 @@ static void s6e8aa0_etc_elvss_control(struct s6e8aa0 *lcd)
static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ struct backlight_device *bd = lcd->bd;
+ int brightness = bd->props.brightness;
unsigned char data_to_send[] = {
0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x0f,
0x40, 0x41, 0xd9, 0x00, 0x60, 0x19
@@ -358,11 +478,15 @@ static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *lcd)
if (lcd->ver == VER_32) {
data_to_send[8] = 0x07;
data_to_send[11] = 0xc1;
+ } else if (lcd->ver == VER_96) {
+ data_to_send[8] = 0x07;
+ data_to_send[9] = 0xc0;
+ data_to_send[11] = 0xc1;
} else if (lcd->ver == VER_210 || lcd->ver == VER_174) {
data_to_send[8] = 0x07;
data_to_send[11] = 0xd0;
} else {
- switch (lcd->brightness) {
+ switch (brightness) {
case 0 ... 6: /* 30cd ~ 100cd */
data_to_send[11] = 0xdf;
break;
@@ -428,19 +552,21 @@ static void s6e8aa0_acl_on(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_SHORT_WRITE, 0xc0, 0x01);
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xc0, 0x01);
}
static void s6e8aa0_acl_off(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
ops->cmd_write(lcd_to_master(lcd),
- MIPI_DSI_DCS_SHORT_WRITE, 0xc0, 0x00);
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xc0, 0x00);
}
static void s6e8aa0_acl_ctrl_set(struct s6e8aa0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ struct backlight_device *bd = lcd->bd;
+ int brightness = bd->props.brightness;
/* FIXME: !! must be review acl % value */
/* Full white 50% reducing setting */
const unsigned char cutoff_50[] = {
@@ -466,14 +592,14 @@ static void s6e8aa0_acl_ctrl_set(struct s6e8aa0 *lcd)
if (lcd->acl_enable) {
if (lcd->cur_acl == 0) {
- if (lcd->brightness == 0 || lcd->brightness == 1) {
+ if (brightness == 0 || brightness == 1) {
s6e8aa0_acl_off(lcd);
dev_dbg(&lcd->ld->dev,
"cur_acl=%d\n", lcd->cur_acl);
} else
s6e8aa0_acl_on(lcd);
}
- switch (lcd->brightness) {
+ switch (brightness) {
case 0 ... 1: /* 30cd */
s6e8aa0_acl_off(lcd);
lcd->cur_acl = 0;
@@ -570,7 +696,7 @@ unsigned int convert_brightness_to_gamma(int brightness)
return gamma_table[brightness] - 1;
}
-static int s6e8aa0_update_gamma_ctrl(struct s6e8aa0 *lcd, int brightness)
+static int s6e8aa0_gamma_ctrl(struct s6e8aa0 *lcd, int brightness)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
@@ -597,22 +723,16 @@ static int s6e8aa0_update_gamma_ctrl(struct s6e8aa0 *lcd, int brightness)
ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
0xf7, 0x03);
- lcd->brightness = brightness;
-
s6e8aa0_acl_ctrl_set(lcd);
return 0;
}
-static int s6e8aa0_gamma_ctrl(struct s6e8aa0 *lcd, int brightness)
-{
- s6e8aa0_update_gamma_ctrl(lcd, brightness);
-
- return 0;
-}
-
static int s6e8aa0_panel_init(struct s6e8aa0 *lcd)
{
+ struct backlight_device *bd = lcd->bd;
+ int brightness = bd->props.brightness;
+
s6e8aa0_apply_level_1_key(lcd);
if (system_rev == 3)
s6e8aa0_apply_level_2_key(lcd);
@@ -620,10 +740,10 @@ static int s6e8aa0_panel_init(struct s6e8aa0 *lcd)
s6e8aa0_sleep_out(lcd);
usleep_range(5000, 6000);
- s6e8aa0_panel_cond(1);
+ s6e8aa0_panel_cond(lcd, 1);
s6e8aa0_display_condition_set(lcd);
- s6e8aa0_gamma_ctrl(lcd, lcd->bd->props.brightness);
+ s6e8aa0_gamma_ctrl(lcd, brightness);
s6e8aa0_etc_source_control(lcd);
s6e8aa0_etc_pentile_control(lcd);
@@ -633,6 +753,7 @@ static int s6e8aa0_panel_init(struct s6e8aa0 *lcd)
/* if ID3 value is not 33h, branch private elvss mode */
mdelay(lcd->ddi_pd->power_on_delay);
+ dev_info(lcd->dev, "panel init sequence done.\n");
return 0;
}
@@ -712,7 +833,7 @@ static int s6e8aa0_set_brightness(struct backlight_device *bd)
int ret = 0, brightness = bd->props.brightness;
struct s6e8aa0 *lcd = bl_get_data(bd);
- if (!lcd->enabled) {
+ if (lcd->power == FB_BLANK_POWERDOWN) {
dev_err(lcd->dev,
"lcd off: brightness set failed.\n");
return -EINVAL;
@@ -802,9 +923,11 @@ static void s6e8aa0_power_on(struct mipi_dsim_lcd_device *dsim_dev,
{
struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ dev_dbg(lcd->dev, "%s:enable[%d]\n", __func__, enable);
+
if (enable) {
/* lcd power on */
- s6e8aa0_regulator_enable(lcd);
+ s6e8aa0_regulator_ctl(lcd, true);
mdelay(lcd->ddi_pd->reset_delay);
@@ -813,8 +936,10 @@ static void s6e8aa0_power_on(struct mipi_dsim_lcd_device *dsim_dev,
lcd->ddi_pd->reset(lcd->ld);
mdelay(5);
- } else
- s6e8aa0_regulator_disable(lcd);
+ } else {
+ /* lcd power off */
+ s6e8aa0_regulator_ctl(lcd, false);
+ }
}
@@ -924,10 +1049,14 @@ static int s6e8aa0_write_reg(struct s6e8aa0 *lcd, char *name)
return ret;
}
- if (fw->size < 2)
+ if (fw->size == 1)
ret = ops->cmd_write(lcd_to_master(lcd),
MIPI_DSI_DCS_SHORT_WRITE,
- (unsigned int)fw->data, fw->size);
+ (unsigned int)fw->data[0], 0);
+ else if (fw->size == 2)
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ (unsigned int)fw->data[0], fw->data[1]);
else
ret = ops->cmd_write(lcd_to_master(lcd),
MIPI_DSI_DCS_LONG_WRITE,
@@ -1017,11 +1146,38 @@ static struct panel_model s6e8aa0_model[] = {
.ver = VER_32, /* MACH_SLP_PQ M0 B-Type */
.name = "SMD_AMS480GYXX-0",
}, {
+ .ver = VER_96, /* MACH_SLP_PQ Galaxy S3 */
+ .name = "SMD_AMS480GYXX-0",
+ }, {
.ver = VER_210, /* MACH_SLP_PQ M0 A-Type */
.name = "SMD_AMS465GS0x",
}
};
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+static int s6e8aa0_notifier_callback(struct notifier_block *this,
+ unsigned long event, void *_data)
+{
+ struct s6e8aa0 *lcd = container_of(this, struct s6e8aa0, nb_disp);
+
+ if (lcd->power == FB_BLANK_POWERDOWN)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case EXYNOS4_DISPLAY_LV_HF:
+ s6e8aa0_panel_cond(lcd, 1);
+ break;
+ case EXYNOS4_DISPLAY_LV_LF:
+ s6e8aa0_panel_cond(lcd, 0);
+ break;
+ default:
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_DONE;
+}
+#endif
+
static int s6e8aa0_probe(struct mipi_dsim_lcd_device *dsim_dev)
{
struct s6e8aa0 *lcd;
@@ -1072,9 +1228,20 @@ static int s6e8aa0_probe(struct mipi_dsim_lcd_device *dsim_dev)
goto err_unregister_lcd;
}
+ if (lcd->ddi_pd)
+ lcd->property = lcd->ddi_pd->pdata;
+
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+ if (lcd->property && lcd->property->dynamic_refresh) {
+ lcd->nb_disp.notifier_call = s6e8aa0_notifier_callback;
+ ret = exynos4_display_register_client(&lcd->nb_disp);
+ if (ret < 0)
+ dev_warn(&lcd->ld->dev, "failed to register exynos-display notifier\n");
+ }
+#endif
+
lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
lcd->bd->props.brightness = MAX_BRIGHTNESS;
-
lcd->acl_enable = 1;
lcd->cur_acl = 0;
lcd->model = s6e8aa0_model;
@@ -1090,11 +1257,9 @@ static int s6e8aa0_probe(struct mipi_dsim_lcd_device *dsim_dev)
dev_set_drvdata(&dsim_dev->dev, lcd);
- s6e8aa0_regulator_enable(lcd);
+ s6e8aa0_regulator_ctl(lcd, true);
lcd->power = FB_BLANK_UNBLANK;
- lcd_global = lcd;
-
dev_info(lcd->dev, "probed s6e8aa0 panel driver(%s).\n",
dev_name(&lcd->ld->dev));
@@ -1121,9 +1286,13 @@ static void s6e8aa0_remove(struct mipi_dsim_lcd_device *dsim_dev)
lcd_device_unregister(lcd->ld);
regulator_put(lcd->reg_vci);
-
regulator_put(lcd->reg_vdd3);
+#if defined(CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ) || defined(CONFIG_DISPFREQ_OPP)
+ if (lcd->property && lcd->property->dynamic_refresh)
+ exynos4_display_unregister_client(&lcd->nb_disp);
+#endif
+
kfree(lcd);
}
@@ -1183,5 +1352,7 @@ module_exit(s6e8aa0_exit);
MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
+MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/s6e8aa0.h b/drivers/video/backlight/s6e8aa0.h
index 4e19d7d..0510ec2 100644
--- a/drivers/video/backlight/s6e8aa0.h
+++ b/drivers/video/backlight/s6e8aa0.h
@@ -6,6 +6,8 @@
*
* Inki Dae, <inki.dae@samsung.com>
* Donghwa Lee <dh09.lee@samsung.com>
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.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
@@ -15,12 +17,7 @@
#ifndef _S6E8AA0_H
#define _S6E8AA0_H
-extern void s6e8aa0_init(void);
-extern void s6e8aa0_set_link(void *pd, unsigned int dsim_base,
- unsigned char (*cmd_write) (unsigned int dsim_base, unsigned int data0,
- unsigned int data1, unsigned int data2),
- unsigned char (*cmd_read) (unsigned int dsim_base, unsigned int data0,
- unsigned int data1, unsigned int data2));
+/* ToDo */
#endif
diff --git a/drivers/video/backlight/smart_dimming.c b/drivers/video/backlight/smart_dimming.c
index 42438ad..5f8bea0 100644
--- a/drivers/video/backlight/smart_dimming.c
+++ b/drivers/video/backlight/smart_dimming.c
@@ -167,6 +167,14 @@ const unsigned char gamma_300cd_d2[] = {
0x00, 0xBD, 0x00, 0xAC, 0x00, 0xDE,
};
+/* SM2, C1/M0 4.8" - D*/
+const unsigned char gamma_300cd_60[] = {
+ 0x3F, 0x12, 0x41, 0xB4, 0xCB, 0xB0,
+ 0xB2, 0xC4, 0xB2, 0xC4, 0xCF, 0xC2,
+ 0x9A, 0xA7, 0x97, 0xB2, 0xBA, 0xB0,
+ 0x00, 0xA0, 0x00, 0x98, 0x00, 0xB7,
+};
+
const unsigned char *gamma_300cd_list[GAMMA_300CD_MAX] = {
gamma_300cd_23,
gamma_300cd_33,
@@ -182,11 +190,12 @@ const unsigned char *gamma_300cd_list[GAMMA_300CD_MAX] = {
gamma_300cd_8e,
gamma_300cd_ae,
gamma_300cd_d2,
+ gamma_300cd_60,
};
const unsigned char gamma_id_list[GAMMA_300CD_MAX] = {
0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x20,
- 0x2a, 0x29, 0x4e, 0x8e, 0xae, 0xd2
+ 0x2a, 0x29, 0x4e, 0x8e, 0xae, 0xd2, 0x60
};
static s16 s9_to_s16(s16 v)
diff --git a/drivers/video/backlight/smart_dimming.h b/drivers/video/backlight/smart_dimming.h
index ae21182..3531213 100644
--- a/drivers/video/backlight/smart_dimming.h
+++ b/drivers/video/backlight/smart_dimming.h
@@ -23,7 +23,7 @@
#define MAX_GRADATION 300
#define PANEL_ID_MAX 3
-#define GAMMA_300CD_MAX 14
+#define GAMMA_300CD_MAX 15
enum {