Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1/*
   2 * MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver.
   3 *
   4 * Copyright (c) 2013 Samsung Electronics Co., Ltd
   5 *
   6 * Inki Dae, <inki.dae@samsung.com>
   7 * Donghwa Lee, <dh09.lee@samsung.com>
   8 * Joongmock Shin <jmock.shin@samsung.com>
   9 * Eunchul Kim <chulspro.kim@samsung.com>
  10 * Tomasz Figa <t.figa@samsung.com>
  11 * Andrzej Hajda <a.hajda@samsung.com>
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License version 2 as
  15 * published by the Free Software Foundation.
  16*/
  17
  18#include <drm/drmP.h>
  19#include <drm/drm_mipi_dsi.h>
  20#include <drm/drm_panel.h>
  21
  22#include <linux/gpio/consumer.h>
  23#include <linux/regulator/consumer.h>
  24
  25#include <video/mipi_display.h>
  26#include <video/of_videomode.h>
  27#include <video/videomode.h>
  28
  29#define LDI_MTP_LENGTH			24
  30#define GAMMA_LEVEL_NUM			25
  31#define GAMMA_TABLE_LEN			26
  32
  33#define PANELCTL_SS_MASK		(1 << 5)
  34#define PANELCTL_SS_1_800		(0 << 5)
  35#define PANELCTL_SS_800_1		(1 << 5)
  36#define PANELCTL_GTCON_MASK		(7 << 2)
  37#define PANELCTL_GTCON_110		(6 << 2)
  38#define PANELCTL_GTCON_111		(7 << 2)
  39
  40#define PANELCTL_CLK1_CON_MASK		(7 << 3)
  41#define PANELCTL_CLK1_000		(0 << 3)
  42#define PANELCTL_CLK1_001		(1 << 3)
  43#define PANELCTL_CLK2_CON_MASK		(7 << 0)
  44#define PANELCTL_CLK2_000		(0 << 0)
  45#define PANELCTL_CLK2_001		(1 << 0)
  46
  47#define PANELCTL_INT1_CON_MASK		(7 << 3)
  48#define PANELCTL_INT1_000		(0 << 3)
  49#define PANELCTL_INT1_001		(1 << 3)
  50#define PANELCTL_INT2_CON_MASK		(7 << 0)
  51#define PANELCTL_INT2_000		(0 << 0)
  52#define PANELCTL_INT2_001		(1 << 0)
  53
  54#define PANELCTL_BICTL_CON_MASK		(7 << 3)
  55#define PANELCTL_BICTL_000		(0 << 3)
  56#define PANELCTL_BICTL_001		(1 << 3)
  57#define PANELCTL_BICTLB_CON_MASK	(7 << 0)
  58#define PANELCTL_BICTLB_000		(0 << 0)
  59#define PANELCTL_BICTLB_001		(1 << 0)
  60
  61#define PANELCTL_EM_CLK1_CON_MASK	(7 << 3)
  62#define PANELCTL_EM_CLK1_110		(6 << 3)
  63#define PANELCTL_EM_CLK1_111		(7 << 3)
  64#define PANELCTL_EM_CLK1B_CON_MASK	(7 << 0)
  65#define PANELCTL_EM_CLK1B_110		(6 << 0)
  66#define PANELCTL_EM_CLK1B_111		(7 << 0)
  67
  68#define PANELCTL_EM_CLK2_CON_MASK	(7 << 3)
  69#define PANELCTL_EM_CLK2_110		(6 << 3)
  70#define PANELCTL_EM_CLK2_111		(7 << 3)
  71#define PANELCTL_EM_CLK2B_CON_MASK	(7 << 0)
  72#define PANELCTL_EM_CLK2B_110		(6 << 0)
  73#define PANELCTL_EM_CLK2B_111		(7 << 0)
  74
  75#define PANELCTL_EM_INT1_CON_MASK	(7 << 3)
  76#define PANELCTL_EM_INT1_000		(0 << 3)
  77#define PANELCTL_EM_INT1_001		(1 << 3)
  78#define PANELCTL_EM_INT2_CON_MASK	(7 << 0)
  79#define PANELCTL_EM_INT2_000		(0 << 0)
  80#define PANELCTL_EM_INT2_001		(1 << 0)
  81
  82#define AID_DISABLE			(0x4)
  83#define AID_1				(0x5)
  84#define AID_2				(0x6)
  85#define AID_3				(0x7)
  86
  87typedef u8 s6e8aa0_gamma_table[GAMMA_TABLE_LEN];
  88
  89struct s6e8aa0_variant {
  90	u8 version;
  91	const s6e8aa0_gamma_table *gamma_tables;
  92};
  93
  94struct s6e8aa0 {
  95	struct device *dev;
  96	struct drm_panel panel;
  97
  98	struct regulator_bulk_data supplies[2];
  99	struct gpio_desc *reset_gpio;
 100	u32 power_on_delay;
 101	u32 reset_delay;
 102	u32 init_delay;
 103	bool flip_horizontal;
 104	bool flip_vertical;
 105	struct videomode vm;
 106	u32 width_mm;
 107	u32 height_mm;
 108
 109	u8 version;
 110	u8 id;
 111	const struct s6e8aa0_variant *variant;
 112	int brightness;
 113
 114	/* This field is tested by functions directly accessing DSI bus before
 115	 * transfer, transfer is skipped if it is set. In case of transfer
 116	 * failure or unexpected response the field is set to error value.
 117	 * Such construct allows to eliminate many checks in higher level
 118	 * functions.
 119	 */
 120	int error;
 121};
 122
 123#define panel_to_s6e8aa0(p) container_of(p, struct s6e8aa0, panel)
 124
 125static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
 126{
 127	int ret = ctx->error;
 128
 129	ctx->error = 0;
 130	return ret;
 131}
 132
 133static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
 134{
 135	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 136	int ret;
 137
 138	if (ctx->error < 0)
 139		return;
 140
 141	ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len);
 142	if (ret < 0) {
 143		dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
 144			data);
 145		ctx->error = ret;
 146	}
 147}
 148
 149static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len)
 150{
 151	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 152	int ret;
 153
 154	if (ctx->error < 0)
 155		return ctx->error;
 156
 157	ret = mipi_dsi_dcs_read(dsi, dsi->channel, cmd, data, len);
 158	if (ret < 0) {
 159		dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd);
 160		ctx->error = ret;
 161	}
 162
 163	return ret;
 164}
 165
 166#define s6e8aa0_dcs_write_seq(ctx, seq...) \
 167({\
 168	const u8 d[] = { seq };\
 169	BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
 170	s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
 171})
 172
 173#define s6e8aa0_dcs_write_seq_static(ctx, seq...) \
 174({\
 175	static const u8 d[] = { seq };\
 176	s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
 177})
 178
 179static void s6e8aa0_apply_level_1_key(struct s6e8aa0 *ctx)
 180{
 181	s6e8aa0_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
 182}
 183
 184static void s6e8aa0_panel_cond_set_v142(struct s6e8aa0 *ctx)
 185{
 186	static const u8 aids[] = {
 187		0x04, 0x04, 0x04, 0x04, 0x04, 0x60, 0x80, 0xA0
 188	};
 189	u8 aid = aids[ctx->id >> 5];
 190	u8 cfg = 0x3d;
 191	u8 clk_con = 0xc8;
 192	u8 int_con = 0x08;
 193	u8 bictl_con = 0x48;
 194	u8 em_clk1_con = 0xff;
 195	u8 em_clk2_con = 0xff;
 196	u8 em_int_con = 0xc8;
 197
 198	if (ctx->flip_vertical) {
 199		/* GTCON */
 200		cfg &= ~(PANELCTL_GTCON_MASK);
 201		cfg |= (PANELCTL_GTCON_110);
 202	}
 203
 204	if (ctx->flip_horizontal) {
 205		/* SS */
 206		cfg &= ~(PANELCTL_SS_MASK);
 207		cfg |= (PANELCTL_SS_1_800);
 208	}
 209
 210	if (ctx->flip_horizontal || ctx->flip_vertical) {
 211		/* CLK1,2_CON */
 212		clk_con &= ~(PANELCTL_CLK1_CON_MASK |
 213			PANELCTL_CLK2_CON_MASK);
 214		clk_con |= (PANELCTL_CLK1_000 | PANELCTL_CLK2_001);
 215
 216		/* INT1,2_CON */
 217		int_con &= ~(PANELCTL_INT1_CON_MASK |
 218			PANELCTL_INT2_CON_MASK);
 219		int_con |= (PANELCTL_INT1_000 | PANELCTL_INT2_001);
 220
 221		/* BICTL,B_CON */
 222		bictl_con &= ~(PANELCTL_BICTL_CON_MASK |
 223			PANELCTL_BICTLB_CON_MASK);
 224		bictl_con |= (PANELCTL_BICTL_000 |
 225			PANELCTL_BICTLB_001);
 226
 227		/* EM_CLK1,1B_CON */
 228		em_clk1_con &= ~(PANELCTL_EM_CLK1_CON_MASK |
 229			PANELCTL_EM_CLK1B_CON_MASK);
 230		em_clk1_con |= (PANELCTL_EM_CLK1_110 |
 231			PANELCTL_EM_CLK1B_110);
 232
 233		/* EM_CLK2,2B_CON */
 234		em_clk2_con &= ~(PANELCTL_EM_CLK2_CON_MASK |
 235			PANELCTL_EM_CLK2B_CON_MASK);
 236		em_clk2_con |= (PANELCTL_EM_CLK2_110 |
 237			PANELCTL_EM_CLK2B_110);
 238
 239		/* EM_INT1,2_CON */
 240		em_int_con &= ~(PANELCTL_EM_INT1_CON_MASK |
 241			PANELCTL_EM_INT2_CON_MASK);
 242		em_int_con |= (PANELCTL_EM_INT1_000 |
 243			PANELCTL_EM_INT2_001);
 244	}
 245
 246	s6e8aa0_dcs_write_seq(ctx,
 247		0xf8, cfg, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00,
 248		0x3c, 0x78, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00,
 249		0x00, 0x20, aid, 0x08, 0x6e, 0x00, 0x00, 0x00,
 250		0x02, 0x07, 0x07, 0x23, 0x23, 0xc0, clk_con, int_con,
 251		bictl_con, 0xc1, 0x00, 0xc1, em_clk1_con, em_clk2_con,
 252		em_int_con);
 253}
 254
 255static void s6e8aa0_panel_cond_set(struct s6e8aa0 *ctx)
 256{
 257	if (ctx->version < 142)
 258		s6e8aa0_dcs_write_seq_static(ctx,
 259			0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x94, 0x00,
 260			0x3c, 0x78, 0x10, 0x27, 0x08, 0x6e, 0x00, 0x00,
 261			0x00, 0x00, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00,
 262			0x00, 0x07, 0x07, 0x23, 0x6e, 0xc0, 0xc1, 0x01,
 263			0x81, 0xc1, 0x00, 0xc3, 0xf6, 0xf6, 0xc1
 264		);
 265	else
 266		s6e8aa0_panel_cond_set_v142(ctx);
 267}
 268
 269static void s6e8aa0_display_condition_set(struct s6e8aa0 *ctx)
 270{
 271	s6e8aa0_dcs_write_seq_static(ctx, 0xf2, 0x80, 0x03, 0x0d);
 272}
 273
 274static void s6e8aa0_etc_source_control(struct s6e8aa0 *ctx)
 275{
 276	s6e8aa0_dcs_write_seq_static(ctx, 0xf6, 0x00, 0x02, 0x00);
 277}
 278
 279static void s6e8aa0_etc_pentile_control(struct s6e8aa0 *ctx)
 280{
 281	static const u8 pent32[] = {
 282		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xc0, 0x44, 0x44, 0xc0, 0x00
 283	};
 284
 285	static const u8 pent142[] = {
 286		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, 0x00
 287	};
 288
 289	if (ctx->version < 142)
 290		s6e8aa0_dcs_write(ctx, pent32, ARRAY_SIZE(pent32));
 291	else
 292		s6e8aa0_dcs_write(ctx, pent142, ARRAY_SIZE(pent142));
 293}
 294
 295static void s6e8aa0_etc_power_control(struct s6e8aa0 *ctx)
 296{
 297	static const u8 pwr142[] = {
 298		0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02
 299	};
 300
 301	static const u8 pwr32[] = {
 302		0xf4, 0xcf, 0x0a, 0x15, 0x10, 0x19, 0x33, 0x02
 303	};
 304
 305	if (ctx->version < 142)
 306		s6e8aa0_dcs_write(ctx, pwr32, ARRAY_SIZE(pwr32));
 307	else
 308		s6e8aa0_dcs_write(ctx, pwr142, ARRAY_SIZE(pwr142));
 309}
 310
 311static void s6e8aa0_etc_elvss_control(struct s6e8aa0 *ctx)
 312{
 313	u8 id = ctx->id ? 0 : 0x95;
 314
 315	s6e8aa0_dcs_write_seq(ctx, 0xb1, 0x04, id);
 316}
 317
 318static void s6e8aa0_elvss_nvm_set_v142(struct s6e8aa0 *ctx)
 319{
 320	u8 br;
 321
 322	switch (ctx->brightness) {
 323	case 0 ... 6: /* 30cd ~ 100cd */
 324		br = 0xdf;
 325		break;
 326	case 7 ... 11: /* 120cd ~ 150cd */
 327		br = 0xdd;
 328		break;
 329	case 12 ... 15: /* 180cd ~ 210cd */
 330	default:
 331		br = 0xd9;
 332		break;
 333	case 16 ... 24: /* 240cd ~ 300cd */
 334		br = 0xd0;
 335		break;
 336	}
 337
 338	s6e8aa0_dcs_write_seq(ctx, 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e,
 339		0xc4, 0x0f, 0x40, 0x41, br, 0x00, 0x60, 0x19);
 340}
 341
 342static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *ctx)
 343{
 344	if (ctx->version < 142)
 345		s6e8aa0_dcs_write_seq_static(ctx,
 346			0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x07,
 347			0x40, 0x41, 0xc1, 0x00, 0x60, 0x19);
 348	else
 349		s6e8aa0_elvss_nvm_set_v142(ctx);
 350};
 351
 352static void s6e8aa0_apply_level_2_key(struct s6e8aa0 *ctx)
 353{
 354	s6e8aa0_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
 355}
 356
 357static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v142[GAMMA_LEVEL_NUM] = {
 358	{
 359		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x62, 0x55, 0x55,
 360		0xaf, 0xb1, 0xb1, 0xbd, 0xce, 0xb7, 0x9a, 0xb1,
 361		0x90, 0xb2, 0xc4, 0xae, 0x00, 0x60, 0x00, 0x40,
 362		0x00, 0x70,
 363	}, {
 364		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x74, 0x68, 0x69,
 365		0xb8, 0xc1, 0xb7, 0xbd, 0xcd, 0xb8, 0x93, 0xab,
 366		0x88, 0xb4, 0xc4, 0xb1, 0x00, 0x6b, 0x00, 0x4d,
 367		0x00, 0x7d,
 368	}, {
 369		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x95, 0x8a, 0x89,
 370		0xb4, 0xc6, 0xb2, 0xc5, 0xd2, 0xbf, 0x90, 0xa8,
 371		0x85, 0xb5, 0xc4, 0xb3, 0x00, 0x7b, 0x00, 0x5d,
 372		0x00, 0x8f,
 373	}, {
 374		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9f, 0x98, 0x92,
 375		0xb3, 0xc4, 0xb0, 0xbc, 0xcc, 0xb4, 0x91, 0xa6,
 376		0x87, 0xb5, 0xc5, 0xb4, 0x00, 0x87, 0x00, 0x6a,
 377		0x00, 0x9e,
 378	}, {
 379		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x99, 0x93, 0x8b,
 380		0xb2, 0xc2, 0xb0, 0xbd, 0xce, 0xb4, 0x90, 0xa6,
 381		0x87, 0xb3, 0xc3, 0xb2, 0x00, 0x8d, 0x00, 0x70,
 382		0x00, 0xa4,
 383	}, {
 384		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xa5, 0x99,
 385		0xb2, 0xc2, 0xb0, 0xbb, 0xcd, 0xb1, 0x93, 0xa7,
 386		0x8a, 0xb2, 0xc1, 0xb0, 0x00, 0x92, 0x00, 0x75,
 387		0x00, 0xaa,
 388	}, {
 389		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xa0, 0x93,
 390		0xb6, 0xc4, 0xb4, 0xb5, 0xc8, 0xaa, 0x94, 0xa9,
 391		0x8c, 0xb2, 0xc0, 0xb0, 0x00, 0x97, 0x00, 0x7a,
 392		0x00, 0xaf,
 393	}, {
 394		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xa7, 0x96,
 395		0xb3, 0xc2, 0xb0, 0xba, 0xcb, 0xb0, 0x94, 0xa8,
 396		0x8c, 0xb0, 0xbf, 0xaf, 0x00, 0x9f, 0x00, 0x83,
 397		0x00, 0xb9,
 398	}, {
 399		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9d, 0xa2, 0x90,
 400		0xb6, 0xc5, 0xb3, 0xb8, 0xc9, 0xae, 0x94, 0xa8,
 401		0x8d, 0xaf, 0xbd, 0xad, 0x00, 0xa4, 0x00, 0x88,
 402		0x00, 0xbf,
 403	}, {
 404		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xac, 0x97,
 405		0xb4, 0xc4, 0xb1, 0xbb, 0xcb, 0xb2, 0x93, 0xa7,
 406		0x8d, 0xae, 0xbc, 0xad, 0x00, 0xa7, 0x00, 0x8c,
 407		0x00, 0xc3,
 408	}, {
 409		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa2, 0xa9, 0x93,
 410		0xb6, 0xc5, 0xb2, 0xba, 0xc9, 0xb0, 0x93, 0xa7,
 411		0x8d, 0xae, 0xbb, 0xac, 0x00, 0xab, 0x00, 0x90,
 412		0x00, 0xc8,
 413	}, {
 414		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9e, 0xa6, 0x8f,
 415		0xb7, 0xc6, 0xb3, 0xb8, 0xc8, 0xb0, 0x93, 0xa6,
 416		0x8c, 0xae, 0xbb, 0xad, 0x00, 0xae, 0x00, 0x93,
 417		0x00, 0xcc,
 418	}, {
 419		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb4, 0x9c,
 420		0xb3, 0xc3, 0xaf, 0xb7, 0xc7, 0xaf, 0x93, 0xa6,
 421		0x8c, 0xaf, 0xbc, 0xad, 0x00, 0xb1, 0x00, 0x97,
 422		0x00, 0xcf,
 423	}, {
 424		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xb1, 0x98,
 425		0xb1, 0xc2, 0xab, 0xba, 0xc9, 0xb2, 0x93, 0xa6,
 426		0x8d, 0xae, 0xba, 0xab, 0x00, 0xb5, 0x00, 0x9b,
 427		0x00, 0xd4,
 428	}, {
 429		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xae, 0x94,
 430		0xb2, 0xc3, 0xac, 0xbb, 0xca, 0xb4, 0x91, 0xa4,
 431		0x8a, 0xae, 0xba, 0xac, 0x00, 0xb8, 0x00, 0x9e,
 432		0x00, 0xd8,
 433	}, {
 434		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb7, 0x9c,
 435		0xae, 0xc0, 0xa9, 0xba, 0xc9, 0xb3, 0x92, 0xa5,
 436		0x8b, 0xad, 0xb9, 0xab, 0x00, 0xbb, 0x00, 0xa1,
 437		0x00, 0xdc,
 438	}, {
 439		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb4, 0x97,
 440		0xb0, 0xc1, 0xaa, 0xb9, 0xc8, 0xb2, 0x92, 0xa5,
 441		0x8c, 0xae, 0xb9, 0xab, 0x00, 0xbe, 0x00, 0xa4,
 442		0x00, 0xdf,
 443	}, {
 444		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
 445		0xb0, 0xc2, 0xab, 0xbb, 0xc9, 0xb3, 0x91, 0xa4,
 446		0x8b, 0xad, 0xb8, 0xaa, 0x00, 0xc1, 0x00, 0xa8,
 447		0x00, 0xe2,
 448	}, {
 449		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
 450		0xae, 0xbf, 0xa8, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
 451		0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xc4, 0x00, 0xab,
 452		0x00, 0xe6,
 453	}, {
 454		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb6, 0x98,
 455		0xaf, 0xc0, 0xa8, 0xb8, 0xc7, 0xb2, 0x93, 0xa5,
 456		0x8d, 0xad, 0xb7, 0xa9, 0x00, 0xc7, 0x00, 0xae,
 457		0x00, 0xe9,
 458	}, {
 459		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
 460		0xaf, 0xc1, 0xa9, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
 461		0x8b, 0xad, 0xb7, 0xaa, 0x00, 0xc9, 0x00, 0xb0,
 462		0x00, 0xec,
 463	}, {
 464		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
 465		0xac, 0xbe, 0xa6, 0xbb, 0xc9, 0xb4, 0x90, 0xa3,
 466		0x8a, 0xad, 0xb7, 0xa9, 0x00, 0xcc, 0x00, 0xb4,
 467		0x00, 0xf0,
 468	}, {
 469		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xb0, 0x91,
 470		0xae, 0xc0, 0xa6, 0xba, 0xc8, 0xb4, 0x91, 0xa4,
 471		0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xcf, 0x00, 0xb7,
 472		0x00, 0xf3,
 473	}, {
 474		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb8, 0x98,
 475		0xab, 0xbd, 0xa4, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
 476		0x8b, 0xac, 0xb6, 0xa8, 0x00, 0xd1, 0x00, 0xb9,
 477		0x00, 0xf6,
 478	}, {
 479		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb5, 0x95,
 480		0xa9, 0xbc, 0xa1, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
 481		0x8a, 0xad, 0xb6, 0xa8, 0x00, 0xd6, 0x00, 0xbf,
 482		0x00, 0xfc,
 483	},
 484};
 485
 486static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v96[GAMMA_LEVEL_NUM] = {
 487	{
 488		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 489		0xdf, 0x1f, 0xd7, 0xdc, 0xb7, 0xe1, 0xc0, 0xaf,
 490		0xc4, 0xd2, 0xd0, 0xcf, 0x00, 0x4d, 0x00, 0x40,
 491		0x00, 0x5f,
 492	}, {
 493		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 494		0xd5, 0x35, 0xcf, 0xdc, 0xc1, 0xe1, 0xbf, 0xb3,
 495		0xc1, 0xd2, 0xd1, 0xce,	0x00, 0x53, 0x00, 0x46,
 496		0x00, 0x67,
 497	}, {
 498		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 499		0xd2, 0x64, 0xcf, 0xdb, 0xc6, 0xe1, 0xbd, 0xb3,
 500		0xbd, 0xd2, 0xd2, 0xce,	0x00, 0x59, 0x00, 0x4b,
 501		0x00, 0x6e,
 502	}, {
 503		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 504		0xd0, 0x7c, 0xcf, 0xdb, 0xc9, 0xe0, 0xbc, 0xb4,
 505		0xbb, 0xcf, 0xd1, 0xcc, 0x00, 0x5f, 0x00, 0x50,
 506		0x00, 0x75,
 507	}, {
 508		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 509		0xd0, 0x8e, 0xd1, 0xdb, 0xcc, 0xdf, 0xbb, 0xb6,
 510		0xb9, 0xd0, 0xd1, 0xcd,	0x00, 0x63, 0x00, 0x54,
 511		0x00, 0x7a,
 512	}, {
 513		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 514		0xd1, 0x9e, 0xd5, 0xda, 0xcd, 0xdd, 0xbb, 0xb7,
 515		0xb9, 0xce, 0xce, 0xc9,	0x00, 0x68, 0x00, 0x59,
 516		0x00, 0x81,
 517	}, {
 518		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
 519		0xd0, 0xa5, 0xd6, 0xda, 0xcf, 0xdd, 0xbb, 0xb7,
 520		0xb8, 0xcc, 0xcd, 0xc7,	0x00, 0x6c, 0x00, 0x5c,
 521		0x00, 0x86,
 522	}, {
 523		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xfe,
 524		0xd0, 0xae, 0xd7, 0xd9, 0xd0, 0xdb, 0xb9, 0xb6,
 525		0xb5, 0xca, 0xcc, 0xc5,	0x00, 0x74, 0x00, 0x63,
 526		0x00, 0x90,
 527	}, {
 528		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf9,
 529		0xcf, 0xb0, 0xd6, 0xd9, 0xd1, 0xdb, 0xb9, 0xb6,
 530		0xb4, 0xca, 0xcb, 0xc5,	0x00, 0x77, 0x00, 0x66,
 531		0x00, 0x94,
 532	}, {
 533		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf7,
 534		0xcf, 0xb3, 0xd7, 0xd8, 0xd1, 0xd9, 0xb7, 0xb6,
 535		0xb3, 0xc9, 0xca, 0xc3,	0x00, 0x7b, 0x00, 0x69,
 536		0x00, 0x99,
 537
 538	}, {
 539		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfd, 0x2f, 0xf7,
 540		0xdf, 0xb5, 0xd6, 0xd8, 0xd1, 0xd8, 0xb6, 0xb5,
 541		0xb2, 0xca, 0xcb, 0xc4,	0x00, 0x7e, 0x00, 0x6c,
 542		0x00, 0x9d,
 543	}, {
 544		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfa, 0x2f, 0xf5,
 545		0xce, 0xb6, 0xd5, 0xd7, 0xd2, 0xd8, 0xb6, 0xb4,
 546		0xb0, 0xc7, 0xc9, 0xc1,	0x00, 0x84, 0x00, 0x71,
 547		0x00, 0xa5,
 548	}, {
 549		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf7, 0x2f, 0xf2,
 550		0xce, 0xb9, 0xd5, 0xd8, 0xd2, 0xd8, 0xb4, 0xb4,
 551		0xaf, 0xc7, 0xc9, 0xc1,	0x00, 0x87, 0x00, 0x73,
 552		0x00, 0xa8,
 553	}, {
 554		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf5, 0x2f, 0xf0,
 555		0xdf, 0xba, 0xd5, 0xd7, 0xd2, 0xd7, 0xb4, 0xb4,
 556		0xaf, 0xc5, 0xc7, 0xbf,	0x00, 0x8a, 0x00, 0x76,
 557		0x00, 0xac,
 558	}, {
 559		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf2, 0x2f, 0xed,
 560		0xcE, 0xbb, 0xd4, 0xd6, 0xd2, 0xd6, 0xb5, 0xb4,
 561		0xaF, 0xc5, 0xc7, 0xbf,	0x00, 0x8c, 0x00, 0x78,
 562		0x00, 0xaf,
 563	}, {
 564		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x2f, 0xeb,
 565		0xcd, 0xbb, 0xd2, 0xd7, 0xd3, 0xd6, 0xb3, 0xb4,
 566		0xae, 0xc5, 0xc6, 0xbe,	0x00, 0x91, 0x00, 0x7d,
 567		0x00, 0xb6,
 568	}, {
 569		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xee, 0x2f, 0xea,
 570		0xce, 0xbd, 0xd4, 0xd6, 0xd2, 0xd5, 0xb2, 0xb3,
 571		0xad, 0xc3, 0xc4, 0xbb,	0x00, 0x94, 0x00, 0x7f,
 572		0x00, 0xba,
 573	}, {
 574		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xec, 0x2f, 0xe8,
 575		0xce, 0xbe, 0xd3, 0xd6, 0xd3, 0xd5, 0xb2, 0xb2,
 576		0xac, 0xc3, 0xc5, 0xbc,	0x00, 0x96, 0x00, 0x81,
 577		0x00, 0xbd,
 578	}, {
 579		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xeb, 0x2f, 0xe7,
 580		0xce, 0xbf, 0xd3, 0xd6, 0xd2, 0xd5, 0xb1, 0xb2,
 581		0xab, 0xc2, 0xc4, 0xbb,	0x00, 0x99, 0x00, 0x83,
 582		0x00, 0xc0,
 583	}, {
 584		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x5f, 0xe9,
 585		0xca, 0xbf, 0xd3, 0xd5, 0xd2, 0xd4, 0xb2, 0xb2,
 586		0xab, 0xc1, 0xc4, 0xba,	0x00, 0x9b, 0x00, 0x85,
 587		0x00, 0xc3,
 588	}, {
 589		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xea, 0x5f, 0xe8,
 590		0xee, 0xbf, 0xd2, 0xd5, 0xd2, 0xd4, 0xb1, 0xb2,
 591		0xab, 0xc1, 0xc2, 0xb9,	0x00, 0x9D, 0x00, 0x87,
 592		0x00, 0xc6,
 593	}, {
 594		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe9, 0x5f, 0xe7,
 595		0xcd, 0xbf, 0xd2, 0xd6, 0xd2, 0xd4, 0xb1, 0xb2,
 596		0xab, 0xbe, 0xc0, 0xb7,	0x00, 0xa1, 0x00, 0x8a,
 597		0x00, 0xca,
 598	}, {
 599		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x61, 0xe6,
 600		0xcd, 0xbf, 0xd1, 0xd6, 0xd3, 0xd4, 0xaf, 0xb0,
 601		0xa9, 0xbe, 0xc1, 0xb7,	0x00, 0xa3, 0x00, 0x8b,
 602		0x00, 0xce,
 603	}, {
 604		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x62, 0xe5,
 605		0xcc, 0xc0, 0xd0, 0xd6, 0xd2, 0xd4, 0xaf, 0xb1,
 606		0xa9, 0xbd, 0xc0, 0xb6,	0x00, 0xa5, 0x00, 0x8d,
 607		0x00, 0xd0,
 608	}, {
 609		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3,
 610		0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3, 0xae, 0xaf,
 611		0xa8, 0xbe, 0xc0, 0xb7,	0x00, 0xa8, 0x00, 0x90,
 612		0x00, 0xd3,
 613	}
 614};
 615
 616static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v32[GAMMA_LEVEL_NUM] = {
 617	{
 618		0xfa, 0x01, 0x43, 0x14, 0x45, 0x72, 0x5e, 0x6b,
 619		0xa1, 0xa7, 0x9a, 0xb4, 0xcb, 0xb8, 0x92, 0xac,
 620		0x97, 0xb4, 0xc3, 0xb5, 0x00, 0x4e, 0x00, 0x37,
 621		0x00, 0x58,
 622	}, {
 623		0xfa, 0x01, 0x43, 0x14, 0x45, 0x85, 0x71, 0x7d,
 624		0xa6, 0xb6, 0xa1, 0xb5, 0xca, 0xba, 0x93, 0xac,
 625		0x98, 0xb2, 0xc0, 0xaf, 0x00, 0x59, 0x00, 0x43,
 626		0x00, 0x64,
 627	}, {
 628		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa4, 0x94, 0x9e,
 629		0xa0, 0xbb, 0x9c, 0xc3, 0xd2, 0xc6, 0x93, 0xaa,
 630		0x95, 0xb7, 0xc2, 0xb4, 0x00, 0x65, 0x00, 0x50,
 631		0x00, 0x74,
 632	}, {
 633		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa1, 0xa6,
 634		0xa0, 0xb9, 0x9b, 0xc3, 0xd1, 0xc8, 0x90, 0xa6,
 635		0x90, 0xbb, 0xc3, 0xb7, 0x00, 0x6f, 0x00, 0x5b,
 636		0x00, 0x80,
 637	}, {
 638		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa6, 0x9d, 0x9f,
 639		0x9f, 0xb8, 0x9a, 0xc7, 0xd5, 0xcc, 0x90, 0xa5,
 640		0x8f, 0xb8, 0xc1, 0xb6, 0x00, 0x74, 0x00, 0x60,
 641		0x00, 0x85,
 642	}, {
 643		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb3, 0xae, 0xae,
 644		0x9e, 0xb7, 0x9a, 0xc8, 0xd6, 0xce, 0x91, 0xa6,
 645		0x90, 0xb6, 0xc0, 0xb3, 0x00, 0x78, 0x00, 0x65,
 646		0x00, 0x8a,
 647	}, {
 648		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa9, 0xa8,
 649		0xa3, 0xb9, 0x9e, 0xc4, 0xd3, 0xcb, 0x94, 0xa6,
 650		0x90, 0xb6, 0xbf, 0xb3, 0x00, 0x7c, 0x00, 0x69,
 651		0x00, 0x8e,
 652	}, {
 653		0xfa, 0x01, 0x43, 0x14, 0x45, 0xaf, 0xaf, 0xa9,
 654		0xa5, 0xbc, 0xa2, 0xc7, 0xd5, 0xcd, 0x93, 0xa5,
 655		0x8f, 0xb4, 0xbd, 0xb1, 0x00, 0x83, 0x00, 0x70,
 656		0x00, 0x96,
 657	}, {
 658		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xab, 0xa3,
 659		0xaa, 0xbf, 0xa7, 0xc5, 0xd3, 0xcb, 0x93, 0xa5,
 660		0x8f, 0xb2, 0xbb, 0xb0, 0x00, 0x86, 0x00, 0x74,
 661		0x00, 0x9b,
 662	}, {
 663		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xb5, 0xab,
 664		0xab, 0xc0, 0xa9, 0xc7, 0xd4, 0xcc, 0x94, 0xa4,
 665		0x8f, 0xb1, 0xbb, 0xaf, 0x00, 0x8a, 0x00, 0x77,
 666		0x00, 0x9e,
 667	}, {
 668		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb2, 0xa7,
 669		0xae, 0xc2, 0xab, 0xc5, 0xd3, 0xca, 0x93, 0xa4,
 670		0x8f, 0xb1, 0xba, 0xae, 0x00, 0x8d, 0x00, 0x7b,
 671		0x00, 0xa2,
 672	}, {
 673		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xaf, 0xa3,
 674		0xb0, 0xc3, 0xae, 0xc4, 0xd1, 0xc8, 0x93, 0xa4,
 675		0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x8f, 0x00, 0x7d,
 676		0x00, 0xa5,
 677	}, {
 678		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbd, 0xaf,
 679		0xae, 0xc1, 0xab, 0xc2, 0xd0, 0xc6, 0x94, 0xa4,
 680		0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x92, 0x00, 0x80,
 681		0x00, 0xa8,
 682	}, {
 683		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xb9, 0xac,
 684		0xad, 0xc1, 0xab, 0xc4, 0xd1, 0xc7, 0x95, 0xa4,
 685		0x90, 0xb0, 0xb9, 0xad, 0x00, 0x95, 0x00, 0x84,
 686		0x00, 0xac,
 687	}, {
 688		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb6, 0xa7,
 689		0xaf, 0xc2, 0xae, 0xc5, 0xd1, 0xc7, 0x93, 0xa3,
 690		0x8e, 0xb0, 0xb9, 0xad, 0x00, 0x98, 0x00, 0x86,
 691		0x00, 0xaf,
 692	}, {
 693		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbf, 0xaf,
 694		0xad, 0xc1, 0xab, 0xc3, 0xd0, 0xc6, 0x94, 0xa3,
 695		0x8f, 0xaf, 0xb8, 0xac, 0x00, 0x9a, 0x00, 0x89,
 696		0x00, 0xb2,
 697	}, {
 698		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xbc, 0xac,
 699		0xaf, 0xc2, 0xad, 0xc2, 0xcf, 0xc4, 0x94, 0xa3,
 700		0x90, 0xaf, 0xb8, 0xad, 0x00, 0x9c, 0x00, 0x8b,
 701		0x00, 0xb5,
 702	}, {
 703		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
 704		0xb1, 0xc4, 0xaf, 0xc3, 0xcf, 0xc5, 0x94, 0xa3,
 705		0x8f, 0xae, 0xb7, 0xac, 0x00, 0x9f, 0x00, 0x8e,
 706		0x00, 0xb8,
 707	}, {
 708		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
 709		0xaf, 0xc2, 0xad, 0xc1, 0xce, 0xc3, 0x95, 0xa3,
 710		0x90, 0xad, 0xb6, 0xab, 0x00, 0xa2, 0x00, 0x91,
 711		0x00, 0xbb,
 712	}, {
 713		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xbe, 0xac,
 714		0xb1, 0xc4, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa4,
 715		0x91, 0xad, 0xb6, 0xab, 0x00, 0xa4, 0x00, 0x93,
 716		0x00, 0xbd,
 717	}, {
 718		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
 719		0xb3, 0xc5, 0xb2, 0xc1, 0xcd, 0xc2, 0x95, 0xa3,
 720		0x90, 0xad, 0xb6, 0xab, 0x00, 0xa6, 0x00, 0x95,
 721		0x00, 0xc0,
 722	}, {
 723		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
 724		0xb0, 0xc3, 0xaf, 0xc2, 0xce, 0xc2, 0x94, 0xa2,
 725		0x90, 0xac, 0xb6, 0xab, 0x00, 0xa8, 0x00, 0x98,
 726		0x00, 0xc3,
 727	}, {
 728		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xb8, 0xa5,
 729		0xb3, 0xc5, 0xb2, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
 730		0x90, 0xad, 0xb6, 0xab, 0x00, 0xaa, 0x00, 0x9a,
 731		0x00, 0xc5,
 732	}, {
 733		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xc0, 0xac,
 734		0xb0, 0xc3, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa2,
 735		0x90, 0xac, 0xb5, 0xa9, 0x00, 0xac, 0x00, 0x9c,
 736		0x00, 0xc8,
 737	}, {
 738		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbd, 0xa8,
 739		0xaf, 0xc2, 0xaf, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
 740		0x90, 0xac, 0xb5, 0xaa, 0x00, 0xb1, 0x00, 0xa1,
 741		0x00, 0xcc,
 742	},
 743};
 744
 745static const struct s6e8aa0_variant s6e8aa0_variants[] = {
 746	{
 747		.version = 32,
 748		.gamma_tables = s6e8aa0_gamma_tables_v32,
 749	}, {
 750		.version = 96,
 751		.gamma_tables = s6e8aa0_gamma_tables_v96,
 752	}, {
 753		.version = 142,
 754		.gamma_tables = s6e8aa0_gamma_tables_v142,
 755	}, {
 756		.version = 210,
 757		.gamma_tables = s6e8aa0_gamma_tables_v142,
 758	}
 759};
 760
 761static void s6e8aa0_brightness_set(struct s6e8aa0 *ctx)
 762{
 763	const u8 *gamma;
 764
 765	if (ctx->error)
 766		return;
 767
 768	gamma = ctx->variant->gamma_tables[ctx->brightness];
 769
 770	if (ctx->version >= 142)
 771		s6e8aa0_elvss_nvm_set(ctx);
 772
 773	s6e8aa0_dcs_write(ctx, gamma, GAMMA_TABLE_LEN);
 774
 775	/* update gamma table. */
 776	s6e8aa0_dcs_write_seq_static(ctx, 0xf7, 0x03);
 777}
 778
 779static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
 780{
 781	s6e8aa0_apply_level_1_key(ctx);
 782	s6e8aa0_apply_level_2_key(ctx);
 783	msleep(20);
 784
 785	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
 786	msleep(40);
 787
 788	s6e8aa0_panel_cond_set(ctx);
 789	s6e8aa0_display_condition_set(ctx);
 790	s6e8aa0_brightness_set(ctx);
 791	s6e8aa0_etc_source_control(ctx);
 792	s6e8aa0_etc_pentile_control(ctx);
 793	s6e8aa0_elvss_nvm_set(ctx);
 794	s6e8aa0_etc_power_control(ctx);
 795	s6e8aa0_etc_elvss_control(ctx);
 796	msleep(ctx->init_delay);
 797}
 798
 799static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
 800						   int size)
 801{
 802	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 803	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
 804	u8 buf[] = {size, 0};
 805	struct mipi_dsi_msg msg = {
 806		.channel = dsi->channel,
 807		.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
 808		.tx_len = sizeof(buf),
 809		.tx_buf = buf
 810	};
 811	int ret;
 812
 813	if (ctx->error < 0)
 814		return;
 815
 816	if (!ops || !ops->transfer)
 817		ret = -EIO;
 818	else
 819		ret = ops->transfer(dsi->host, &msg);
 820
 821	if (ret < 0) {
 822		dev_err(ctx->dev,
 823			"error %d setting maximum return packet size to %d\n",
 824			ret, size);
 825		ctx->error = ret;
 826	}
 827}
 828
 829static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx)
 830{
 831	u8 id[3];
 832	int ret, i;
 833
 834	ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id));
 835	if (ret < ARRAY_SIZE(id) || id[0] == 0x00) {
 836		dev_err(ctx->dev, "read id failed\n");
 837		ctx->error = -EIO;
 838		return;
 839	}
 840
 841	dev_info(ctx->dev, "ID: 0x%2x, 0x%2x, 0x%2x\n", id[0], id[1], id[2]);
 842
 843	for (i = 0; i < ARRAY_SIZE(s6e8aa0_variants); ++i) {
 844		if (id[1] == s6e8aa0_variants[i].version)
 845			break;
 846	}
 847	if (i >= ARRAY_SIZE(s6e8aa0_variants)) {
 848		dev_err(ctx->dev, "unsupported display version %d\n", id[1]);
 849		ctx->error = -EINVAL;
 850	}
 851
 852	ctx->variant = &s6e8aa0_variants[i];
 853	ctx->version = id[1];
 854	ctx->id = id[2];
 855}
 856
 857static void s6e8aa0_set_sequence(struct s6e8aa0 *ctx)
 858{
 859	s6e8aa0_set_maximum_return_packet_size(ctx, 3);
 860	s6e8aa0_read_mtp_id(ctx);
 861	s6e8aa0_panel_init(ctx);
 862	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
 863}
 864
 865static int s6e8aa0_power_on(struct s6e8aa0 *ctx)
 866{
 867	int ret;
 868
 869	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 870	if (ret < 0)
 871		return ret;
 872
 873	msleep(ctx->power_on_delay);
 874
 875	gpiod_set_value(ctx->reset_gpio, 0);
 876	usleep_range(10000, 11000);
 877	gpiod_set_value(ctx->reset_gpio, 1);
 878
 879	msleep(ctx->reset_delay);
 880
 881	return 0;
 882}
 883
 884static int s6e8aa0_power_off(struct s6e8aa0 *ctx)
 885{
 886	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 887}
 888
 889static int s6e8aa0_disable(struct drm_panel *panel)
 890{
 891	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
 892
 893	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
 894	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
 895	msleep(40);
 896
 897	s6e8aa0_clear_error(ctx);
 898
 899	return s6e8aa0_power_off(ctx);
 900}
 901
 902static int s6e8aa0_enable(struct drm_panel *panel)
 903{
 904	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
 905	int ret;
 906
 907	ret = s6e8aa0_power_on(ctx);
 908	if (ret < 0)
 909		return ret;
 910
 911	s6e8aa0_set_sequence(ctx);
 912	ret = ctx->error;
 913
 914	if (ret < 0)
 915		s6e8aa0_disable(panel);
 916
 917	return ret;
 918}
 919
 920static int s6e8aa0_get_modes(struct drm_panel *panel)
 921{
 922	struct drm_connector *connector = panel->connector;
 923	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
 924	struct drm_display_mode *mode;
 925
 926	mode = drm_mode_create(connector->dev);
 927	if (!mode) {
 928		DRM_ERROR("failed to create a new display mode\n");
 929		return 0;
 930	}
 931
 932	drm_display_mode_from_videomode(&ctx->vm, mode);
 933	mode->width_mm = ctx->width_mm;
 934	mode->height_mm = ctx->height_mm;
 935	connector->display_info.width_mm = mode->width_mm;
 936	connector->display_info.height_mm = mode->height_mm;
 937
 938	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 939	drm_mode_probed_add(connector, mode);
 940
 941	return 1;
 942}
 943
 944static const struct drm_panel_funcs s6e8aa0_drm_funcs = {
 945	.disable = s6e8aa0_disable,
 946	.enable = s6e8aa0_enable,
 947	.get_modes = s6e8aa0_get_modes,
 948};
 949
 950static int s6e8aa0_parse_dt(struct s6e8aa0 *ctx)
 951{
 952	struct device *dev = ctx->dev;
 953	struct device_node *np = dev->of_node;
 954	int ret;
 955
 956	ret = of_get_videomode(np, &ctx->vm, 0);
 957	if (ret < 0)
 958		return ret;
 959
 960	of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
 961	of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
 962	of_property_read_u32(np, "init-delay", &ctx->init_delay);
 963	of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
 964	of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
 965
 966	ctx->flip_horizontal = of_property_read_bool(np, "flip-horizontal");
 967	ctx->flip_vertical = of_property_read_bool(np, "flip-vertical");
 968
 969	return 0;
 970}
 971
 972static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
 973{
 974	struct device *dev = &dsi->dev;
 975	struct s6e8aa0 *ctx;
 976	int ret;
 977
 978	ctx = devm_kzalloc(dev, sizeof(struct s6e8aa0), GFP_KERNEL);
 979	if (!ctx)
 980		return -ENOMEM;
 981
 982	mipi_dsi_set_drvdata(dsi, ctx);
 983
 984	ctx->dev = dev;
 985
 986	dsi->lanes = 4;
 987	dsi->format = MIPI_DSI_FMT_RGB888;
 988	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
 989		| MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP
 990		| MIPI_DSI_MODE_VIDEO_HSA | MIPI_DSI_MODE_EOT_PACKET
 991		| MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
 992
 993	ret = s6e8aa0_parse_dt(ctx);
 994	if (ret < 0)
 995		return ret;
 996
 997	ctx->supplies[0].supply = "vdd3";
 998	ctx->supplies[1].supply = "vci";
 999	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
1000				      ctx->supplies);
1001	if (ret < 0) {
1002		dev_err(dev, "failed to get regulators: %d\n", ret);
1003		return ret;
1004	}
1005
1006	ctx->reset_gpio = devm_gpiod_get(dev, "reset");
1007	if (IS_ERR(ctx->reset_gpio)) {
1008		dev_err(dev, "cannot get reset-gpios %ld\n",
1009			PTR_ERR(ctx->reset_gpio));
1010		return PTR_ERR(ctx->reset_gpio);
1011	}
1012	ret = gpiod_direction_output(ctx->reset_gpio, 1);
1013	if (ret < 0) {
1014		dev_err(dev, "cannot configure reset-gpios %d\n", ret);
1015		return ret;
1016	}
1017
1018	ctx->brightness = GAMMA_LEVEL_NUM - 1;
1019
1020	drm_panel_init(&ctx->panel);
1021	ctx->panel.dev = dev;
1022	ctx->panel.funcs = &s6e8aa0_drm_funcs;
1023
1024	ret = drm_panel_add(&ctx->panel);
1025	if (ret < 0)
1026		return ret;
1027
1028	ret = mipi_dsi_attach(dsi);
1029	if (ret < 0)
1030		drm_panel_remove(&ctx->panel);
1031
1032	return ret;
1033}
1034
1035static int s6e8aa0_remove(struct mipi_dsi_device *dsi)
1036{
1037	struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi);
1038
1039	mipi_dsi_detach(dsi);
1040	drm_panel_remove(&ctx->panel);
1041
1042	return 0;
1043}
1044
1045static struct of_device_id s6e8aa0_of_match[] = {
1046	{ .compatible = "samsung,s6e8aa0" },
1047	{ }
1048};
1049MODULE_DEVICE_TABLE(of, s6e8aa0_of_match);
1050
1051static struct mipi_dsi_driver s6e8aa0_driver = {
1052	.probe = s6e8aa0_probe,
1053	.remove = s6e8aa0_remove,
1054	.driver = {
1055		.name = "panel_s6e8aa0",
1056		.owner = THIS_MODULE,
1057		.of_match_table = s6e8aa0_of_match,
1058	},
1059};
1060module_mipi_dsi_driver(s6e8aa0_driver);
1061
1062MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
1063MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1064MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
1065MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
1066MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
1067MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
1068MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver");
1069MODULE_LICENSE("GPL v2");