[9609] fbdev: panel: added sysfs for supporting CABC of NT36672A Panel
authorhwangjae lee <hj-yo.lee@samsung.com>
Thu, 2 Aug 2018 01:06:14 +0000 (10:06 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:23:43 +0000 (20:23 +0300)
Change-Id: I3b30b191121ab0db21280f528b7226d1e22fbf90
Signed-off-by: hwangjae lee <hj-yo.lee@samsung.com>
drivers/video/fbdev/exynos/dpu20/dsim_drv.c
drivers/video/fbdev/exynos/dpu20/panels/Kconfig
drivers/video/fbdev/exynos/dpu20/panels/nt36672a_mipi_lcd.c
drivers/video/fbdev/exynos/dpu20/panels/nt36672a_param.h

index de9da141f0fea2cd0892de299317b2d7187d56b4..9c409c6ebbb31388f959b17911186fba7be3c22e 100644 (file)
@@ -1940,7 +1940,6 @@ static int dsim_probe(struct platform_device *pdev)
 #if defined(READ_ESD_SOLUTION_TEST)
        dsim_create_esd_test_sysfs(dsim);
 #endif
-#endif
 
 #ifdef DPHY_LOOP
        dsim_reg_set_dphy_loop_back_test(dsim->id);
index f987588b7111259014dac9fe3572ca0d8e7bab48..5892ef14db00b4bbe78682a87d7fc87ef5c9588e 100644 (file)
@@ -41,7 +41,7 @@ config EXYNOS_DECON_LCD_S6E3FA7
 
 config EXYNOS_DECON_LCD_NT36672A
        depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
-       tristate "NT3667A TFT FHD+ LCD driver(1080 x 2246)"
+       tristate "NT36672A TFT FHD+ LCD driver(1080 x 2246)"
        default n
 
 config EXYNOS_DECON_LCD_EMUL_DISP
index 5550f0c02b8e66e6ed37b2862437f4d442a0f1e1..f09b013722bcc3867be940fc9c109716f4136025 100644 (file)
 static struct dsim_device *dsim_base;
 static struct backlight_device *bd;
 
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+struct panel_device {
+       struct device *dev;
+       struct dsim_device *dsim;
+       struct mutex lock;
+       int cabc_mode;
+};
+
+struct panel_device *panel_drvdata;
+struct class *panel_class;
+#endif
+
 static int nt36672a_get_brightness(struct backlight_device *bd)
 {
        return bd->props.brightness;
@@ -165,27 +177,191 @@ static const struct backlight_ops nt36672a_backlight_ops = {
        .update_status = nt36672a_set_brightness,
 };
 
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+static int nt36672a_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;
+}
+
+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);
+
+       ret = nt36672a_cabc_mode(panel->dsim, CABC_READ_MODE);
+
+       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);
+
+       nt36672a_cabc_mode(panel->dsim, panel->cabc_mode);
+
+       return count;
+}
+
+static DEVICE_ATTR(cabc_mode, 0660, panel_cabc_mode_show,
+               panel_cabc_mode_store);
+
+static struct attribute *panel_attrs[] = {
+       &dev_attr_cabc_mode.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(panel);
+#endif
+
 static int nt36672a_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, &nt36672a_backlight_ops, NULL);
+                       NULL, &nt36672a_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;
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       panel = kzalloc(sizeof(struct panel_device), GFP_KERNEL);
+       if (!panel) {
+               pr_err("failed to allocate panel\n");
+               ret = -ENOMEM;
+               goto exit0;
+       }
 
-       return 0;
+       panel_drvdata = panel;
+
+       panel->dsim = dsim;
+       panel->cabc_mode = 0;
+
+       if (IS_ERR_OR_NULL(panel_class)) {
+               panel_class = class_create(THIS_MODULE, "panel");
+               if (IS_ERR_OR_NULL(panel_class)) {
+                       pr_err("failed to create panel class\n");
+                       ret = -EINVAL;
+                       goto exit1;
+               }
+
+               panel_class->dev_groups = panel_groups;
+       }
+
+       panel->dev = device_create(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);
+       dev_set_drvdata(panel->dev, panel);
+
+       panel_no++;
+
+       return ret;
+
+exit2:
+       class_destroy(panel_class);
+exit1:
+       kfree(panel);
+exit0:
+#endif
+       return ret;
 }
 
 static int nt36672a_displayon(struct dsim_device *dsim)
 {
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       struct panel_device *panel = panel_drvdata;
+#endif
        dsim_info("%s +\n", __func__);
        nt36672a_lcd_init(dsim->id, &dsim->lcd_info);
        nt36672a_lcd_enable(dsim->id);
        dsim_info("%s -\n", __func__);
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+       if (panel)
+               nt36672a_cabc_mode(dsim, panel->cabc_mode);
+#endif
        return 1;
 }
 
index 5973b30450e2fab406b2750e530f0d8ee8f49512..ec6ff3579b46d45918918c7bc0ee0eaea12e9130 100644 (file)
 #ifndef __NT36672A_PARAM_H__
 #define __NT36672A_PARAM_H__
 
+#if defined(CONFIG_EXYNOS_PANEL_CABC)
+/*
+ *cabc_mode[1:0] must be re-mapped according to DDI command
+ *3FA0 is OLED, so CABC command is not supported.
+ *Following values represent for ACL2 control of 3FA0.
+ *- [2'b00] ACL off
+ *- [2'b01] ACL low
+ *- [2'b10] ACL mid
+ *- [2'b11] ACL high
+ */
+enum cabc_mode {
+       CABC_OFF = 0,
+       CABC_USER_IMAGE,
+       CABC_STILL_PICTURE,
+       CABC_MOVING_IMAGE,
+       CABC_READ_MODE = 0x80,
+};
+
+enum power_mode {
+       POWER_SAVE_OFF = 0,
+       POWER_SAVE_LOW = 1,
+       POWER_SAVE_MEDIUM = 2,
+       POWER_SAVE_HIGH = 3,
+       POWER_SAVE_MAX = 4,
+};
+#endif
 /* MIPI commands list */
 static const unsigned char SEQ_SLEEP_OUT[] = {
        0x11,