From 24c1cc5ccc366f915450a5f74f2ad0682c76466d Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Tue, 1 Jun 2021 08:23:14 +0200 Subject: [PATCH] drm/panel: Add driver for Samsung AMS497EE01 panel This patch adds support for Samsung's AMOLED AMS497EE01 panel with an EA8061V controller. The driver is mostly based on the driver for s6e3fa2 and s6e63m0, with data taken from the downstream android kernel for the device with codename a500f. The panel is used in the msm8916 Samsung Galaxy A5U (EUR) devices, for which there is already partial support in the mainline kernel. Signed-off-by: Henrik Grimler --- arch/arm64/configs/msm8916_defconfig | 1 + drivers/gpu/drm/panel/Kconfig | 7 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/msm8916-generated/Makefile | 1 - .../panel-samsung-ea8061v-ams497ee01.c | 273 ----- .../panel/panel-samsung-ea8061v-ams497ee01.c | 970 ++++++++++++++++++ 6 files changed, 979 insertions(+), 274 deletions(-) delete mode 100644 drivers/gpu/drm/panel/msm8916-generated/panel-samsung-ea8061v-ams497ee01.c create mode 100644 drivers/gpu/drm/panel/panel-samsung-ea8061v-ams497ee01.c diff --git a/arch/arm64/configs/msm8916_defconfig b/arch/arm64/configs/msm8916_defconfig index af5635aa1be862..bb9d88c0190d96 100644 --- a/arch/arm64/configs/msm8916_defconfig +++ b/arch/arm64/configs/msm8916_defconfig @@ -279,6 +279,7 @@ CONFIG_DRM_MSM=m # CONFIG_DRM_MSM_DSI_7NM_PHY is not set # CONFIG_DRM_MSM_HDMI is not set CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_PANEL_SAMSUNG_EA8061V_AMS497EE01=m CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01=m CONFIG_DRM_PANEL_MSM8916_GENERATED=m CONFIG_DRM_DISPLAY_CONNECTOR=m diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index ded73c5e6246e5..d444b5405d081e 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -536,6 +536,13 @@ config DRM_PANEL_SAMSUNG_DB7430 DB7430 DPI display controller used in such devices as the LMS397KF04 480x800 DPI panel. +config DRM_PANEL_SAMSUNG_EA8061V_AMS497EE01 + tristate "Samsung AMS497EE01 panel with EA8061V DSI video mode controller" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_S6D16D0 tristate "Samsung S6D16D0 DSI video mode panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 4ebd34fc1896fc..f5e94acae2bc8b 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_EA8061V_AMS497EE01) += panel-samsung-ea8061v-ams497ee01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o diff --git a/drivers/gpu/drm/panel/msm8916-generated/Makefile b/drivers/gpu/drm/panel/msm8916-generated/Makefile index 4c4eebbe602204..fcb27b3ed4510c 100644 --- a/drivers/gpu/drm/panel/msm8916-generated/Makefile +++ b/drivers/gpu/drm/panel/msm8916-generated/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_DRM_PANEL_MOTOROLA_OSPREY_INX) += panel-motorola-osprey-inx.o obj-$(CONFIG_DRM_PANEL_MOTOROLA_SURNIA_BOE) += panel-motorola-surnia-boe.o obj-$(CONFIG_DRM_PANEL_MOTOROLA_SURNIA_INX) += panel-motorola-surnia-inx.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_EA8061_AMS549BU19_ID400418) += panel-samsung-ea8061-ams549bu19-id400418.o -obj-$(CONFIG_DRM_PANEL_SAMSUNG_EA8061V_AMS497EE01) += panel-samsung-ea8061v-ams497ee01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_HX8389C_GH9607501A) += panel-samsung-hx8389c-gh9607501a.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_NT51017_B4P096WX5VP09) += panel-samsung-nt51017-b4p096wx5vp09.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6288A0) += panel-samsung-s6288a0.o diff --git a/drivers/gpu/drm/panel/msm8916-generated/panel-samsung-ea8061v-ams497ee01.c b/drivers/gpu/drm/panel/msm8916-generated/panel-samsung-ea8061v-ams497ee01.c deleted file mode 100644 index f6597d5dc6617c..00000000000000 --- a/drivers/gpu/drm/panel/msm8916-generated/panel-samsung-ea8061v-ams497ee01.c +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2023 FIXME -// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: -// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME) - -#include -#include -#include -#include -#include - -#include -#include -#include - -struct ea8061v_ams497ee01 { - struct drm_panel panel; - struct mipi_dsi_device *dsi; - struct regulator_bulk_data supplies[2]; - struct gpio_desc *reset_gpio; - bool prepared; -}; - -static inline -struct ea8061v_ams497ee01 *to_ea8061v_ams497ee01(struct drm_panel *panel) -{ - return container_of(panel, struct ea8061v_ams497ee01, panel); -} - -static void ea8061v_ams497ee01_reset(struct ea8061v_ams497ee01 *ctx) -{ - gpiod_set_value_cansleep(ctx->reset_gpio, 0); - msleep(20); - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - usleep_range(1000, 2000); - gpiod_set_value_cansleep(ctx->reset_gpio, 0); - msleep(20); -} - -static int ea8061v_ams497ee01_on(struct ea8061v_ams497ee01 *ctx) -{ - struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; - - dsi->mode_flags |= MIPI_DSI_MODE_LPM; - - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); - mipi_dsi_dcs_write_seq(dsi, 0xf1, 0x5a, 0x5a); - mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x19, 0x10); - mipi_dsi_dcs_write_seq(dsi, 0xba, 0x57); - mipi_dsi_dcs_write_seq(dsi, 0xfc, 0x5a, 0x5a); - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x0b); - mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x00, 0x85); - mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x70); - mipi_dsi_dcs_write_seq(dsi, 0xfc, 0xa5, 0xa5); - mipi_dsi_dcs_write_seq(dsi, 0xca, - 0x01, 0x00, 0x01, 0x00, 0x01, 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, 0x00, 0x00, - 0x00); - mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x00, 0x00, 0x0a); - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x5c, 0x8a); - mipi_dsi_dcs_write_seq(dsi, 0xf7, 0x01); - - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } - msleep(120); - - mipi_dsi_dcs_write_seq(dsi, 0xf1, 0xa5, 0xa5); - - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display on: %d\n", ret); - return ret; - } - - return 0; -} - -static int ea8061v_ams497ee01_off(struct ea8061v_ams497ee01 *ctx) -{ - struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; - - dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; - - ret = mipi_dsi_dcs_set_display_off(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display off: %d\n", ret); - return ret; - } - msleep(35); - - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to enter sleep mode: %d\n", ret); - return ret; - } - msleep(100); - - return 0; -} - -static int ea8061v_ams497ee01_prepare(struct drm_panel *panel) -{ - struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel); - struct device *dev = &ctx->dsi->dev; - int ret; - - if (ctx->prepared) - return 0; - - ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - if (ret < 0) { - dev_err(dev, "Failed to enable regulators: %d\n", ret); - return ret; - } - - ea8061v_ams497ee01_reset(ctx); - - ret = ea8061v_ams497ee01_on(ctx); - if (ret < 0) { - dev_err(dev, "Failed to initialize panel: %d\n", ret); - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - return ret; - } - - ctx->prepared = true; - return 0; -} - -static int ea8061v_ams497ee01_unprepare(struct drm_panel *panel) -{ - struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel); - struct device *dev = &ctx->dsi->dev; - int ret; - - if (!ctx->prepared) - return 0; - - ret = ea8061v_ams497ee01_off(ctx); - if (ret < 0) - dev_err(dev, "Failed to un-initialize panel: %d\n", ret); - - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); - - ctx->prepared = false; - return 0; -} - -static const struct drm_display_mode ea8061v_ams497ee01_mode = { - .clock = (720 + 80 + 96 + 128) * (1280 + 14 + 2 + 8) * 60 / 1000, - .hdisplay = 720, - .hsync_start = 720 + 80, - .hsync_end = 720 + 80 + 96, - .htotal = 720 + 80 + 96 + 128, - .vdisplay = 1280, - .vsync_start = 1280 + 14, - .vsync_end = 1280 + 14 + 2, - .vtotal = 1280 + 14 + 2 + 8, - .width_mm = 62, - .height_mm = 110, -}; - -static int ea8061v_ams497ee01_get_modes(struct drm_panel *panel, - struct drm_connector *connector) -{ - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &ea8061v_ams497ee01_mode); - if (!mode) - return -ENOMEM; - - drm_mode_set_name(mode); - - mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - connector->display_info.width_mm = mode->width_mm; - connector->display_info.height_mm = mode->height_mm; - drm_mode_probed_add(connector, mode); - - return 1; -} - -static const struct drm_panel_funcs ea8061v_ams497ee01_panel_funcs = { - .prepare = ea8061v_ams497ee01_prepare, - .unprepare = ea8061v_ams497ee01_unprepare, - .get_modes = ea8061v_ams497ee01_get_modes, -}; - -static int ea8061v_ams497ee01_probe(struct mipi_dsi_device *dsi) -{ - struct device *dev = &dsi->dev; - struct ea8061v_ams497ee01 *ctx; - int ret; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->supplies[0].supply = "vdd3"; - ctx->supplies[1].supply = "vci"; - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), - ctx->supplies); - if (ret < 0) - return dev_err_probe(dev, ret, "Failed to get regulators\n"); - - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ctx->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), - "Failed to get reset-gpios\n"); - - ctx->dsi = dsi; - mipi_dsi_set_drvdata(dsi, ctx); - - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_NO_EOT_PACKET; - - drm_panel_init(&ctx->panel, dev, &ea8061v_ams497ee01_panel_funcs, - DRM_MODE_CONNECTOR_DSI); - - drm_panel_add(&ctx->panel); - - ret = mipi_dsi_attach(dsi); - if (ret < 0) { - dev_err(dev, "Failed to attach to DSI host: %d\n", ret); - drm_panel_remove(&ctx->panel); - return ret; - } - - return 0; -} - -static void ea8061v_ams497ee01_remove(struct mipi_dsi_device *dsi) -{ - struct ea8061v_ams497ee01 *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - - ret = mipi_dsi_detach(dsi); - if (ret < 0) - dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); - - drm_panel_remove(&ctx->panel); -} - -static const struct of_device_id ea8061v_ams497ee01_of_match[] = { - { .compatible = "samsung,ea8061v-ams497ee01" }, // FIXME - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, ea8061v_ams497ee01_of_match); - -static struct mipi_dsi_driver ea8061v_ams497ee01_driver = { - .probe = ea8061v_ams497ee01_probe, - .remove = ea8061v_ams497ee01_remove, - .driver = { - .name = "panel-ea8061v-ams497ee01", - .of_match_table = ea8061v_ams497ee01_of_match, - }, -}; -module_mipi_dsi_driver(ea8061v_ams497ee01_driver); - -MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator "); // FIXME -MODULE_DESCRIPTION("DRM driver for ss_dsi_panel_EA8061V_AMS497EE01_HD"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-samsung-ea8061v-ams497ee01.c b/drivers/gpu/drm/panel/panel-samsung-ea8061v-ams497ee01.c new file mode 100644 index 00000000000000..acf9c42f579f07 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-ea8061v-ams497ee01.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2023 FIXME +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME) +// +// Mostly based on s6e3fa2 and s6e63m0. Table values taken from Samsung's +// android kernel + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define EA8061V_AMS497EE01_NUM_GAMMA_LEVELS 62 +#define EA8061V_AMS497EE01_GAMMA_CMD_CNT 34 + +#define EA8061V_AMS497EE01_MIN_BRIGHTNESS 0 +#define EA8061V_AMS497EE01_MAX_BRIGHTNESS (EA8061V_AMS497EE01_NUM_GAMMA_LEVELS - 1) +#define EA8061V_AMS497EE01_DEFAULT_BRIGHTNESS 40 + +/* Commands from manufacturer */ +#define MCS_ACL_OFF 0x5c +#define MCS_ACL_ON 0x4c +#define MCS_ACL_CONTROL 0x55 +#define MCS_AID_CONTROL 0xb2 /* Samsung AMOLED Impulsive Driving */ +#define MCS_ACL_OPR_CONTROL 0xb5 +#define MCS_ELVSS_CONTROL 0xb6 /* Amoled negative power supply */ +#define MCS_TSET 0xb8 /* Set reference conditions */ +#define MCS_GAMMA 0xca +#define MCS_GAMMA_UPDATE 0xf7 + +/* Which ELVSS sequence to use for which candela level. + */ +static const u8 map_candela_to_elvss[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 2, 3, 4, 4, 5, 6, + 7, 7, 7, 8, 9, 10, + 11, 11, 11, 12, 13, 14, 15, 16, 17 +}; + +static const u8 seq_ea8061v_ams497ee01_lux[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS][EA8061V_AMS497EE01_GAMMA_CMD_CNT] = { + { MCS_GAMMA, + 0x00, 0x92, 0x00, 0xac, 0x00, 0x7e, 0x8a, 0x8f, 0x8b, + 0x8d, 0x91, 0x8d, 0x96, 0xa1, 0x99, 0x9b, 0xa5, 0x00, + 0x9c, 0x95, 0xa1, 0x8d, 0x9d, 0xa3, 0xa1, 0xba, 0xbb, + 0xec, 0xbd, 0xd5, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x93, 0x00, 0xac, 0x00, 0x7e, 0x8b, 0x8e, 0x8b, + 0x8d, 0x90, 0x8c, 0x93, 0x9e, 0x96, 0x94, 0xa1, 0x00, + 0x96, 0x96, 0xa2, 0x8d, 0x9e, 0xa2, 0xa1, 0xb9, 0xba, + 0xe1, 0xb4, 0xcd, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8a, 0x8d, 0x8a, + 0x89, 0x8e, 0x8a, 0x92, 0x9d, 0x95, 0x95, 0xa1, 0x00, + 0x97, 0x97, 0xa1, 0x8e, 0x98, 0xa0, 0x9d, 0xb3, 0xb7, + 0xe0, 0xb3, 0xcb, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8b, 0x8d, 0x8b, + 0x89, 0x8e, 0x8a, 0x92, 0x9c, 0x94, 0x93, 0x9e, 0x00, + 0x96, 0x95, 0x9f, 0x8d, 0x98, 0xa0, 0x9c, 0xb2, 0xb4, + 0xe9, 0xba, 0xd2, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8a, 0x8c, 0x8b, + 0x89, 0x8d, 0x89, 0x91, 0x9b, 0x94, 0x93, 0x9e, 0x00, + 0x95, 0x94, 0x9e, 0x8c, 0x97, 0x9e, 0x9c, 0xb3, 0xb4, + 0xde, 0xb1, 0xc5, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x95, 0x00, 0xac, 0x00, 0x80, 0x89, 0x8c, 0x8a, + 0x8a, 0x8d, 0x8b, 0x90, 0x99, 0x92, 0x8f, 0x9a, 0x00, + 0x93, 0x93, 0x9e, 0x8c, 0x99, 0x9e, 0x9c, 0xb1, 0xb3, + 0xd9, 0xae, 0xbf, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8c, 0x8a, + 0x89, 0x8b, 0x89, 0x90, 0x98, 0x92, 0x92, 0x9c, 0x00, + 0x95, 0x90, 0x9b, 0x88, 0x98, 0x9e, 0x9c, 0xb1, 0xb1, + 0xdd, 0xb0, 0xc3, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8c, 0x8a, + 0x8a, 0x8b, 0x8a, 0x8e, 0x96, 0x91, 0x92, 0x9b, 0x00, + 0x97, 0x92, 0x9b, 0x8a, 0x92, 0x9d, 0x96, 0xae, 0xae, + 0xdc, 0xb0, 0xc2, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8b, 0x88, + 0x8b, 0x8c, 0x8b, 0x8f, 0x96, 0x92, 0x8f, 0x99, 0x00, + 0x93, 0x91, 0x9b, 0x88, 0x93, 0x9a, 0x98, 0xaf, 0xad, + 0xe0, 0xb3, 0xc6, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x8a, 0x8b, 0x89, + 0x89, 0x8b, 0x87, 0x91, 0x97, 0x94, 0x8b, 0x96, 0x00, + 0x91, 0x90, 0x9b, 0x89, 0x93, 0x9b, 0x95, 0xad, 0xac, + 0xdf, 0xb3, 0xc5, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88, + 0x89, 0x8b, 0x88, 0x90, 0x96, 0x92, 0x8f, 0x98, 0x00, + 0x94, 0x8d, 0x98, 0x87, 0x93, 0x9a, 0x95, 0xad, 0xac, + 0xdf, 0xb3, 0xc5, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88, + 0x8a, 0x8b, 0x88, 0x90, 0x96, 0x92, 0x8c, 0x95, 0x00, + 0x92, 0x8d, 0x98, 0x87, 0x92, 0x9a, 0x93, 0xae, 0xac, + 0xd9, 0xae, 0xbf, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88, + 0x8a, 0x8b, 0x88, 0x8e, 0x93, 0x90, 0x8e, 0x97, 0x00, + 0x93, 0x8d, 0x98, 0x88, 0x92, 0x9a, 0x93, 0xa7, 0xa6, + 0xea, 0xbb, 0xd1, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a, + 0x88, 0x8a, 0x87, 0x8c, 0x93, 0x90, 0x8e, 0x96, 0x00, + 0x93, 0x8a, 0x95, 0x84, 0x90, 0x98, 0x8f, 0xad, 0xab, + 0xdb, 0xb0, 0xc2, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a, + 0x88, 0x8a, 0x87, 0x8d, 0x93, 0x91, 0x8b, 0x93, 0x00, + 0x91, 0x8e, 0x96, 0x88, 0x90, 0x98, 0x8e, 0xa6, 0xa5, + 0xe3, 0xb7, 0xca, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a, + 0x88, 0x8a, 0x87, 0x8d, 0x93, 0x91, 0x8c, 0x93, 0x00, + 0x92, 0x89, 0x94, 0x83, 0x8c, 0x94, 0x8b, 0xab, 0xab, + 0xd2, 0xab, 0xba, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a, + 0x88, 0x8a, 0x87, 0x8c, 0x91, 0x8e, 0x8d, 0x93, 0x00, + 0x92, 0x8c, 0x96, 0x86, 0x91, 0x98, 0x8f, 0xa6, 0xa6, + 0xe7, 0xba, 0xce, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89, + 0x89, 0x8a, 0x88, 0x8d, 0x92, 0x8f, 0x8d, 0x93, 0x00, + 0x92, 0x89, 0x93, 0x83, 0x8f, 0x97, 0x8f, 0xa4, 0xa4, + 0xd7, 0xae, 0xbf, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a, + 0x88, 0x89, 0x87, 0x8d, 0x92, 0x8f, 0x8d, 0x92, 0x00, + 0x92, 0x89, 0x93, 0x83, 0x8c, 0x94, 0x8b, 0xa2, 0xa2, + 0xe7, 0xba, 0xce, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89, + 0x89, 0x8a, 0x88, 0x8d, 0x91, 0x90, 0x89, 0x8f, 0x00, + 0x8f, 0x8c, 0x95, 0x84, 0x8b, 0x94, 0x8a, 0xa2, 0xa0, + 0xe1, 0xb6, 0xc8, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89, + 0x89, 0x8a, 0x88, 0x8e, 0x91, 0x90, 0x89, 0x8f, 0x00, + 0x90, 0x88, 0x91, 0x81, 0x8c, 0x94, 0x8a, 0xa6, 0xa6, + 0xd6, 0xae, 0xbe, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89, + 0x89, 0x8a, 0x88, 0x8d, 0x90, 0x90, 0x89, 0x8f, 0x00, + 0x8f, 0x88, 0x91, 0x81, 0x8c, 0x93, 0x8a, 0xa7, 0xa6, + 0xd1, 0xaa, 0xb8, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89, + 0x89, 0x8a, 0x88, 0x8e, 0x90, 0x90, 0x86, 0x8c, 0x00, + 0x8e, 0x87, 0x90, 0x7f, 0x8f, 0x96, 0x8e, 0xa2, 0xa0, + 0xd6, 0xad, 0xbd, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x88, 0x89, 0x87, 0x8d, 0x8f, 0x8f, 0x88, 0x8d, 0x00, + 0x90, 0x87, 0x90, 0x7f, 0x8f, 0x96, 0x8e, 0xa2, 0xa0, + 0xd6, 0xad, 0xbd, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x89, 0x87, 0x8c, 0x8f, 0x8f, 0x8a, 0x8d, 0x00, + 0x91, 0x88, 0x90, 0x81, 0x8b, 0x93, 0x8a, 0xa1, 0x9e, + 0xcf, 0xa9, 0xb7, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x89, 0x87, 0x8a, 0x8e, 0x8e, 0x89, 0x8c, 0x00, + 0x91, 0x87, 0x8f, 0x7f, 0x90, 0x96, 0x90, 0x99, 0x97, + 0xe0, 0xb5, 0xc8, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x89, 0x87, 0x8b, 0x8e, 0x8f, 0x89, 0x8c, 0x00, + 0x91, 0x87, 0x8f, 0x7f, 0x89, 0x91, 0x88, 0x9f, 0x9e, + 0xda, 0xb1, 0xc2, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x89, 0x87, 0x8b, 0x8e, 0x8f, 0x87, 0x89, 0x00, + 0x8f, 0x87, 0x8d, 0x7e, 0x8f, 0x95, 0x8d, 0x9a, 0x97, + 0xd4, 0xad, 0xbc, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x8a, 0x89, 0x88, 0x8a, 0x8e, 0x8e, 0x88, 0x89, 0x00, + 0x90, 0x81, 0x8a, 0x79, 0x93, 0x98, 0x92, 0x9b, 0x98, + 0xd4, 0xad, 0xbc, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x88, 0x87, 0x89, 0x8d, 0x8d, 0x8a, 0x8b, 0x00, + 0x91, 0x81, 0x8a, 0x79, 0x93, 0x97, 0x92, 0x9b, 0x98, + 0xba, 0x9d, 0xa8, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x88, 0x87, 0x8a, 0x8d, 0x8e, 0x86, 0x88, 0x00, + 0x8e, 0x87, 0x8d, 0x7d, 0x8e, 0x93, 0x8e, 0x94, 0x91, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x88, 0x87, 0x8a, 0x8d, 0x8e, 0x87, 0x88, 0x00, + 0x8f, 0x82, 0x89, 0x79, 0x8d, 0x92, 0x8b, 0x97, 0x95, + 0xdf, 0xb5, 0xc7, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x86, 0x88, 0x00, + 0x8f, 0x82, 0x88, 0x79, 0x8c, 0x92, 0x8b, 0x99, 0x96, + 0xd2, 0xad, 0xbc, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89, + 0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x86, 0x87, 0x00, + 0x8f, 0x82, 0x88, 0x79, 0x8d, 0x92, 0x8c, 0x9b, 0x97, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x89, 0x88, + 0x8a, 0x89, 0x88, 0x8b, 0x8d, 0x8e, 0x86, 0x87, 0x00, + 0x8f, 0x83, 0x88, 0x7a, 0x8e, 0x92, 0x8d, 0x93, 0x8f, + 0xbc, 0xa1, 0xac, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0x9b, 0x00, 0xaf, 0x00, 0x87, 0x88, 0x89, 0x88, + 0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x87, 0x86, 0x00, + 0x8f, 0x83, 0x88, 0x7a, 0x8e, 0x92, 0x8d, 0x94, 0x90, + 0xa1, 0x91, 0x97, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xa0, 0x00, 0xb3, 0x00, 0x8d, 0x89, 0x89, 0x88, + 0x89, 0x88, 0x86, 0x8b, 0x8c, 0x8d, 0x85, 0x85, 0x00, + 0x8d, 0x84, 0x89, 0x7c, 0x8a, 0x8e, 0x89, 0x93, 0x8f, + 0xca, 0xa9, 0xb7, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xa4, 0x00, 0xb6, 0x00, 0x92, 0x88, 0x89, 0x89, + 0x88, 0x87, 0x86, 0x8a, 0x8b, 0x8b, 0x87, 0x86, 0x00, + 0x8c, 0x81, 0x86, 0x79, 0x89, 0x8e, 0x88, 0x9b, 0x98, + 0x81, 0x7d, 0x7d, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xa8, 0x00, 0xba, 0x00, 0x97, 0x88, 0x88, 0x88, + 0x88, 0x87, 0x86, 0x87, 0x8b, 0x8a, 0x8a, 0x88, 0x00, + 0x8f, 0x83, 0x88, 0x7d, 0x87, 0x8c, 0x87, 0x95, 0x91, + 0xa9, 0x95, 0x9d, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xad, 0x00, 0xbe, 0x00, 0x9d, 0x87, 0x88, 0x88, + 0x88, 0x87, 0x86, 0x8a, 0x8b, 0x8c, 0x86, 0x85, 0x00, + 0x89, 0x82, 0x88, 0x7d, 0x87, 0x8b, 0x87, 0x96, 0x91, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xb1, 0x00, 0xc1, 0x00, 0xa2, 0x87, 0x88, 0x88, + 0x88, 0x87, 0x86, 0x87, 0x89, 0x89, 0x87, 0x86, 0x00, + 0x8b, 0x80, 0x85, 0x7b, 0x8c, 0x8f, 0x8c, 0x8f, 0x8c, + 0xc4, 0xa5, 0xb2, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xb7, 0x00, 0xc5, 0x00, 0xa8, 0x86, 0x87, 0x87, + 0x88, 0x86, 0x85, 0x88, 0x89, 0x89, 0x87, 0x86, 0x00, + 0x8a, 0x81, 0x86, 0x7d, 0x8a, 0x8d, 0x88, 0x8f, 0x8c, + 0xb7, 0x9d, 0xa7, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xae, 0x86, 0x87, 0x87, + 0x87, 0x86, 0x85, 0x87, 0x88, 0x87, 0x86, 0x87, 0x00, + 0x8a, 0x80, 0x84, 0x7b, 0x8a, 0x8c, 0x88, 0x90, 0x8d, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xc1, 0x00, 0xcd, 0x00, 0xb4, 0x86, 0x87, 0x87, + 0x87, 0x86, 0x86, 0x86, 0x88, 0x87, 0x87, 0x86, 0x00, + 0x88, 0x82, 0x84, 0x7c, 0x85, 0x89, 0x86, 0x91, 0x8e, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xc6, 0x00, 0xd1, 0x00, 0xba, 0x85, 0x86, 0x86, + 0x86, 0x85, 0x85, 0x85, 0x86, 0x86, 0x88, 0x87, 0x00, + 0x89, 0x82, 0x86, 0x7d, 0x80, 0x86, 0x82, 0x91, 0x8e, + 0xb7, 0x9d, 0xa7, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xca, 0x00, 0xd4, 0x00, 0xbf, 0x86, 0x87, 0x87, + 0x86, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x84, 0x00, + 0x86, 0x82, 0x85, 0x7f, 0x80, 0x86, 0x82, 0x91, 0x8e, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xd0, 0x00, 0xd9, 0x00, 0xc6, 0x84, 0x85, 0x85, + 0x85, 0x84, 0x84, 0x83, 0x85, 0x84, 0x86, 0x85, 0x00, + 0x86, 0x7f, 0x82, 0x7c, 0x87, 0x8a, 0x87, 0x8e, 0x8a, + 0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xd5, 0x00, 0xdd, 0x00, 0xcc, 0x85, 0x86, 0x86, + 0x85, 0x84, 0x84, 0x82, 0x84, 0x83, 0x86, 0x85, 0x00, + 0x85, 0x80, 0x83, 0x7e, 0x83, 0x86, 0x84, 0x8d, 0x89, + 0xa9, 0x95, 0x9d, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd3, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x86, 0x85, 0x00, + 0x85, 0x83, 0x85, 0x7f, 0x7f, 0x84, 0x81, 0x8f, 0x8b, + 0x8f, 0x85, 0x88, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x86, 0x85, 0x00, + 0x85, 0x84, 0x85, 0x80, 0x7f, 0x83, 0x81, 0x8f, 0x8b, + 0x74, 0x75, 0x73, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x83, 0x84, 0x00, + 0x84, 0x82, 0x83, 0x7f, 0x7f, 0x81, 0x80, 0x8e, 0x8a, + 0x85, 0x81, 0x81, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x83, 0x84, 0x00, + 0x84, 0x7f, 0x80, 0x7b, 0x83, 0x85, 0x85, 0x87, 0x84, + 0xa5, 0x94, 0x9c, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x82, 0x83, 0x83, 0x82, 0x82, 0x00, + 0x83, 0x82, 0x82, 0x7e, 0x82, 0x85, 0x85, 0x89, 0x85, + 0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x82, 0x83, 0x83, 0x83, 0x82, 0x00, + 0x84, 0x81, 0x82, 0x7d, 0x83, 0x85, 0x85, 0x86, 0x86, + 0x97, 0x8c, 0x91, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84, + 0x82, 0x82, 0x82, 0x83, 0x84, 0x84, 0x84, 0x82, 0x00, + 0x84, 0x82, 0x82, 0x7e, 0x7e, 0x80, 0x80, 0x8d, 0x8b, + 0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x83, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x82, 0x82, 0x00, + 0x85, 0x82, 0x82, 0x7e, 0x84, 0x85, 0x85, 0x8b, 0x8a, + 0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xe0, 0x00, 0xe6, 0x00, 0xda, 0x83, 0x83, 0x83, + 0x83, 0x82, 0x82, 0x83, 0x83, 0x83, 0x82, 0x81, 0x00, + 0x84, 0x83, 0x83, 0x80, 0x81, 0x81, 0x81, 0x8b, 0x8a, + 0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xe6, 0x00, 0xeb, 0x00, 0xe1, 0x82, 0x83, 0x83, + 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x00, + 0x83, 0x84, 0x84, 0x82, 0x83, 0x83, 0x83, 0x86, 0x85, + 0x89, 0x84, 0x86, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xec, 0x00, 0xf0, 0x00, 0xe8, 0x82, 0x83, 0x83, + 0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x82, 0x82, 0x00, + 0x83, 0x81, 0x81, 0x80, 0x83, 0x83, 0x83, 0x86, 0x85, + 0x89, 0x84, 0x86, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xee, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x80, 0x00, + 0x82, 0x81, 0x81, 0x80, 0x83, 0x83, 0x83, 0x86, 0x85, + 0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x00, 0xf6, 0x00, 0xf8, 0x00, 0xf4, 0x82, 0x82, 0x82, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x81, 0x82, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x86, 0x85, + 0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 }, + { MCS_GAMMA, + 0x01, 0x00, 0x01, 0x00, 0x01, 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, 0x00, 0x00, 0x00 } +}; + +/* ELVSS (Amoled negative power supply) tables */ +#define EA8061V_AMS497EE01_NUM_ELVSS_SEQUENCES 18 +#define ELVSS_SEQUENCE_LEN 3 +static const u8 seq_ea8061v_ams497ee01_elvss[EA8061V_AMS497EE01_NUM_ELVSS_SEQUENCES][ELVSS_SEQUENCE_LEN] = { + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x9b }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x9a }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x99 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x98 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x97 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x96 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x95 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x94 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x93 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x92 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x91 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x90 }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8f }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8e }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8d }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8c }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8b }, + { MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8a } +}; + +#define EA8061V_AMS497EE01_NUM_AID_LEVELS 42 +#define EA8061V_AMS497EE01_AID_CMD_CNT 5 +/* Which AID sequence to use for each candela level. + */ +static const u8 map_candela_to_aid[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 41, 41, + 41, 41 +}; + +static const u8 seq_ea8061v_ams497ee01_aid[EA8061V_AMS497EE01_NUM_AID_LEVELS][EA8061V_AMS497EE01_AID_CMD_CNT] = { + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xdf }, /* 95.63 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xd3 }, /* 94.71 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xc7 }, /* 93.79 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xbb }, /* 92.87 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xb0 }, /* 92.02 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xa4 }, /* 91.10 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x99 }, /* 90.26 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x8d }, /* 89.34 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x82 }, /* 88.50 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x76 }, /* 87.58 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x6a }, /* 86.66 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x5f }, /* 85.81 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x52 }, /* 84.82 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x3b }, /* 83.05 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x31 }, /* 82.29 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x25 }, /* 81.37 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x18 }, /* 80.37 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x01 }, /* 78.60 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xf5 }, /* 77.68 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xdb }, /* 75.69 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xc5 }, /* 74.00 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xb7 }, /* 72.93 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x9e }, /* 71.01 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x88 }, /* 69.33 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x64 }, /* 66.56 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x4b }, /* 64.64 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x32 }, /* 62.73 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x0d }, /* 59.89 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0xe7 }, /* 56.98 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0xc2 }, /* 54.14 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x9d }, /* 51.30 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x79 }, /* 48.54 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x45 }, /* 44.56 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x13 }, /* 40.72 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0xe7 }, /* 37.35 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0xae }, /* 32.98 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0x76 }, /* 28.68 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0x39 }, /* 24.00 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0xf8 }, /* 19.02 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0xb4 }, /* 13.80 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0x63 }, /* 7.59 % */ + { MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0x0a } /* 0.77 % */ +}; + +struct ea8061v_ams497ee01 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + + struct backlight_device *bl_dev; + + struct regulator_bulk_data supplies[2]; + struct gpio_desc *reset_gpio; + + bool prepared; + bool enabled; +}; + +static inline +struct ea8061v_ams497ee01 *to_ea8061v_ams497ee01(struct drm_panel *panel) +{ + return container_of(panel, struct ea8061v_ams497ee01, panel); +} + +static int ea8061v_ams497ee01_unlock(struct ea8061v_ams497ee01 *ctx, u8 lock) +{ + switch (lock) { + case 0xf0: + mipi_dsi_dcs_write_seq(ctx->dsi, 0xf0, 0x5a, 0x5a); + break; + case 0xf1: + mipi_dsi_dcs_write_seq(ctx->dsi, 0xf1, 0x5a, 0x5a); + break; + case 0xfc: + mipi_dsi_dcs_write_seq(ctx->dsi, 0xfc, 0x5a, 0x5a); + break; + default: + return -EINVAL; + } + return 0; +} + +static int ea8061v_ams497ee01_lock(struct ea8061v_ams497ee01 *ctx, u8 lock) +{ + switch (lock) { + case 0xf0: + mipi_dsi_dcs_write_seq(ctx->dsi, 0xf0, 0xa5, 0xa5); + break; + case 0xf1: + mipi_dsi_dcs_write_seq(ctx->dsi, 0xf1, 0xa5, 0xa5); + break; + case 0xfc: + mipi_dsi_dcs_write_seq(ctx->dsi, 0xfc, 0xa5, 0xa5); + break; + default: + return -EINVAL; + } + return 0; +} + +static int ea8061v_ams497ee01_apply_gamma(struct ea8061v_ams497ee01 *ctx) +{ + mipi_dsi_dcs_write_seq(ctx->dsi, MCS_GAMMA_UPDATE, 0x01); + return 0; +} + +static int ea8061v_ams497ee01_update_aid(struct ea8061v_ams497ee01 *ctx, + unsigned int brightness) +{ + int ret; + int index = map_candela_to_aid[brightness]; + + ret = mipi_dsi_dcs_write_buffer(ctx->dsi, + seq_ea8061v_ams497ee01_aid[index], + EA8061V_AMS497EE01_AID_CMD_CNT); + if (ret < 0) + return ret; + return 0; +} + +static int ea8061v_ams497ee01_update_elvss(struct ea8061v_ams497ee01 *ctx, + unsigned int brightness) +{ + int ret; + int index = map_candela_to_elvss[brightness]; + + ret = mipi_dsi_dcs_write_buffer(ctx->dsi, + seq_ea8061v_ams497ee01_elvss[index], + ELVSS_SEQUENCE_LEN); + if (ret < 0) + return ret; + return 0; +} + +static int ea8061v_ams497ee01_update_gamma(struct ea8061v_ams497ee01 *ctx, + unsigned int brightness) +{ + int ret; + struct backlight_device *bl_dev = ctx->bl_dev; + + ret = mipi_dsi_dcs_write_buffer(ctx->dsi, + seq_ea8061v_ams497ee01_lux[brightness], + EA8061V_AMS497EE01_GAMMA_CMD_CNT); + if (ret < 0) + return ret; + + bl_dev->props.brightness = brightness; + + return 0; +} + +static int ea8061v_ams497ee01_set_brightness(struct backlight_device *bl_dev) +{ + struct ea8061v_ams497ee01 *ctx = bl_get_data(bl_dev); + unsigned int brightness = bl_dev->props.brightness; + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + ret = ea8061v_ams497ee01_unlock(ctx, 0xf0); + if (ret < 0) { + dev_err(dev, "Failed to unlock 0xf0: %d\n", ret); + return ret; + } + ret = ea8061v_ams497ee01_unlock(ctx, 0xf1); + if (ret < 0) { + dev_err(dev, "Failed to unlock 0xf1: %d\n", ret); + return ret; + } + + /* aid/aor */ + ret = ea8061v_ams497ee01_update_aid(ctx, brightness); + if (ret < 0) { + dev_err(dev, "Failed to send aid sequence: %d\n", ret); + return ret; + } + mipi_dsi_dcs_write_seq(dsi, MCS_ACL_OPR_CONTROL, 0x29); + mipi_dsi_dcs_write_seq(dsi, MCS_ACL_CONTROL, 0x00); + + ret = ea8061v_ams497ee01_update_elvss(ctx, brightness); + if (ret < 0) { + dev_err(dev, "Failed to update elvss: %d\n", ret); + return ret; + } + + ret = ea8061v_ams497ee01_update_gamma(ctx, brightness); + if (ret < 0) { + dev_err(dev, "Failed to update gamma: %d\n", ret); + return ret; + } + + ret = ea8061v_ams497ee01_apply_gamma(ctx); + if (ret < 0) { + dev_err(dev, "Failed to apply gamma update: %d\n", ret); + return ret; + } + + ea8061v_ams497ee01_lock(ctx, 0xf1); + if (ret < 0) { + dev_err(dev, "Failed to lock 0xf1: %d\n", ret); + return ret; + } + ea8061v_ams497ee01_lock(ctx, 0xf0); + if (ret < 0) { + dev_err(dev, "Failed to lock 0xf0: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct backlight_ops ea8061v_ams497ee01_bl_ops = { + .update_status = ea8061v_ams497ee01_set_brightness, +}; + +static int ea8061v_ams497ee01_init(struct ea8061v_ams497ee01 *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + unsigned int brightness = ctx->bl_dev->props.brightness; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + ret = ea8061v_ams497ee01_unlock(ctx, 0xf0); + if (ret < 0) { + dev_err(dev, "Failed to unlock 0xf0: %d\n", ret); + return ret; + } + ret = ea8061v_ams497ee01_unlock(ctx, 0xf1); + if (ret < 0) { + dev_err(dev, "Failed to unlock 0xf1: %d\n", ret); + return ret; + } + + /* Common conditions */ + /* set ref temperature/voltage (0x19 = 25 degC, 0x10 = 7.6 V) */ + mipi_dsi_dcs_write_seq(dsi, MCS_TSET, 0x19, 0x10); + /* ? */ + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x57); + + ret = ea8061v_ams497ee01_unlock(ctx, 0xfc); + if (ret < 0) { + dev_err(dev, "Failed to unlock 0xfc: %d\n", ret); + return ret; + } + + /* skip 11 parameters in HBM sequence? */ + mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x0b); + /* ? */ + mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x00, 0x85); + /* ? */ + mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x70); + + ret = ea8061v_ams497ee01_lock(ctx, 0xfc); + if (ret < 0) { + dev_err(dev, "Failed to lock 0xfc: %d\n", ret); + return ret; + } + /* Brightness control */ + ret = ea8061v_ams497ee01_update_gamma(ctx, brightness); + if (ret < 0) { + dev_err(dev, "Failed to update gamma: %d\n", ret); + return ret; + } + ret = ea8061v_ams497ee01_update_aid(ctx, brightness); + if (ret < 0) { + dev_err(dev, "Failed to send aid sequence: %d\n", ret); + return ret; + } + ret = ea8061v_ams497ee01_update_elvss(ctx, brightness); + if (ret < 0) { + dev_err(dev, "Failed to update elvss: %d\n", ret); + return ret; + } + ret = ea8061v_ams497ee01_apply_gamma(ctx); + if (ret < 0) { + dev_err(dev, "Failed to apply gamma update: %d\n", ret); + return ret; + } + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(120); + + ret = ea8061v_ams497ee01_lock(ctx, 0xf1); + if (ret < 0) { + dev_err(dev, "Failed to lock 0xf1: %d\n", ret); + return ret; + } + // ret = ea8061v_ams497ee01_lock(ctx, 0xf0); + // if (ret < 0) { + // dev_err(dev, "Failed to lock 0xf0: %d\n", ret); + // return ret; + // } + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display on: %d\n", ret); + return ret; + } + + return 0; +} + +static int ea8061v_ams497ee01_power_on(struct ea8061v_ams497ee01 *ctx) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(&ctx->dsi->dev, + "Failed to enable regulators: %d\n", ret); + return ret; + } + + /* send reset pulse */ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(20); + + return 0; +} + +static int ea8061v_ams497ee01_power_off(struct ea8061v_ams497ee01 *ctx) +{ + int ret; + + gpiod_set_value(ctx->reset_gpio, 1); + + ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + return ret; + + return 0; +} + +static int ea8061v_ams497ee01_enable(struct drm_panel *panel) +{ + struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + int ret; + + if (ctx->prepared) + return 0; + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + }; + msleep(120); + + backlight_enable(ctx->bl_dev); + + ctx->enabled = true; + return 0; +} + + +static int ea8061v_ams497ee01_disable(struct drm_panel *panel) +{ + struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + int ret; + + if (!ctx->enabled) + return 0; + + backlight_disable(ctx->bl_dev); + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to set display off: %d\n", ret); + return ret; + } + msleep(35); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(&dsi->dev, "Failed to enter sleep mode: %d\n", ret); + return ret; + } + msleep(100); + + ctx->enabled = false; + return 0; +} + +static int ea8061v_ams497ee01_prepare(struct drm_panel *panel) +{ + struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + if (ctx->prepared) + return 0; + + ret = ea8061v_ams497ee01_power_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to power on panel: %d\n", ret); + return ret; + } + + ret = ea8061v_ams497ee01_init(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + ea8061v_ams497ee01_power_off(ctx); + return ret; + } + + ctx->prepared = true; + return 0; +} + +static int ea8061v_ams497ee01_unprepare(struct drm_panel *panel) +{ + struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + if (!ctx->prepared) + return 0; + + ret = ea8061v_ams497ee01_power_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + ctx->prepared = false; + return 0; +} + +static const struct drm_display_mode ea8061v_ams497ee01_mode = { + .clock = (720 + 80 + 96 + 128) * (1280 + 14 + 2 + 8) * 60 / 1000, + .hdisplay = 720, + .hsync_start = 720 + 80, + .hsync_end = 720 + 80 + 96, + .htotal = 720 + 80 + 96 + 128, + .vdisplay = 1280, + .vsync_start = 1280 + 14, + .vsync_end = 1280 + 14 + 2, + .vtotal = 1280 + 14 + 2 + 8, + .width_mm = 62, + .height_mm = 110, +}; + +static int ea8061v_ams497ee01_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &ea8061v_ams497ee01_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs ea8061v_ams497ee01_panel_funcs = { + .prepare = ea8061v_ams497ee01_prepare, + .enable = ea8061v_ams497ee01_enable, + .disable = ea8061v_ams497ee01_disable, + .unprepare = ea8061v_ams497ee01_unprepare, + .get_modes = ea8061v_ams497ee01_get_modes, +}; + +static int ea8061v_ams497ee01_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct ea8061v_ams497ee01 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->supplies[0].supply = "vdd3"; + ctx->supplies[1].supply = "vci"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->bl_dev = backlight_device_register("panel", dev, ctx, + &ea8061v_ams497ee01_bl_ops, + NULL); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_NO_EOT_PACKET; + + if (IS_ERR(ctx->bl_dev)) { + dev_err(dev, "Failed to register backlight device\n"); + return PTR_ERR(ctx->bl_dev); + } + + ctx->bl_dev->props.max_brightness = EA8061V_AMS497EE01_MAX_BRIGHTNESS; + ctx->bl_dev->props.brightness = EA8061V_AMS497EE01_DEFAULT_BRIGHTNESS; + ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; + + drm_panel_init(&ctx->panel, dev, &ea8061v_ams497ee01_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void ea8061v_ams497ee01_remove(struct mipi_dsi_device *dsi) +{ + struct ea8061v_ams497ee01 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, + "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id ea8061v_ams497ee01_of_match[] = { + { .compatible = "samsung,ea8061v-ams497ee01" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ea8061v_ams497ee01_of_match); + +static struct mipi_dsi_driver ea8061v_ams497ee01_driver = { + .probe = ea8061v_ams497ee01_probe, + .remove = ea8061v_ams497ee01_remove, + .driver = { + .name = "panel-ea8061v-ams497ee01", + .of_match_table = ea8061v_ams497ee01_of_match, + }, +}; +module_mipi_dsi_driver(ea8061v_ams497ee01_driver); + +MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator "); // FIXME +MODULE_DESCRIPTION("DRM driver for ss_dsi_panel_EA8061V_AMS497EE01_HD"); +MODULE_LICENSE("GPL");