fbdev: dpu20: sync-up dpu panel code
authorChiHun Won <chihun.won@samsung.com>
Wed, 4 Jul 2018 06:14:41 +0000 (15:14 +0900)
committerWooyeon Kim <wooy88.kim@samsung.com>
Fri, 6 Jul 2018 01:43:20 +0000 (10:43 +0900)
Change-Id: Ide0732f669b599411308056a795220fd7b4716a6
Signed-off-by: ChiHun Won <chihun.won@samsung.com>
drivers/video/fbdev/exynos/dpu20/dsim.h
drivers/video/fbdev/exynos/dpu20/dsim_drv.c
drivers/video/fbdev/exynos/dpu20/panels/Kconfig
drivers/video/fbdev/exynos/dpu20/panels/Makefile
drivers/video/fbdev/exynos/dpu20/panels/s6e3fa7_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3fa7_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_param.h

index e456974b9270e70f27a12edd3847de5f2929f4a2..481ae72add38aaa3df27419b2e23fbf5d96a7a00 100644 (file)
@@ -92,6 +92,7 @@ extern struct dsim_lcd_driver s6e3ha6_mipi_lcd_driver;
 extern struct dsim_lcd_driver s6e3ha8_mipi_lcd_driver;
 extern struct dsim_lcd_driver s6e3aa2_mipi_lcd_driver;
 extern struct dsim_lcd_driver s6e3fa0_mipi_lcd_driver;
+extern struct dsim_lcd_driver s6e3fa7_mipi_lcd_driver;
 
 /* define video timer interrupt */
 enum {
index 0f2b46f0ababc5ec0ef1fbe3f0806e4275222ab3..db0f8f477fa8572a85c1538dcdfceecf6c6b4dd4 100644 (file)
@@ -1470,6 +1470,8 @@ static void dsim_register_panel(struct dsim_device *dsim)
        dsim->panel_ops = &s6e3aa2_mipi_lcd_driver;
 #elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3FA0)
        dsim->panel_ops = &s6e3fa0_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3FA7)
+       dsim->panel_ops = &s6e3fa7_mipi_lcd_driver;
 #elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_EMUL_DISP)
        dsim->panel_ops = &emul_disp_mipi_lcd_driver;
 #else
index c083ae5576cf8d4374cdf7f4bcf56660ef161be1..df2a3383b27761f4a787793be54f4d70cfaf1f13 100644 (file)
@@ -31,6 +31,11 @@ config EXYNOS_DECON_LCD_S6E3FA0
        tristate "S6E3FA0 AMOLED HD LCD driver(1080 x 1920)"
        default n
 
+config EXYNOS_DECON_LCD_S6E3FA7
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "S6E3FA7 AMOLED FHD LCD driver(1080 x 2220)"
+       default n
+
 config EXYNOS_DECON_LCD_EMUL_DISP
        depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
        tristate "Virtual LCD driver for emulator(800 x 1280)"
index d22f4b052ec079687da785fdf5cbe935d9d398df..9774c668ac303a27bf40e57cd2f02d56ca04e384 100644 (file)
@@ -4,4 +4,5 @@ obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA6)  += s6e3ha6_mipi_lcd.o s6e3ha6_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA8) += s6e3ha8_mipi_lcd.o s6e3ha8_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3AA2) += s6e3aa2_mipi_lcd.o s6e3aa2_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3FA0) += s6e3fa0_mipi_lcd.o s6e3fa0_lcd_ctrl.o
+obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3FA7) += s6e3fa7_mipi_lcd.o s6e3fa7_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_EMUL_DISP) += emul_disp_mipi_lcd.o emul_disp_lcd_ctrl.o
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3fa7_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3fa7_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..d8cb6b2
--- /dev/null
@@ -0,0 +1,323 @@
+/* drivers/video/exynos/panels/s6e3fa7_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * Jiun Yu, <jiun.yu@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 "lcd_ctrl.h"
+
+#include "../dsim.h"
+#include <video/mipi_display.h>
+
+#define EXTEND_BRIGHTNESS      365
+#define UI_MAX_BRIGHTNESS      255
+#define UI_MIN_BRIGHTNESS      0
+#define UI_DEFAULT_BRIGHTNESS  128
+#define NORMAL_TEMPERATURE     25      /* 25 degrees Celsius */
+
+#define GAMMA_CMD_CNT                          ((u16)ARRAY_SIZE(SEQ_GAMMA_CONDITION_SET))
+#define ACL_CMD_CNT                            ((u16)ARRAY_SIZE(SEQ_ACL_OFF))
+#define OPR_CMD_CNT                            ((u16)ARRAY_SIZE(SEQ_ACL_OPR_OFF))
+#define ELVSS_CMD_CNT                          ((u16)ARRAY_SIZE(SEQ_ELVSS_SET))
+#define AID_CMD_CNT                            ((u16)ARRAY_SIZE(SEQ_AID_SETTING))
+#define IRC_CMD_CNT                            ((u16)ARRAY_SIZE(SEQ_IRC_SETTING))
+
+#define LDI_REG_ELVSS                          0xB5
+#define LDI_REG_COORDINATE                     0xA1
+#define LDI_REG_DATE                           LDI_REG_MTP
+#define LDI_REG_ID                             0x04
+#define LDI_REG_CHIP_ID                                0xD6
+#define LDI_REG_MTP                            0xC8
+#define LDI_REG_HBM                            0xB3
+#define LDI_REG_MANUFACTURE_INFO               0xC9
+#define LDI_REG_IRC                            0xB8
+#define LDI_REG_RDDPM                          0x0A
+#define LDI_REG_RDDSM                          0x0E
+#define LDI_REG_ESDERR                         0xEE
+
+/* len is read length */
+#define LDI_LEN_ELVSS                          (ELVSS_CMD_CNT - 1)
+#define LDI_LEN_COORDINATE                     4
+#define LDI_LEN_DATE                           7
+#define LDI_LEN_ID                             3
+#define LDI_LEN_CHIP_ID                                5
+#define LDI_LEN_MTP                            32
+#define LDI_LEN_HBM                            34
+#define LDI_LEN_MANUFACTURE_INFO               21
+#define LDI_LEN_IRC                            (IRC_CMD_CNT - 1)
+#define LDI_LEN_RDDPM                          1
+#define LDI_LEN_RDDSM                          1
+#define LDI_LEN_ESDERR                         1
+
+/* offset is position including addr, not only para */
+#define LDI_OFFSET_AOR_1       1
+#define LDI_OFFSET_AOR_2       2
+
+#define LDI_OFFSET_ELVSS_1     1       /* B5h 1st Para: TSET */
+#define LDI_OFFSET_ELVSS_2     2       /* B5h 2nd Para: MPS_CON */
+#define LDI_OFFSET_ELVSS_3     3       /* B5h 3rd Para: ELVSS_Dim_offset */
+#define LDI_OFFSET_ELVSS_4     23      /* B5h 23th Para: ELVSS_Cal_Offset */
+
+#define LDI_OFFSET_OPR_1       1       /* B4h 1st Para: 16 Frame Avg at ACL Off (HBM OPR Cal mode) */
+#define LDI_OFFSET_OPR_2       5       /* B4h 5th Para: ACL Percent */
+#define LDI_OFFSET_OPR_3       13      /* B4h 13th Para: 16 Frame Avg at ACL Off (Normal OPR Cal mode) */
+
+#define LDI_OFFSET_ACL         1
+
+#define LDI_GPARA_DATE         40      /* C8h 41th Para: Manufacture Year, Month */
+#define LDI_GPARA_HBM_ELVSS    23      /* B5h 24th Para: ELVSS_Cal_Offset for HBM */
+
+/*
+ * 3FA7 lcd init sequence
+ *
+ * Parameters
+ *     - mic : if mic is enabled, MIC_ENABLE command must be sent
+ *     - mode : LCD init sequence depends on command or video mode
+ */
+
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
+       0xF0,
+       0x5A, 0x5A
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_FC[] = {
+       0xFC,
+       0x5A, 0x5A
+};
+
+static const unsigned char SEQ_PCD_SET_DET_LOW[] = {
+       0xCC,
+       0x5C
+};
+
+static const unsigned char SEQ_ERR_FG_SETTING[] = {
+       0xED,
+       0x44
+};
+
+static const unsigned char SEQ_GAMMA_CONDITION_SET[] = {
+       0xCA,
+       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+};
+
+static const unsigned char SEQ_AID_SETTING[] = {
+       0xB1,
+       0x00, 0x10
+};
+
+static const unsigned char SEQ_ELVSS_SET[] = {
+       0xB5,
+       0x19,   /* B5h 1st Para: TSET */
+       0xDC,   /* B5h 2nd Para: MPS_CON */
+       0x04,   /* B5h 3rd Para: ELVSS_Dim_offset */
+       0x01, 0x34, 0x67, 0x9A, 0xCD, 0x01, 0x22,
+       0x33, 0x44, 0xC0, 0x00, 0x09, 0x99, 0x33, 0x13, 0x01, 0x11,
+       0x10, 0x00,
+       0x00,   /* RESERVED: B5h 23th Para: ELVSS_Cal_Offset */
+       0x00    /* RESERVED: B5h 24th Para: ELVSS_Cal_Offset for HBM */
+};
+
+static const unsigned char SEQ_GAMMA_UPDATE[] = {
+       0xF7,
+       0x03
+};
+
+static const unsigned char SEQ_ACL_OPR_OFF[] = {
+       0xB4,
+       0x40,   /* B4h 1st Para: Para : 0x40 = 16 Frame Avg at ACL Off (HBM OPR Cal mode) */
+       0x40, 0xFC, 0x48,
+       0x48,   /* B4h 5th Para: 0x48 = ACL 15% */
+       0x9C, 0x55, 0x55, 0x55, 0x3F,
+       0xB7, 0x12,
+       0x40    /* B4h 13th Para: 0x40 = 16 Frame Avg at ACL Off (Normal OPR Cal mode) */
+};
+
+static const unsigned char SEQ_ACL_OFF[] = {
+       0x55,
+       0x00    /* 0x00 : ACL OFF */
+};
+
+static const unsigned char SEQ_IRC_SETTING[] = {
+       0xB8,
+       0x40, 0x20, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+       0x61, 0x3D, 0x46, 0x6F, 0xE3, 0x33, 0x69, 0x12, 0x7A, 0x8C,
+       0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
+       0xF0,
+       0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_FC[] = {
+       0xFC,
+       0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TE_ON[] = {
+       0x35,
+       0x00
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29
+};
+
+static int dsi_write(u32 id, const unsigned char *wbuf, int size)
+{
+       int ret = 0;
+
+       if (size == 1)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, wbuf[0], 0);
+       else
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)wbuf, size);
+
+       mdelay(12);
+
+       return ret;
+}
+
+#if 0
+static int dsi_read(u32 id, const u8 addr, u16 len, u8 *buf)
+{
+       int ret = 0;
+
+       ret = dsim_rd_data(id, MIPI_DSI_DCS_READ, addr, len, buf);
+
+       return ret;
+}
+#endif
+static int s6e3fa7_read_id(u32 id)
+{
+#if 0
+       int i, ret, retry_cnt = 1;
+       u8 buf[LDI_LEN_ID];
+
+       for (i = 0; i < LDI_LEN_ID; i++)
+               buf[i] = 0;
+retry:
+       ret = dsi_read(id, LDI_REG_ID, LDI_LEN_ID, (u8 *)buf);
+       if (ret <= 0) {
+               if (retry_cnt) {
+                       dsim_err("%s: retry: %d\n", __func__, retry_cnt);
+                       retry_cnt--;
+                       goto retry;
+               } else
+                       dsim_err("%s: 0x%02x\n", __func__, LDI_REG_ID);
+               return 0;
+       }
+
+       for (i = 0; i < LDI_LEN_ID; i++)
+               dsim_dbg("%x, ", buf[i]);
+       dsim_dbg("\n");
+
+       return ret;
+#else
+       return 1;
+#endif
+}
+
+void lcd_init(int id, struct decon_lcd *lcd)
+{
+       dsim_dbg("%s +\n", __func__);
+
+       /* 7. Sleep Out(11h) */
+       if (dsi_write(id, SEQ_SLEEP_OUT, ARRAY_SIZE(SEQ_SLEEP_OUT)) < 0)
+               dsim_err("fail to send SEQ_SLEEP_OUT command.\n");
+
+       /* 8. Wait 20ms */
+       msleep(20);
+
+       /* 9. ID READ */
+       s6e3fa7_read_id(id);
+
+       /* Test Key Enable */
+       if (dsi_write(id, SEQ_TEST_KEY_ON_F0, ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
+               dsim_err("fail to send SEQ_TEST_KEY_ON_F0 command.\n");
+
+       /* 10. Common Setting */
+       /* 4.1.2 PCD Setting */
+       if (dsi_write(id, SEQ_PCD_SET_DET_LOW, ARRAY_SIZE(SEQ_PCD_SET_DET_LOW)) < 0)
+               dsim_err("fail to send SEQ_PCD_SET_DET_LOW command.\n");
+       /* 4.1.3 ERR_FG Setting */
+       if (dsi_write(id, SEQ_ERR_FG_SETTING, ARRAY_SIZE(SEQ_ERR_FG_SETTING)) < 0)
+               dsim_err("fail to send SEQ_ERR_FG_SETTING command.\n");
+
+       /* 11. Brightness control */
+       if (dsi_write(id, SEQ_GAMMA_CONDITION_SET, ARRAY_SIZE(SEQ_GAMMA_CONDITION_SET)) < 0)
+               dsim_err("fail to send SEQ_GAMMA_CONDITION_SET command.\n");
+       if (dsi_write(id, SEQ_AID_SETTING, ARRAY_SIZE(SEQ_AID_SETTING)) < 0)
+               dsim_err("fail to send SEQ_AID_SETTING command.\n");
+       if (dsi_write(id, SEQ_ELVSS_SET, ARRAY_SIZE(SEQ_ELVSS_SET)) < 0)
+               dsim_err("fail to send SEQ_ELVSS_SET command.\n");
+
+       /* 4.2.4 ACL ON/OFF */
+       if (dsi_write(id, SEQ_ACL_OPR_OFF, ARRAY_SIZE(SEQ_ACL_OPR_OFF)) < 0)
+               dsim_err("fail to send SEQ_ACL_OPR_OFF command.\n");
+       if (dsi_write(id, SEQ_ACL_OFF, ARRAY_SIZE(SEQ_ACL_OFF)) < 0)
+               dsim_err("fail to send SEQ_ACL_OFF command.\n");
+       if (dsi_write(id, SEQ_IRC_SETTING, ARRAY_SIZE(SEQ_IRC_SETTING)) < 0)
+               dsim_err("fail to send SEQ_IRC_SETTING command.\n");
+
+       if (dsi_write(id, SEQ_GAMMA_UPDATE, ARRAY_SIZE(SEQ_GAMMA_UPDATE)) < 0)
+               dsim_err("fail to send SEQ_GAMMA_UPDATE command.\n");
+
+       /* Test Key Disable */
+       if (dsi_write(id, SEQ_TEST_KEY_OFF_F0, ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0)
+               dsim_err("fail to send SEQ_TEST_KEY_OFF_F0 command.\n");
+
+       /* 4.1.1 TE(Vsync) ON/OFF */
+       if (dsi_write(id, SEQ_TE_ON, ARRAY_SIZE(SEQ_TE_ON)) < 0)
+               dsim_err("fail to send SEQ_TE_ON command.\n");
+
+       /* 12. Wait 80ms */
+       msleep(80);
+
+       dsim_dbg("%s -\n", __func__);
+}
+
+void lcd_enable(int id)
+{
+       dsim_dbg("%s +\n", __func__);
+
+       /* 16. Display On(29h) */
+       if (dsi_write(id, SEQ_DISPLAY_ON, ARRAY_SIZE(SEQ_DISPLAY_ON)) < 0)
+               dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
+
+       dsim_dbg("%s -\n", __func__);
+}
+
+void lcd_disable(int id)
+{
+       /* This function needs to implement */
+}
+
+/*
+ * Set gamma values
+ *
+ * Parameter
+ *     - backlightlevel : It is from 0 to 26.
+ */
+int lcd_gamma_ctrl(int id, u32 backlightlevel)
+{
+       return 0;
+}
+
+int lcd_gamma_update(int id)
+{
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3fa7_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3fa7_mipi_lcd.c
new file mode 100644 (file)
index 0000000..28bb160
--- /dev/null
@@ -0,0 +1,374 @@
+/* drivers/video/exynos/panels/s6e3fa0_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * Haowei Li, <haowei.li@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/delay.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+#include "../dsim.h"
+
+#define MAX_VOLTAGE_PULSE      0x04
+#define MAX_BRIGHTNESS         255
+/* set the minimum brightness value to see the screen */
+#define MIN_BRIGHTNESS         0
+#define DEFAULT_BRIGHTNESS     98
+
+#define PANEL_STATE_SUSPENED   0
+#define PANEL_STATE_RESUMED    1
+#define PANEL_STATE_SUSPENDING 2
+
+struct panel_private {
+       unsigned int lcd_connected;
+       void *par;
+};
+
+struct lcd_info {
+       unsigned int    connected;
+       unsigned int    state;
+       struct dsim_device      *dsim;
+       struct mutex    lock;
+       struct notifier_block   fb_notifier;
+};
+
+struct panel_private panel_priv;
+
+static BLOCKING_NOTIFIER_HEAD(decon_notifier_list);
+
+int decon_register_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&decon_notifier_list, nb);
+}
+
+int decon_unregister_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&decon_notifier_list, nb);
+}
+
+int decon_notifier_call_chain(unsigned long val, void *v)
+{
+       return blocking_notifier_call_chain(&decon_notifier_list, val, v);
+}
+static int decon_notifier_event(struct notifier_block *this,
+       unsigned long val, void *v)
+{
+       if (decon_notifier_list.head == NULL)
+               return NOTIFY_DONE;
+
+       switch (val) {
+       case FB_EVENT_BLANK:
+       case FB_EARLY_EVENT_BLANK:
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+
+       /*pr_info("lcd panel: %s: %02lx\n", __func__, val);*/
+
+       decon_notifier_call_chain(val, v);
+
+       return NOTIFY_DONE;
+}
+
+static int s6e3fa7_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int update_brightness(struct dsim_device *dsim, int brightness)
+{
+       #if 0
+       int vol_pulse;
+       int id = dsim->id;
+       unsigned char gamma_update[3];
+       unsigned char aor_control[12];
+
+       if (dsim->state != DSIM_STATE_HSCLKEN) {
+               return 0;
+       }
+
+       memcpy(gamma_update, SEQ_GAMMA_UPDATE, 3);
+       memcpy(aor_control, SEQ_AOR_CONTROL, 12);
+
+       /*
+        * In order to change brightness to be set to one of values in the
+        * gamma_control parameter. Brightness value(real_br) from 0 to 255.
+        * This value is controlled by the control bar.
+        */
+       if (brightness > 100)
+               vol_pulse = MAX_VOLTAGE_PULSE + ((255 - brightness) * 10);
+       else
+               vol_pulse = MAX_VOLTAGE_PULSE + 0x604 + ((101 - brightness) * 4);
+
+       aor_control[2] = aor_control[4] = 0xFF & vol_pulse;
+       aor_control[1] = aor_control[3] = ((0xF00 & vol_pulse) >> 8);
+
+       /* It updates the changed brightness value to ddi */
+       gamma_update[1] = 0x00;
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)aor_control,
+                               ARRAY_SIZE(aor_control)) < 0)
+               dsim_err("fail to send aor_control command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_GAMMA_UPDATE,
+                               ARRAY_SIZE(SEQ_GAMMA_UPDATE)) < 0)
+               dsim_err("fail to send SEQ_GAMMA_UPDATE command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)gamma_update,
+                               ARRAY_SIZE(gamma_update)) < 0)
+               dsim_err("fail to send gamma_update command.\n");
+       #endif
+
+       return 0;
+}
+
+static int s6e3fa7_set_brightness(struct backlight_device *bd)
+{
+       struct dsim_device *dsim;
+       struct v4l2_subdev *sd;
+       int brightness = bd->props.brightness;
+
+       sd = dev_get_drvdata(bd->dev.parent);
+       dsim = container_of(sd, struct dsim_device, sd);
+
+       if (brightness == 146 || brightness == 226)
+               return 1;
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               printk(KERN_ALERT "Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+
+       update_brightness(dsim, brightness);
+
+       return 1;
+}
+
+static const struct backlight_ops s6e3fa7_backlight_ops = {
+       .get_brightness = s6e3fa7_get_brightness,
+       .update_status = s6e3fa7_set_brightness,
+};
+
+static int s6e3fa7_probe(struct dsim_device *dsim)
+{
+       int ret = 0;
+       struct lcd_info *lcd = panel_priv.par;
+       struct panel_private *priv = &panel_priv;
+
+       priv->lcd_connected = lcd->connected = 1;
+
+       lcd->dsim = dsim;
+       lcd->state = PANEL_STATE_SUSPENED;
+
+       dsim->bd = backlight_device_register("panel", dsim->dev,
+               NULL, &s6e3fa7_backlight_ops, NULL);
+       if (IS_ERR(dsim->bd))
+               printk(KERN_ALERT "failed to register backlight device!\n");
+
+       dsim->bd->props.max_brightness = MAX_BRIGHTNESS;
+       dsim->bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       dsim_info("lcd panel: %s: done\n", __func__);
+
+       return ret;
+}
+
+static int s6e3fa7_init(struct lcd_info *lcd)
+{
+       int ret = 0;
+       struct dsim_device *dsim = lcd->dsim;
+
+       dsim_info("lcd panel: %s\n", __func__);
+
+       lcd_init(dsim->id, &dsim->lcd_info);
+
+       return ret;
+}
+
+static int s6e3fa7_displayon(struct lcd_info *lcd)
+{
+       int ret = 0;
+       struct dsim_device *dsim = lcd->dsim;
+
+       dsim_info("lcd panel: %s\n", __func__);
+
+       lcd_enable(dsim->id);
+
+       return ret;
+}
+
+static int s6e3fa7_suspend(struct lcd_info *lcd)
+{
+       return 0;
+}
+
+static int fb_notifier_callback(struct notifier_block *self,
+                       unsigned long event, void *data)
+{
+       struct fb_event *evdata = data;
+       struct lcd_info *lcd = NULL;
+       int fb_blank;
+
+       switch (event) {
+       case FB_EVENT_BLANK:
+       case FB_EARLY_EVENT_BLANK:
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+
+       lcd = container_of(self, struct lcd_info, fb_notifier);
+
+       fb_blank = *(int *)evdata->data;
+
+       dsim_info("lcd panel: %s: %02lx, %d\n", __func__, event, fb_blank);
+
+       if (evdata->info->node != 0)
+               return NOTIFY_DONE;
+
+       if (event == FB_EVENT_BLANK && fb_blank == FB_BLANK_UNBLANK)
+               s6e3fa7_displayon(lcd);
+
+       return NOTIFY_DONE;
+}
+
+static int s6e3fa7_register_notifier(struct lcd_info *lcd)
+{
+       int ret = 0;
+
+       lcd->fb_notifier.notifier_call = fb_notifier_callback;
+       decon_register_notifier(&lcd->fb_notifier);
+
+       return ret;
+}
+
+static int dsim_panel_probe(struct dsim_device *dsim)
+{
+       int ret = 0;
+       struct lcd_info *lcd;
+
+       panel_priv.par = lcd = kzalloc(sizeof(struct lcd_info), GFP_KERNEL);
+       if (!lcd) {
+               pr_err("%s: failed to allocate for lcd\n", __func__);
+               ret = -ENOMEM;
+               goto probe_err;
+       }
+
+       mutex_init(&lcd->lock);
+
+       ret = s6e3fa7_probe(dsim);
+       if (ret < 0) {
+               pr_err("%s: failed to probe panel\n", __func__);
+               goto probe_err;
+       }
+
+       s6e3fa7_register_notifier(lcd);
+
+       dsim_info("lcd panel: %s: %s: done\n", kbasename(__FILE__), __func__);
+probe_err:
+       return ret;
+}
+
+static int dsim_panel_displayon(struct dsim_device *dsim)
+{
+       struct lcd_info *lcd = panel_priv.par;
+       int ret = 0;
+
+       dsim_info("lcd panel: +%s: %d\n", __func__, lcd->state);
+
+       if (lcd->state == PANEL_STATE_SUSPENED) {
+               ret = s6e3fa7_init(lcd);
+               if (ret) {
+                       dsim_info("%s: failed to panel init, %d\n", __func__, ret);
+                       goto displayon_err;
+               }
+       }
+
+displayon_err:
+       mutex_lock(&lcd->lock);
+       lcd->state = PANEL_STATE_RESUMED;
+       mutex_unlock(&lcd->lock);
+
+       dsim_info("lcd panel: -%s: %d\n", __func__, lcd->connected);
+
+       return ret;
+}
+
+static int dsim_panel_suspend(struct dsim_device *dsim)
+{
+       struct lcd_info *lcd = panel_priv.par;
+       int ret = 0;
+
+       dsim_info("lcd panel: +%s: %d\n", __func__, lcd->state);
+
+       if (lcd->state == PANEL_STATE_SUSPENED)
+               goto suspend_err;
+
+       mutex_lock(&lcd->lock);
+       lcd->state = PANEL_STATE_SUSPENDING;
+       mutex_unlock(&lcd->lock);
+
+       ret = s6e3fa7_suspend(lcd);
+       if (ret) {
+               dsim_info("lcd panel: %s: failed to panel exit, %d\n", __func__, ret);
+               goto suspend_err;
+       }
+
+suspend_err:
+       mutex_lock(&lcd->lock);
+       lcd->state = PANEL_STATE_SUSPENED;
+       mutex_unlock(&lcd->lock);
+
+       dsim_info("lcd panel: -%s: %d\n", __func__, lcd->state);
+
+       return ret;
+}
+
+static int dsim_panel_dump(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+struct dsim_lcd_driver s6e3fa7_mipi_lcd_driver = {
+       .probe          = dsim_panel_probe,
+       .displayon      = dsim_panel_displayon,
+       .suspend        = dsim_panel_suspend,
+       .resume         = dsim_panel_dump,
+};
+
+static struct notifier_block decon_fb_notifier = {
+       .notifier_call = decon_notifier_event,
+};
+
+static void __exit decon_notifier_exit(void)
+{
+       fb_unregister_client(&decon_fb_notifier);
+}
+
+static int __init decon_notifier_init(void)
+{
+       fb_register_client(&decon_fb_notifier);
+
+       return 0;
+}
+
+late_initcall(decon_notifier_init);
+module_exit(decon_notifier_exit);
+
index 987ecf45caeb2b401c5070c40d4ae4cdcdf8e1cf..4a545fb994260fb40ab98d769fdba5ba42e733eb 100644 (file)
@@ -54,7 +54,7 @@ static const unsigned char SEQ_SLEEP_OUT[] = {
 
 static const unsigned char SEQ_TSP_HSYNC[] = {
        0xB9,
-       0x01, 0xB0, 0x81, 0x09, 0x00, 0x00, 0x00, 0x11, 0x01
+       0x00, 0xB0, 0x8F, 0x09, 0x00, 0x00, 0x00, 0x11, 0x01
 
 };
 
@@ -75,7 +75,7 @@ static const unsigned char SEQ_ERR_FG[] = {
 };
 
 static const unsigned char SEQ_TE_START_SETTING[] = {
-       0xB9, 0x01, 0xB0, 0x96, 0x09
+       0xB9, 0x00, 0xB0, 0x8F, 0x09
 };
 
 static const unsigned char SEQ_FFC[] = {