(CR):[Kane]:[factory]add tm second lcd driver
authorwangjiao <wangjiao1@huaqin.com>
Thu, 22 Nov 2018 09:02:07 +0000 (17:02 +0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:29:58 +0000 (17:29 +0800)
Change-Id: Ib02b30851dd3a197429493bb19d776b9b9ddb391
Signed-off-by: wangjiao <wangjiao1@huaqin.com>
arch/arm64/boot/dts/exynos/exynos9610-display-lcd.dtsi
drivers/video/fbdev/exynos/dpu20/dsim.h
drivers/video/fbdev/exynos/dpu20/dsim_drv.c
drivers/video/fbdev/exynos/dpu20/panels/Makefile
drivers/video/fbdev/exynos/dpu20/panels/lcd_ctrl.h
drivers/video/fbdev/exynos/dpu20/panels/nov36672a_lcd_ctrl.c [new file with mode: 0755]
drivers/video/fbdev/exynos/dpu20/panels/nov36672a_mipi_lcd.c [new file with mode: 0755]
drivers/video/fbdev/exynos/dpu20/panels/nov36672a_param.h [new file with mode: 0755]

index 8a8452a72138244b836979e265748555264d1a34..a7519f062b0220cc11fc5b6b68ba0ea53766204b 100755 (executable)
                                hdr_max_avg_luma = <1200000>;   /* 120 */
                                hdr_min_luma = <5>;                             /* 0.0005 */
                        };
+
+                       nov36672a: nov36672a {
+                               device_type = "novatek-nov36672a";
+                               mode = <0>; /* 0: video mode, 1: DP command mode, 2: MIPI command mode */
+                               resolution = <1080 2520>;
+                               size = <80 120>;
+                               timing,refresh = <60>;
+                               timing,h-porch = <40 40 20>;
+                               timing,v-porch = <8 10 2>;
+                               timing,dsi-hs-clk = <1440>;
+                               /* TODO : pms value to be set */
+                               timing,pmsk = <4 443 1 0>;
+                               timing,dsi-escape-clk = <10>;
+                               mic_en = <0>;           /* 0: Disable, 1: Enable */
+                               mic_ratio = <0>;        /* 0: 1/2 mic, 1: 1/3 mic */
+                               mic_ver = <0>;          /* 0: mic v1.1, 1: v1.2, 2: v2.0 */
+                               type_of_ddi = <2>;      /* 0: Samsung Mobile, 1: MAGNA, 2: Normal(Etc) */
+                               dsc_en = <0>;           /* 0: Disable, 1: Enable */
+                               dsc_cnt = <0>;          /* used DSC count */
+                               dsc_slice_num = <0>;    /* count of dsc slice */
+                               data_lane = <4>;        /* number of using data lane */
+                               cmd_underrun_lp_ref = <4942>;   /* for underrun detect at command mode*/
+                               vt_compensation = <0>;  /* for underrun detect at video mode*/
+                               mres_en = <0>;
+                               mres_number = <3>;
+                               mres_width = <1440 1080 720>;
+                               mres_height = <2960 2220 1480>;
+                               mres_dsc_width = <720 540 360>;
+                               mres_dsc_height = <40 30 74>;
+                               mres_dsc_en = <1 1 0>;
+                               hdr_num = <1>;          /* max: 4 */
+                               hdr_type = <2 0 0 0>;   /* 1: DOLBY_VISION, 2: HDR10, 3: HLG */
+                               hdr_max_luma = <5400000>;               /* 540 */
+                               hdr_max_avg_luma = <1200000>;   /* 120 */
+                               hdr_min_luma = <5>;                             /* 0.0005 */
+                       };
                };
        };
 };
index f1208ea5f199e80509e0f17c1fca681fca2ffc89..c22597b460d422792500cbd783bff67a3598582e 100755 (executable)
@@ -83,6 +83,7 @@ extern struct dsim_lcd_driver s6e3fa7_mipi_lcd_driver;
 extern struct dsim_lcd_driver nt36672a_mipi_lcd_driver;
 extern struct dsim_lcd_driver default_mipi_lcd_driver;
 extern struct dsim_lcd_driver hix83112a_mipi_lcd_driver;
+extern struct dsim_lcd_driver nov36672a_mipi_lcd_driver;
 
 /* define video timer interrupt */
 enum {
index 3d70566bb7b2729ffef5961a6ae456116558792a..4663bd1f9eacaf5317369b24e63d53ae7a0e879e 100755 (executable)
@@ -1615,6 +1615,11 @@ static void dsim_parse_lcd_info(struct dsim_device *dsim)
                dsim_info("ddi type : %s\n", ddi_device_type);
                break;
 
+       case 0x92120101:
+               ddi_device_type = "novatek-nov36672a";
+               dsim_info("ddi type : %s\n", ddi_device_type);
+               break;
+
        default:
                dsim_info("read ddi_device_type default lcd\n");
                ddi_device_type = "default-lcd-vdo";
@@ -1849,6 +1854,10 @@ static void dsim_register_panel(struct dsim_device *dsim)
                dsim->panel_ops = &hix83112a_mipi_lcd_driver;
                dsim_info("panel ops : hix83112a_mipi_lcd_driver\n");
                break;
+       case 0x92120101:
+               dsim->panel_ops = &nov36672a_mipi_lcd_driver;
+               dsim_info("panel ops : nov36672a_mipi_lcd_driver\n");
+               break;
        default:
                dsim_info("panel ops is default lcd\n");
                dsim->panel_ops = &default_mipi_lcd_driver;
index 220d4327076f8d6f3e0157db75814e2811694f03..6c6f2c81884cb8912a6cc23f25acee01eb042728 100755 (executable)
@@ -1,7 +1,8 @@
 obj-$(CONFIG_EXYNOS_DECON_LCD_MULTI)   += s6e3fa0_mipi_lcd.o s6e3fa0_lcd_ctrl.o \
                                        nt36672a_mipi_lcd.o nt36672a_lcd_ctrl.o \
                                        default_mipi_lcd.o default_lcd_ctrl.o \
-                                       hix83112a_mipi_lcd.o hix83112a_lcd_ctrl.o
+                                       hix83112a_mipi_lcd.o hix83112a_lcd_ctrl.o \
+                                       nov36672a_mipi_lcd.o nov36672a_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA2K)        += s6e3ha2k_mipi_lcd.o s6e3ha2k_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HF4) += s6e3hf4_mipi_lcd.o s6e3hf4_lcd_ctrl.o
 obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA6) += s6e3ha6_mipi_lcd.o s6e3ha6_lcd_ctrl.o
index 2aa3e8bdd9f562d167d970b148f8127176b0c8d6..eef0beb7a003c6f37b980d29db480a4170a0e26a 100755 (executable)
@@ -58,4 +58,15 @@ int hix83112a_lcd_dump(int id);
 void hix83112a_lcd_mres(int id, int mres_idx, int dsc_en);
 void hix83112a_lcd_lane_ctl(int id, unsigned int lane_num);
 
+void nov36672a_lcd_init(int id, struct decon_lcd *lcd);
+void nov36672a_lcd_enable(int id);
+void nov36672a_lcd_disable(int id);
+void nov36672a_lcd_sleepin(int id);
+void nov36672a_lcd_sleepout(int id);
+int nov36672a_lcd_gamma_ctrl(int id, unsigned int backlightlevel);
+int nov36672a_lcd_gamma_update(int id);
+int nov36672a_lcd_dump(int id);
+void nov36672a_lcd_mres(int id, int mres_idx, int dsc_en);
+void nov36672a_lcd_lane_ctl(int id, unsigned int lane_num);
+
 #endif /* __LCD_CTRL_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/nov36672a_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/nov36672a_lcd_ctrl.c
new file mode 100755 (executable)
index 0000000..6b46fd3
--- /dev/null
@@ -0,0 +1,129 @@
+/* drivers/video/fbdev/exynos/dpu20/panels/nov36672a_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2018 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 "nov36672a_param.h"
+#include "lcd_ctrl.h"
+
+/* use FW_TEST definition when you test CAL on firmware */
+/* #define FW_TEST */
+#ifdef FW_TEST
+#include "../dsim_fw.h"
+#include "mipi_display.h"
+#else
+#include "../dsim.h"
+#include <video/mipi_display.h>
+#endif
+
+#define GAMMA_PARAM_SIZE 26
+
+#define NOV36672A_VIDEO_VBP    8
+#define NOV36672A_VIDEO_VFP    10
+#define NOV36672A_VIDEO_VSA    2
+#define NOV36672A_VIDEO_HBP    40
+#define NOV36672A_VIDEO_HFP    40
+#define NOV36672A_VIDEO_HSA    20
+
+#define NOV36672A_HORIZONTAL   1080
+#define NOV36672A_VERTICAL     2520
+
+#ifdef FW_TEST /* This information is moved to DT */
+#define CONFIG_FB_I80_COMMAND_MODE
+
+struct decon_lcd nov36672a_lcd_info = {
+       .mode = DECON_VIDEO_MODE,
+       .vfp = NOV36672A_VIDEO_VFP,
+       .vbp = NOV36672A_VIDEO_VBP,
+       .hfp = NOV36672A_VIDEO_HFP,
+       .hbp = NOV36672A_VIDEO_HBP,
+       .vsa = NOV36672A_VIDEO_VSA,
+       .hsa = NOV36672A_VIDEO_HSA,
+       .xres = NOV36672A_HORIZONTAL,
+       .yres = NOV36672A_VERTICAL,
+
+       /* Maybe, width and height will be removed */
+       .width = 80,
+       .height = 120,
+
+       /* Mhz */
+       .hs_clk = 1440,
+       .esc_clk = 10,
+
+       .fps = 60,
+       .mic_enabled = 0,
+       .mic_ver = MIC_VER_1_2,
+};
+#endif
+
+/*
+ * NOV36672A 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
+ */
+void nov36672a_lcd_init(int id, struct decon_lcd *lcd)
+{
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               SEQ_CMD_0[0],
+                               SEQ_CMD_0[1]) < 0)
+               dsim_err("fail to send SEQ_CMD_0 command.\n");
+       mdelay(1);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               SEQ_CMD_1[0],
+                               SEQ_CMD_1[1]) < 0)
+               dsim_err("fail to send SEQ_CMD_1 command.\n");
+       mdelay(1);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               SEQ_CMD_2[0],
+                               SEQ_CMD_2[1]) < 0)
+               dsim_err("fail to send SEQ_CMD_2 command.\n");
+       mdelay(1);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_SLEEP_OUT[0], 0) < 0)
+               dsim_err("fail to send SEQ_SLEEP_OUT command.\n");
+       mdelay(125);
+}
+
+void nov36672a_lcd_enable(int id)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_DISPLAY_ON[0], 0) < 0)
+               dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
+       mdelay(20);
+}
+
+void nov36672a_lcd_disable(int id)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_DISPLAY_OFF[0], 0) < 0)
+               dsim_err("fail to send SEQ_DISPLAY_OFF command.\n");
+       mdelay(20);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_SLEEP_IN[0], 0) < 0)
+               dsim_err("fail to send SEQ_SLEEP_IN command.\n");
+       mdelay(125);
+}
+
+/*
+ * Set gamma values
+ *
+ * Parameter
+ *     - backlightlevel : It is from 0 to 26.
+ */
+int nov36672a_lcd_gamma_ctrl(int id, u32 backlightlevel)
+{
+       return 0;
+}
+
+int nov36672a_lcd_gamma_update(int id)
+{
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/nov36672a_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/nov36672a_mipi_lcd.c
new file mode 100755 (executable)
index 0000000..77f21a2
--- /dev/null
@@ -0,0 +1,526 @@
+/* drivers/video/fbdev/exynos/dpu20/panels/nov36672a_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2018 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 <linux/gpio.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+#include "nov36672a_param.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 170
+
+static struct dsim_device *dsim_base;
+static struct backlight_device *bd;
+
+struct panel_device {
+       struct device *dev;
+       struct dsim_device *dsim;
+       struct mutex lock;
+       int cabc_mode;
+};
+
+struct panel_device *nov36672a_panel_drvdata;
+struct class *nov36672a_panel_class;
+
+static int nov36672a_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int nov36672a_get_backlight_level(int brightness)
+{
+       int backlightlevel;
+
+       switch (brightness) {
+       case 0:
+               backlightlevel = 0;
+               break;
+       case 1 ... 29:
+               backlightlevel = 0;
+               break;
+       case 30 ... 34:
+               backlightlevel = 1;
+               break;
+       case 35 ... 39:
+               backlightlevel = 2;
+               break;
+       case 40 ... 44:
+               backlightlevel = 3;
+               break;
+       case 45 ... 49:
+               backlightlevel = 4;
+               break;
+       case 50 ... 54:
+               backlightlevel = 5;
+               break;
+       case 55 ... 64:
+               backlightlevel = 6;
+               break;
+       case 65 ... 74:
+               backlightlevel = 7;
+               break;
+       case 75 ... 83:
+               backlightlevel = 8;
+               break;
+       case 84 ... 93:
+               backlightlevel = 9;
+               break;
+       case 94 ... 103:
+               backlightlevel = 10;
+               break;
+       case 104 ... 113:
+               backlightlevel = 11;
+               break;
+       case 114 ... 122:
+               backlightlevel = 12;
+               break;
+       case 123 ... 132:
+               backlightlevel = 13;
+               break;
+       case 133 ... 142:
+               backlightlevel = 14;
+               break;
+       case 143 ... 152:
+               backlightlevel = 15;
+               break;
+       case 153 ... 162:
+               backlightlevel = 16;
+               break;
+       case 163 ... 171:
+               backlightlevel = 17;
+               break;
+       case 172 ... 181:
+               backlightlevel = 18;
+               break;
+       case 182 ... 191:
+               backlightlevel = 19;
+               break;
+       case 192 ... 201:
+               backlightlevel = 20;
+               break;
+       case 202 ... 210:
+               backlightlevel = 21;
+               break;
+       case 211 ... 220:
+               backlightlevel = 22;
+               break;
+       case 221 ... 230:
+               backlightlevel = 23;
+               break;
+       case 231 ... 240:
+               backlightlevel = 24;
+               break;
+       case 241 ... 250:
+               backlightlevel = 25;
+               break;
+       case 251 ... 255:
+               backlightlevel = 26;
+               break;
+       default:
+               backlightlevel = 12;
+               break;
+       }
+
+       return backlightlevel;
+}
+
+static int nov36672a_update_brightness(int brightness)
+{
+       int backlightlevel;
+
+       backlightlevel = nov36672a_get_backlight_level(brightness);
+
+       pr_info("brightness [%d]\n", brightness);
+       if (dsim_wr_data(0, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               SEQ_CMD_0[0],
+                               brightness) < 0)
+               dsim_err("fail to send SEQ_CMD_0 command.\n");
+
+       mdelay(12);
+       return 0;
+}
+
+static int nov36672a_set_brightness(struct backlight_device *bd)
+{
+       struct dsim_device *dsim;
+       int brightness = bd->props.brightness;
+
+       dsim = get_dsim_drvdata(0);
+
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               pr_err("Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+
+       dsim->user_brightness = brightness;
+       if ((brightness > dsim->max_brightness) &&
+                       (brightness <= MAX_BRIGHTNESS)) {
+               brightness = dsim->max_brightness;
+       }
+
+       nov36672a_update_brightness(brightness);
+       dsim->brightness = brightness;
+
+       return 0;
+}
+
+static const struct backlight_ops nov36672a_backlight_ops = {
+       .get_brightness = nov36672a_get_brightness,
+       .update_status = nov36672a_set_brightness,
+};
+
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+static int nov36672a_cabc_mode(struct dsim_device *dsim, int mode)
+{
+       int ret = 0;
+       int count;
+       unsigned char buf[] = {0x0, 0x0};
+       unsigned char SEQ_CABC_CMD[] = {0x55, 0x00, 0x00};
+       unsigned char cmd = MIPI_DCS_WRITE_POWER_SAVE; /* 0x55 */
+
+       dsim_dbg("%s: CABC mode[%d] write/read\n", __func__, mode);
+
+       switch (mode) {
+               /* read */
+               case CABC_READ_MODE:
+                       cmd = MIPI_DCS_GET_POWER_SAVE; /* 0x56 */
+                       ret = dsim_read_data(dsim, MIPI_DSI_DCS_READ, cmd, 0x1, buf);
+                       if (ret < 0) {
+                               pr_err("CABC REG(0x%02X) read failure!\n", cmd);
+                               count = 0;
+                       } else {
+                               pr_info("CABC REG(0x%02X) read success: 0x%02x\n",
+                                               cmd, *(unsigned int *)buf & 0xFF);
+                               count = 1;
+                       }
+                       return count;
+
+                       /* write */
+               case POWER_SAVE_OFF:
+                       SEQ_CABC_CMD[1] = CABC_OFF;
+                       break;
+               case POWER_SAVE_LOW:
+                       SEQ_CABC_CMD[1] = CABC_USER_IMAGE;
+                       break;
+               case POWER_SAVE_MEDIUM:
+                       SEQ_CABC_CMD[1] = CABC_STILL_PICTURE;
+                       break;
+               case POWER_SAVE_HIGH:
+                       SEQ_CABC_CMD[1] = CABC_MOVING_IMAGE;
+                       break;
+               default:
+                       pr_err("Unavailable CABC mode(%d)!\n", mode);
+                       return -EINVAL;
+       }
+
+       ret = dsim_write_data(dsim, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned long)SEQ_CABC_CMD /*cmd*/,
+                       ARRAY_SIZE(SEQ_CABC_CMD));
+       if (ret < 0) {
+               pr_err("CABC write command failure!\n");
+               count = 0;
+       } else {
+               dsim_dbg("CABC write command success!\n");
+               count = ARRAY_SIZE(SEQ_CABC_CMD);
+       }
+
+       return count;
+}
+#endif
+
+static ssize_t panel_cabc_mode_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       ssize_t count = 0;
+       int ret = 0;
+       struct panel_device *panel = dev_get_drvdata(dev);
+
+       mutex_lock(&panel->lock);
+
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       ret = nov36672a_cabc_mode(panel->dsim, CABC_READ_MODE);
+#endif
+       mutex_unlock(&panel->lock);
+
+       count = snprintf(buf, PAGE_SIZE, "cabc_mode = %d, ret = %d\n",
+                       panel->cabc_mode, ret);
+
+       return count;
+}
+
+static ssize_t panel_cabc_mode_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int value = 0;
+       struct panel_device *panel = dev_get_drvdata(dev);
+
+       ret = kstrtouint(buf, 0, &value);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&panel->lock);
+       panel->cabc_mode = value;
+       mutex_unlock(&panel->lock);
+
+       pr_info("%s: %d\n", __func__, value);
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       nov36672a_cabc_mode(panel->dsim, panel->cabc_mode);
+#endif
+       return count;
+}
+
+static ssize_t panel_max_brightness_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       ssize_t count = 0;
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+
+       count = snprintf(buf, PAGE_SIZE, "max_brightness = %d\n",
+                       dsim->max_brightness);
+
+       return count;
+}
+
+static ssize_t panel_max_brightness_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int value = 0;
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+       int old_brightness;
+
+       ret = kstrtouint(buf, 0, &value);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&dsim->bl_lock);
+
+       old_brightness = dsim->brightness;
+
+       if (value > MAX_BRIGHTNESS) {
+               dsim->max_brightness = MAX_BRIGHTNESS;
+               dsim->brightness = dsim->user_brightness;
+       } else if ((value >= MIN_BRIGHTNESS) && (value <= MAX_BRIGHTNESS)) {
+               dsim->max_brightness = value;
+               if (dsim->user_brightness > dsim->max_brightness)
+                       dsim->brightness = dsim->max_brightness;
+               else
+                       dsim->brightness = dsim->user_brightness;
+       } else {
+               goto end;
+       }
+
+       if (old_brightness != dsim->brightness) {
+               nov36672a_update_brightness(dsim->brightness);
+       }
+
+end:
+       mutex_unlock(&dsim->bl_lock);
+
+       pr_info("%s: %d\n", __func__, dsim->max_brightness);
+
+       return count;
+}
+
+static DEVICE_ATTR(max_brightness, 0660, panel_max_brightness_show,
+                       panel_max_brightness_store);
+
+
+static ssize_t panel_brightness_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       ssize_t count = 0;
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+
+       count = snprintf(buf, PAGE_SIZE, "brightness = %d\n",
+                       dsim->brightness);
+
+       return count;
+}
+
+static ssize_t panel_brightness_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned int value = 0;
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+
+       ret = kstrtouint(buf, 0, &value);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&dsim->bl_lock);
+
+       if (value <= dsim->max_brightness) {
+               dsim->brightness = value;
+               nov36672a_update_brightness(dsim->brightness);
+       } else if (value <= MAX_BRIGHTNESS) {
+               dsim->user_brightness = value;
+       } else {
+               pr_err("%s, brightness value is wrong[%d]\n",
+                               __func__, value);
+       }
+
+       mutex_unlock(&dsim->bl_lock);
+
+       pr_info("%s: %d\n", __func__, dsim->brightness);
+
+       return count;
+}
+
+static DEVICE_ATTR(brightness, 0660, panel_brightness_show,
+                       panel_brightness_store);
+
+static DEVICE_ATTR(cabc_mode, 0660, panel_cabc_mode_show,
+               panel_cabc_mode_store);
+
+static ssize_t lcd_panel_supplier_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       ssize_t count = 0;
+
+       count = snprintf(buf, PAGE_SIZE, "%s\n","nov36672a");
+       return count;
+}
+
+static DEVICE_ATTR(panel_supplier, 0644, lcd_panel_supplier_show,NULL);
+
+static struct attribute *panel_attrs[] = {
+       &dev_attr_cabc_mode.attr,
+       &dev_attr_panel_supplier.attr,
+       &dev_attr_max_brightness.attr,
+       &dev_attr_brightness.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(panel);
+
+static struct attribute_group panel = {
+       .attrs = panel_attrs,
+};
+
+static int nov36672a_create_sysfs(struct dsim_device *dsim)
+{
+       int rc;
+       rc = sysfs_create_group(&dsim->dev->kobj, &panel);
+       if (rc)
+               pr_err("sysfs group creation failed, rc=%d\n", rc);
+       return rc;
+}
+
+
+static int nov36672a_probe(struct dsim_device *dsim)
+{
+       int ret = 1;
+       struct panel_device *panel;
+       static unsigned int panel_no;
+
+       dsim_base = dsim;
+
+       bd = backlight_device_register("backlight_0", NULL,
+                       NULL, &nov36672a_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_err("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+       dsim->max_brightness = MAX_BRIGHTNESS;
+       dsim->brightness = DEFAULT_BRIGHTNESS;
+       nov36672a_create_sysfs(dsim);
+       panel = kzalloc(sizeof(struct panel_device), GFP_KERNEL);
+       if (!panel) {
+               pr_err("failed to allocate panel\n");
+               ret = -ENOMEM;
+               goto exit0;
+       }
+
+       nov36672a_panel_drvdata = panel;
+
+       panel->dsim = dsim;
+       panel->cabc_mode = 0;
+
+       if (IS_ERR_OR_NULL(nov36672a_panel_class)) {
+               nov36672a_panel_class = class_create(THIS_MODULE, "panel");
+               if (IS_ERR_OR_NULL(nov36672a_panel_class)) {
+                       pr_err("failed to create panel class\n");
+                       ret = -EINVAL;
+                       goto exit1;
+               }
+
+               nov36672a_panel_class->dev_groups = panel_groups;
+       }
+
+       panel->dev = device_create(nov36672a_panel_class, dsim->dev, 0,
+                       &panel, !panel_no ? "panel" : "panel%d", panel_no);
+       if (IS_ERR_OR_NULL(panel->dev)) {
+               pr_err("failed to create panel device\n");
+               ret = -EINVAL;
+               goto exit2;
+       }
+
+       mutex_init(&panel->lock);
+       mutex_init(&dsim->bl_lock);
+       dev_set_drvdata(panel->dev, panel);
+
+       panel_no++;
+
+       return ret;
+
+exit2:
+       class_destroy(nov36672a_panel_class);
+exit1:
+       kfree(panel);
+exit0:
+       return ret;
+}
+
+static int nov36672a_displayon(struct dsim_device *dsim)
+{
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       struct panel_device *panel = nov36672a_panel_drvdata;
+#endif
+       dsim_info("%s +\n", __func__);
+       nov36672a_lcd_init(dsim->id, &dsim->lcd_info);
+       nov36672a_lcd_enable(dsim->id);
+       dsim_info("%s -\n", __func__);
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       if (panel)
+               nov36672a_cabc_mode(dsim, panel->cabc_mode);
+#endif
+       return 1;
+}
+
+static int nov36672a_suspend(struct dsim_device *dsim)
+{
+       dsim_info("%s +\n", __func__);
+       nov36672a_lcd_disable(dsim->id);
+       dsim_info("%s -\n", __func__);
+       return 1;
+}
+
+static int nov36672a_resume(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+struct dsim_lcd_driver nov36672a_mipi_lcd_driver = {
+       .probe          = nov36672a_probe,
+       .displayon      = nov36672a_displayon,
+       .suspend        = nov36672a_suspend,
+       .resume         = nov36672a_resume,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/nov36672a_param.h b/drivers/video/fbdev/exynos/dpu20/panels/nov36672a_param.h
new file mode 100755 (executable)
index 0000000..ffa692f
--- /dev/null
@@ -0,0 +1,44 @@
+/* linux/drivers/video/decon_display/nt36672a_param.h
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Hwangjae Lee <hj-yo.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 __NOV36672A_PARAM_H__
+#define __NOV36672A_PARAM_H__
+
+/* MIPI commands list */
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11,
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29,
+};
+
+static const unsigned char SEQ_DISPLAY_OFF[] = {
+       0x28,
+};
+
+static const unsigned char SEQ_SLEEP_IN[] = {
+       0x10,
+};
+
+static const unsigned char SEQ_CMD_0[] = {
+       0x51, 0xFF
+};
+
+static const unsigned char SEQ_CMD_1[] = {
+       0x53, 0x24
+};
+
+static const unsigned char SEQ_CMD_2[] = {
+       0x55, 0x02
+};
+
+#endif /* __NOV36672A_GAMMA_H__ */