aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/backlight
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/backlight')
-rw-r--r--drivers/video/backlight/Kconfig76
-rw-r--r--drivers/video/backlight/Makefile8
-rw-r--r--drivers/video/backlight/ams369fg06.c636
-rw-r--r--drivers/video/backlight/ams369fg06_gamma.h61
-rw-r--r--drivers/video/backlight/backlight.c46
-rw-r--r--drivers/video/backlight/lcd.c22
-rw-r--r--drivers/video/backlight/lms501kf03.c598
-rw-r--r--drivers/video/backlight/pwm_bl.c8
-rw-r--r--drivers/video/backlight/s6e39a0x02.c799
-rw-r--r--drivers/video/backlight/s6e39a0x02_gamma.h180
-rw-r--r--drivers/video/backlight/s6e63m0_mipi_lcd.c166
-rw-r--r--drivers/video/backlight/s6e8aa0.c1187
-rw-r--r--drivers/video/backlight/s6e8aa0.h26
-rw-r--r--drivers/video/backlight/s6e8aa0_gamma.h220
-rw-r--r--drivers/video/backlight/s6e8aa0_volt_tbl.h967
-rw-r--r--drivers/video/backlight/s6e8ab0_mipi_lcd.c77
-rw-r--r--drivers/video/backlight/smart_dimming.c771
-rw-r--r--drivers/video/backlight/smart_dimming.h104
-rw-r--r--drivers/video/backlight/tc358764_mipi_lcd.c110
19 files changed, 6062 insertions, 0 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 2d93c8d..80f42e6 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -109,6 +109,30 @@ config LCD_S6E63M0
If you have an S6E63M0 LCD Panel, say Y to enable its
LCD control driver.
+config LCD_MIPI_S6E63M0
+ tristate "S6E63M0 AMOLED MIPI LCD Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an S6E63M0 MIPI LCD Panel, say Y to enable its
+ LCD control driver.
+
+config LCD_MIPI_S6E8AB0
+ tristate "1280 X 800 S6E8AB0 AMOLED MIPI LCD Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an S6E8AB0 MIPI LCD Panel, say Y to enable its
+ LCD control driver.
+
+config LCD_MIPI_TC358764
+ tristate "1280 X 800 TC358764 AMOLED MIPI LCD Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an TC358764 MIPI LCD Panel, say Y to enable its
+ LCD control driver.
+
config LCD_LD9040
tristate "LD9040 AMOLED LCD Driver"
depends on SPI && BACKLIGHT_CLASS_DEVICE
@@ -117,6 +141,52 @@ config LCD_LD9040
If you have an LD9040 Panel, say Y to enable its
control driver.
+config LCD_AMS369FG06
+ tristate "AMS369FG06 AMOLED LCD Driver"
+ depends on SPI_GPIO && BACKLIGHT_CLASS_DEVICE && FB_S3C
+ default y
+ help
+ If you have an AMS369FG06 AMOLED Panel, say Y to enable its
+ LCD control driver.
+
+config LCD_LMS501KF03
+ tristate "LMS501KF03 TFT LCD Driver"
+ depends on SPI_GPIO && BACKLIGHT_CLASS_DEVICE && FB_S3C
+ default y
+ help
+ If you have an LMS501KF03 AMOLED Panel, say Y to enable its
+ LCD control driver.
+
+config LCD_WA101S
+ tristate "LCD_WA101S LCD Driver"
+ default n
+ help
+ If you have a WA101S Panel(WXGA), say Y to enable its
+ LCD control driver.
+
+config LCD_LTE480WV
+ tristate "LCD_LTE480WV LCD Driver"
+ default n
+ help
+ If you have an LTE480 Panel(WVGA), say Y to enable its
+ LCD control drvier.
+
+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)
+ default n
+ help
+ If you have an S6E8AA0 MIPI AMOLED LCD Panel, say Y to enable its
+ LCD control driver.
+
+config LCD_S6E39A0X02
+ tristate "S6E39A0X02 MIPI AMOLED LCD Driver"
+ depends on S5P_MIPI_DSI2 && BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an S6E39A0X02 MIPI AMOLED LCD Panel, say Y to enable its
+ LCD control driver.
endif # LCD_CLASS_DEVICE
#
@@ -327,6 +397,12 @@ config BACKLIGHT_PCF50633
If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
enable its driver.
+config BACKLIGHT_SMART_DIMMING
+ bool "SLP Backlight driver feature for smart dimming"
+ depends on (MACH_SLP_MIDAS || MACH_SLP_PQ_LTE || MACH_SLP_PQ)
+ help
+ Say Y to enable the Smart Dimming Feature.
+
endif # BACKLIGHT_CLASS_DEVICE
endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index ee72adb..16737d6 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -12,7 +12,14 @@ obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
+obj-$(CONFIG_LCD_MIPI_S6E63M0) += s6e63m0_mipi_lcd.o
+obj-$(CONFIG_LCD_MIPI_S6E8AB0) += s6e8ab0_mipi_lcd.o
+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_S6E39A0X02) += s6e39a0x02.o
+obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
@@ -37,4 +44,5 @@ obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o
obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o
obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
+obj-$(CONFIG_BACKLIGHT_SMART_DIMMING) += smart_dimming.o
diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c
new file mode 100644
index 0000000..66643a1
--- /dev/null
+++ b/drivers/video/backlight/ams369fg06.c
@@ -0,0 +1,636 @@
+/*
+ * ams369fg06 AMOLED LCD panel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * Derived from drivers/video/s6e63m0.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/wait.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include "ams369fg06_gamma.h"
+
+#define SLEEPMSEC 0x1000
+#define ENDDEF 0x2000
+#define DEFMASK 0xFF00
+#define COMMAND_ONLY 0xFE
+#define DATA_ONLY 0xFF
+
+#define MIN_BRIGHTNESS 0
+#define MAX_BRIGHTNESS 255
+#define DEFAULT_BRIGHTNESS 150
+
+#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
+
+struct ams369fg06 {
+ struct device *dev;
+ struct spi_device *spi;
+ unsigned int power;
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+ struct lcd_platform_data *lcd_pd;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+const unsigned short SEQ_DISPLAY_ON[] = {
+ 0x14, 0x03,
+ ENDDEF, 0x0000
+};
+
+const unsigned short SEQ_DISPLAY_OFF[] = {
+ 0x14, 0x00,
+ ENDDEF, 0x0000
+};
+
+const unsigned short SEQ_STAND_BY_ON[] = {
+ 0x1D, 0xA1,
+ SLEEPMSEC, 200,
+ ENDDEF, 0x0000
+};
+
+const unsigned short SEQ_STAND_BY_OFF[] = {
+ 0x1D, 0xA0,
+ SLEEPMSEC, 250,
+ ENDDEF, 0x0000
+};
+
+const unsigned short SEQ_SETTING[] = {
+ 0x31, 0x08,
+ 0x32, 0x14,
+ 0x30, 0x02,
+ 0x27, 0x01,
+ 0x12, 0x08,
+ 0x13, 0x08,
+ 0x15, 0x00,
+ 0x16, 0x00,
+
+ 0xef, 0xd0,
+ DATA_ONLY, 0xe8,
+
+ 0x39, 0x44,
+ 0x40, 0x00,
+ 0x41, 0x3f,
+ 0x42, 0x2a,
+ 0x43, 0x27,
+ 0x44, 0x27,
+ 0x45, 0x1f,
+ 0x46, 0x44,
+ 0x50, 0x00,
+ 0x51, 0x00,
+ 0x52, 0x17,
+ 0x53, 0x24,
+ 0x54, 0x26,
+ 0x55, 0x1f,
+ 0x56, 0x43,
+ 0x60, 0x00,
+ 0x61, 0x3f,
+ 0x62, 0x2a,
+ 0x63, 0x25,
+ 0x64, 0x24,
+ 0x65, 0x1b,
+ 0x66, 0x5c,
+
+ 0x17, 0x22,
+ 0x18, 0x33,
+ 0x19, 0x03,
+ 0x1a, 0x01,
+ 0x22, 0xa4,
+ 0x23, 0x00,
+ 0x26, 0xa0,
+
+ 0x1d, 0xa0,
+ SLEEPMSEC, 300,
+
+ 0x14, 0x03,
+
+ ENDDEF, 0x0000
+};
+
+static int ams369fg06_spi_write_byte(struct ams369fg06 *lcd, int addr, int data)
+{
+ u16 buf[1];
+ struct spi_message msg;
+
+ struct spi_transfer xfer = {
+ .len = 2,
+ .tx_buf = buf,
+ };
+
+ buf[0] = (addr << 8) | data;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ return spi_sync(lcd->spi, &msg);
+}
+
+static int ams369fg06_spi_write(struct ams369fg06 *lcd, unsigned char address,
+ unsigned char command)
+{
+ int ret = 0;
+
+ if (address != DATA_ONLY)
+ ret = ams369fg06_spi_write_byte(lcd, 0x70, address);
+ if (command != COMMAND_ONLY)
+ ret = ams369fg06_spi_write_byte(lcd, 0x72, command);
+
+ return ret;
+}
+
+static int ams369fg06_panel_send_sequence(struct ams369fg06 *lcd,
+ const unsigned short *wbuf)
+{
+ int ret = 0, i = 0;
+
+ while ((wbuf[i] & DEFMASK) != ENDDEF) {
+ if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
+ ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]);
+ if (ret)
+ break;
+ } else
+ udelay(wbuf[i+1]*1000);
+ i += 2;
+ }
+
+ return ret;
+}
+
+static int _ams369fg06_gamma_ctl(struct ams369fg06 *lcd,
+ const unsigned int *gamma)
+{
+ unsigned int i = 0;
+ int ret = 0;
+
+ for (i = 0 ; i < GAMMA_TABLE_COUNT / 3; i++) {
+ ret = ams369fg06_spi_write(lcd, 0x40 + i, gamma[i]);
+ ret = ams369fg06_spi_write(lcd, 0x50 + i, gamma[i+7*1]);
+ ret = ams369fg06_spi_write(lcd, 0x60 + i, gamma[i+7*2]);
+ if (ret) {
+ dev_err(lcd->dev, "failed to set gamma table.\n");
+ goto gamma_err;
+ }
+ }
+
+gamma_err:
+ return ret;
+}
+
+static int ams369fg06_gamma_ctl(struct ams369fg06 *lcd, int brightness)
+{
+ int ret = 0;
+ int gamma = 0;
+
+ if ((brightness >= 0) && (brightness <= 50))
+ gamma = 0;
+ else if ((brightness > 50) && (brightness <= 100))
+ gamma = 1;
+ else if ((brightness > 100) && (brightness <= 150))
+ gamma = 2;
+ else if ((brightness > 150) && (brightness <= 200))
+ gamma = 3;
+ else if ((brightness > 200) && (brightness <= 255))
+ gamma = 4;
+
+ ret = _ams369fg06_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
+
+ return ret;
+}
+
+static int ams369fg06_ldi_init(struct ams369fg06 *lcd)
+{
+ int ret, i;
+ const unsigned short *init_seq[] = {
+ SEQ_SETTING,
+ SEQ_STAND_BY_OFF,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int ams369fg06_ldi_enable(struct ams369fg06 *lcd)
+{
+ int ret, i;
+ const unsigned short *init_seq[] = {
+ SEQ_STAND_BY_OFF,
+ SEQ_DISPLAY_ON,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int ams369fg06_ldi_disable(struct ams369fg06 *lcd)
+{
+ int ret, i;
+
+ const unsigned short *init_seq[] = {
+ SEQ_DISPLAY_OFF,
+ SEQ_STAND_BY_ON,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int ams369fg06_power_on(struct ams369fg06 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+ struct backlight_device *bd = NULL;
+
+ pd = lcd->lcd_pd;
+ if (!pd) {
+ dev_err(lcd->dev, "platform data is NULL.\n");
+ return -EFAULT;
+ }
+
+ bd = lcd->bd;
+ if (!bd) {
+ dev_err(lcd->dev, "backlight device is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!pd->power_on) {
+ dev_err(lcd->dev, "power_on is NULL.\n");
+ return -EFAULT;
+ } else {
+ pd->power_on(lcd->ld, 1);
+ mdelay(pd->power_on_delay);
+ }
+
+ if (!pd->reset) {
+ dev_err(lcd->dev, "reset is NULL.\n");
+ return -EFAULT;
+ } else {
+ pd->reset(lcd->ld);
+ mdelay(pd->reset_delay);
+ }
+
+ ret = ams369fg06_ldi_init(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "failed to initialize ldi.\n");
+ return ret;
+ }
+
+ ret = ams369fg06_ldi_enable(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "failed to enable ldi.\n");
+ return ret;
+ }
+
+ /* set brightness to current value after power on or resume. */
+ ret = ams369fg06_gamma_ctl(lcd, bd->props.brightness);
+ if (ret) {
+ dev_err(lcd->dev, "lcd gamma setting failed.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ams369fg06_power_off(struct ams369fg06 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+
+ pd = lcd->lcd_pd;
+ if (!pd) {
+ dev_err(lcd->dev, "platform data is NULL\n");
+ return -EFAULT;
+ }
+
+ ret = ams369fg06_ldi_disable(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "lcd setting failed.\n");
+ return -EIO;
+ }
+
+ mdelay(pd->power_off_delay);
+
+ if (!pd->power_on) {
+ dev_err(lcd->dev, "power_on is NULL.\n");
+ return -EFAULT;
+ } else
+ pd->power_on(lcd->ld, 0);
+
+ return 0;
+}
+
+static int ams369fg06_power(struct ams369fg06 *lcd, int power)
+{
+ int ret = 0;
+
+ if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+ ret = ams369fg06_power_on(lcd);
+ else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+ ret = ams369fg06_power_off(lcd);
+
+ if (!ret)
+ lcd->power = power;
+
+ return ret;
+}
+
+static int ams369fg06_get_power(struct lcd_device *ld)
+{
+ struct ams369fg06 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static int ams369fg06_set_power(struct lcd_device *ld, int power)
+{
+ struct ams369fg06 *lcd = lcd_get_data(ld);
+
+ 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;
+ }
+
+ return ams369fg06_power(lcd, power);
+}
+
+static int ams369fg06_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int ams369fg06_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0;
+ int brightness = bd->props.brightness;
+ struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev);
+
+ if (brightness < MIN_BRIGHTNESS ||
+ brightness > bd->props.max_brightness) {
+ dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ ret = ams369fg06_gamma_ctl(lcd, bd->props.brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static struct lcd_ops ams369fg06_lcd_ops = {
+ .get_power = ams369fg06_get_power,
+ .set_power = ams369fg06_set_power,
+};
+
+static const struct backlight_ops ams369fg06_backlight_ops = {
+ .get_brightness = ams369fg06_get_brightness,
+ .update_status = ams369fg06_set_brightness,
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+unsigned int before_power;
+
+static void ams369fg06_early_suspend(struct early_suspend *handler)
+{
+ struct ams369fg06 *lcd = NULL;
+
+ lcd = container_of(handler, struct ams369fg06, early_suspend);
+
+ before_power = lcd->power;
+
+ ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static void ams369fg06_late_resume(struct early_suspend *handler)
+{
+ struct ams369fg06 *lcd = NULL;
+
+ lcd = container_of(handler, struct ams369fg06, early_suspend);
+
+ if (before_power == FB_BLANK_UNBLANK)
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ ams369fg06_power(lcd, before_power);
+}
+#endif
+
+static int __init ams369fg06_probe(struct spi_device *spi)
+{
+ int ret = 0;
+ struct ams369fg06 *lcd = NULL;
+ struct lcd_device *ld = NULL;
+ struct backlight_device *bd = NULL;
+
+ lcd = kzalloc(sizeof(struct ams369fg06), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ /* ams369fg06 lcd panel uses 3-wire 16bits SPI Mode. */
+ spi->bits_per_word = 16;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi setup failed.\n");
+ goto out_free_lcd;
+ }
+
+ lcd->spi = spi;
+ lcd->dev = &spi->dev;
+
+ lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data;
+ if (!lcd->lcd_pd) {
+ dev_err(&spi->dev, "platform data is NULL\n");
+ goto out_free_lcd;
+ }
+
+ ld = lcd_device_register("ams369fg06", &spi->dev, lcd,
+ &ams369fg06_lcd_ops);
+ if (IS_ERR(ld)) {
+ ret = PTR_ERR(ld);
+ goto out_free_lcd;
+ }
+
+ lcd->ld = ld;
+
+ bd = backlight_device_register("ams369fg06-bl", &spi->dev, lcd,
+ &ams369fg06_backlight_ops, NULL);
+ if (IS_ERR(bd)) {
+ ret = PTR_ERR(bd);
+ goto out_lcd_unregister;
+ }
+
+ bd->props.max_brightness = MAX_BRIGHTNESS;
+ bd->props.brightness = DEFAULT_BRIGHTNESS;
+ bd->props.type = BACKLIGHT_RAW;
+ lcd->bd = bd;
+
+ if (!lcd->lcd_pd->lcd_enabled) {
+ /*
+ * if lcd panel was off from bootloader then
+ * current lcd status is powerdown and then
+ * it enables lcd panel.
+ */
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ ams369fg06_power(lcd, FB_BLANK_UNBLANK);
+ } else
+ lcd->power = FB_BLANK_UNBLANK;
+
+ dev_set_drvdata(&spi->dev, lcd);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ lcd->early_suspend.suspend = ams369fg06_early_suspend;
+ lcd->early_suspend.resume = ams369fg06_late_resume;
+ lcd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1;
+ register_early_suspend(&lcd->early_suspend);
+#endif
+ dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n");
+
+ return 0;
+
+out_lcd_unregister:
+ lcd_device_unregister(ld);
+out_free_lcd:
+ kfree(lcd);
+ return ret;
+}
+
+static int __devexit ams369fg06_remove(struct spi_device *spi)
+{
+ struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+
+ ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+ lcd_device_unregister(lcd->ld);
+ kfree(lcd);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+#ifndef CONFIG_HAS_EARLYSUSPEND
+unsigned int before_power;
+
+static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ int ret = 0;
+ struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+ before_power = lcd->power;
+
+ /*
+ * when lcd panel is suspend, lcd panel becomes off
+ * regardless of status.
+ */
+ ret = ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+
+ return ret;
+}
+
+static int ams369fg06_resume(struct spi_device *spi)
+{
+ int ret = 0;
+ struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+
+ /*
+ * after suspended, if lcd panel status is FB_BLANK_UNBLANK
+ * (at that time, before_power is FB_BLANK_UNBLANK) then
+ * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
+ */
+ if (before_power == FB_BLANK_UNBLANK)
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ dev_dbg(&spi->dev, "before_power = %d\n", before_power);
+
+ ret = ams369fg06_power(lcd, before_power);
+
+ return ret;
+}
+#endif
+#else
+#define ams369fg06_suspend NULL
+#define ams369fg06_resume NULL
+#endif
+
+void ams369fg06_shutdown(struct spi_device *spi)
+{
+ struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+
+ ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ams369fg06_driver = {
+ .driver = {
+ .name = "ams369fg06",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ams369fg06_probe,
+ .remove = __devexit_p(ams369fg06_remove),
+ .shutdown = ams369fg06_shutdown,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = ams369fg06_suspend,
+ .resume = ams369fg06_resume,
+#endif
+};
+
+static int __init ams369fg06_init(void)
+{
+ return spi_register_driver(&ams369fg06_driver);
+}
+
+static void __exit ams369fg06_exit(void)
+{
+ spi_unregister_driver(&ams369fg06_driver);
+}
+
+module_init(ams369fg06_init);
+module_exit(ams369fg06_exit);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("ams369fg06 LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ams369fg06_gamma.h b/drivers/video/backlight/ams369fg06_gamma.h
new file mode 100644
index 0000000..6ecea88
--- /dev/null
+++ b/drivers/video/backlight/ams369fg06_gamma.h
@@ -0,0 +1,61 @@
+/*
+ * Gamma level definitions.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * Jingoo Han <jg1.han@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 _AMS369FG06_BRIGHTNESS_H
+#define _AMS369FG06_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL 5
+#define GAMMA_TABLE_COUNT 21
+
+/* gamma value: 2.2 */
+static const unsigned int ams369fg06_22_250[] = {
+ 0x00, 0x3f, 0x2a, 0x27, 0x27, 0x1f, 0x44,
+ 0x00, 0x00, 0x17, 0x24, 0x26, 0x1f, 0x43,
+ 0x00, 0x3f, 0x2a, 0x25, 0x24, 0x1b, 0x5c,
+};
+
+static const unsigned int ams369fg06_22_200[] = {
+ 0x00, 0x3f, 0x28, 0x29, 0x27, 0x21, 0x3e,
+ 0x00, 0x00, 0x10, 0x25, 0x27, 0x20, 0x3d,
+ 0x00, 0x3f, 0x28, 0x27, 0x25, 0x1d, 0x53,
+};
+
+static const unsigned int ams369fg06_22_150[] = {
+ 0x00, 0x3f, 0x2d, 0x29, 0x28, 0x23, 0x37,
+ 0x00, 0x00, 0x0b, 0x25, 0x28, 0x22, 0x36,
+ 0x00, 0x3f, 0x2b, 0x28, 0x26, 0x1f, 0x4a,
+};
+
+static const unsigned int ams369fg06_22_100[] = {
+ 0x00, 0x3f, 0x30, 0x2a, 0x2b, 0x24, 0x2f,
+ 0x00, 0x00, 0x00, 0x25, 0x29, 0x24, 0x2e,
+ 0x00, 0x3f, 0x2f, 0x29, 0x29, 0x21, 0x3f,
+};
+
+static const unsigned int ams369fg06_22_50[] = {
+ 0x00, 0x3f, 0x3c, 0x2c, 0x2d, 0x27, 0x24,
+ 0x00, 0x00, 0x00, 0x22, 0x2a, 0x27, 0x23,
+ 0x00, 0x3f, 0x3b, 0x2c, 0x2b, 0x24, 0x31,
+};
+
+struct ams369fg06_gamma {
+ unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
+};
+
+struct ams369fg06_gamma gamma_table = {
+ .gamma_22_table[0] = (unsigned int *)&ams369fg06_22_50,
+ .gamma_22_table[1] = (unsigned int *)&ams369fg06_22_100,
+ .gamma_22_table[2] = (unsigned int *)&ams369fg06_22_150,
+ .gamma_22_table[3] = (unsigned int *)&ams369fg06_22_200,
+ .gamma_22_table[4] = (unsigned int *)&ams369fg06_22_250,
+};
+
+#endif
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 80d292f..1a6fe06 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -19,6 +19,10 @@
#include <asm/backlight.h>
#endif
+#ifdef CONFIG_DRM
+#include <drm/drm_backlight.h>
+#endif
+
static const char const *backlight_types[] = {
[BACKLIGHT_RAW] = "raw",
[BACKLIGHT_PLATFORM] = "platform",
@@ -101,6 +105,43 @@ static void backlight_generate_event(struct backlight_device *bd,
sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
}
+static ssize_t backlight_store_dimming(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc;
+ struct backlight_device *bd = to_backlight_device(dev);
+ unsigned long dimming;
+
+ rc = strict_strtoul(buf, 0, &dimming);
+ if (rc)
+ return rc;
+
+ if (dimming < 0)
+ rc = -EINVAL;
+ else {
+ pr_debug("set dimming mode\n");
+
+ if (dimming)
+ bd->props.dimming = true;
+ else
+ bd->props.dimming = false;
+
+ backlight_set_dimming(bd);
+
+ rc = count;
+ }
+
+ return rc;
+}
+
+static ssize_t backlight_show_dimming(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct backlight_device *bd = to_backlight_device(dev);
+
+ return sprintf(buf, "%d\n", bd->props.dimming);
+}
+
static ssize_t backlight_show_power(struct device *dev,
struct device_attribute *attr,char *buf)
{
@@ -242,6 +283,7 @@ static void bl_device_release(struct device *dev)
}
static struct device_attribute bl_device_attributes[] = {
+ __ATTR(dimming, 0644, backlight_show_dimming, backlight_store_dimming),
__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
__ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
@@ -354,6 +396,10 @@ void backlight_device_unregister(struct backlight_device *bd)
if (!bd)
return;
+#ifdef CONFIG_DRM
+ drm_bl_unregister(&bd->dev);
+#endif
+
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight == bd)
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 71a11ca..cc2c538 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -15,6 +15,10 @@
#include <linux/fb.h>
#include <linux/slab.h>
+#ifdef CONFIG_DRM
+#include <drm/drm_backlight.h>
+#endif
+
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
/* This callback gets called when something important happens inside a
@@ -32,6 +36,8 @@ static int fb_notifier_callback(struct notifier_block *self,
case FB_EVENT_BLANK:
case FB_EVENT_MODE_CHANGE:
case FB_EVENT_MODE_CHANGE_ALL:
+ case FB_EARLY_EVENT_BLANK:
+ case FB_R_EARLY_EVENT_BLANK:
break;
default:
return 0;
@@ -46,6 +52,14 @@ static int fb_notifier_callback(struct notifier_block *self,
if (event == FB_EVENT_BLANK) {
if (ld->ops->set_power)
ld->ops->set_power(ld, *(int *)evdata->data);
+ } else if (event == FB_EARLY_EVENT_BLANK) {
+ if (ld->ops->early_set_power)
+ ld->ops->early_set_power(ld,
+ *(int *)evdata->data);
+ } else if (event == FB_R_EARLY_EVENT_BLANK) {
+ if (ld->ops->r_early_set_power)
+ ld->ops->r_early_set_power(ld,
+ *(int *)evdata->data);
} else {
if (ld->ops->set_mode)
ld->ops->set_mode(ld, evdata->data);
@@ -226,6 +240,10 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent,
new_ld->ops = ops;
+#ifdef CONFIG_DRM
+ drm_bl_register(&new_ld->dev, BL_LCD_CLASS);
+#endif
+
return new_ld;
}
EXPORT_SYMBOL(lcd_device_register);
@@ -241,6 +259,10 @@ void lcd_device_unregister(struct lcd_device *ld)
if (!ld)
return;
+#ifdef CONFIG_DRM
+ drm_bl_unregister(&ld->dev);
+#endif
+
mutex_lock(&ld->ops_lock);
ld->ops = NULL;
mutex_unlock(&ld->ops_lock);
diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c
new file mode 100644
index 0000000..6876be8
--- /dev/null
+++ b/drivers/video/backlight/lms501kf03.c
@@ -0,0 +1,598 @@
+/* linux/drivers/video/backlight/lms501kf03.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * LMS501KF03 5.0" WVGA Landscape LCD module driver for the SMDK
+ *
+ * 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/wait.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#define ENDDEF 0xFF00
+#define COMMAND_ONLY 0x00
+#define DATA_ONLY 0x01
+
+#define MIN_BRIGHTNESS 0
+#define MAX_BRIGHTNESS 255
+#define DEFAULT_BRIGHTNESS 150
+
+#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
+
+struct lms501kf03 {
+ struct device *dev;
+ struct spi_device *spi;
+ unsigned int power;
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+ struct lcd_platform_data *lcd_pd;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+const unsigned short SEQ_PASSWORD[] = {
+ 0xb9, 0xff, 0x83, 0x69,
+ ENDDEF
+};
+
+const unsigned short SEQ_POWER[] = {
+ 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28,
+ 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+ ENDDEF
+};
+
+const unsigned short SEQ_DISPLAY[] = {
+ 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
+ ENDDEF
+};
+
+const unsigned short SEQ_RGB_IF[] = {
+ 0xb3, 0x09,
+ ENDDEF
+};
+
+const unsigned short SEQ_DISPLAY_INV[] = {
+ 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06,
+ ENDDEF
+};
+
+const unsigned short SEQ_VCOM[] = {
+ 0xb6, 0x4c, 0x2e,
+ ENDDEF
+};
+
+const unsigned short SEQ_GATE[] = {
+ 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13,
+ 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75,
+ 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07,
+ ENDDEF
+};
+
+const unsigned short SEQ_PANEL[] = {
+ 0xcc, 0x02,
+ ENDDEF
+};
+
+const unsigned short SEQ_COL_MOD[] = {
+ 0x3a, 0x77,
+ ENDDEF
+};
+
+const unsigned short SEQ_W_GAMMA[] = {
+ 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a,
+ 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04,
+ 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16,
+ 0x18, 0x16, 0x17, 0x0d, 0x15,
+ ENDDEF
+};
+
+const unsigned short SEQ_RGB_GAMMA[] = {
+ 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c,
+ 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92,
+ 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde,
+ 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb,
+ 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a,
+ 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b,
+ 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca,
+ 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe,
+ 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17,
+ 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63,
+ 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0,
+ 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ENDDEF
+};
+
+const unsigned short SEQ_UP_DN[] = {
+ 0x36, 0x10,
+ ENDDEF
+};
+
+const unsigned short SEQ_SLEEP_IN[] = {
+ 0x10,
+ ENDDEF
+};
+
+const unsigned short SEQ_SLEEP_OUT[] = {
+ 0x11,
+ ENDDEF
+};
+
+const unsigned short SEQ_DISPLAY_ON[] = {
+ 0x29,
+ ENDDEF
+};
+
+const unsigned short SEQ_DISPLAY_OFF[] = {
+ 0x10,
+ ENDDEF
+};
+
+static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data)
+{
+ u16 buf[1];
+ struct spi_message msg;
+
+ struct spi_transfer xfer = {
+ .len = 2,
+ .tx_buf = buf,
+ };
+
+ buf[0] = (addr << 8) | data;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ return spi_sync(lcd->spi, &msg);
+}
+
+static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address,
+ unsigned char command)
+{
+ int ret = 0;
+
+ ret = lms501kf03_spi_write_byte(lcd, address, command);
+
+ return ret;
+}
+
+static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd,
+ const unsigned short *wbuf)
+{
+ int ret = 0, i = 0;
+
+ while (wbuf[i] != ENDDEF) {
+ if (i == 0)
+ ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]);
+ else
+ ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]);
+ if (ret)
+ break;
+
+ udelay(100);
+ i += 1;
+ }
+ return ret;
+}
+
+static int lms501kf03_ldi_init(struct lms501kf03 *lcd)
+{
+ int ret, i;
+ const unsigned short *init_seq[] = {
+ SEQ_PASSWORD,
+ SEQ_POWER,
+ SEQ_DISPLAY,
+ SEQ_RGB_IF,
+ SEQ_DISPLAY_INV,
+ SEQ_VCOM,
+ SEQ_GATE,
+ SEQ_PANEL,
+ SEQ_COL_MOD,
+ SEQ_W_GAMMA,
+ SEQ_RGB_GAMMA,
+ SEQ_SLEEP_OUT,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = lms501kf03_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+ mdelay(120);
+
+ return ret;
+}
+
+static int lms501kf03_ldi_enable(struct lms501kf03 *lcd)
+{
+ int ret, i;
+ const unsigned short *init_seq[] = {
+ SEQ_DISPLAY_ON,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = lms501kf03_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int lms501kf03_ldi_disable(struct lms501kf03 *lcd)
+{
+ int ret, i;
+
+ const unsigned short *init_seq[] = {
+ SEQ_DISPLAY_OFF,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = lms501kf03_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int lms501kf03_power_on(struct lms501kf03 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+ struct backlight_device *bd = NULL;
+
+ pd = lcd->lcd_pd;
+ if (!pd) {
+ dev_err(lcd->dev, "platform data is NULL.\n");
+ return -EFAULT;
+ }
+
+ bd = lcd->bd;
+ if (!bd) {
+ dev_err(lcd->dev, "backlight device is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!pd->power_on) {
+ dev_err(lcd->dev, "power_on is NULL.\n");
+ return -EFAULT;
+ } else {
+ pd->power_on(lcd->ld, 1);
+ mdelay(pd->power_on_delay);
+ }
+
+ if (!pd->reset) {
+ dev_err(lcd->dev, "reset is NULL.\n");
+ return -EFAULT;
+ } else {
+ pd->reset(lcd->ld);
+ mdelay(pd->reset_delay);
+ }
+
+ ret = lms501kf03_ldi_init(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "failed to initialize ldi.\n");
+ return ret;
+ }
+
+ ret = lms501kf03_ldi_enable(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "failed to enable ldi.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lms501kf03_power_off(struct lms501kf03 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+
+ pd = lcd->lcd_pd;
+ if (!pd) {
+ dev_err(lcd->dev, "platform data is NULL\n");
+ return -EFAULT;
+ }
+
+ ret = lms501kf03_ldi_disable(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "lcd setting failed.\n");
+ return -EIO;
+ }
+
+ mdelay(pd->power_off_delay);
+
+ if (!pd->power_on) {
+ dev_err(lcd->dev, "power_on is NULL.\n");
+ return -EFAULT;
+ } else
+ pd->power_on(lcd->ld, 0);
+
+ return 0;
+}
+
+static int lms501kf03_power(struct lms501kf03 *lcd, int power)
+{
+ int ret = 0;
+
+ if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+ ret = lms501kf03_power_on(lcd);
+ else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+ ret = lms501kf03_power_off(lcd);
+
+ if (!ret)
+ lcd->power = power;
+
+ return ret;
+}
+
+static int lms501kf03_get_power(struct lcd_device *ld)
+{
+ struct lms501kf03 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static int lms501kf03_set_power(struct lcd_device *ld, int power)
+{
+ struct lms501kf03 *lcd = lcd_get_data(ld);
+
+ 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;
+ }
+
+ return lms501kf03_power(lcd, power);
+}
+
+static int lms501kf03_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int lms501kf03_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0;
+ 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.\n",
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct lcd_ops lms501kf03_lcd_ops = {
+ .get_power = lms501kf03_get_power,
+ .set_power = lms501kf03_set_power,
+};
+
+static const struct backlight_ops lms501kf03_backlight_ops = {
+ .get_brightness = lms501kf03_get_brightness,
+ .update_status = lms501kf03_set_brightness,
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+unsigned int before_power;
+
+static void lms501kf03_early_suspend(struct early_suspend *handler)
+{
+ struct lms501kf03 *lcd = NULL;
+
+ lcd = container_of(handler, struct lms501kf03, early_suspend);
+
+ before_power = lcd->power;
+
+ lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static void lms501kf03_late_resume(struct early_suspend *handler)
+{
+ struct lms501kf03 *lcd = NULL;
+
+ lcd = container_of(handler, struct lms501kf03, early_suspend);
+
+ if (before_power == FB_BLANK_UNBLANK)
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ lms501kf03_power(lcd, before_power);
+}
+#endif
+
+static int __init lms501kf03_probe(struct spi_device *spi)
+{
+ int ret = 0;
+ struct lms501kf03 *lcd = NULL;
+ struct lcd_device *ld = NULL;
+ struct backlight_device *bd = NULL;
+
+ lcd = kzalloc(sizeof(struct lms501kf03), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */
+ spi->bits_per_word = 9;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi setup failed.\n");
+ goto out_free_lcd;
+ }
+
+ lcd->spi = spi;
+ lcd->dev = &spi->dev;
+
+ lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data;
+ if (!lcd->lcd_pd) {
+ dev_err(&spi->dev, "platform data is NULL\n");
+ goto out_free_lcd;
+ }
+
+ ld = lcd_device_register("lms501kf03", &spi->dev, lcd,
+ &lms501kf03_lcd_ops);
+ if (IS_ERR(ld)) {
+ ret = PTR_ERR(ld);
+ goto out_free_lcd;
+ }
+
+ lcd->ld = ld;
+
+ bd = backlight_device_register("lms501kf03-bl", &spi->dev, lcd,
+ &lms501kf03_backlight_ops, NULL);
+ if (IS_ERR(bd)) {
+ ret = PTR_ERR(bd);
+ goto out_lcd_unregister;
+ }
+
+ bd->props.max_brightness = MAX_BRIGHTNESS;
+ bd->props.brightness = DEFAULT_BRIGHTNESS;
+ bd->props.type = BACKLIGHT_RAW;
+ lcd->bd = bd;
+
+ if (!lcd->lcd_pd->lcd_enabled) {
+ /*
+ * if lcd panel was off from bootloader then
+ * current lcd status is powerdown and then
+ * it enables lcd panel.
+ */
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ lms501kf03_power(lcd, FB_BLANK_UNBLANK);
+ } else
+ lcd->power = FB_BLANK_UNBLANK;
+
+ dev_set_drvdata(&spi->dev, lcd);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ lcd->early_suspend.suspend = lms501kf03_early_suspend;
+ lcd->early_suspend.resume = lms501kf03_late_resume;
+ lcd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1;
+ register_early_suspend(&lcd->early_suspend);
+#endif
+ dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n");
+
+ return 0;
+
+out_lcd_unregister:
+ lcd_device_unregister(ld);
+out_free_lcd:
+ kfree(lcd);
+ return ret;
+}
+
+static int __devexit lms501kf03_remove(struct spi_device *spi)
+{
+ struct lms501kf03 *lcd = dev_get_drvdata(&spi->dev);
+
+ lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+ lcd_device_unregister(lcd->ld);
+ kfree(lcd);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+#ifndef CONFIG_HAS_EARLYSUSPEND
+unsigned int before_power;
+
+static int lms501kf03_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ int ret = 0;
+ struct lms501kf03 *lcd = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+ before_power = lcd->power;
+
+ /*
+ * when lcd panel is suspend, lcd panel becomes off
+ * regardless of status.
+ */
+ ret = lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+
+ return ret;
+}
+
+static int lms501kf03_resume(struct spi_device *spi)
+{
+ int ret = 0;
+ struct lms501kf03 *lcd = dev_get_drvdata(&spi->dev);
+
+ /*
+ * after suspended, if lcd panel status is FB_BLANK_UNBLANK
+ * (at that time, before_power is FB_BLANK_UNBLANK) then
+ * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
+ */
+ if (before_power == FB_BLANK_UNBLANK)
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ dev_dbg(&spi->dev, "before_power = %d\n", before_power);
+
+ ret = lms501kf03_power(lcd, before_power);
+
+ return ret;
+}
+#endif
+#else
+#define lms501kf03_suspend NULL
+#define lms501kf03_resume NULL
+#endif
+
+void lms501kf03_shutdown(struct spi_device *spi)
+{
+ struct lms501kf03 *lcd = dev_get_drvdata(&spi->dev);
+
+ lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver lms501kf03_driver = {
+ .driver = {
+ .name = "lms501kf03",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = lms501kf03_probe,
+ .remove = __devexit_p(lms501kf03_remove),
+ .shutdown = lms501kf03_shutdown,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = lms501kf03_suspend,
+ .resume = lms501kf03_resume,
+#endif
+};
+
+static int __init lms501kf03_init(void)
+{
+ return spi_register_driver(&lms501kf03_driver);
+}
+
+static void __exit lms501kf03_exit(void)
+{
+ spi_unregister_driver(&lms501kf03_driver);
+}
+
+module_init(lms501kf03_init);
+module_exit(lms501kf03_exit);
+
+MODULE_AUTHOR("Ilho Lee <Ilho215.lee@samsung.com>");
+MODULE_DESCRIPTION("lms501kf03 LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index b8f38ec..37837f5 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -31,11 +31,19 @@ struct pwm_bl_data {
int (*check_fb)(struct device *, struct fb_info *);
};
+/*H/W team requirement for MWC Demo*/
+/* lcd max brightnessis restrictd to PWM 80% MAX PWM Duty : 80 (204)%*/
+#define CONFIG_MWC_DEMO
+
static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
int brightness = bl->props.brightness;
int max = bl->props.max_brightness;
+#ifdef CONFIG_MWC_DEMO
+ if (brightness >= 204)
+ brightness = 204;
+#endif
if (bl->props.power != FB_BLANK_UNBLANK)
brightness = 0;
diff --git a/drivers/video/backlight/s6e39a0x02.c b/drivers/video/backlight/s6e39a0x02.c
new file mode 100644
index 0000000..c054ba4
--- /dev/null
+++ b/drivers/video/backlight/s6e39a0x02.c
@@ -0,0 +1,799 @@
+/* linux/drivers/video/s6e39a0x.c
+ *
+ * MIPI-DSI based s6e39a0x AMOLED lcd 5.3 inch panel driver.
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@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/fb.h>
+#include <linux/backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/mipi_dsim2.h>
+#include <plat/regs-dsim2.h>
+#include <plat/gpio-cfg.h>
+
+#include "s6e39a0x02_gamma.h"
+
+#define LDI_MTP_LENGTH 24
+#define DSIM_PM_STABLE_TIME (10)
+#define MIN_BRIGHTNESS (0)
+#define MAX_BRIGHTNESS (10)
+
+#define VER_142 (0x8e) /* MACH_SLP_PQ */
+#define VER_42 (0x2a) /* MACH_SLP_PQ_LTE */
+
+#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)
+
+enum {
+ DSIM_NONE_STATE = 0,
+ DSIM_RESUME_COMPLETE = 1,
+ DSIM_FRAME_DONE = 2,
+};
+
+struct s6e39a0x02 {
+ struct device *dev;
+ unsigned int id;
+ unsigned int ver;
+ unsigned int power;
+ unsigned int current_brightness;
+ unsigned int updated;
+ unsigned int gamma;
+ unsigned int resume_complete;
+ unsigned int acl_enable;
+ unsigned int cur_acl;
+
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+
+ struct mipi_dsim_lcd_device *dsim_dev;
+ struct lcd_platform_data *ddi_pd;
+
+ struct mutex lock;
+ struct regulator *reg_vci;
+ bool enabled;
+};
+
+static struct mipi_dsim_device *dsim;
+
+static void s6e39a0x02_regulator_enable(struct s6e39a0x02 *lcd)
+{
+ mutex_lock(&lcd->lock);
+ if (!lcd->enabled) {
+ if (lcd->reg_vci)
+ regulator_enable(lcd->reg_vci);
+
+ lcd->enabled = true;
+ }
+ mutex_unlock(&lcd->lock);
+}
+
+static void s6e39a0x02_regulator_disable(struct s6e39a0x02 *lcd)
+{
+ mutex_lock(&lcd->lock);
+ if (lcd->enabled) {
+ if (lcd->reg_vci)
+ regulator_disable(lcd->reg_vci);
+
+ lcd->enabled = false;
+ }
+ mutex_unlock(&lcd->lock);
+}
+
+static void s6e39a0x02_sleep_in(struct s6e39a0x02 *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 s6e39a0x02_sleep_out(struct s6e39a0x02 *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 s6e39a0x02_display_on(struct s6e39a0x02 *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 s6e39a0x02_acl_on(struct s6e39a0x02 *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);
+}
+
+static void s6e39a0x02_acl_off(struct s6e39a0x02 *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);
+}
+
+static void s6e39a0x02_acl_ctrl_set(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ /* Full white 50% reducing setting */
+ const unsigned char cutoff_50[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
+ 0x3f, 0x46
+ };
+ /* Full white 45% reducing setting */
+ const unsigned char cutoff_45[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
+ 0x37, 0x3d
+ };
+ /* Full white 40% reducing setting */
+ const unsigned char cutoff_40[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
+ 0x31, 0x36
+ };
+
+ if (lcd->acl_enable) {
+ if (lcd->cur_acl == 0) {
+ if (lcd->gamma == 0 || lcd->gamma == 1) {
+ s6e39a0x02_acl_off(lcd);
+ dev_dbg(&lcd->ld->dev,
+ "cur_acl=%d\n", lcd->cur_acl);
+ } else
+ s6e39a0x02_acl_on(lcd);
+ }
+ switch (lcd->gamma) {
+ case 0: /* 30cd */
+ s6e39a0x02_acl_off(lcd);
+ lcd->cur_acl = 0;
+ break;
+ case 1 ... 3: /* 50cd ~ 90cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)cutoff_40,
+ ARRAY_SIZE(cutoff_40));
+ lcd->cur_acl = 40;
+ break;
+ case 4 ... 7: /* 120cd ~ 210cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)cutoff_45,
+ ARRAY_SIZE(cutoff_45));
+ lcd->cur_acl = 45;
+ break;
+ case 8 ... 10: /* 220cd ~ 300cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)cutoff_50,
+ ARRAY_SIZE(cutoff_50));
+ lcd->cur_acl = 50;
+ break;
+ default:
+ break;
+ }
+ } else {
+ s6e39a0x02_acl_off(lcd);
+ lcd->cur_acl = 0;
+ dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
+ }
+}
+
+static void s6e39a0x02_etc_cond1(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ unsigned char data_to_send_1[3] = {
+ 0xf0, 0x5a, 0x5a
+ };
+
+ unsigned char data_to_send_2[3] = {
+ 0xf1, 0x5a, 0x5a
+ };
+
+ unsigned char data_to_send_3[3] = {
+ 0xfc, 0x5a, 0x5a
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_1, sizeof(data_to_send_1));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_2, sizeof(data_to_send_2));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_3, sizeof(data_to_send_3));
+}
+
+static void s6e39a0x02_gamma_cond(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ unsigned char data_to_send[26] = {
+ 0xfa, 0x02, 0x10, 0x10, 0x10, 0xf0, 0x8c, 0xed, 0xd5,
+ 0xca, 0xd8, 0xdc, 0xdb, 0xdc, 0xbb, 0xbd, 0xb7, 0xcb,
+ 0xcd, 0xc5, 0x00, 0x9c, 0x00, 0x7a, 0x00, 0xb2
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send, sizeof(data_to_send));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xfa, 0x03);
+}
+
+static void s6e39a0x02_panel_cond(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ unsigned char data_to_send_1[14] = {
+ 0xf8, 0x27, 0x27, 0x08, 0x08, 0x4e, 0xaa,
+ 0x5e, 0x8a, 0x10, 0x3f, 0x10, 0x10, 0x00
+ };
+
+ unsigned char data_to_send_2[6] = {
+ 0xb3, 0x63, 0x02, 0xc3, 0x32, 0xff
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_1, sizeof(data_to_send_1));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xf7, 0x03);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_2, sizeof(data_to_send_2));
+}
+
+static void s6e39a0x02_etc_cond2(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ unsigned char data_to_send_1[4] = {
+ 0xf6, 0x00, 0x84, 0x09
+ };
+
+ unsigned char data_to_send_2[4] = {
+ 0xd5, 0xa4, 0x7e, 0x20
+ };
+
+ unsigned char data_to_send_3[4] = {
+ 0xb1, 0x01, 0x00, 0x16
+ };
+
+ unsigned char data_to_send_4[5] = {
+ 0xb2, 0x15, 0x15, 0x15, 0x15
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_1, sizeof(data_to_send_1));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x09);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xd5, 0x64);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x0b);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_2, sizeof(data_to_send_2));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x08);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xfd, 0xf8);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x01);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xf2, 0x07);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x04);
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xf2, 0x4d);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_3, sizeof(data_to_send_3));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_4, sizeof(data_to_send_4));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x11, 0x00);
+}
+
+static void s6e39a0x02_memory_window_1(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ unsigned char data_to_send_1[5] = {
+ 0x2a, 0x00, 0x00, 0x02, 0x57
+ };
+
+ unsigned char data_to_send_2[5] = {
+ 0x2b, 0x00, 0x00, 0x03, 0xff
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_1, sizeof(data_to_send_1));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_2, sizeof(data_to_send_2));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x2C, 0x00);
+}
+
+static void s6e39a0x02_memory_window_2(struct s6e39a0x02 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ unsigned char data_to_send_1[5] = {
+ 0x2a, 0x00, 0x1e, 0x02, 0x39
+ };
+
+ unsigned char data_to_send_2[5] = {
+ 0x2b, 0x00, 0x00, 0x03, 0xbf
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE, 0x35, 0x00);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_1, sizeof(data_to_send_1));
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send_2, sizeof(data_to_send_2));
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xd1, 0x8a);
+}
+
+static int s6e39a0x02_panel_init(struct s6e39a0x02 *lcd)
+{
+ mdelay(10);
+
+ s6e39a0x02_etc_cond1(lcd);
+ s6e39a0x02_gamma_cond(lcd);
+ s6e39a0x02_panel_cond(lcd);
+ s6e39a0x02_etc_cond2(lcd);
+
+ mdelay(120);
+
+ s6e39a0x02_memory_window_1(lcd);
+
+ mdelay(20);
+
+ s6e39a0x02_memory_window_2(lcd);
+
+ return 0;
+}
+
+static int s6e39a0x02_update_gamma_ctrl(struct s6e39a0x02 *lcd, int gamma)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)s6e39a0x02_22_gamma_table[gamma],
+ GAMMA_TABLE_COUNT);
+
+ /* update gamma table. */
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ 0xfA, 0x03);
+
+ lcd->gamma = gamma;
+
+ return 0;
+}
+
+static int s6e39a0x02_gamma_ctrl(struct s6e39a0x02 *lcd, int gamma)
+{
+ s6e39a0x02_update_gamma_ctrl(lcd, gamma);
+
+ return 0;
+}
+
+static int s6e39a0x02_early_set_power(struct lcd_device *ld, int power)
+{
+ struct s6e39a0x02 *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 s6e39a0x02_set_power(struct lcd_device *ld, int power)
+{
+ struct s6e39a0x02 *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 s6e39a0x02_get_power(struct lcd_device *ld)
+{
+ struct s6e39a0x02 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static int s6e39a0x02_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int s6e39a0x02_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0, brightness = bd->props.brightness;
+ struct s6e39a0x02 *lcd = bl_get_data(bd);
+
+ 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 = s6e39a0x02_gamma_ctrl(lcd, brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static struct lcd_ops s6e39a0x02_lcd_ops = {
+ .early_set_power = s6e39a0x02_early_set_power,
+ .set_power = s6e39a0x02_set_power,
+ .get_power = s6e39a0x02_get_power,
+};
+
+static const struct backlight_ops s6e39a0x02_backlight_ops = {
+ .get_brightness = s6e39a0x02_get_brightness,
+ .update_status = s6e39a0x02_set_brightness,
+};
+
+static void s6e39a0x02_power_on(struct mipi_dsim_lcd_device *dsim_dev,
+ unsigned int enable)
+{
+ struct s6e39a0x02 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ if (enable) {
+ mdelay(lcd->ddi_pd->power_on_delay);
+
+ /* lcd power on */
+ s6e39a0x02_regulator_enable(lcd);
+
+ mdelay(lcd->ddi_pd->reset_delay);
+
+ /* lcd reset */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+
+ mdelay(5);
+ } else
+ s6e39a0x02_regulator_disable(lcd);
+
+}
+
+static void s6e39a0x02_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e39a0x02 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e39a0x02_panel_init(lcd);
+ s6e39a0x02_display_on(lcd);
+
+ mdelay(50);
+}
+
+static ssize_t acl_control_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct s6e39a0x02 *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 s6e39a0x02 *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;
+ s6e39a0x02_acl_ctrl_set(lcd);
+ }
+ return size;
+}
+
+static irqreturn_t te_interrupt(int irq, void *dev_id)
+{
+ struct device *dev = NULL;
+ u32 intsrc = 0;
+ static bool suspended;
+
+ dev = (struct device *)dev_id;
+
+ intsrc = readl_relaxed(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ if (intsrc & (1 << 24)) {
+ int val;
+
+ val = __raw_readl(dsim->reg_base + S5P_DSIM_INTSRC);
+ val |= (1 << 24);
+ __raw_writel(val, dsim->reg_base + S5P_DSIM_INTSRC);
+ dsim->master_ops->trigger(NULL);
+ }
+
+ if (suspended == true && dsim->suspended == false) {
+ dev_info(dev, "te_interrupt: dsim->suspended is false.\n");
+ dsim->master_ops->trigger(NULL);
+ }
+
+ suspended = dsim->suspended;
+
+ return IRQ_HANDLED;
+}
+
+static DEVICE_ATTR(acl_control, 0664, acl_control_show, acl_control_store);
+
+static int s6e39a0x02_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e39a0x02 *lcd;
+ int ret;
+
+ dsim = dsim_dev->master;
+
+ lcd = kzalloc(sizeof(struct s6e39a0x02), GFP_KERNEL);
+ if (!lcd) {
+ dev_err(&dsim_dev->dev, "failed to allocate s6e39a0x02 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_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("s6e39a0x02", lcd->dev, lcd,
+ &s6e39a0x02_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("s6e39a0x02-bl", lcd->dev, lcd,
+ &s6e39a0x02_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;
+ }
+
+ lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
+ lcd->bd->props.brightness = MAX_BRIGHTNESS;
+
+ lcd->acl_enable = 1;
+ lcd->cur_acl = 0;
+
+ ret = device_create_file(&lcd->ld->dev, &dev_attr_acl_control);
+ if (ret < 0)
+ dev_err(&lcd->ld->dev, "failed to add sysfs entries\n");
+
+ dev_set_drvdata(&dsim_dev->dev, lcd);
+
+ gpio_request(EXYNOS4_GPF0(2), "TE_INT");
+ s5p_register_gpio_interrupt(EXYNOS4_GPF0(2));
+
+ s3c_gpio_cfgpin(EXYNOS4_GPF0(2), S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(EXYNOS4_GPF0(2), S3C_GPIO_PULL_NONE);
+ s5p_gpio_set_drvstr(EXYNOS4_GPF0(2), S5P_GPIO_DRVSTR_LV1);
+ irq_set_irq_type(gpio_to_irq(EXYNOS4_GPF0(2)), IRQ_TYPE_EDGE_RISING);
+
+ ret = request_irq(gpio_to_irq(EXYNOS4_GPF0(2)), te_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ "te_signal", lcd->dev);
+
+ if (ret < 0) {
+ dev_err(lcd->dev, "%s: request_irq failed. %d\n",
+ __func__, ret);
+ goto err_te_irq;
+ }
+
+ mdelay(100);
+
+ s6e39a0x02_regulator_enable(lcd);
+
+ lcd->power = FB_BLANK_UNBLANK;
+
+ if (!lcd->ddi_pd->lcd_enabled) {
+ s6e39a0x02_panel_init(lcd);
+ s6e39a0x02_display_on(lcd);
+ }
+
+ dev_info(lcd->dev, "probed s6e39a0x02 panel driver(%s).\n",
+ dev_name(&lcd->ld->dev));
+
+ return 0;
+
+err_unregister_lcd:
+err_te_irq:
+ lcd_device_unregister(lcd->ld);
+
+err_regulator:
+ regulator_put(lcd->reg_vci);
+
+ kfree(lcd);
+
+ return ret;
+}
+
+static void s6e39a0x02_remove(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e39a0x02 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ backlight_device_unregister(lcd->bd);
+
+ lcd_device_unregister(lcd->ld);
+
+ regulator_put(lcd->reg_vci);
+
+ kfree(lcd);
+}
+
+#ifdef CONFIG_PM
+static int s6e39a0x02_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e39a0x02 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e39a0x02_sleep_in(lcd);
+ mdelay(lcd->ddi_pd->power_off_delay);
+
+ return 0;
+}
+
+static int s6e39a0x02_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e39a0x02 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e39a0x02_sleep_out(lcd);
+ mdelay(lcd->ddi_pd->power_on_delay);
+
+ return 0;
+}
+#else
+#define s6e39a0x02_suspend NULL
+#define s6e39a0x02_resume NULL
+#endif
+
+static struct mipi_dsim_lcd_driver s6e39a0x02_dsim_ddi_driver = {
+ .name = "s6e39a0x02",
+ .id = -1,
+
+ .power_on = s6e39a0x02_power_on,
+ .set_sequence = s6e39a0x02_set_sequence,
+ .probe = s6e39a0x02_probe,
+ .remove = s6e39a0x02_remove,
+ .suspend = s6e39a0x02_suspend,
+ .resume = s6e39a0x02_resume,
+};
+
+static int s6e39a0x02_init(void)
+{
+ s5p_mipi_dsi_register_lcd_driver(&s6e39a0x02_dsim_ddi_driver);
+
+ return 0;
+}
+
+static void s6e39a0x02_exit(void)
+{
+ return;
+}
+
+module_init(s6e39a0x02_init);
+module_exit(s6e39a0x02_exit);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6e39a0x02 AMOLED LCD Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/s6e39a0x02_gamma.h b/drivers/video/backlight/s6e39a0x02_gamma.h
new file mode 100644
index 0000000..63412e3
--- /dev/null
+++ b/drivers/video/backlight/s6e39a0x02_gamma.h
@@ -0,0 +1,180 @@
+/* linux/drivers/video/backlight/s6e8aa0_brightness.h
+ *
+ * Brightness level definition.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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 _S6E39A0X02_BRIGHTNESS_H
+#define _S6E39A0X02_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL 11
+#define GAMMA_TABLE_COUNT 26
+
+/* gamma value: 2.2 */
+static const unsigned char s6e39a0x02_22_gamma_70[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xD1, 0x34, 0xD0, 0xD6, 0xBA,
+ 0xDC, 0xE0, 0xD9, 0xE2, 0xC2, 0xC0, 0xBF, 0xD4, 0xD5, 0xD0,
+ 0x00, 0x73, 0x00, 0x59, 0x00, 0x82
+};
+
+static const unsigned char s6e39a0x02_22_gamma_80[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xD7, 0x39, 0xD6, 0xD6, 0xBF,
+ 0xDD, 0xE1, 0xDA, 0xE2, 0xC0, 0xBF, 0xBD, 0xD3, 0xD5, 0xCF,
+ 0x00, 0x78, 0x00, 0x5D, 0x00, 0x88
+};
+
+static const unsigned char s6e39a0x02_22_gamma_90[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xD7, 0x39, 0xD5, 0xD5, 0xBF,
+ 0xDC, 0xDF, 0xDA, 0xE0, 0xC1, 0xC0, 0xBD, 0xD2, 0xD4, 0xCF,
+ 0x00, 0x7C, 0x00, 0x60, 0x00, 0x8C
+};
+
+static const unsigned char s6e39a0x02_22_gamma_100[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xDD, 0x3A, 0xE3, 0xD7, 0xC5,
+ 0xDD, 0xDF, 0xDA, 0xDF, 0xC0, 0xBF, 0xBC, 0xD0, 0xD3, 0xCD,
+ 0x00, 0x81, 0x00, 0x64, 0x00, 0x92
+};
+
+static const unsigned char s6e39a0x02_22_gamma_110[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xE1, 0x43, 0xE2, 0xD6, 0xC5,
+ 0xDC, 0xDE, 0xDA, 0xDF, 0xBF, 0xBF, 0xBB, 0xD0, 0xD3, 0xCD,
+ 0x00, 0x85, 0x00, 0x67, 0x00, 0x96
+};
+
+static const unsigned char s6e39a0x02_22_gamma_120[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xE5, 0x48, 0xE4, 0xD5, 0xC5,
+ 0xDB, 0xDE, 0xDA, 0xDD, 0xBE, 0xBF, 0xBB, 0xD0, 0xD2, 0xCC,
+ 0x00, 0x88, 0x00, 0x6A, 0x00, 0x9A
+};
+
+static const unsigned char s6e39a0x02_22_gamma_130[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xE6, 0x4D, 0xE3, 0xD5, 0xC5,
+ 0xDA, 0xDD, 0xDA, 0xDD, 0xBE, 0xBE, 0xBA, 0xCE, 0xD1, 0xCA,
+ 0x00, 0x8C, 0x00, 0x6D, 0x00, 0x9F
+};
+
+static const unsigned char s6e39a0x02_22_gamma_140[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xE8, 0x51, 0xE4, 0xD6, 0xC9,
+ 0xDB, 0xDC, 0xD9, 0xDC, 0xBE, 0xBF, 0xBA, 0xCD, 0xD0, 0xC9,
+ 0x00, 0x90, 0x00, 0x70, 0x00, 0xA3
+};
+
+static const unsigned char s6e39a0x02_22_gamma_150[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEA, 0x57, 0xE9, 0xD6, 0xC9,
+ 0xDA, 0xDD, 0xDA, 0xDC, 0xBC, 0xBE, 0xB8, 0xCE, 0xD0, 0xCA,
+ 0x00, 0x92, 0x00, 0x72, 0x00, 0xA6
+};
+
+static const unsigned char s6e39a0x02_22_gamma_160[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xF0, 0x61, 0xEE, 0xD5, 0xC9,
+ 0xD9, 0xDD, 0xDA, 0xDB, 0xBC, 0xBE, 0xB9, 0xCC, 0xCF, 0xC8,
+ 0x00, 0x96, 0x00, 0x75, 0x00, 0xAA
+};
+
+static const unsigned char s6e39a0x02_22_gamma_170[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xF1, 0x81, 0xEE, 0xD4, 0xC9,
+ 0xD9, 0xDD, 0xDB, 0xDB, 0xBB, 0xBD, 0xB7, 0xCC, 0xCE, 0xC8,
+ 0x00, 0x99, 0x00, 0x78, 0x00, 0xAE
+};
+
+static const unsigned char s6e39a0x02_22_gamma_180[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xF0, 0x8C, 0xED, 0xD5, 0xCA,
+ 0xD8, 0xDC, 0xDB, 0xDC, 0xBB, 0xBD, 0xB7, 0xCB, 0xCD, 0xC5,
+ 0x00, 0x9C, 0x00, 0x7A, 0x00, 0xB2
+};
+
+static const unsigned char s6e39a0x02_22_gamma_190[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xED, 0x90, 0xEC, 0xD4, 0xC9,
+ 0xD7, 0xDD, 0xDB, 0xDB, 0xBA, 0xBD, 0xB7, 0xCA, 0xCD, 0xC5,
+ 0x00, 0x9F, 0x00, 0x7C, 0x00, 0xB5
+};
+
+static const unsigned char s6e39a0x02_22_gamma_200[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xED, 0x8F, 0xED, 0xD2, 0xC7,
+ 0xD5, 0xDC, 0xDA, 0xDA, 0xBA, 0xBB, 0xB5, 0xCA, 0xCC, 0xC4,
+ 0x00, 0xA0, 0x00, 0x7F, 0x00, 0xBB
+};
+
+static const unsigned char s6e39a0x02_22_gamma_210[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEF, 0x96, 0xEF, 0xD1, 0xC7,
+ 0xD3, 0xDB, 0xD9, 0xD9, 0xB9, 0xBB, 0xB4, 0xCA, 0xCC, 0xC6,
+ 0x00, 0xA3, 0x00, 0x81, 0x00, 0xBD
+};
+
+static const unsigned char s6e39a0x02_22_gamma_220[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xED, 0x99, 0xEE, 0xD3, 0xC8,
+ 0xD3, 0xDB, 0xD9, 0xD9, 0xB8, 0xBB, 0xB4, 0xC9, 0xCC, 0xC4,
+ 0x00, 0xA6, 0x00, 0x83, 0x00, 0xC1
+};
+
+static const unsigned char s6e39a0x02_22_gamma_230[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEE, 0xA3, 0xEF, 0xD2, 0xC9,
+ 0xD3, 0xDB, 0xD9, 0xD9, 0xB9, 0xBA, 0xB3, 0xC8, 0xCC, 0xC4,
+ 0x00, 0xA8, 0x00, 0x85, 0x00, 0xC4
+};
+
+static const unsigned char s6e39a0x02_22_gamma_240[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xED, 0xA4, 0xEE, 0xD2, 0xC9,
+ 0xD3, 0xDC, 0xD9, 0xD9, 0xB7, 0xBA, 0xB3, 0xC8, 0xCB, 0xC2,
+ 0x00, 0xAB, 0x00, 0x87, 0x00, 0xC8
+};
+
+static const unsigned char s6e39a0x02_22_gamma_250[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xED, 0xA8, 0xEF, 0xD2, 0xC8,
+ 0xD2, 0xDA, 0xD9, 0xD8, 0xB7, 0xB9, 0xB2, 0xC8, 0xCB, 0xC2,
+ 0x00, 0xAD, 0x00, 0x89, 0x00, 0xCB
+};
+
+static const unsigned char s6e39a0x02_22_gamma_260[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEB, 0xB2, 0xEF, 0xD2, 0xC9,
+ 0xD3, 0xDB, 0xDA, 0xD9, 0xB6, 0xB9, 0xBA, 0xC7, 0xCA, 0xC1,
+ 0x00, 0xB0, 0x00, 0x8B, 0x00, 0xCE
+};
+
+static const unsigned char s6e39a0x02_22_gamma_270[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB0, 0xEF, 0xD1, 0xC9,
+ 0xD2, 0xDB, 0xDA, 0xD9, 0xB7, 0xB9, 0xB1, 0xC6, 0xC9, 0xC0,
+ 0x00, 0xB2, 0x00, 0x8D, 0x00, 0xD1
+};
+
+static const unsigned char s6e39a0x02_22_gamma_280[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xED, 0xB6, 0xF0, 0xD1, 0xC9,
+ 0xD2, 0xDB, 0xDA, 0xD9, 0xB6, 0xB8, 0xAF, 0xC7, 0xCA, 0xC2,
+ 0x00, 0xB4, 0x00, 0x8F, 0x00, 0xD3
+};
+
+static const unsigned char s6e39a0x02_22_gamma_290[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB7, 0xEE, 0xD0, 0xC8,
+ 0xD1, 0xDB, 0xDA, 0xD9, 0xB6, 0xB8, 0xB0, 0xC5, 0xC9, 0xC1,
+ 0x00, 0xB7, 0x00, 0x91, 0x00, 0xD5
+};
+
+static const unsigned char s6e39a0x02_22_gamma_300[] = {
+ 0xFA, 0x02, 0x10, 0x10, 0x10, 0xEC, 0xB7, 0xEF, 0xD1, 0xCA,
+ 0xD1, 0xDB, 0xDA, 0xD8, 0xB5, 0xB8, 0xB0, 0xC5, 0xC8, 0xBF,
+ 0x00, 0xB9, 0x00, 0x93, 0x00, 0xD9
+};
+
+static const unsigned char *s6e39a0x02_22_gamma_table[MAX_GAMMA_LEVEL] = {
+ s6e39a0x02_22_gamma_70,
+ s6e39a0x02_22_gamma_90,
+ s6e39a0x02_22_gamma_110,
+ s6e39a0x02_22_gamma_130,
+ s6e39a0x02_22_gamma_150,
+ s6e39a0x02_22_gamma_170,
+ s6e39a0x02_22_gamma_190,
+ s6e39a0x02_22_gamma_210,
+ s6e39a0x02_22_gamma_240,
+ s6e39a0x02_22_gamma_270,
+ s6e39a0x02_22_gamma_300,
+};
+
+#endif
diff --git a/drivers/video/backlight/s6e63m0_mipi_lcd.c b/drivers/video/backlight/s6e63m0_mipi_lcd.c
new file mode 100644
index 0000000..f0b2d00
--- /dev/null
+++ b/drivers/video/backlight/s6e63m0_mipi_lcd.c
@@ -0,0 +1,166 @@
+/* linux/drivers/video/backlight/s6e63m0_mipi_lcd.c
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-dsim.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+
+void init_lcd(struct mipi_dsim_device *dsim)
+{
+ unsigned char buf1[4] = {0xf2, 0x02, 0x03, 0x1b};
+ unsigned char buf2[15] = {0xf8, 0x01, 0x27, 0x27, 0x07, 0x07, 0x54,
+ 0x9f, 0x63, 0x86, 0x1a,
+ 0x33, 0x0d, 0x00, 0x00};
+ unsigned char buf3[4] = {0xf6, 0x00, 0x8c, 0x07};
+
+ /* password */
+ unsigned char rf[3] = {0x00, 0x5a, 0x5a};
+
+ rf[0] = 0xf0;
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) rf, 3);
+
+ rf[0] = 0xf1;
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) rf, 3);
+
+ rf[0] = 0xfc;
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) rf, 3);
+
+ /* HZ (0x16 = 60Hz) */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ 0xfd, 0x14);
+
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x09);
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xd5, 0x64);
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xb0, 0x09);
+
+ /* nonBurstSyncPulse */
+ if (dsim->pd->dsim_config->e_burst_mode == DSIM_NON_BURST_SYNC_PULSE)
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xd5, 0x84);
+ else
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xd5, 0xc4);
+
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_LONG_WRITE, (unsigned int) buf1, sizeof(buf1));
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_LONG_WRITE, (unsigned int) buf2, sizeof(buf2));
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_LONG_WRITE, (unsigned int) buf3, sizeof(buf3));
+
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xfa, 0x01);
+ /* Exit sleep */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x11, 0);
+ mdelay(600);
+ /* Set Display ON */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x29, 0);
+}
+
+void s6e63m0_mipi_lcd_off(struct mipi_dsim_device *dsim)
+{
+ /* softreset */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x1, 0);
+ /* Enter sleep */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x10, 0);
+ mdelay(60);
+
+ /* Set Display off */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x28, 0);
+}
+
+static int s6e63m0_mipi_lcd_bl_update_status(struct backlight_device *bd)
+{
+ return 0;
+}
+
+static const struct backlight_ops s6e63m0_mipi_lcd_bl_ops = {
+ .update_status = s6e63m0_mipi_lcd_bl_update_status,
+};
+
+static int s6e63m0_mipi_lcd_probe(struct mipi_dsim_device *dsim)
+{
+ struct mipi_dsim_device *dsim_drv;
+ struct backlight_device *bd = NULL;
+ struct backlight_properties props;
+
+ dsim_drv = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
+ if (!dsim_drv)
+ return -ENOMEM;
+
+ dsim_drv = (struct mipi_dsim_device *) dsim;
+
+ props.max_brightness = 1;
+ props.type = BACKLIGHT_PLATFORM;
+
+ bd = backlight_device_register("pwm-backlight",
+ dsim_drv->dev, dsim_drv, &s6e63m0_mipi_lcd_bl_ops, &props);
+
+ return 0;
+}
+
+static int s6e63m0_mipi_lcd_suspend(struct mipi_dsim_device *dsim)
+{
+ s6e63m0_mipi_lcd_off(dsim);
+ return 0;
+}
+
+static int s6e63m0_mipi_lcd_displayon(struct mipi_dsim_device *dsim)
+{
+ init_lcd(dsim);
+
+ return 0;
+}
+
+static int s6e63m0_mipi_lcd_resume(struct mipi_dsim_device *dsim)
+{
+ init_lcd(dsim);
+ return 0;
+}
+
+struct mipi_dsim_lcd_driver s6e63m0_mipi_lcd_driver = {
+ .probe = s6e63m0_mipi_lcd_probe,
+ .suspend = s6e63m0_mipi_lcd_suspend,
+ .displayon = s6e63m0_mipi_lcd_displayon,
+ .resume = s6e63m0_mipi_lcd_resume,
+};
+
diff --git a/drivers/video/backlight/s6e8aa0.c b/drivers/video/backlight/s6e8aa0.c
new file mode 100644
index 0000000..c9b1184
--- /dev/null
+++ b/drivers/video/backlight/s6e8aa0.c
@@ -0,0 +1,1187 @@
+/* linux/drivers/video/s6e8aa0.c
+ *
+ * MIPI-DSI based s6e8aa0 AMOLED lcd 5.3 inch panel driver.
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@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/fb.h>
+#include <linux/backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/mipi_dsim2.h>
+
+#include "s6e8aa0_gamma.h"
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+#include "smart_dimming.h"
+#endif
+
+#define LDI_FW_PATH "s6e8aa0/reg_%s.bin"
+#define MAX_STR 255
+#define LDI_MTP_LENGTH 24
+#define MAX_READ_LENGTH 64
+#define DSIM_PM_STABLE_TIME (10)
+#define MIN_BRIGHTNESS (0)
+#define MAX_BRIGHTNESS (24)
+
+#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_210 (0xd2) /* MACH_SLP_PQ M0 A-Type */
+
+#define AID_DISABLE (0x4)
+#define AID_1 (0x5)
+#define AID_2 (0x6)
+#define AID_3 (0x7)
+
+#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 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 mipi_dsim_lcd_device *dsim_dev;
+ struct lcd_platform_data *ddi_pd;
+
+ struct mutex lock;
+ struct regulator *reg_vdd3;
+ struct regulator *reg_vci;
+
+ const struct panel_model *model;
+ 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;
+#endif
+};
+
+struct s6e8aa0 *lcd_global;
+
+static void s6e8aa0_regulator_enable(struct s6e8aa0 *lcd)
+{
+ mutex_lock(&lcd->lock);
+ if (!lcd->enabled) {
+ 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) {
+ 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);
+}
+
+static void s6e8aa0_apply_level_1_key(struct s6e8aa0 *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 unsigned char s6e8aa0_apply_aid_panel_cond(unsigned int aid)
+{
+ unsigned char ret;
+
+ switch (aid) {
+ case AID_1:
+ ret = 0x60;
+ break;
+ case AID_2:
+ ret = 0x80;
+ break;
+ case AID_3:
+ ret = 0xA0;
+ break;
+ default:
+ ret = 0x04;
+ break;
+ }
+
+ return ret;
+}
+
+void s6e8aa0_panel_cond(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,
+ 0x7d, 0x08, 0x27, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08,
+ 0x23, 0x63, 0xc0, 0xc1, 0x01, 0x81, 0xc1, 0x00, 0xc8,
+ 0xc1, 0xd3, 0x01
+ };
+ /* same with v174(0xae) panel */
+ unsigned char data_to_send_v142[] = {
+ 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c,
+ 0x7d, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20,
+ 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08,
+ 0x23, 0x23, 0xc0, 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1,
+ 0xff, 0xff, 0xc8
+ };
+ unsigned char data_to_send_v32[] = {
+ 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, 0x6e, 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,
+ 0x04, 0x08, 0x69, 0x00, 0x00, 0x00, 0x02, 0x07, 0x07,
+ 0x21, 0x21, 0xc0, 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1,
+ 0xff, 0xff, 0xc8
+ };
+ unsigned char *data_to_send;
+ unsigned int size;
+
+ 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) {
+ 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_210) {
+ data_to_send = data_to_send_v210;
+ size = ARRAY_SIZE(data_to_send_v210);
+ } else
+ return;
+
+ if (!high_freq) {
+ data_to_send[9] = 0x7e;
+ data_to_send[25] = 0x0a;
+ data_to_send[26] = 0x0a;
+ }
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, size);
+}
+
+static void s6e8aa0_display_condition_set(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xf2, 0x80, 0x03, 0x0d
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8aa0_etc_source_control(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xf6, 0x00, 0x02, 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 s6e8aa0_etc_pentile_control(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[] = {
+ 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
+ 0x00
+ };
+
+ if (lcd->ver == VER_32)
+ data_to_send[5] = 0xc0;
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8aa0_etc_mipi_control1(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8aa0_etc_mipi_control2(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8aa0_etc_power_control(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[] = {
+ 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02
+ };
+
+ if (lcd->ver == VER_32) {
+ data_to_send[3] = 0x15;
+ data_to_send[5] = 0x19;
+ }
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+static void s6e8aa0_etc_mipi_control3(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_PARAM, 0xe3, 0x40);
+}
+
+static void s6e8aa0_etc_mipi_control4(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe4, 0x00, 0x00, 0x14, 0x80, 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 s6e8aa0_etc_elvss_control(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[] = {
+ 0xb1, 0x04, 0x00
+ };
+
+ if (lcd->id == 0x00)
+ data_to_send[2] = 0x95;
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[] = {
+ 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x0f,
+ 0x40, 0x41, 0xd9, 0x00, 0x60, 0x19
+ };
+
+ /* FIXME: !! need to change brightness and elvss */
+ if (lcd->ver == VER_32) {
+ data_to_send[8] = 0x07;
+ 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) {
+ case 0 ... 6: /* 30cd ~ 100cd */
+ data_to_send[11] = 0xdf;
+ break;
+ case 7 ... 11: /* 120cd ~ 150cd */
+ data_to_send[11] = 0xdd;
+ break;
+ case 12 ... 15: /* 180cd ~ 210cd */
+ data_to_send[11] = 0xd9;
+ break;
+ case 16 ... 24: /* 240cd ~ 300cd */
+ data_to_send[11] = 0xd0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8aa0_sleep_in(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, 0x10, 0x00);
+}
+
+static void s6e8aa0_sleep_out(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, 0x11, 0x00);
+}
+
+static void s6e8aa0_display_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, 0x29, 0x00);
+}
+
+static void s6e8aa0_display_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, 0x28, 0x00);
+}
+
+static void s6e8aa0_apply_level_2_key(struct s6e8aa0 *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 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);
+}
+
+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);
+}
+
+static void s6e8aa0_acl_ctrl_set(struct s6e8aa0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ /* FIXME: !! must be review acl % value */
+ /* Full white 50% reducing setting */
+ const unsigned char cutoff_50[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
+ 0x3f, 0x46
+ };
+ /* Full white 45% reducing setting */
+ const unsigned char cutoff_45[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
+ 0x37, 0x3d
+ };
+ /* Full white 40% reducing setting */
+ const unsigned char cutoff_40[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
+ 0x31, 0x36
+ };
+
+ if (lcd->acl_enable) {
+ if (lcd->cur_acl == 0) {
+ if (lcd->brightness == 0 || lcd->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) {
+ case 0 ... 1: /* 30cd */
+ s6e8aa0_acl_off(lcd);
+ lcd->cur_acl = 0;
+ break;
+ case 2 ... 6: /* 50cd ~ 100cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)cutoff_40,
+ ARRAY_SIZE(cutoff_40));
+ lcd->cur_acl = 40;
+ break;
+ case 7 ... 16: /* 120cd ~ 210cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)cutoff_45,
+ ARRAY_SIZE(cutoff_45));
+ lcd->cur_acl = 45;
+ break;
+ case 17 ... 24: /* 220cd ~ 300cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int)cutoff_50,
+ ARRAY_SIZE(cutoff_50));
+ lcd->cur_acl = 50;
+ break;
+ default:
+ break;
+ }
+ } else {
+ s6e8aa0_acl_off(lcd);
+ lcd->cur_acl = 0;
+ dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
+ }
+}
+
+static void s6e8aa0_enable_mtp_register(struct s6e8aa0 *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 s6e8aa0_disable_mtp_register(struct s6e8aa0 *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 s6e8aa0_read_id(struct s6e8aa0 *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 s6e8aa0_read_mtp(struct s6e8aa0 *lcd, u8 *mtp_data)
+{
+ unsigned int ret;
+ unsigned int addr = 0xd3; /* MTP addr */
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ s6e8aa0_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);
+
+ s6e8aa0_disable_mtp_register(lcd);
+
+ return ret;
+}
+
+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 s6e8aa0_update_gamma_ctrl(struct s6e8aa0 *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)s6e8aa0_22_gamma_table[brightness],
+ GAMMA_TABLE_COUNT);
+#endif
+
+ /* update gamma table. */
+ 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)
+{
+ s6e8aa0_apply_level_1_key(lcd);
+ if (system_rev == 3)
+ s6e8aa0_apply_level_2_key(lcd);
+
+ s6e8aa0_sleep_out(lcd);
+ usleep_range(5000, 6000);
+
+ s6e8aa0_panel_cond(1);
+ s6e8aa0_display_condition_set(lcd);
+
+ s6e8aa0_gamma_ctrl(lcd, lcd->bd->props.brightness);
+
+ s6e8aa0_etc_source_control(lcd);
+ s6e8aa0_etc_pentile_control(lcd);
+ s6e8aa0_elvss_nvm_set(lcd);
+ s6e8aa0_etc_power_control(lcd);
+ s6e8aa0_etc_elvss_control(lcd);
+
+ /* if ID3 value is not 33h, branch private elvss mode */
+ mdelay(lcd->ddi_pd->power_on_delay);
+
+ return 0;
+}
+
+static int s6e8aa0_early_set_power(struct lcd_device *ld, int power)
+{
+ struct s6e8aa0 *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 s6e8aa0_set_power(struct lcd_device *ld, int power)
+{
+ struct s6e8aa0 *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 s6e8aa0_get_power(struct lcd_device *ld)
+{
+ struct s6e8aa0 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static int s6e8aa0_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+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) {
+ 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 = s6e8aa0_gamma_ctrl(lcd, brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static struct lcd_ops s6e8aa0_lcd_ops = {
+ .early_set_power = s6e8aa0_early_set_power,
+ .set_power = s6e8aa0_set_power,
+ .get_power = s6e8aa0_get_power,
+};
+
+const static struct backlight_ops s6e8aa0_backlight_ops = {
+ .get_brightness = s6e8aa0_get_brightness,
+ .update_status = s6e8aa0_set_brightness,
+};
+
+static int s6e8aa0_check_mtp(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+ int ret;
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+ int i;
+#endif
+ u8 mtp_data[LDI_MTP_LENGTH] = {0, };
+ u8 mtp_id[3] = {0, };
+
+ s6e8aa0_read_id(lcd, mtp_id);
+ if (mtp_id[0] == 0x00) {
+ dev_err(lcd->dev, "read id failed\n");
+ return -EIO;
+ }
+
+ dev_info(lcd->dev,
+ "Read ID : %x, %x, %x\n", mtp_id[0], mtp_id[1], mtp_id[2]);
+
+ if (mtp_id[2] == 0x33)
+ dev_info(lcd->dev,
+ "ID-3 is 0xff does not support dynamic elvss\n");
+ else {
+ dev_info(lcd->dev,
+ "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
+ dev_info(lcd->dev, "Dynamic ELVSS Information\n");
+ }
+
+ lcd->ver = mtp_id[1];
+ lcd->id = mtp_id[2];
+ lcd->aid = (mtp_id[2] >> 5);
+
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+ for (i = 0; i < PANEL_ID_MAX; i++)
+ lcd->smart_dim.panelid[i] = mtp_id[i];
+
+ init_table_info(&lcd->smart_dim);
+#endif
+
+ ret = s6e8aa0_read_mtp(lcd, mtp_data);
+ if (!ret) {
+ dev_err(lcd->dev, "read mtp failed\n");
+ return -EIO;
+ }
+
+#ifdef CONFIG_BACKLIGHT_SMART_DIMMING
+ calc_voltage_table(&lcd->smart_dim, mtp_data);
+#endif
+
+ return 0;
+}
+
+static void s6e8aa0_power_on(struct mipi_dsim_lcd_device *dsim_dev,
+ unsigned int enable)
+{
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ if (enable) {
+ /* lcd power on */
+ s6e8aa0_regulator_enable(lcd);
+
+ mdelay(lcd->ddi_pd->reset_delay);
+
+ /* lcd reset */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+
+ mdelay(5);
+ } else
+ s6e8aa0_regulator_disable(lcd);
+
+}
+
+static void s6e8aa0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e8aa0_panel_init(lcd);
+ s6e8aa0_display_on(lcd);
+}
+
+static ssize_t acl_control_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct s6e8aa0 *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 s6e8aa0 *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;
+ s6e8aa0_acl_ctrl_set(lcd);
+ }
+ return size;
+}
+
+static ssize_t lcd_type_show(struct device *dev, struct
+ device_attribute * attr, char *buf)
+{
+ struct s6e8aa0 *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 s6e8aa0_read_reg(struct s6e8aa0 *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 s6e8aa0_write_reg(struct s6e8aa0 *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 < 2)
+ ret = ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ (unsigned int)fw->data, fw->size);
+ 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 s6e8aa0 *lcd = dev_get_drvdata(dev);
+
+ if (lcd->cur_addr == 0) {
+ dev_err(dev, "failed to set current lcd register.\n");
+ return -EINVAL;
+ }
+
+ return s6e8aa0_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 s6e8aa0 *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 s6e8aa0 *lcd = dev_get_drvdata(dev);
+ char name[32];
+ int ret;
+
+ ret = sscanf(buf, "%s", name);
+ if (ret < 0)
+ return ret;
+
+ ret = s6e8aa0_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 s6e8aa0_model[] = {
+ {
+ .ver = VER_142, /* MACH_SLP_PQ */
+ .name = "SMD_AMS465GS0x",
+ }, {
+ .ver = VER_174, /* MACH_SLP_PQ Dali */
+ .name = "SMD_AMS465GS0x",
+ }, {
+ .ver = VER_42, /* MACH_SLP_PQ_LTE */
+ .name = "SMD_AMS465GS0x",
+ }, {
+ .ver = VER_32, /* MACH_SLP_PQ M0 B-Type */
+ .name = "SMD_AMS480GYXX-0",
+ }, {
+ .ver = VER_210, /* MACH_SLP_PQ M0 A-Type */
+ .name = "SMD_AMS465GS0x",
+ }
+};
+
+static int s6e8aa0_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *lcd;
+ int ret;
+ int i;
+
+ lcd = kzalloc(sizeof(struct s6e8aa0), GFP_KERNEL);
+ if (!lcd) {
+ dev_err(&dsim_dev->dev, "failed to allocate s6e8aa0 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("s6e8aa0", lcd->dev, lcd,
+ &s6e8aa0_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("s6e8aa0-bl", lcd->dev, lcd,
+ &s6e8aa0_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;
+ }
+
+ 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;
+ lcd->model_count = ARRAY_SIZE(s6e8aa0_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);
+
+ s6e8aa0_regulator_enable(lcd);
+ lcd->power = FB_BLANK_UNBLANK;
+
+ lcd_global = lcd;
+
+ dev_info(lcd->dev, "probed s6e8aa0 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 s6e8aa0_remove(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *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);
+
+ kfree(lcd);
+}
+
+#ifdef CONFIG_PM
+static int s6e8aa0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e8aa0_display_off(lcd);
+ s6e8aa0_sleep_in(lcd);
+ mdelay(lcd->ddi_pd->power_off_delay);
+
+ return 0;
+}
+
+static int s6e8aa0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8aa0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e8aa0_sleep_out(lcd);
+ mdelay(lcd->ddi_pd->power_on_delay);
+
+ return 0;
+}
+#else
+#define s6e8aa0_suspend NULL
+#define s6e8aa0_resume NULL
+#endif
+
+static struct mipi_dsim_lcd_driver s6e8aa0_dsim_ddi_driver = {
+ .name = "s6e8aa0",
+ .id = -1,
+
+ .power_on = s6e8aa0_power_on,
+ .check_mtp = s6e8aa0_check_mtp,
+ .set_sequence = s6e8aa0_set_sequence,
+ .probe = s6e8aa0_probe,
+ .remove = s6e8aa0_remove,
+ .suspend = s6e8aa0_suspend,
+ .resume = s6e8aa0_resume,
+};
+
+static int s6e8aa0_init(void)
+{
+ s5p_mipi_dsi_register_lcd_driver(&s6e8aa0_dsim_ddi_driver);
+
+ return 0;
+}
+
+static void s6e8aa0_exit(void)
+{
+ return;
+}
+
+module_init(s6e8aa0_init);
+module_exit(s6e8aa0_exit);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_AUTHOR("Inki Dae <inki.dae@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
new file mode 100644
index 0000000..4e19d7d
--- /dev/null
+++ b/drivers/video/backlight/s6e8aa0.h
@@ -0,0 +1,26 @@
+/* linux/drivers/video/samsung/s6e8aa0.h
+ *
+ * MIPI-DSI based s6e8aa0 AMOLED LCD Panel definitions.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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 _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));
+
+#endif
+
diff --git a/drivers/video/backlight/s6e8aa0_gamma.h b/drivers/video/backlight/s6e8aa0_gamma.h
new file mode 100644
index 0000000..f76f7d2
--- /dev/null
+++ b/drivers/video/backlight/s6e8aa0_gamma.h
@@ -0,0 +1,220 @@
+/* linux/drivers/video/backlight/s6e8aa0_brightness.h
+ *
+ * Brightness level definition.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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 _S6E8AA0_BRIGHTNESS_H
+#define _S6E8AA0_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL 25
+#define GAMMA_TABLE_COUNT 26
+
+/* gamma value: 2.2 */
+static const unsigned char s6e8aa0_22_gamma_30[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xDF, 0x1F,
+ 0xD7, 0xDC, 0xB7, 0xE1, 0xC0, 0xAF, 0xC4, 0xD2, 0xD0, 0xCF,
+ 0x00, 0x4D, 0x00, 0x40, 0x00, 0x5F,
+};
+
+static const unsigned char s6e8aa0_22_gamma_40[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xD5, 0x35,
+ 0xCF, 0xDC, 0xC1, 0xE1, 0xBF, 0xB3, 0xC1, 0xD2, 0xD1, 0xCE,
+ 0x00, 0x53, 0x00, 0x46, 0x00, 0x67,
+
+};
+
+static const unsigned char s6e8aa0_22_gamma_50[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xD2, 0x64,
+ 0xCF, 0xDB, 0xC6, 0xE1, 0xBD, 0xB3, 0xBD, 0xD2, 0xD2, 0xCE,
+ 0x00, 0x59, 0x00, 0x4B, 0x00, 0x6E,
+};
+
+static const unsigned char s6e8aa0_22_gamma_60[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xD0, 0x7C,
+ 0xCF, 0xDB, 0xC9, 0xE0, 0xBC, 0xB4, 0xBB, 0xCF, 0xD1, 0xCC,
+ 0x00, 0x5F, 0x00, 0x50, 0x00, 0x75,
+};
+
+static const unsigned char s6e8aa0_22_gamma_70[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xD0, 0x8E,
+ 0xD1, 0xDB, 0xCC, 0xDF, 0xBB, 0xB6, 0xB9, 0xD0, 0xD1, 0xCD,
+ 0x00, 0x63, 0x00, 0x54, 0x00, 0x7A,
+};
+
+static const unsigned char s6e8aa0_22_gamma_80[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xD1, 0x9E,
+ 0xD5, 0xDA, 0xCD, 0xDD, 0xBB, 0xB7, 0xB9, 0xCE, 0xCE, 0xC9,
+ 0x00, 0x68, 0x00, 0x59, 0x00, 0x81,
+};
+
+static const unsigned char s6e8aa0_22_gamma_90[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xD0, 0xA5,
+ 0xD6, 0xDA, 0xCF, 0xDD, 0xBB, 0xB7, 0xB8, 0xCC, 0xCD, 0xC7,
+ 0x00, 0x6C, 0x00, 0x5C, 0x00, 0x86,
+};
+
+static const unsigned char s6e8aa0_22_gamma_100[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x00, 0xFF, 0xCF, 0xA7,
+ 0xD6, 0xDA, 0xD0, 0xDC, 0xB8, 0xB6, 0xB5, 0xCB, 0xCC, 0xC6,
+ 0x00, 0x71, 0x00, 0x60, 0x00, 0x8C,
+};
+
+static const unsigned char s6e8aa0_22_gamma_110[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x1F, 0xFE, 0xD0, 0xAE,
+ 0xD7, 0xD9, 0xD0, 0xDB, 0xB9, 0xB6, 0xB5, 0xCA, 0xCC, 0xC5,
+ 0x00, 0x74, 0x00, 0x63, 0x00, 0x90,
+};
+
+static const unsigned char s6e8aa0_22_gamma_120[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x1F, 0xF9, 0xCF, 0xB0,
+ 0xD6, 0xD9, 0xD1, 0xDB, 0xB9, 0xB6, 0xB4, 0xCA, 0xCB, 0xC5,
+ 0x00, 0x77, 0x00, 0x66, 0x00, 0x94,
+};
+
+static const unsigned char s6e8aa0_22_gamma_130[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFF, 0x1F, 0xF7, 0xCF, 0xB3,
+ 0xD7, 0xD8, 0xD1, 0xD9, 0xB7, 0xB6, 0xB3, 0xC9, 0xCA, 0xC3,
+ 0x00, 0x7B, 0x00, 0x69, 0x00, 0x99,
+};
+
+static const unsigned char s6e8aa0_22_gamma_140[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFD, 0x2F, 0xF7, 0xDF, 0xB5,
+ 0xD6, 0xD8, 0xD1, 0xD8, 0xB6, 0xB5, 0xB2, 0xCA, 0xCB, 0xC4,
+ 0x00, 0x7E, 0x00, 0x6C, 0x00, 0x9D,
+};
+
+static const unsigned char s6e8aa0_22_gamma_150[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFB, 0x2F, 0xF5, 0xD0, 0xB7,
+ 0xD7, 0xD7, 0xD1, 0xD8, 0xB6, 0xB5, 0xB1, 0xC8, 0xCA, 0xC3,
+ 0x00, 0x81, 0x00, 0x6E, 0x00, 0xA0,
+};
+
+static const unsigned char s6e8aa0_22_gamma_160[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xFA, 0x2F, 0xF5, 0xCE, 0xB6,
+ 0xD5, 0xD7, 0xD2, 0xD8, 0xB6, 0xB4, 0xB0, 0xC7, 0xC9, 0xC1,
+ 0x00, 0x84, 0x00, 0x71, 0x00, 0xA5,
+};
+
+static const unsigned char s6e8aa0_22_gamma_170[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xF7, 0x2F, 0xF2, 0xCE, 0xB9,
+ 0xD5, 0xD8, 0xD2, 0xD8, 0xB4, 0xB4, 0xAF, 0xC7, 0xC9, 0xC1,
+ 0x00, 0x87, 0x00, 0x73, 0x00, 0xA8,
+};
+
+static const unsigned char s6e8aa0_22_gamma_180[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xF5, 0x2F, 0xF0, 0xDF, 0xBA,
+ 0xD5, 0xD7, 0xD2, 0xD7, 0xB4, 0xB4, 0xAF, 0xC5, 0xC7, 0xBF,
+ 0x00, 0x8A, 0x00, 0x76, 0x00, 0xAC,
+};
+
+static const unsigned char s6e8aa0_22_gamma_190[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xF2, 0x2F, 0xED, 0xCE, 0xBB,
+ 0xD4, 0xD6, 0xD2, 0xD6, 0xB5, 0xB4, 0xAF, 0xC5, 0xC7, 0xBF,
+ 0x00, 0x8c, 0x00, 0x78, 0x00, 0xAF,
+};
+
+static const unsigned char s6e8aa0_22_gamma_200[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xF2, 0x2F, 0xED, 0xCE, 0xBB,
+ 0xD4, 0xD7, 0xD3, 0xD6, 0xB3, 0xB3, 0xAE, 0xC6, 0xC7, 0xBF,
+ 0x00, 0x8E, 0x00, 0x7A, 0x00, 0xB2,
+};
+
+static const unsigned char s6e8aa0_22_gamma_210[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEF, 0x2F, 0xEB, 0xCD, 0xBB,
+ 0xD2, 0xD7, 0xD3, 0xD6, 0xB3, 0xB4, 0xAE, 0xC5, 0xC6, 0xBE,
+ 0x00, 0x91, 0x00, 0x7D, 0x00, 0xB6,
+};
+
+static const unsigned char s6e8aa0_22_gamma_220[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEE, 0x2F, 0xEA, 0xCE, 0xBD,
+ 0xD4, 0xD6, 0xD2, 0xD5, 0xB2, 0xB3, 0xAD, 0xC3, 0xC4, 0xBB,
+ 0x00, 0x94, 0x00, 0x7F, 0x00, 0xBA,
+};
+
+static const unsigned char s6e8aa0_22_gamma_230[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEC, 0x2F, 0xE8, 0xCE, 0xBE,
+ 0xD3, 0xD6, 0xD3, 0xD5, 0xB2, 0xB2, 0xAC, 0xC3, 0xC5, 0xBC,
+ 0x00, 0x96, 0x00, 0x81, 0x00, 0xBD,
+};
+
+static const unsigned char s6e8aa0_22_gamma_240[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEB, 0x2F, 0xE7, 0xCE, 0xBF,
+ 0xD3, 0xD6, 0xD2, 0xD5, 0xB1, 0xB2, 0xAB, 0xC2, 0xC4, 0xBB,
+ 0x00, 0x99, 0x00, 0x83, 0x00, 0xC0,
+};
+
+static const unsigned char s6e8aa0_22_gamma_250[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEF, 0x5F, 0xE9, 0xCA, 0xBF,
+ 0xD3, 0xD5, 0xD2, 0xD4, 0xB2, 0xB2, 0xAB, 0xC1, 0xC4, 0xBA,
+ 0x00, 0x9B, 0x00, 0x85, 0x00, 0xC3,
+};
+
+static const unsigned char s6e8aa0_22_gamma_260[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xEA, 0x5F, 0xE8, 0xCE, 0xBF,
+ 0xD2, 0xD5, 0xD2, 0xD4, 0xB1, 0xB2, 0xAB, 0xC1, 0xC2, 0xB9,
+ 0x00, 0x9D, 0x00, 0x87, 0x00, 0xC6,
+};
+
+static const unsigned char s6e8aa0_22_gamma_270[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xE9, 0x5F, 0xE7, 0xCD, 0xBF,
+ 0xD2, 0xD6, 0xD2, 0xD4, 0xB1, 0xB2, 0xAB, 0xBE, 0xC0, 0xB7,
+ 0x00, 0xA1, 0x00, 0x8A, 0x00, 0xCA,
+};
+
+static const unsigned char s6e8aa0_22_gamma_280[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xE8, 0x61, 0xE6, 0xCD, 0xBF,
+ 0xD1, 0xD6, 0xD3, 0xD4, 0xAF, 0xB0, 0xA9, 0xBE, 0xC1, 0xB7,
+ 0x00, 0xA3, 0x00, 0x8B, 0x00, 0xCE,
+};
+
+static const unsigned char s6e8aa0_22_gamma_290[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xE8, 0x62, 0xE5, 0xCC, 0xC0,
+ 0xD0, 0xD6, 0xD2, 0xD4, 0xAF, 0xB1, 0xA9, 0xBD, 0xC0, 0xB6,
+ 0x00, 0xA5, 0x00, 0x8D, 0x00, 0xD0,
+
+};
+
+static const unsigned char s6e8aa0_22_gamma_300[] = {
+ 0xFA, 0x01, 0x1F, 0x1F, 0x1F, 0xE7, 0x7F, 0xE3, 0xCC, 0xC1,
+ 0xD0, 0xD5, 0xD3, 0xD3, 0xAE, 0xAF, 0xA8, 0xBE, 0xC0, 0xB7,
+ 0x00, 0xA8, 0x00, 0x90, 0x00, 0xD3,
+};
+
+static const unsigned char *s6e8aa0_22_gamma_table[MAX_GAMMA_LEVEL] = {
+ s6e8aa0_22_gamma_30,
+ s6e8aa0_22_gamma_50,
+ s6e8aa0_22_gamma_60,
+ s6e8aa0_22_gamma_70,
+ s6e8aa0_22_gamma_80,
+ s6e8aa0_22_gamma_90,
+ s6e8aa0_22_gamma_100,
+ s6e8aa0_22_gamma_110,
+ s6e8aa0_22_gamma_120,
+ s6e8aa0_22_gamma_130,
+ s6e8aa0_22_gamma_140,
+ s6e8aa0_22_gamma_150,
+ s6e8aa0_22_gamma_160,
+ s6e8aa0_22_gamma_170,
+ s6e8aa0_22_gamma_180,
+ s6e8aa0_22_gamma_190,
+ s6e8aa0_22_gamma_200,
+ s6e8aa0_22_gamma_210,
+ s6e8aa0_22_gamma_220,
+ s6e8aa0_22_gamma_230,
+ s6e8aa0_22_gamma_240,
+ s6e8aa0_22_gamma_270,
+ s6e8aa0_22_gamma_280,
+ s6e8aa0_22_gamma_290,
+ s6e8aa0_22_gamma_300,
+};
+
+#endif
diff --git a/drivers/video/backlight/s6e8aa0_volt_tbl.h b/drivers/video/backlight/s6e8aa0_volt_tbl.h
new file mode 100644
index 0000000..3f187b9
--- /dev/null
+++ b/drivers/video/backlight/s6e8aa0_volt_tbl.h
@@ -0,0 +1,967 @@
+#ifndef __REF_VOLT_TABLE_H__
+#define __REF_VOLT_TABLE_H__
+
+u32 volt_table_v1[256] = {
+4671488, 4663296, 4655104, 4647936,
+4639744, 4631552, 4624384, 4616192,
+4608000, 4600832, 4592640, 4584448,
+4577280, 4569088, 4560896, 4553728,
+4545536, 4537344, 4530176, 4521984,
+4513792, 4506624, 4498432, 4490240,
+4483072, 4474880, 4466688, 4459520,
+4451328, 4443136, 4435968, 4427776,
+4419584, 4412416, 4404224, 4396032,
+4388864, 4380672, 4372480, 4365312,
+4357120, 4348928, 4341760, 4333568,
+4325376, 4318208, 4310016, 4301824,
+4294656, 4286464, 4278272, 4271104,
+4262912, 4254720, 4247552, 4239360,
+4231168, 4224000, 4215808, 4207616,
+4200448, 4192256, 4184064, 4176896,
+4168704, 4160512, 4153344, 4145152,
+4136960, 4129792, 4121600, 4113408,
+4106240, 4098048, 4089856, 4082688,
+4074496, 4066304, 4059136, 4050944,
+4042752, 4035584, 4027392, 4019200,
+4012032, 4003840, 3995648, 3988480,
+3980288, 3972096, 3964928, 3956736,
+3948544, 3941376, 3933184, 3924992,
+3917824, 3909632, 3901440, 3894272,
+3886080, 3877888, 3870720, 3862528,
+3854336, 3847168, 3838976, 3830784,
+3823616, 3815424, 3807232, 3800064,
+3791872, 3783680, 3776512, 3768320,
+3760128, 3752960, 3744768, 3736576,
+3729408, 3721216, 3713024, 3705856,
+3697664, 3689472, 3682304, 3674112,
+3665920, 3658752, 3650560, 3642368,
+3635200, 3627008, 3618816, 3611648,
+3603456, 3595264, 3588096, 3579904,
+3571712, 3564544,
+};
+
+
+u32 volt_table_v255[432] = {
+3924992, 3917824, 3909632, 3901440,
+3894272, 3886080, 3877888, 3870720,
+3862528, 3854336, 3847168, 3838976,
+3830784, 3823616, 3815424, 3807232,
+3800064, 3791872, 3783680, 3776512,
+3768320, 3760128, 3752960, 3744768,
+3736576, 3729408, 3721216, 3713024,
+3705856, 3697664, 3689472, 3682304,
+3674112, 3665920, 3658752, 3650560,
+3642368, 3635200, 3627008, 3618816,
+3611648, 3603456, 3595264, 3588096,
+3579904, 3571712, 3564544, 3556352,
+3548160, 3540992, 3532800, 3524608,
+3517440, 3509248, 3501056, 3493888,
+3485696, 3477504, 3470336, 3462144,
+3453952, 3446784, 3438592, 3430400,
+3423232, 3415040, 3406848, 3399680,
+3391488, 3383296, 3376128, 3367936,
+3359744, 3352576, 3344384, 3336192,
+3329024, 3320832, 3312640, 3305472,
+3297280, 3289088, 3281920, 3273728,
+3265536, 3258368, 3250176, 3241984,
+3234816, 3226624, 3218432, 3211264,
+3203072, 3194880, 3187712, 3179520,
+3171328, 3164160, 3155968, 3147776,
+3140608, 3132416, 3124224, 3117056,
+3108864, 3100672, 3093504, 3085312,
+3077120, 3069952, 3061760, 3053568,
+3046400, 3038208, 3030016, 3022848,
+3014656, 3006464, 2999296, 2991104,
+2982912, 2975744, 2967552, 2959360,
+2952192, 2944000, 2935808, 2928640,
+2920448, 2912256, 2905088, 2896896,
+2888704, 2881536, 2873344, 2865152,
+2857984, 2849792, 2841600, 2834432,
+2826240, 2818048, 2810880, 2802688,
+2794496, 2787328, 2779136, 2770944,
+2763776, 2755584, 2747392, 2740224,
+2732032, 2723840, 2716672, 2708480,
+2700288, 2693120, 2684928, 2676736,
+2669568, 2661376, 2653184, 2646016,
+2637824, 2629632, 2622464, 2614272,
+2606080, 2598912, 2590720, 2582528,
+2575360, 2567168, 2558976, 2551808,
+2543616, 2535424, 2528256, 2520064,
+2511872, 2504704, 2496512, 2488320,
+2481152, 2472960, 2464768, 2457600,
+2449408, 2441216, 2434048, 2425856,
+2417664, 2410496, 2402304, 2394112,
+2386944, 2378752, 2370560, 2363392,
+2355200, 2347008, 2339840, 2331648,
+2323456, 2316288, 2308096, 2299904,
+2292736, 2284544, 2276352, 2269184,
+2260992, 2252800, 2245632, 2237440,
+2229248, 2222080, 2213888, 2205696,
+2198528, 2190336, 2182144, 2174976,
+2166784, 2158592, 2151424, 2143232,
+2135040, 2127872, 2119680, 2111488,
+2104320, 2096128, 2087936, 2080768,
+2072576, 2064384, 2057216, 2049024,
+2040832, 2033664, 2025472, 2017280,
+2010112, 2001920, 1993728, 1986560,
+1978368, 1970176, 1963008, 1954816,
+1946624, 1939456, 1931264, 1923072,
+1915904, 1907712, 1899520, 1892352,
+1884160, 1875968, 1868800, 1860608,
+1852416, 1845248, 1837056, 1828864,
+1821696, 1813504, 1805312, 1798144,
+1789952, 1781760, 1774592, 1766400,
+1758208, 1751040, 1742848, 1734656,
+1727488, 1719296, 1711104, 1703936,
+1695744, 1687552, 1680384, 1672192,
+1664000, 1656832, 1648640, 1640448,
+1633280, 1625088, 1616896, 1609728,
+1601536, 1593344, 1586176, 1577984,
+1569792, 1562624, 1554432, 1546240,
+1539072, 1530880, 1522688, 1515520,
+1507328, 1499136, 1491968, 1483776,
+1475584, 1468416, 1460224, 1452032,
+1444864, 1436672, 1428480, 1421312,
+1413120, 1404928, 1397760, 1389568,
+1381376, 1374208, 1366016, 1357824,
+1350656, 1342464, 1334272, 1327104,
+1318912, 1310720, 1303552, 1295360,
+1287168, 1280000, 1271808, 1263616,
+1256448, 1248256, 1240064, 1232896,
+1224704, 1216512, 1209344, 1201152,
+1192960, 1185792, 1177600, 1169408,
+1162240, 1154048, 1145856, 1138688,
+1130496, 1122304, 1115136, 1106944,
+1098752, 1091584, 1083392, 1075200,
+1068032, 1059840, 1051648, 1044480,
+1036288, 1028096, 1020928, 1012736,
+1004544, 997376, 989184, 980992,
+973824, 965632, 957440, 950272,
+942080, 933888, 926720, 918528,
+910336, 903168, 894976, 886784,
+879616, 871424, 863232, 856064,
+847872, 839680, 832512, 824320,
+816128, 808960, 800768, 792576,
+785408, 777216, 769024, 761856,
+753664, 745472, 738304, 730112,
+721920, 714752, 706560, 698368,
+691200, 683008, 674816, 667648,
+659456, 651264, 644096, 635904,
+627712, 620544, 612352, 604160,
+596992, 588800, 580608, 573440,
+565248, 557056, 549888, 541696,
+
+};
+
+u32 volt_table_cv_20_dv_320[256] = {
+64,
+67,
+70,
+74,
+77,
+80,
+83,
+86,
+90,
+93,
+96,
+99,
+102,
+106,
+109,
+112,
+115,
+118,
+122,
+125,
+128,
+131,
+134,
+138,
+141,
+144,
+147,
+150,
+154,
+157,
+160,
+163,
+166,
+170,
+173,
+176,
+179,
+182,
+186,
+189,
+192,
+195,
+198,
+202,
+205,
+208,
+211,
+214,
+218,
+221,
+224,
+227,
+230,
+234,
+237,
+240,
+243,
+246,
+250,
+253,
+256,
+259,
+262,
+266,
+269,
+272,
+275,
+278,
+282,
+285,
+288,
+291,
+294,
+298,
+301,
+304,
+307,
+310,
+314,
+317,
+320,
+323,
+326,
+330,
+333,
+336,
+339,
+342,
+346,
+349,
+352,
+355,
+358,
+362,
+365,
+368,
+371,
+374,
+378,
+381,
+384,
+387,
+390,
+394,
+397,
+400,
+403,
+406,
+410,
+413,
+416,
+419,
+422,
+426,
+429,
+432,
+435,
+438,
+442,
+445,
+448,
+451,
+454,
+458,
+461,
+464,
+467,
+470,
+474,
+477,
+480,
+483,
+486,
+490,
+493,
+496,
+499,
+502,
+506,
+509,
+512,
+515,
+518,
+522,
+525,
+528,
+531,
+534,
+538,
+541,
+544,
+547,
+550,
+554,
+557,
+560,
+563,
+566,
+570,
+573,
+576,
+579,
+582,
+586,
+589,
+592,
+595,
+598,
+602,
+605,
+608,
+611,
+614,
+618,
+621,
+624,
+627,
+630,
+634,
+637,
+640,
+643,
+646,
+650,
+653,
+656,
+659,
+662,
+666,
+669,
+672,
+675,
+678,
+682,
+685,
+688,
+691,
+694,
+698,
+701,
+704,
+707,
+710,
+714,
+717,
+720,
+723,
+726,
+730,
+733,
+736,
+739,
+742,
+746,
+749,
+752,
+755,
+758,
+762,
+765,
+768,
+771,
+774,
+778,
+781,
+784,
+787,
+790,
+794,
+797,
+800,
+803,
+806,
+810,
+813,
+816,
+819,
+822,
+826,
+829,
+832,
+835,
+838,
+842,
+845,
+848,
+851,
+854,
+858,
+861,
+864,
+867,
+870,
+874,
+877,
+880
+};
+
+u32 volt_table_cv_65_dv_320[256] = {
+208,
+211,
+214,
+218,
+221,
+224,
+227,
+230,
+234,
+237,
+240,
+243,
+246,
+250,
+253,
+256,
+259,
+262,
+266,
+269,
+272,
+275,
+278,
+282,
+285,
+288,
+291,
+294,
+298,
+301,
+304,
+307,
+310,
+314,
+317,
+320,
+323,
+326,
+330,
+333,
+336,
+339,
+342,
+346,
+349,
+352,
+355,
+358,
+362,
+365,
+368,
+371,
+374,
+378,
+381,
+384,
+387,
+390,
+394,
+397,
+400,
+403,
+406,
+410,
+413,
+416,
+419,
+422,
+426,
+429,
+432,
+435,
+438,
+442,
+445,
+448,
+451,
+454,
+458,
+461,
+464,
+467,
+470,
+474,
+477,
+480,
+483,
+486,
+490,
+493,
+496,
+499,
+502,
+506,
+509,
+512,
+515,
+518,
+522,
+525,
+528,
+531,
+534,
+538,
+541,
+544,
+547,
+550,
+554,
+557,
+560,
+563,
+566,
+570,
+573,
+576,
+579,
+582,
+586,
+589,
+592,
+595,
+598,
+602,
+605,
+608,
+611,
+614,
+618,
+621,
+624,
+627,
+630,
+634,
+637,
+640,
+643,
+646,
+650,
+653,
+656,
+659,
+662,
+666,
+669,
+672,
+675,
+678,
+682,
+685,
+688,
+691,
+694,
+698,
+701,
+704,
+707,
+710,
+714,
+717,
+720,
+723,
+726,
+730,
+733,
+736,
+739,
+742,
+746,
+749,
+752,
+755,
+758,
+762,
+765,
+768,
+771,
+774,
+778,
+781,
+784,
+787,
+790,
+794,
+797,
+800,
+803,
+806,
+810,
+813,
+816,
+819,
+822,
+826,
+829,
+832,
+835,
+838,
+842,
+845,
+848,
+851,
+854,
+858,
+861,
+864,
+867,
+870,
+874,
+877,
+880,
+883,
+886,
+890,
+893,
+896,
+899,
+902,
+906,
+909,
+912,
+915,
+918,
+922,
+925,
+928,
+931,
+934,
+938,
+941,
+944,
+947,
+950,
+954,
+957,
+960,
+963,
+966,
+970,
+973,
+976,
+979,
+982,
+986,
+989,
+992,
+995,
+998,
+1002,
+1005,
+1008,
+1011,
+1014,
+1018,
+1021,
+1024,
+};
+
+const u32 gamma_300_gra_table[256] = {
+0, 2, 7, 17,
+32, 53, 78, 110,
+148, 191, 241, 298,
+361, 430, 506, 589,
+679, 776, 880, 991,
+1109, 1235, 1368, 1508,
+1657, 1812, 1975, 2147,
+2325, 2512, 2706, 2909,
+3119, 3338, 3564, 3799,
+4042, 4293, 4553, 4820,
+5096, 5381, 5674, 5975,
+6285, 6604, 6931, 7267,
+7611, 7965, 8327, 8697,
+9077, 9465, 9863, 10269,
+10684, 11109, 11542, 11984,
+12436, 12896, 13366, 13845,
+14333, 14830, 15337, 15852,
+16378, 16912, 17456, 18009,
+18572, 19144, 19726, 20317,
+20918, 21528, 22148, 22778,
+23417, 24066, 24724, 25392,
+26070, 26758, 27456, 28163,
+28880, 29607, 30344, 31090,
+31847, 32613, 33390, 34176,
+34973, 35779, 36596, 37422,
+38259, 39106, 39963, 40830,
+41707, 42594, 43492, 44399,
+45317, 46246, 47184, 48133,
+49092, 50062, 51042, 52032,
+53032, 54043, 55065, 56097,
+57139, 58192, 59255, 60329,
+61413, 62508, 63613, 64729,
+65856, 66993, 68141, 69299,
+70469, 71648, 72839, 74040,
+75252, 76475, 77708, 78952,
+80207, 81473, 82750, 84037,
+85336, 86645, 87965, 89296,
+90638, 91990, 93354, 94729,
+96114, 97511, 98919, 100337,
+101767, 103208, 104659, 106122,
+107596, 109081, 110577, 112085,
+113603, 115132, 116673, 118225,
+119788, 121362, 122948, 124544,
+126152, 127772, 129402, 131044,
+132697, 134361, 136037, 137724,
+139422, 141132, 142853, 144586,
+146330, 148085, 149852, 151630,
+153419, 155220, 157033, 158857,
+160692, 162540, 164398, 166268,
+168150, 170043, 171948, 173864,
+175792, 177731, 179683, 181645,
+183620, 185606, 187603, 189613,
+191634, 193667, 195711, 197767,
+199835, 201915, 204006, 206109,
+208224, 210351, 212489, 214640,
+216802, 218976, 221161, 223359,
+225569, 227790, 230023, 232268,
+234525, 236794, 239075, 241368,
+243672, 245989, 248318, 250658,
+253011, 255375, 257752, 260141,
+262541, 264954, 267379, 269815,
+272264, 274725, 277198, 279683,
+282180, 284689, 287211, 289744,
+292290, 294848, 297418, 300000,
+};
+
+
+const u32 gamma_22_table[256] = {
+0, 0, 0, 0,
+0, 0, 0, 0,
+0, 1, 1, 1,
+1, 1, 2, 2,
+2, 3, 3, 3,
+4, 4, 5, 5,
+6, 6, 7, 7,
+8, 8, 9, 10,
+10, 11, 12, 13,
+13, 14, 15, 16,
+17, 18, 19, 20,
+21, 22, 23, 24,
+25, 27, 28, 29,
+30, 32, 33, 34,
+36, 37, 38, 40,
+41, 43, 45, 46,
+48, 49, 51, 53,
+55, 56, 58, 60,
+62, 64, 66, 68,
+70, 72, 74, 76,
+78, 80, 82, 85,
+87, 89, 92, 94,
+96, 99, 101, 104,
+106, 109, 111, 114,
+117, 119, 122, 125,
+128, 130, 133, 136,
+139, 142, 145, 148,
+151, 154, 157, 160,
+164, 167, 170, 173,
+177, 180, 184, 187,
+190, 194, 198, 201,
+205, 208, 212, 216,
+220, 223, 227, 231,
+235, 239, 243, 247,
+251, 255, 259, 263,
+267, 272, 276, 280,
+284, 289, 293, 298,
+302, 307, 311, 316,
+320, 325, 330, 334,
+339, 344, 349, 354,
+359, 364, 369, 374,
+379, 384, 389, 394,
+399, 405, 410, 415,
+421, 426, 431, 437,
+442, 448, 453, 459,
+465, 470, 476, 482,
+488, 494, 500, 505,
+511, 517, 523, 530,
+536, 542, 548, 554,
+560, 567, 573, 580,
+586, 592, 599, 605,
+612, 619, 625, 632,
+639, 646, 652, 659,
+666, 673, 680, 687,
+694, 701, 708, 715,
+723, 730, 737, 745,
+752, 759, 767, 774,
+782, 789, 797, 805,
+812, 820, 828, 836,
+843, 851, 859, 867,
+875, 883, 891, 899,
+908, 916, 924, 932,
+941, 949, 957, 966,
+974, 983, 991, 1000,
+};
+
+
+const struct str_flookup_table flookup_table[302] = {
+{ 0, 0}, { 1, 20},
+{ 20, 7}, { 27, 5},
+{ 32, 4}, { 36, 4},
+{ 40, 4}, { 44, 3},
+{ 47, 3}, { 50, 2},
+{ 52, 3}, { 55, 2},
+{ 57, 3}, { 60, 2},
+{ 62, 2}, { 64, 2},
+{ 66, 2}, { 68, 2},
+{ 70, 1}, { 71, 2},
+{ 73, 2}, { 75, 2},
+{ 77, 1}, { 78, 2},
+{ 80, 1}, { 81, 2},
+{ 83, 1}, { 84, 2},
+{ 86, 1}, { 87, 2},
+{ 89, 1}, { 90, 1},
+{ 91, 2}, { 93, 1},
+{ 94, 1}, { 95, 2},
+{ 97, 1}, { 98, 1},
+{ 99, 1}, {100, 1},
+{101, 2}, {103, 1},
+{104, 1}, {105, 1},
+{106, 1}, {107, 1},
+{108, 1}, {109, 1},
+{110, 1}, {111, 1},
+{112, 1}, {113, 1},
+{114, 1}, {115, 1},
+{116, 1}, {117, 1},
+{118, 1}, {119, 1},
+{120, 1}, {121, 1},
+{122, 1}, {123, 1},
+{124, 1}, {125, 1},
+{126, 1}, {127, 1},
+{128, 1}, {129, 1},
+{ 0, 0}, {130, 1},
+{131, 1}, {132, 1},
+{133, 1}, {134, 1},
+{ 0, 0}, {135, 1},
+{136, 1}, {137, 1},
+{138, 1}, {139, 1},
+{ 0, 0}, {140, 1},
+{141, 1}, {142, 1},
+{ 0, 0}, {143, 1},
+{144, 1}, {145, 1},
+{146, 1}, { 0, 0},
+{147, 1}, {148, 1},
+{149, 1}, { 0, 0},
+{150, 1}, {151, 1},
+{ 0, 0}, {152, 1},
+{153, 1}, {154, 1},
+{ 0, 0}, {155, 1},
+{156, 1}, { 0, 0},
+{157, 1}, {158, 1},
+{ 0, 0}, {159, 1},
+{160, 1}, { 0, 0},
+{161, 1}, {162, 1},
+{ 0, 0}, {163, 1},
+{164, 1}, { 0, 0},
+{165, 1}, {166, 1},
+{ 0, 0}, {167, 1},
+{168, 1}, { 0, 0},
+{169, 1}, {170, 1},
+{ 0, 0}, {171, 1},
+{ 0, 0}, {172, 1},
+{173, 1}, { 0, 0},
+{174, 1}, { 0, 0},
+{175, 1}, {176, 1},
+{ 0, 0}, {177, 1},
+{ 0, 0}, {178, 1},
+{179, 1}, { 0, 0},
+{180, 1}, { 0, 0},
+{181, 1}, {182, 1},
+{ 0, 0}, {183, 1},
+{ 0, 0}, {184, 1},
+{ 0, 0}, {185, 1},
+{186, 1}, { 0, 0},
+{187, 1}, { 0, 0},
+{188, 1}, { 0, 0},
+{189, 1}, { 0, 0},
+{190, 1}, {191, 1},
+{ 0, 0}, {192, 1},
+{ 0, 0}, {193, 1},
+{ 0, 0}, {194, 1},
+{ 0, 0}, {195, 1},
+{ 0, 0}, {196, 1},
+{ 0, 0}, {197, 1},
+{198, 1}, { 0, 0},
+{199, 1}, { 0, 0},
+{200, 1}, { 0, 0},
+{201, 1}, { 0, 0},
+{202, 1}, { 0, 0},
+{203, 1}, { 0, 0},
+{204, 1}, { 0, 0},
+{205, 1}, { 0, 0},
+{206, 1}, { 0, 0},
+{207, 1}, { 0, 0},
+{208, 1}, { 0, 0},
+{209, 1}, { 0, 0},
+{210, 1}, { 0, 0},
+{211, 1}, { 0, 0},
+{212, 1}, { 0, 0},
+{213, 1}, { 0, 0},
+{ 0, 0}, {214, 1},
+{ 0, 0}, {215, 1},
+{ 0, 0}, {216, 1},
+{ 0, 0}, {217, 1},
+{ 0, 0}, {218, 1},
+{ 0, 0}, {219, 1},
+{ 0, 0}, {220, 1},
+{ 0, 0}, {221, 1},
+{ 0, 0}, { 0, 0},
+{222, 1}, { 0, 0},
+{223, 1}, { 0, 0},
+{224, 1}, { 0, 0},
+{225, 1}, { 0, 0},
+{ 0, 0}, {226, 1},
+{ 0, 0}, {227, 1},
+{ 0, 0}, {228, 1},
+{ 0, 0}, {229, 1},
+{ 0, 0}, { 0, 0},
+{230, 1}, { 0, 0},
+{231, 1}, { 0, 0},
+{232, 1}, { 0, 0},
+{233, 1}, { 0, 0},
+{ 0, 0}, {234, 1},
+{ 0, 0}, {235, 1},
+{ 0, 0}, { 0, 0},
+{236, 1}, { 0, 0},
+{237, 1}, { 0, 0},
+{238, 1}, { 0, 0},
+{ 0, 0}, {239, 1},
+{ 0, 0}, {240, 1},
+{ 0, 0}, {241, 1},
+{ 0, 0}, { 0, 0},
+{242, 1}, { 0, 0},
+{243, 1}, { 0, 0},
+{ 0, 0}, {244, 1},
+{ 0, 0}, {245, 1},
+{ 0, 0}, { 0, 0},
+{246, 1}, { 0, 0},
+{247, 1}, { 0, 0},
+{ 0, 0}, {248, 1},
+{ 0, 0}, {249, 1},
+{ 0, 0}, { 0, 0},
+{250, 1}, { 0, 0},
+{251, 1}, { 0, 0},
+{ 0, 0}, {252, 1},
+{ 0, 0}, {253, 1},
+{ 0, 0}, { 0, 0},
+{254, 1}, { 0, 0},
+{ 0, 0}, {255, 1},
+
+};
+
+
+
+#endif
diff --git a/drivers/video/backlight/s6e8ab0_mipi_lcd.c b/drivers/video/backlight/s6e8ab0_mipi_lcd.c
new file mode 100644
index 0000000..ef5c41f
--- /dev/null
+++ b/drivers/video/backlight/s6e8ab0_mipi_lcd.c
@@ -0,0 +1,77 @@
+/* linux/drivers/video/backlight/s6e8ab0_mipi_lcd.c
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-dsim.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+
+void init_lcd(struct mipi_dsim_device *dsim)
+{
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0, 0);
+ msleep(60);
+ /* Exit sleep */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x11, 0);
+ msleep(600);
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_TURN_ON_PERIPHERAL,
+ 0, 0);
+}
+
+void s6e8ab0_mipi_lcd_off(struct mipi_dsim_device *dsim)
+{
+ usleep_range(1000, 1200);
+}
+
+static int s6e8ab0_mipi_lcd_suspend(struct mipi_dsim_device *dsim)
+{
+ s6e8ab0_mipi_lcd_off(dsim);
+ return 0;
+}
+
+static int s6e8ab0_mipi_lcd_displayon(struct mipi_dsim_device *dsim)
+{
+ init_lcd(dsim);
+
+ return 0;
+}
+
+static int s6e8ab0_mipi_lcd_resume(struct mipi_dsim_device *dsim)
+{
+ init_lcd(dsim);
+ return 0;
+}
+
+struct mipi_dsim_lcd_driver s6e8ab0_mipi_lcd_driver = {
+ .suspend = s6e8ab0_mipi_lcd_suspend,
+ .displayon = s6e8ab0_mipi_lcd_displayon,
+ .resume = s6e8ab0_mipi_lcd_resume,
+};
diff --git a/drivers/video/backlight/smart_dimming.c b/drivers/video/backlight/smart_dimming.c
new file mode 100644
index 0000000..42438ad
--- /dev/null
+++ b/drivers/video/backlight/smart_dimming.c
@@ -0,0 +1,771 @@
+/* linux/drivers/video/samsung/smartdimming.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+
+ * Samsung Smart Dimming for OCTA
+ *
+ * Minwoo Kim, <minwoo7945.kim@samsung.com>
+ *
+*/
+
+
+#include "smart_dimming.h"
+#include "s6e8aa0_volt_tbl.h"
+
+#define MTP_REVERSE 1
+#define VALUE_DIM_1000 1000
+
+
+const u8 v1_offset_table[14] = {
+ 47, 42, 37, 32,
+ 27, 23, 19, 15,
+ 12, 9, 6, 4,
+ 2, 0
+};
+
+
+const u8 v15_offset_table[20] = {
+ 66, 62, 58, 54,
+ 50, 46, 43, 38,
+ 34, 30, 27, 24,
+ 21, 18, 15, 12,
+ 9, 6, 3, 0,
+};
+
+
+const u8 range_table_count[IV_TABLE_MAX] = {
+ 1, 14, 20, 24, 28, 84, 84, 1
+};
+
+
+const u32 table_radio[IV_TABLE_MAX] = {
+ 0, 630, 468, 1365, 1170, 390, 390, 0
+};
+
+
+const u32 dv_value[IV_MAX] = {
+ 0, 15, 35, 59, 87, 171, 255
+};
+
+
+const char color_name[3] = {'R', 'G', 'B'};
+
+
+const u8 *offset_table[IV_TABLE_MAX] = {
+ NULL,
+ v1_offset_table,
+ v15_offset_table,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+const unsigned char gamma_300cd_23[] = {
+ 0x0f, 0x0f, 0x0f, 0xee, 0xb4, 0xee,
+ 0xcb, 0xc2, 0xc4, 0xda, 0xd7, 0xd5,
+ 0xae, 0xaf, 0xa7, 0xc0, 0xc1, 0xbb,
+ 0x00, 0x9f, 0x00, 0x95, 0x00, 0xd4,
+};
+
+const unsigned char gamma_300cd_33[] = {
+ 0x0f, 0x00, 0x0f, 0xda, 0xc0, 0xe4,
+ 0xc8, 0xc8, 0xc6, 0xd3, 0xd6, 0xd0,
+ 0xab, 0xb2, 0xa6, 0xbf, 0xc2, 0xb9,
+ 0x00, 0x93, 0x00, 0x86, 0x00, 0xd1,
+};
+
+const unsigned char gamma_300cd_43[] = {
+ 0x1f, 0x1f, 0x1f, 0xe3, 0x69, 0xe0,
+ 0xcc, 0xc1, 0xce, 0xd4, 0xd2, 0xd2,
+ 0xae, 0xae, 0xa6, 0xbf, 0xc0, 0xb6,
+ 0x00, 0xa3, 0x00, 0x90, 0x00, 0xd7,
+};
+
+const unsigned char gamma_300cd_53[] = {
+ 0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3,
+ 0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3,
+ 0xae, 0xaf, 0xa8, 0xbe, 0xc0, 0xb7,
+ 0x00, 0xa8, 0x00, 0x90, 0x00, 0xd3,
+};
+
+const unsigned char gamma_300cd_63[] = {
+ 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd,
+ 0xb1, 0xd2, 0xb0, 0xc0, 0xdc, 0xc0,
+ 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
+ 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
+};
+
+const unsigned char gamma_300cd_73[] = {
+ 0x1f, 0x1f, 0x1f, 0xed, 0xe6, 0xe7,
+ 0xd1, 0xd3, 0xd4, 0xda, 0xd8, 0xd7,
+ 0xb1, 0xaf, 0xab, 0xbd, 0xbb, 0xb8,
+ 0x00, 0xd6, 0x00, 0xda, 0x00, 0xfa,
+};
+
+const unsigned char gamma_300cd_83[] = {
+ 0x69, 0x5A, 0x6C, 0xA1, 0xB7, 0x9D,
+ 0xAB, 0xB6, 0xAF, 0xB8, 0xC1, 0xB9,
+ 0x8E, 0x96, 0x8B, 0xA6, 0xAC, 0xA4,
+ 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xF1
+};
+
+/* SM2 , DALI PANEL - Midas Universal board */
+const unsigned char gamma_300cd_4e[] = {
+ 0x58, 0x1F, 0x63, 0xAC, 0xB4, 0x99,
+ 0xAD, 0xBA, 0xA3, 0xC0, 0xCB, 0xBB,
+ 0x93, 0x9F, 0x8B, 0xAD, 0xB4, 0xA7,
+ 0x00, 0xBE, 0x00, 0xAB, 0x00, 0xE7,
+};
+
+/* SM2 C1/M0 4.8" */
+const unsigned char gamma_300cd_20[] = {
+ 0x43, 0x14, 0x45, 0xAD, 0xBE, 0xA9,
+ 0xB0, 0xC3, 0xAF, 0xC1, 0xCD, 0xC0,
+ 0x95, 0xA2, 0x91, 0xAC, 0xB5, 0xAA,
+ 0x00, 0xB0, 0x00, 0xA0, 0x00, 0xCC,
+};
+
+/* M3, DALI PANEL - Midas Universal board */
+const unsigned char gamma_300cd_2a[] = {
+ 0x4A, 0x01, 0x4D, 0xBC, 0xF1, 0xC6,
+ 0xB1, 0xD6, 0xB3, 0xC2, 0xDD, 0xC2,
+ 0x96, 0xBD, 0x96, 0xAF, 0xC9, 0xAE,
+ 0x00, 0xA5, 0x00, 0x91, 0x00, 0xC8,
+};
+
+const unsigned char gamma_300cd_29[] = {
+ 0x4A, 0x01, 0x4D, 0xBC, 0xF1, 0xC6,
+ 0xB1, 0xD6, 0xB3, 0xC2, 0xDD, 0xC2,
+ 0x96, 0xBD, 0x96, 0xAF, 0xC9, 0xAE,
+ 0x00, 0xA5, 0x00, 0x91, 0x00, 0xC8,
+};
+
+/* SM2, C1/M0 DALI Panel */
+const unsigned char gamma_300cd_8e[] = {
+ 0x71, 0x31, 0x7B, 0xA4, 0xB6, 0x95,
+ 0xA9, 0xBC, 0xA2, 0xBB, 0xC9, 0xB6,
+ 0x91, 0xA3, 0x8B, 0xAD, 0xB6, 0xA9,
+ 0x00, 0xD6, 0x00, 0xBE, 0x00, 0xFC,
+};
+
+/* SM2, C1/M0 Cellox Panel */
+const unsigned char gamma_300cd_ae[] = {
+ 0x5F, 0x2E, 0x67, 0xAA, 0xC6, 0xAC,
+ 0xB0, 0xC8, 0xBB, 0xBE, 0xCB, 0xBD,
+ 0x97, 0xA5, 0x91, 0xAF, 0xB8, 0xAB,
+ 0x00, 0xC2, 0x00, 0xBA, 0x00, 0xE2,
+};
+
+/* M0 A-Type Panel */
+const unsigned char gamma_300cd_d2[] = {
+ 0x41, 0x0A, 0x47, 0xAB, 0xBE, 0xA8,
+ 0xAF, 0xC5, 0xB7, 0xC3, 0xCC, 0xC3,
+ 0x9A, 0xA3, 0x96, 0xB1, 0xB7, 0xAF,
+ 0x00, 0xBD, 0x00, 0xAC, 0x00, 0xDE,
+};
+
+const unsigned char *gamma_300cd_list[GAMMA_300CD_MAX] = {
+ gamma_300cd_23,
+ gamma_300cd_33,
+ gamma_300cd_43,
+ gamma_300cd_53,
+ gamma_300cd_63,
+ gamma_300cd_73,
+ gamma_300cd_83,
+ gamma_300cd_20,
+ gamma_300cd_2a,
+ gamma_300cd_29,
+ gamma_300cd_4e,
+ gamma_300cd_8e,
+ gamma_300cd_ae,
+ gamma_300cd_d2,
+};
+
+const unsigned char gamma_id_list[GAMMA_300CD_MAX] = {
+ 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x20,
+ 0x2a, 0x29, 0x4e, 0x8e, 0xae, 0xd2
+};
+
+static s16 s9_to_s16(s16 v)
+{
+ return (s16)(v << 7) >> 7;
+}
+
+
+u32 calc_v1_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ u32 ret = 0;
+
+ ret = volt_table_v1[gamma] >> 10;
+
+ return ret;
+}
+
+
+u32 calc_v15_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ /* for CV : 20, DV :320 */
+ int ret = 0;
+ u32 v1, v35;
+ u32 ratio = 0;
+
+ v1 = adjust_volt[rgb_index][AD_IV1];
+ v35 = adjust_volt[rgb_index][AD_IV35];
+ ratio = volt_table_cv_20_dv_320[gamma];
+
+ ret = (v1 << 10) - ((v1-v35)*ratio);
+ ret = ret >> 10;
+
+ return ret;
+}
+
+
+u32 calc_v35_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ /* for CV : 65, DV :320 */
+ int ret = 0;
+ u32 v1, v59;
+ u32 ratio = 0;
+
+ v1 = adjust_volt[rgb_index][AD_IV1];
+ v59 = adjust_volt[rgb_index][AD_IV59];
+ ratio = volt_table_cv_65_dv_320[gamma];
+
+ ret = (v1 << 10) - ((v1-v59)*ratio);
+ ret = ret >> 10;
+
+ return ret;
+}
+
+
+u32 calc_v50_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ /* for CV : 65, DV :320 */
+ int ret = 0;
+ u32 v1, v87;
+ u32 ratio = 0;
+
+ v1 = adjust_volt[rgb_index][AD_IV1];
+ v87 = adjust_volt[rgb_index][AD_IV87];
+ ratio = volt_table_cv_65_dv_320[gamma];
+
+ ret = (v1 << 10) - ((v1-v87)*ratio);
+ ret = ret >> 10;
+
+ return ret;
+}
+
+
+u32 calc_v87_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ /* for CV : 65, DV :320 */
+ int ret = 0;
+ u32 v1, v171;
+ u32 ratio = 0;
+
+ v1 = adjust_volt[rgb_index][AD_IV1];
+ v171 = adjust_volt[rgb_index][AD_IV171];
+ ratio = volt_table_cv_65_dv_320[gamma];
+
+ ret = (v1 << 10) - ((v1-v171)*ratio);
+ ret = ret >> 10;
+
+ return ret;
+}
+
+
+u32 calc_v171_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ /* for CV : 65, DV :320 */
+ int ret = 0;
+ u32 v1, v255;
+ u32 ratio = 0;
+
+ v1 = adjust_volt[rgb_index][AD_IV1];
+ v255 = adjust_volt[rgb_index][AD_IV255];
+ ratio = volt_table_cv_65_dv_320[gamma];
+
+ ret = (v1 << 10) - ((v1-v255)*ratio);
+ ret = ret >> 10;
+
+ return ret;
+}
+
+
+u32 calc_v255_volt(s16 gamma, int rgb_index, u32 adjust_volt[CI_MAX][AD_IVMAX])
+{
+ u32 ret = 0;
+
+ ret = volt_table_v255[gamma] >> 10;
+
+ return ret;
+}
+
+
+u8 calc_voltage_table(struct str_smart_dim *smart, const u8 *mtp)
+{
+ int c, i, j;
+#if defined(MTP_REVERSE)
+ int offset1 = 0;
+#endif
+ int offset = 0;
+ s16 t1, t2;
+ s16 adjust_mtp[CI_MAX][IV_MAX];
+ /* u32 adjust_volt[CI_MAX][AD_IVMAX] = {0, }; */
+ u8 index;
+ u8 table_index = 0;
+
+ u32 v1, v2;
+ u32 ratio;
+
+ u32(*calc_volt[IV_MAX])(s16 gamma, int rgb_index,
+ u32 adjust_volt[CI_MAX][AD_IVMAX]) = {
+ calc_v1_volt,
+ calc_v15_volt,
+ calc_v35_volt,
+ calc_v50_volt,
+ calc_v87_volt,
+ calc_v171_volt,
+ calc_v255_volt,
+ };
+
+ u8 calc_seq[6] = {IV_1, IV_171, IV_87, IV_59, IV_35, IV_15};
+ u8 ad_seq[6] = {AD_IV1, AD_IV171, AD_IV87, AD_IV59, AD_IV35, AD_IV15};
+
+ memset(adjust_mtp, 0, sizeof(adjust_mtp));
+
+ for (c = CI_RED; c < CI_MAX; c++) {
+ offset = IV_255*CI_MAX+c*2;
+#if defined(MTP_REVERSE)
+ offset1 = IV_255*(c+1)+(c*2);
+ t1 = s9_to_s16(mtp[offset1]<<8|mtp[offset1+1]);
+#else
+ t1 = s9_to_s16(mtp[offset]<<8|mtp[offset+1]);
+#endif
+ t2 = s9_to_s16(smart->default_gamma[offset]<<8|
+ smart->default_gamma[offset+1]) + t1;
+ smart->mtp[c][IV_255] = t1;
+ adjust_mtp[c][IV_255] = t2;
+ smart->adjust_volt[c][AD_IV255] =
+ calc_volt[IV_255](t2, c, smart->adjust_volt);
+
+ /* for V0 All RGB Voltage Value is Reference Voltage */
+ smart->adjust_volt[c][AD_IV0] = 4600;
+ }
+
+ for (c = CI_RED; c < CI_MAX; c++) {
+ for (i = IV_1; i < IV_255; i++) {
+#if defined(MTP_REVERSE)
+ t1 = (s8)mtp[(calc_seq[i])+(c*8)];
+#else
+ t1 = (s8)mtp[CI_MAX*calc_seq[i]+c];
+#endif
+ t2 = smart->default_gamma[CI_MAX*calc_seq[i]+c] + t1;
+
+ smart->mtp[c][calc_seq[i]] = t1;
+ adjust_mtp[c][calc_seq[i]] = t2;
+ smart->adjust_volt[c][ad_seq[i]] =
+ calc_volt[calc_seq[i]](t2, c,
+ smart->adjust_volt);
+ }
+ }
+
+ for (i = 0; i < AD_IVMAX; i++) {
+ for (c = CI_RED; c < CI_MAX; c++)
+ smart->ve[table_index].v[c] = smart->adjust_volt[c][i];
+
+ index = 0;
+ for (j = table_index + 1;
+ j < table_index + range_table_count[i]; j++) {
+ for (c = CI_RED; c < CI_MAX; c++) {
+ if (smart->t_info[i].offset != NULL)
+ ratio = smart->t_info[i].offset[index]
+ * smart->t_info[i].rv;
+ else
+ ratio = (range_table_count[i] -
+ (index + 1)) *
+ smart->t_info[i].rv;
+
+ v1 = smart->adjust_volt[c][i+1] << 15;
+ v2 = (smart->adjust_volt[c][i] -
+ smart->adjust_volt[c][i+1]) * ratio;
+ smart->ve[j].v[c] = ((v1+v2) >> 15);
+ }
+ index++;
+ }
+ table_index = j;
+ }
+
+#if 0
+ for (i = IV_1; i < IV_MAX; i++) {
+ printk(KERN_INFO "V Level : %d - ", i);
+ for (c = CI_RED; c < CI_MAX; c++)
+ printk(" %c : 0x%08x(%04d)",
+ color_name[c], smart->mtp[c][i], smart->mtp[c][i]);
+ printk("\n");
+ }
+
+ for (i = IV_1; i < IV_MAX; i++) {
+ printk(KERN_INFO "V Level : %d - ", i);
+ for (c = CI_RED; c < CI_MAX; c++)
+ printk(" %c : 0x%08x(%04d)", color_name[c],
+ adjust_mtp[c][i], adjust_mtp[c][i]);
+ printk("\n");
+ }
+
+ for (i = AD_IV0; i < AD_IVMAX; i++) {
+ printk(KERN_INFO "V Level : %d - ", i);
+ for (c = CI_RED; c < CI_MAX; c++)
+ printk(" %c : %04dV",
+ color_name[c], smart->adjust_volt[c][i]);
+ printk("\n");
+ }
+
+ for (i = 0; i < 256; i++) {
+ printk(KERN_INFO "Gray Level : %03d - ", i);
+ for (c = CI_RED; c < CI_MAX; c++)
+ printk(" %c : %04dV",
+ color_name[c], smart->ve[i].v[c]);
+ printk("\n");
+ }
+#endif
+ return 0;
+}
+
+
+int init_table_info(struct str_smart_dim *smart)
+{
+ int i;
+ int offset = 0;
+
+ for (i = 0; i < IV_TABLE_MAX; i++) {
+ smart->t_info[i].count = (u8)range_table_count[i];
+ smart->t_info[i].offset = offset_table[i];
+ smart->t_info[i].rv = table_radio[i];
+ offset += range_table_count[i];
+ }
+ smart->flooktbl = flookup_table;
+ smart->g300_gra_tbl = gamma_300_gra_table;
+ smart->g22_tbl = gamma_22_table;
+
+ for (i = 0; i < GAMMA_300CD_MAX; i++) {
+ if (smart->panelid[1] == gamma_id_list[i])
+ break;
+ }
+
+ if (i >= GAMMA_300CD_MAX) {
+ printk(KERN_ERR "Can't found default gamma table\n");
+ smart->default_gamma = gamma_300cd_list[GAMMA_300CD_MAX-1];
+ } else
+ smart->default_gamma = gamma_300cd_list[i];
+
+ return 0;
+}
+
+
+u32 lookup_vtbl_idx(struct str_smart_dim *smart, u32 gamma)
+{
+ u32 lookup_index;
+ u16 table_count, table_index;
+ u32 gap, i;
+ u32 minimum = smart->g300_gra_tbl[255];
+ u32 candidate = 0;
+ u32 offset = 0;
+
+ /* printk("Input Gamma Value : %d\n", gamma); */
+
+ lookup_index = (gamma/VALUE_DIM_1000)+1;
+ if (lookup_index > MAX_GRADATION) {
+ printk(KERN_ERR "ERROR Wrong input value LOOKUP INDEX : %d\n",
+ lookup_index);
+ return 0;
+ }
+
+ /* printk("lookup index : %d\n",lookup_index); */
+
+ if (smart->flooktbl[lookup_index].count) {
+ if (smart->flooktbl[lookup_index-1].count) {
+ table_index = smart->flooktbl[lookup_index-1].entry;
+ table_count = smart->flooktbl[lookup_index].count +
+ smart->flooktbl[lookup_index-1].count;
+ } else {
+ table_index = smart->flooktbl[lookup_index].entry;
+ table_count = smart->flooktbl[lookup_index].count;
+ }
+ } else {
+ offset += 1;
+ while (!(smart->flooktbl[lookup_index + offset].count ||
+ smart->flooktbl[lookup_index - offset].count))
+ offset++;
+
+ if (smart->flooktbl[lookup_index-offset].count)
+ table_index =
+ smart->flooktbl[lookup_index - offset].entry;
+ else
+ table_index =
+ smart->flooktbl[lookup_index + offset].entry;
+ table_count = smart->flooktbl[lookup_index + offset].count +
+ smart->flooktbl[lookup_index - offset].count;
+ }
+
+
+ for (i = 0; i < table_count; i++) {
+ if (gamma > smart->g300_gra_tbl[table_index])
+ gap = gamma - smart->g300_gra_tbl[table_index];
+ else
+ gap = smart->g300_gra_tbl[table_index] - gamma;
+
+ if (gap == 0) {
+ candidate = table_index;
+ break;
+ }
+
+ if (gap < minimum) {
+ minimum = gap;
+ candidate = table_index;
+ }
+ table_index++;
+ }
+#if 0
+ printk(KERN_INFO "cal : found index : %d\n", candidate);
+ printk(KERN_INFO "gamma : %d, found index : %d found gamma : %d\n",
+ gamma, candidate, smart->g300_gra_tbl[candidate]);
+#endif
+ return candidate;
+}
+
+
+u32 calc_v1_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 ret;
+ u32 v1;
+
+ v1 = dv[ci][IV_1];
+ ret = (595 * 1000) - (130 * v1);
+ ret = ret/1000;
+
+ return ret;
+}
+
+
+u32 calc_v15_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 t1, t2;
+ u32 v1, v15, v35;
+ u32 ret;
+
+ v1 = dv[ci][IV_1];
+ v15 = dv[ci][IV_15];
+ v35 = dv[ci][IV_35];
+
+#if 0
+ t1 = (v1 - v15) * 1000;
+ t2 = v1 - v35;
+
+ ret = 320*(t1/t2)-(20*1000);
+
+ ret = ret/1000;
+#else
+ t1 = (v1 - v15) << 10;
+ t2 = (v1 - v35) ? (v1 - v35) : (v1) ? v1 : 1;
+ ret = (320 * (t1/t2)) - (20 << 10);
+ ret >>= 10;
+
+#endif
+ return ret;
+}
+
+
+u32 calc_v35_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 t1, t2;
+ u32 v1, v35, v57;
+ u32 ret;
+
+ v1 = dv[ci][IV_1];
+ v35 = dv[ci][IV_35];
+ v57 = dv[ci][IV_59];
+
+#if 0
+ t1 = (v1 - v35) * 1000;
+ t2 = v1 - v57;
+ ret = 320*(t1/t2) - (65 * 1000);
+
+ ret = ret/1000;
+#else
+ t1 = (v1 - v35) << 10;
+ t2 = (v1 - v57) ? (v1 - v57) : (v1) ? v1 : 1;
+ ret = (320 * (t1/t2)) - (65 << 10);
+
+ ret >>= 10;
+#endif
+
+ return ret;
+}
+
+
+u32 calc_v50_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 t1, t2;
+ u32 v1, v57, v87;
+ u32 ret;
+
+ v1 = dv[ci][IV_1];
+ v57 = dv[ci][IV_59];
+ v87 = dv[ci][IV_87];
+
+#if 0
+ t1 = (v1 - v57) * 1000;
+ t2 = v1 - v87;
+ ret = 320*(t1/t2) - (65 * 1000);
+ ret = ret/1000;
+#else
+ t1 = (v1 - v57) << 10;
+ t2 = (v1 - v87) ? (v1 - v87) : (v1) ? v1 : 1;
+ ret = (320 * (t1/t2)) - (65 << 10);
+ ret >>= 10;
+#endif
+ return ret;
+}
+
+
+u32 calc_v87_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 t1, t2;
+ u32 v1, v87, v171;
+ u32 ret;
+
+ v1 = dv[ci][IV_1];
+ v87 = dv[ci][IV_87];
+ v171 = dv[ci][IV_171];
+
+#if 0
+ t1 = (v1 - v87) * 1000;
+ t2 = v1 - v171;
+ ret = 320*(t1/t2) - (65 * 1000);
+ ret = ret/1000;
+#else
+ t1 = (v1 - v87) << 10;
+ t2 = (v1 - v171) ? (v1 - v171) : (v1) ? v1 : 1;
+ ret = (320 * (t1/t2)) - (65 << 10);
+ ret >>= 10;
+#endif
+
+ return ret;
+}
+
+
+u32 calc_v171_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 t1, t2;
+ u32 v1, v171, v255;
+ u32 ret;
+
+ v1 = dv[ci][IV_1];
+ v171 = dv[ci][IV_171];
+ v255 = dv[ci][IV_255];
+
+#if 0
+ t1 = (v1 - v171) * 1000;
+ t2 = v1 - v255;
+ ret = 320*(t1/t2) - (65 * 1000);
+ ret = ret/1000;
+#else
+ t1 = (v1 - v171) << 10;
+ t2 = (v1 - v255) ? (v1 - v255) : (v1) ? v1 : 1;
+ ret = (320 * (t1/t2)) - (65 << 10);
+ ret >>= 10;
+#endif
+
+ return ret;
+}
+
+
+u32 calc_v255_reg(int ci, u32 dv[CI_MAX][IV_MAX])
+{
+ u32 ret;
+ u32 v255;
+
+ v255 = dv[ci][IV_255];
+
+ ret = (500 * 1000) - (130 * v255);
+ ret = ret / 1000;
+
+ return ret;
+}
+
+
+u32 calc_gamma_table(struct str_smart_dim *smart, u32 gv, u8 result[])
+{
+ u32 i, c;
+ u32 temp;
+ u32 lidx;
+ u32 dv[CI_MAX][IV_MAX];
+ s16 gamma[CI_MAX][IV_MAX];
+ u16 offset;
+ u32(*calc_reg[IV_MAX])(int ci, u32 dv[CI_MAX][IV_MAX]) = {
+ calc_v1_reg,
+ calc_v15_reg,
+ calc_v35_reg,
+ calc_v50_reg,
+ calc_v87_reg,
+ calc_v171_reg,
+ calc_v255_reg,
+ };
+
+ memset(gamma, 0, sizeof(gamma));
+
+ for (c = CI_RED; c < CI_MAX; c++)
+ dv[c][0] = smart->adjust_volt[c][AD_IV1];
+
+
+ for (i = IV_15; i < IV_MAX; i++) {
+ temp = smart->g22_tbl[dv_value[i]] * gv;
+ lidx = lookup_vtbl_idx(smart, temp);
+ for (c = CI_RED; c < CI_MAX; c++)
+ dv[c][i] = smart->ve[lidx].v[c];
+ }
+
+ /* for IV1 does not calculate value */
+ /* just use default gamma value (IV1) */
+ for (c = CI_RED; c < CI_MAX; c++)
+ gamma[c][IV_1] = smart->default_gamma[c];
+
+ for (i = IV_15; i < IV_MAX; i++) {
+ for (c = CI_RED; c < CI_MAX; c++)
+ gamma[c][i] =
+ (s16)calc_reg[i](c, dv) - smart->mtp[c][i];
+ }
+
+ for (c = CI_RED; c < CI_MAX; c++) {
+ offset = IV_255*CI_MAX+c*2;
+ result[offset+1] = gamma[c][IV_255];
+ }
+
+ for (c = CI_RED; c < CI_MAX; c++) {
+ for (i = IV_1; i < IV_255; i++)
+ result[(CI_MAX*i)+c] = gamma[c][i];
+ }
+
+#if 0
+ for (i = IV_1; i < IV_MAX; i++) {
+ printk(KERN_INFO "V Level : %d - ", i);
+ for (c = CI_RED; c < CI_MAX; c++)
+ printk("%c : %04dV", color_name[c], dv[c][i]);
+ printk("\n");
+ }
+
+ for (i = IV_1; i < IV_MAX; i++) {
+ printk(KERN_INFO "V Level : %d - ", i);
+ for (c = CI_RED; c < CI_MAX; c++)
+ printk("%c : %3d, 0x%2x",
+ color_name[c], gamma[c][i], gamma[c][i]);
+ printk("\n");
+ }
+#endif
+ return 0;
+}
+
diff --git a/drivers/video/backlight/smart_dimming.h b/drivers/video/backlight/smart_dimming.h
new file mode 100644
index 0000000..ae21182
--- /dev/null
+++ b/drivers/video/backlight/smart_dimming.h
@@ -0,0 +1,104 @@
+/* linux/drivers/video/samsung/smartdimming.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+
+ * Samsung Smart Dimming for OCTA
+ *
+ * Minwoo Kim, <minwoo7945.kim@samsung.com>
+ *
+*/
+
+
+#ifndef __SMART_DIMMING_H__
+#define __SMART_DIMMING_H__
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/ctype.h>
+
+#define MAX_GRADATION 300
+#define PANEL_ID_MAX 3
+#define GAMMA_300CD_MAX 14
+
+
+enum {
+ CI_RED,
+ CI_GREEN,
+ CI_BLUE,
+ CI_MAX,
+};
+
+
+enum {
+ IV_1,
+ IV_15,
+ IV_35,
+ IV_59,
+ IV_87,
+ IV_171,
+ IV_255,
+ IV_MAX,
+ IV_TABLE_MAX,
+};
+
+
+enum {
+ AD_IV0,
+ AD_IV1,
+ AD_IV15,
+ AD_IV35,
+ AD_IV59,
+ AD_IV87,
+ AD_IV171,
+ AD_IV255,
+ AD_IVMAX,
+};
+
+
+struct str_voltage_entry {
+ u32 v[CI_MAX];
+};
+
+
+struct str_table_info {
+ /* et : start gray value */
+ u8 st;
+ /* end gray value, st + count */
+ u8 et;
+ u8 count;
+ const u8 *offset;
+ /* rv : ratio value */
+ u32 rv;
+};
+
+
+struct str_flookup_table {
+ u16 entry;
+ u16 count;
+};
+
+
+struct str_smart_dim {
+ u8 panelid[PANEL_ID_MAX];
+ s16 mtp[CI_MAX][IV_MAX];
+ struct str_voltage_entry ve[256];
+ const u8 *default_gamma;
+ struct str_table_info t_info[IV_TABLE_MAX];
+ const struct str_flookup_table *flooktbl;
+ const u32 *g22_tbl;
+ const u32 *g300_gra_tbl;
+ u32 adjust_volt[CI_MAX][AD_IVMAX];
+};
+
+
+int init_table_info(struct str_smart_dim *smart);
+u8 calc_voltage_table(struct str_smart_dim *smart, const u8 *mtp);
+u32 calc_gamma_table(struct str_smart_dim *smart, u32 gv, u8 result[]);
+
+
+#endif
diff --git a/drivers/video/backlight/tc358764_mipi_lcd.c b/drivers/video/backlight/tc358764_mipi_lcd.c
new file mode 100644
index 0000000..0563c85
--- /dev/null
+++ b/drivers/video/backlight/tc358764_mipi_lcd.c
@@ -0,0 +1,110 @@
+/* linux/drivers/video/backlight/tc358764_mipi_lcd.c
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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/delay.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+#include <plat/cpu.h>
+
+unsigned char initcode_013c[6] = {0x3c, 0x01, 0x03, 0x00, 0x02, 0x00};
+unsigned char initcode_0114[6] = {0x14, 0x01, 0x02, 0x00, 0x00, 0x00};
+unsigned char initcode_0164[6] = {0x64, 0x01, 0x05, 0x00, 0x00, 0x00};
+unsigned char initcode_0168[6] = {0x68, 0x01, 0x05, 0x00, 0x00, 0x00};
+unsigned char initcode_016c[6] = {0x6c, 0x01, 0x05, 0x00, 0x00, 0x00};
+unsigned char initcode_0170[6] = {0x70, 0x01, 0x05, 0x00, 0x00, 0x00};
+unsigned char initcode_0134[6] = {0x34, 0x01, 0x1f, 0x00, 0x00, 0x00};
+unsigned char initcode_0210[6] = {0x10, 0x02, 0x1f, 0x00, 0x00, 0x00};
+unsigned char initcode_0104[6] = {0x04, 0x01, 0x01, 0x00, 0x00, 0x00};
+unsigned char initcode_0204[6] = {0x04, 0x02, 0x01, 0x00, 0x00, 0x00};
+unsigned char initcode_0450[6] = {0x50, 0x04, 0x20, 0x01, 0xfa, 0x00};
+unsigned char initcode_0454[6] = {0x54, 0x04, 0x20, 0x00, 0x50, 0x00};
+unsigned char initcode_0458[6] = {0x58, 0x04, 0x00, 0x05, 0x30, 0x00};
+unsigned char initcode_045c[6] = {0x5c, 0x04, 0x05, 0x00, 0x0a, 0x00};
+unsigned char initcode_0460[6] = {0x60, 0x04, 0x20, 0x03, 0x0a, 0x00};
+unsigned char initcode_0464[6] = {0x64, 0x04, 0x01, 0x00, 0x00, 0x00};
+unsigned char initcode_04a0_1[6] = {0xa0, 0x04, 0x06, 0x80, 0x44, 0x00};
+unsigned char initcode_04a0_2[6] = {0xa0, 0x04, 0x06, 0x80, 0x04, 0x00};
+unsigned char initcode_0504[6] = {0x04, 0x05, 0x04, 0x00, 0x00, 0x00};
+unsigned char initcode_049c[6] = {0x9c, 0x04, 0x0d, 0x00, 0x00, 0x00};
+
+unsigned int *initcode[20] = {
+ (unsigned int *)initcode_013c,
+ (unsigned int *)initcode_0114,
+ (unsigned int *)initcode_0164,
+ (unsigned int *)initcode_0168,
+ (unsigned int *)initcode_016c,
+ (unsigned int *)initcode_0170,
+ (unsigned int *)initcode_0134,
+ (unsigned int *)initcode_0210,
+ (unsigned int *)initcode_0104,
+ (unsigned int *)initcode_0204,
+ (unsigned int *)initcode_0450,
+ (unsigned int *)initcode_0454,
+ (unsigned int *)initcode_0458,
+ (unsigned int *)initcode_045c,
+ (unsigned int *)initcode_0460,
+ (unsigned int *)initcode_0464,
+ (unsigned int *)initcode_04a0_1,
+ (unsigned int *)initcode_04a0_2,
+ (unsigned int *)initcode_0504,
+ (unsigned int *)initcode_049c
+};
+
+static int init_lcd(struct mipi_dsim_device *dsim)
+{
+ int i;
+
+ if (soc_is_exynos5250() && samsung_rev() >= EXYNOS5250_REV_1_0) {
+ for (i = 0; i <= 19; i++) {
+ s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int)initcode[i], 6);
+ usleep_range(6000, 7000);
+ }
+ } else {
+ for (i = 0; i <= 19; i++) {
+ if (s5p_mipi_dsi_wr_data(dsim,
+ MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int)initcode[i], 6) == -1)
+ return 0;
+ usleep_range(6000, 7000);
+ }
+ }
+
+ msleep(800);
+
+ return 1;
+}
+
+static int tc358764_mipi_lcd_suspend(struct mipi_dsim_device *dsim)
+{
+ return 0;
+}
+
+static int tc358764_mipi_lcd_displayon(struct mipi_dsim_device *dsim)
+{
+ return init_lcd(dsim);
+}
+
+static int tc358764_mipi_lcd_resume(struct mipi_dsim_device *dsim)
+{
+ return init_lcd(dsim);
+}
+
+struct mipi_dsim_lcd_driver tc358764_mipi_lcd_driver = {
+ .suspend = tc358764_mipi_lcd_suspend,
+ .displayon = tc358764_mipi_lcd_displayon,
+ .resume = tc358764_mipi_lcd_resume,
+};