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 {
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
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)"
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+
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
};
};
static const unsigned char SEQ_TE_START_SETTING[] = {
- 0xB9, 0x01, 0xB0, 0x96, 0x09
+ 0xB9, 0x00, 0xB0, 0x8F, 0x09
};
static const unsigned char SEQ_FFC[] = {