// SPDX-License-Identifier: GPL-2.0-only
/*
* MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Donghwa Lee <dh09.lee@samsung.com>
* Hyungwon Hwang <human.hwang@samsung.com>
* Hoegeun Kwon <hoegeun.kwon@samsung.com>
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#define S6E3HA2_MIN_BRIGHTNESS 0
#define S6E3HA2_MAX_BRIGHTNESS 100
#define S6E3HA2_DEFAULT_BRIGHTNESS 80
#define S6E3HA2_NUM_GAMMA_STEPS 46
#define S6E3HA2_GAMMA_CMD_CNT 35
#define S6E3HA2_VINT_STATUS_MAX 10
static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x82, 0 x83,
0 x85, 0 x88, 0 x8b, 0 x8b, 0 x84, 0 x88, 0 x82, 0 x82, 0 x89, 0 x86, 0 x8c,
0 x94, 0 x84, 0 xb1, 0 xaf, 0 x8e, 0 xcf, 0 xad, 0 xc9, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x84, 0 x84,
0 x85, 0 x87, 0 x8b, 0 x8a, 0 x84, 0 x88, 0 x82, 0 x82, 0 x89, 0 x86, 0 x8a,
0 x93, 0 x84, 0 xb0, 0 xae, 0 x8e, 0 xc9, 0 xa8, 0 xc5, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x8a, 0 x8a, 0 x84, 0 x88, 0 x81, 0 x84, 0 x8a, 0 x88, 0 x8a,
0 x91, 0 x84, 0 xb1, 0 xae, 0 x8b, 0 xd5, 0 xb2, 0 xcc, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x8a, 0 x8a, 0 x84, 0 x87, 0 x81, 0 x84, 0 x8a, 0 x87, 0 x8a,
0 x91, 0 x85, 0 xae, 0 xac, 0 x8a, 0 xc3, 0 xa3, 0 xc0, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x85, 0 x85,
0 x86, 0 x85, 0 x88, 0 x89, 0 x84, 0 x89, 0 x82, 0 x84, 0 x87, 0 x85, 0 x8b,
0 x91, 0 x88, 0 xad, 0 xab, 0 x8a, 0 xb7, 0 x9b, 0 xb6, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x89, 0 x8a, 0 x84, 0 x89, 0 x83, 0 x83, 0 x86, 0 x84, 0 x8b,
0 x90, 0 x84, 0 xb0, 0 xae, 0 x8b, 0 xce, 0 xad, 0 xc8, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x83, 0 x83,
0 x85, 0 x87, 0 x89, 0 x8a, 0 x83, 0 x87, 0 x82, 0 x85, 0 x88, 0 x87, 0 x89,
0 x8f, 0 x84, 0 xac, 0 xaa, 0 x89, 0 xb1, 0 x98, 0 xaf, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x88, 0 x89, 0 x84, 0 x88, 0 x83, 0 x82, 0 x85, 0 x84, 0 x8c,
0 x91, 0 x86, 0 xac, 0 xaa, 0 x89, 0 xc2, 0 xa5, 0 xbd, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x85, 0 x87, 0 x89, 0 x8a, 0 x83, 0 x87, 0 x82, 0 x85, 0 x88, 0 x87, 0 x88,
0 x8b, 0 x82, 0 xad, 0 xaa, 0 x8a, 0 xc2, 0 xa5, 0 xbd, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x89, 0 x87, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x87, 0 x89, 0 x84, 0 x88, 0 x83, 0 x82, 0 x85, 0 x84, 0 x8a,
0 x8e, 0 x84, 0 xae, 0 xac, 0 x89, 0 xda, 0 xb7, 0 xd0, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x85, 0 x86, 0 x87, 0 x89, 0 x84, 0 x88, 0 x83, 0 x80, 0 x83, 0 x82, 0 x8b,
0 x8e, 0 x85, 0 xac, 0 xaa, 0 x89, 0 xc8, 0 xaa, 0 xc1, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x85, 0 x86, 0 x87, 0 x89, 0 x81, 0 x85, 0 x81, 0 x84, 0 x86, 0 x84, 0 x8c,
0 x8c, 0 x84, 0 xa9, 0 xa8, 0 x87, 0 xa3, 0 x92, 0 xa1, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x85, 0 x86, 0 x87, 0 x89, 0 x84, 0 x86, 0 x83, 0 x80, 0 x83, 0 x81, 0 x8c,
0 x8d, 0 x84, 0 xaa, 0 xaa, 0 x89, 0 xce, 0 xaf, 0 xc5, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x85, 0 x86, 0 x87, 0 x89, 0 x81, 0 x83, 0 x80, 0 x83, 0 x85, 0 x85, 0 x8c,
0 x8c, 0 x84, 0 xa8, 0 xa8, 0 x88, 0 xb5, 0 x9f, 0 xb0, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x86, 0 x86, 0 x87, 0 x88, 0 x81, 0 x83, 0 x80, 0 x83, 0 x85, 0 x85, 0 x8c,
0 x8b, 0 x84, 0 xab, 0 xa8, 0 x86, 0 xd4, 0 xb4, 0 xc9, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x86, 0 x86, 0 x87, 0 x88, 0 x81, 0 x83, 0 x80, 0 x84, 0 x84, 0 x85, 0 x8b,
0 x8a, 0 x83, 0 xa6, 0 xa5, 0 x84, 0 xbb, 0 xa4, 0 xb3, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x84, 0 x84,
0 x86, 0 x85, 0 x86, 0 x86, 0 x82, 0 x85, 0 x81, 0 x82, 0 x83, 0 x84, 0 x8e,
0 x8b, 0 x83, 0 xa4, 0 xa3, 0 x8a, 0 xa1, 0 x93, 0 x9d, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x87, 0 x87, 0 x82, 0 x85, 0 x81, 0 x82, 0 x82, 0 x84, 0 x8e,
0 x8b, 0 x83, 0 xa4, 0 xa2, 0 x86, 0 xc1, 0 xa9, 0 xb7, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x87, 0 x87, 0 x82, 0 x85, 0 x81, 0 x82, 0 x82, 0 x84, 0 x8d,
0 x89, 0 x82, 0 xa2, 0 xa1, 0 x84, 0 xa7, 0 x98, 0 xa1, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xb8, 0 x00, 0 xc3, 0 x00, 0 xb1, 0 x88, 0 x86, 0 x87, 0 x83, 0 x83,
0 x85, 0 x86, 0 x87, 0 x87, 0 x82, 0 x85, 0 x81, 0 x83, 0 x83, 0 x85, 0 x8c,
0 x87, 0 x7f, 0 xa2, 0 x9d, 0 x88, 0 x8d, 0 x88, 0 x8b, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xbb, 0 x00, 0 xc5, 0 x00, 0 xb4, 0 x87, 0 x86, 0 x86, 0 x84, 0 x83,
0 x86, 0 x87, 0 x87, 0 x87, 0 x80, 0 x82, 0 x7f, 0 x86, 0 x86, 0 x88, 0 x8a,
0 x84, 0 x7e, 0 x9d, 0 x9c, 0 x82, 0 x8d, 0 x88, 0 x8b, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xbd, 0 x00, 0 xc7, 0 x00, 0 xb7, 0 x87, 0 x85, 0 x85, 0 x84, 0 x83,
0 x86, 0 x86, 0 x86, 0 x88, 0 x81, 0 x83, 0 x80, 0 x83, 0 x84, 0 x85, 0 x8a,
0 x85, 0 x7e, 0 x9c, 0 x9b, 0 x85, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xc0, 0 x00, 0 xca, 0 x00, 0 xbb, 0 x87, 0 x86, 0 x85, 0 x83, 0 x83,
0 x85, 0 x86, 0 x86, 0 x88, 0 x81, 0 x83, 0 x80, 0 x84, 0 x85, 0 x86, 0 x89,
0 x83, 0 x7d, 0 x9c, 0 x99, 0 x87, 0 x7b, 0 x7b, 0 x7c, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xc4, 0 x00, 0 xcd, 0 x00, 0 xbe, 0 x87, 0 x86, 0 x85, 0 x83, 0 x83,
0 x86, 0 x85, 0 x85, 0 x87, 0 x81, 0 x82, 0 x80, 0 x82, 0 x82, 0 x83, 0 x8a,
0 x85, 0 x7f, 0 x9f, 0 x9b, 0 x86, 0 xb4, 0 xa1, 0 xac, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xc7, 0 x00, 0 xd0, 0 x00, 0 xc2, 0 x87, 0 x85, 0 x85, 0 x83, 0 x82,
0 x85, 0 x85, 0 x85, 0 x86, 0 x82, 0 x83, 0 x80, 0 x82, 0 x82, 0 x84, 0 x87,
0 x86, 0 x80, 0 x9e, 0 x9a, 0 x87, 0 xa7, 0 x98, 0 xa1, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xca, 0 x00, 0 xd2, 0 x00, 0 xc5, 0 x87, 0 x85, 0 x84, 0 x82, 0 x82,
0 x84, 0 x85, 0 x85, 0 x86, 0 x81, 0 x82, 0 x7f, 0 x82, 0 x82, 0 x84, 0 x88,
0 x86, 0 x81, 0 x9d, 0 x98, 0 x86, 0 x8d, 0 x88, 0 x8b, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xce, 0 x00, 0 xd6, 0 x00, 0 xca, 0 x86, 0 x85, 0 x84, 0 x83, 0 x83,
0 x85, 0 x84, 0 x84, 0 x85, 0 x81, 0 x82, 0 x80, 0 x81, 0 x81, 0 x82, 0 x89,
0 x86, 0 x81, 0 x9c, 0 x97, 0 x86, 0 xa7, 0 x98, 0 xa1, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xd1, 0 x00, 0 xd9, 0 x00, 0 xce, 0 x86, 0 x84, 0 x83, 0 x83, 0 x82,
0 x85, 0 x85, 0 x85, 0 x86, 0 x81, 0 x83, 0 x81, 0 x82, 0 x82, 0 x83, 0 x86,
0 x83, 0 x7f, 0 x99, 0 x95, 0 x86, 0 xbb, 0 xa4, 0 xb3, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xd4, 0 x00, 0 xdb, 0 x00, 0 xd1, 0 x86, 0 x85, 0 x83, 0 x83, 0 x82,
0 x85, 0 x84, 0 x84, 0 x85, 0 x80, 0 x83, 0 x82, 0 x80, 0 x80, 0 x81, 0 x87,
0 x84, 0 x81, 0 x98, 0 x93, 0 x85, 0 xae, 0 x9c, 0 xa8, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xd8, 0 x00, 0 xde, 0 x00, 0 xd6, 0 x86, 0 x84, 0 x83, 0 x81, 0 x81,
0 x83, 0 x85, 0 x85, 0 x85, 0 x82, 0 x83, 0 x81, 0 x81, 0 x81, 0 x83, 0 x86,
0 x84, 0 x80, 0 x98, 0 x91, 0 x85, 0 x7b, 0 x7b, 0 x7c, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xdc, 0 x00, 0 xe2, 0 x00, 0 xda, 0 x85, 0 x84, 0 x83, 0 x82, 0 x82,
0 x84, 0 x84, 0 x84, 0 x85, 0 x81, 0 x82, 0 x82, 0 x80, 0 x80, 0 x81, 0 x83,
0 x82, 0 x7f, 0 x99, 0 x93, 0 x86, 0 x94, 0 x8b, 0 x92, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xdf, 0 x00, 0 xe5, 0 x00, 0 xde, 0 x85, 0 x84, 0 x82, 0 x82, 0 x82,
0 x84, 0 x83, 0 x83, 0 x84, 0 x81, 0 x81, 0 x80, 0 x83, 0 x82, 0 x84, 0 x82,
0 x81, 0 x7f, 0 x99, 0 x92, 0 x86, 0 x7b, 0 x7b, 0 x7c, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x84, 0 x83, 0 x82, 0 x81, 0 x81,
0 x82, 0 x83, 0 x83, 0 x84, 0 x80, 0 x81, 0 x80, 0 x83, 0 x83, 0 x84, 0 x80,
0 x81, 0 x7c, 0 x99, 0 x92, 0 x87, 0 xa1, 0 x93, 0 x9d, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x85, 0 x84, 0 x83, 0 x81, 0 x81,
0 x82, 0 x82, 0 x82, 0 x83, 0 x80, 0 x81, 0 x80, 0 x81, 0 x80, 0 x82, 0 x83,
0 x82, 0 x80, 0 x91, 0 x8d, 0 x83, 0 x9a, 0 x90, 0 x96, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x84, 0 x83, 0 x82, 0 x81, 0 x81,
0 x82, 0 x83, 0 x83, 0 x84, 0 x80, 0 x81, 0 x80, 0 x81, 0 x80, 0 x82, 0 x83,
0 x81, 0 x7f, 0 x91, 0 x8c, 0 x82, 0 x8d, 0 x88, 0 x8b, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x84, 0 x83, 0 x82, 0 x81, 0 x81,
0 x82, 0 x83, 0 x83, 0 x83, 0 x82, 0 x82, 0 x81, 0 x81, 0 x80, 0 x82, 0 x82,
0 x82, 0 x7f, 0 x94, 0 x89, 0 x84, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x84, 0 x83, 0 x82, 0 x81, 0 x81,
0 x82, 0 x83, 0 x83, 0 x83, 0 x82, 0 x82, 0 x81, 0 x81, 0 x80, 0 x82, 0 x83,
0 x82, 0 x7f, 0 x91, 0 x85, 0 x81, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x84, 0 x83, 0 x82, 0 x81, 0 x81,
0 x82, 0 x83, 0 x83, 0 x83, 0 x80, 0 x80, 0 x7f, 0 x83, 0 x82, 0 x84, 0 x83,
0 x82, 0 x7f, 0 x90, 0 x84, 0 x81, 0 x9a, 0 x90, 0 x96, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe4, 0 x00, 0 xe9, 0 x00, 0 xe3, 0 x84, 0 x83, 0 x82, 0 x80, 0 x80,
0 x82, 0 x83, 0 x83, 0 x83, 0 x80, 0 x80, 0 x7f, 0 x80, 0 x80, 0 x81, 0 x81,
0 x82, 0 x83, 0 x7e, 0 x80, 0 x7c, 0 xa4, 0 x97, 0 x9f, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xe9, 0 x00, 0 xec, 0 x00, 0 xe8, 0 x84, 0 x83, 0 x82, 0 x81, 0 x81,
0 x82, 0 x82, 0 x82, 0 x83, 0 x7f, 0 x7f, 0 x7f, 0 x81, 0 x80, 0 x82, 0 x83,
0 x83, 0 x84, 0 x79, 0 x7c, 0 x79, 0 xb1, 0 xa0, 0 xaa, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xed, 0 x00, 0 xf0, 0 x00, 0 xec, 0 x83, 0 x83, 0 x82, 0 x80, 0 x80,
0 x81, 0 x82, 0 x82, 0 x82, 0 x7f, 0 x7f, 0 x7e, 0 x81, 0 x81, 0 x82, 0 x80,
0 x81, 0 x81, 0 x84, 0 x84, 0 x83, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xf1, 0 x00, 0 xf4, 0 x00, 0 xf1, 0 x83, 0 x82, 0 x82, 0 x80, 0 x80,
0 x81, 0 x82, 0 x82, 0 x82, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x81, 0 x7d,
0 x7e, 0 x7f, 0 x84, 0 x84, 0 x83, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xf6, 0 x00, 0 xf7, 0 x00, 0 xf5, 0 x82, 0 x82, 0 x81, 0 x80, 0 x80,
0 x80, 0 x82, 0 x82, 0 x82, 0 x80, 0 x80, 0 x80, 0 x7f, 0 x7f, 0 x7f, 0 x82,
0 x82, 0 x82, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x00, 0 xfa, 0 x00, 0 xfb, 0 x00, 0 xfa, 0 x81, 0 x81, 0 x81, 0 x80, 0 x80,
0 x80, 0 x82, 0 x82, 0 x82, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80,
0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x01, 0 x00, 0 x01, 0 x00, 0 x01, 0 x00, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80,
0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80,
0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 },
{ 0 x01, 0 x00, 0 x01, 0 x00, 0 x01, 0 x00, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80,
0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80,
0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x80, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00 }
};
static const unsigned char vint_table[S6E3HA2_VINT_STATUS_MAX] = {
0 x18, 0 x19, 0 x1a, 0 x1b, 0 x1c,
0 x1d, 0 x1e, 0 x1f, 0 x20, 0 x21
};
enum s6e3ha2_type {
HA2_TYPE,
HF2_TYPE,
};
struct s6e3ha2_panel_desc {
const struct drm_display_mode *mode;
enum s6e3ha2_type type;
};
struct s6e3ha2 {
struct device *dev;
struct drm_panel panel;
struct backlight_device *bl_dev;
struct regulator_bulk_data supplies[2 ];
struct gpio_desc *reset_gpio;
struct gpio_desc *enable_gpio;
const struct s6e3ha2_panel_desc *desc;
};
static int s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
return mipi_dsi_dcs_write_buffer(dsi, data, len);
}
#define s6e3ha2_dcs_write_seq_static(ctx, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d)); \
if (ret < 0 ) \
return ret; \
} while (0 )
#define s6e3ha2_call_write_func(ret, func) do { \
ret = (func); \
if (ret < 0 ) \
return ret; \
} while (0 )
static int s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xf0, 0 x5a, 0 x5a);
return 0 ;
}
static int s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xf0, 0 xa5, 0 xa5);
return 0 ;
}
static int s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xfc, 0 x5a, 0 x5a);
return 0 ;
}
static int s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xfc, 0 xa5, 0 xa5);
return 0 ;
}
static int s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xf2, 0 x67);
s6e3ha2_dcs_write_seq_static(ctx, 0 xf9, 0 x09);
return 0 ;
}
static int s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xfd, 0 x1c);
if (ctx->desc->type == HF2_TYPE)
s6e3ha2_dcs_write_seq_static(ctx, 0 xf2, 0 x67, 0 x40, 0 xc5);
s6e3ha2_dcs_write_seq_static(ctx, 0 xfe, 0 x20, 0 x39);
s6e3ha2_dcs_write_seq_static(ctx, 0 xfe, 0 xa0);
s6e3ha2_dcs_write_seq_static(ctx, 0 xfe, 0 x20);
if (ctx->desc->type == HA2_TYPE)
s6e3ha2_dcs_write_seq_static(ctx, 0 xce, 0 x03, 0 x3b, 0 x12, 0 x62,
0 x40, 0 x80, 0 xc0, 0 x28, 0 x28,
0 x28, 0 x28, 0 x39, 0 xc5);
else
s6e3ha2_dcs_write_seq_static(ctx, 0 xce, 0 x03, 0 x3b, 0 x14, 0 x6d,
0 x40, 0 x80, 0 xc0, 0 x28, 0 x28,
0 x28, 0 x28, 0 x39, 0 xc5);
return 0 ;
}
static int s6e3ha2_aor_control(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb2, 0 x03, 0 x10);
return 0 ;
}
static int s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb6, 0 x9c, 0 x0a);
return 0 ;
}
static int s6e3ha2_acl_off(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 x55, 0 x00);
return 0 ;
}
static int s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb5, 0 x40);
return 0 ;
}
static int s6e3ha2_test_global(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb0, 0 x07);
return 0 ;
}
static int s6e3ha2_test(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb8, 0 x19);
return 0 ;
}
static int s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xbd, 0 x33, 0 x11, 0 x02,
0 x16, 0 x02, 0 x16);
return 0 ;
}
static int s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xc0, 0 x00, 0 x00, 0 xd8, 0 xd8);
return 0 ;
}
static int s6e3ha2_poc_global(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb0, 0 x20);
return 0 ;
}
static int s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xfe, 0 x08);
return 0 ;
}
static int s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xcc, 0 x40, 0 x51);
return 0 ;
}
static int s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xed, 0 x44);
return 0 ;
}
static int s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 x53, 0 x00);
return 0 ;
}
static int s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xb9, 0 x10, 0 x09, 0 xff, 0 x00, 0 x09);
return 0 ;
}
static int s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
{
s6e3ha2_dcs_write_seq_static(ctx, 0 xf7, 0 x03);
ndelay(100 ); /* need for 100ns delay */
s6e3ha2_dcs_write_seq_static(ctx, 0 xf7, 0 x00);
return 0 ;
}
static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
{
return bl_dev->props.brightness;
}
static int s6e3ha2_set_vint(struct s6e3ha2 *ctx)
{
struct backlight_device *bl_dev = ctx->bl_dev;
unsigned int brightness = bl_dev->props.brightness;
unsigned char data[] = { 0 xf4, 0 x8b,
vint_table[brightness * (S6E3HA2_VINT_STATUS_MAX - 1 ) /
S6E3HA2_MAX_BRIGHTNESS] };
return s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
}
static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
{
return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1 )) /
S6E3HA2_MAX_BRIGHTNESS;
}
static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
{
struct backlight_device *bl_dev = ctx->bl_dev;
unsigned int index = s6e3ha2_get_brightness_index(brightness);
u8 data[S6E3HA2_GAMMA_CMD_CNT + 1 ] = { 0 xca, };
int ret;
memcpy(data + 1 , gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
s6e3ha2_call_write_func(ret,
s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data)));
s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
bl_dev->props.brightness = brightness;
return 0 ;
}
static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
{
struct s6e3ha2 *ctx = bl_get_data(bl_dev);
unsigned int brightness = bl_dev->props.brightness;
int ret;
if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
brightness > bl_dev->props.max_brightness) {
dev_err(ctx->dev, "Invalid brightness: %u\n" , brightness);
return -EINVAL;
}
if (bl_dev->props.power > BACKLIGHT_POWER_REDUCED)
return -EPERM;
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_update_gamma(ctx, brightness));
s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_set_vint(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
return 0 ;
}
static const struct backlight_ops s6e3ha2_bl_ops = {
.get_brightness = s6e3ha2_get_brightness,
.update_status = s6e3ha2_set_brightness,
};
static int s6e3ha2_panel_init(struct s6e3ha2 *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
s6e3ha2_call_write_func(ret, mipi_dsi_dcs_exit_sleep_mode(dsi));
usleep_range(5000 , 6000 );
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_single_dsi_set(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_freq_calibration(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
return 0 ;
}
static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
{
return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
}
static int s6e3ha2_disable(struct drm_panel *panel)
{
struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
s6e3ha2_call_write_func(ret, mipi_dsi_dcs_enter_sleep_mode(dsi));
s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_off(dsi));
msleep(40 );
ctx->bl_dev->props.power = BACKLIGHT_POWER_REDUCED;
return 0 ;
}
static int s6e3ha2_unprepare(struct drm_panel *panel)
{
struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
return s6e3ha2_power_off(ctx);
}
static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
{
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0 )
return ret;
msleep(120 );
gpiod_set_value(ctx->enable_gpio, 0 );
usleep_range(5000 , 6000 );
gpiod_set_value(ctx->enable_gpio, 1 );
gpiod_set_value(ctx->reset_gpio, 1 );
usleep_range(5000 , 6000 );
gpiod_set_value(ctx->reset_gpio, 0 );
usleep_range(5000 , 6000 );
return 0 ;
}
static int s6e3ha2_prepare(struct drm_panel *panel)
{
struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
int ret;
ret = s6e3ha2_power_on(ctx);
if (ret < 0 )
return ret;
ret = s6e3ha2_panel_init(ctx);
if (ret < 0 )
goto err;
ctx->bl_dev->props.power = BACKLIGHT_POWER_REDUCED;
return 0 ;
err:
s6e3ha2_power_off(ctx);
return ret;
}
static int s6e3ha2_enable(struct drm_panel *panel)
{
struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
/* common setting */
s6e3ha2_call_write_func(ret,
mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_touch_hsync_on1(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_pentile_control(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_poc_global(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_poc_setting(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
/* pcd setting off for TB */
s6e3ha2_call_write_func(ret, s6e3ha2_pcd_set_off(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_err_fg_set(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_te_start_setting(ctx));
/* brightness setting */
s6e3ha2_call_write_func(ret, s6e3ha2_set_brightness(ctx->bl_dev));
s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_caps_elvss_set(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_acl_off(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_acl_off_opr(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_hbm_off(ctx));
/* elvss temp compensation */
s6e3ha2_call_write_func(ret, s6e3ha2_test_global(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test(ctx));
s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_on(dsi));
ctx->bl_dev->props.power = BACKLIGHT_POWER_ON;
return 0 ;
}
static const struct drm_display_mode s6e3ha2_mode = {
.clock = 222372 ,
.hdisplay = 1440 ,
.hsync_start = 1440 + 1 ,
.hsync_end = 1440 + 1 + 1 ,
.htotal = 1440 + 1 + 1 + 1 ,
.vdisplay = 2560 ,
.vsync_start = 2560 + 1 ,
.vsync_end = 2560 + 1 + 1 ,
.vtotal = 2560 + 1 + 1 + 15 ,
.flags = 0 ,
};
static const struct s6e3ha2_panel_desc samsung_s6e3ha2 = {
.mode = &s6e3ha2_mode,
.type = HA2_TYPE,
};
static const struct drm_display_mode s6e3hf2_mode = {
.clock = 247856 ,
.hdisplay = 1600 ,
.hsync_start = 1600 + 1 ,
.hsync_end = 1600 + 1 + 1 ,
.htotal = 1600 + 1 + 1 + 1 ,
.vdisplay = 2560 ,
.vsync_start = 2560 + 1 ,
.vsync_end = 2560 + 1 + 1 ,
.vtotal = 2560 + 1 + 1 + 15 ,
.flags = 0 ,
};
static const struct s6e3ha2_panel_desc samsung_s6e3hf2 = {
.mode = &s6e3hf2_mode,
.type = HF2_TYPE,
};
static int s6e3ha2_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
if (!mode) {
dev_err(panel->dev, "failed to add mode %ux%u@%u\n" ,
ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
drm_mode_vrefresh(ctx->desc->mode));
return -ENOMEM;
}
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
connector->display_info.width_mm = 71 ;
connector->display_info.height_mm = 125 ;
return 1 ;
}
static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
.disable = s6e3ha2_disable,
.unprepare = s6e3ha2_unprepare,
.prepare = s6e3ha2_prepare,
.enable = s6e3ha2_enable,
.get_modes = s6e3ha2_get_modes,
};
static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct s6e3ha2 *ctx;
int ret;
ctx = devm_drm_panel_alloc(dev, struct s6e3ha2, panel,
&s6e3ha2_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dev = dev;
ctx->desc = of_device_get_match_data(dev);
dsi->lanes = 4 ;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP |
MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET;
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 ) {
dev_err(dev, "failed to get regulators: %d\n" , ret);
return ret;
}
ctx->reset_gpio = devm_gpiod_get(dev, "reset" , GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
dev_err(dev, "cannot get reset-gpios %ld\n" ,
PTR_ERR(ctx->reset_gpio));
return PTR_ERR(ctx->reset_gpio);
}
ctx->enable_gpio = devm_gpiod_get(dev, "enable" , GPIOD_OUT_HIGH);
if (IS_ERR(ctx->enable_gpio)) {
dev_err(dev, "cannot get enable-gpios %ld\n" ,
PTR_ERR(ctx->enable_gpio));
return PTR_ERR(ctx->enable_gpio);
}
ctx->bl_dev = backlight_device_register("s6e3ha2" , dev, ctx,
&s6e3ha2_bl_ops, NULL);
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 = S6E3HA2_MAX_BRIGHTNESS;
ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
ctx->bl_dev->props.power = BACKLIGHT_POWER_OFF;
ctx->panel.prepare_prev_first = true ;
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0 )
goto remove_panel;
return ret;
remove_panel:
drm_panel_remove(&ctx->panel);
backlight_device_unregister(ctx->bl_dev);
return ret;
}
static void s6e3ha2_remove(struct mipi_dsi_device *dsi)
{
struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
mipi_dsi_detach(dsi);
drm_panel_remove(&ctx->panel);
backlight_device_unregister(ctx->bl_dev);
}
static const struct of_device_id s6e3ha2_of_match[] = {
{ .compatible = "samsung,s6e3ha2" , .data = &samsung_s6e3ha2 },
{ .compatible = "samsung,s6e3hf2" , .data = &samsung_s6e3hf2 },
{ }
};
MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
static struct mipi_dsi_driver s6e3ha2_driver = {
.probe = s6e3ha2_probe,
.remove = s6e3ha2_remove,
.driver = {
.name = "panel-samsung-s6e3ha2" ,
.of_match_table = s6e3ha2_of_match,
},
};
module_mipi_dsi_driver(s6e3ha2_driver);
MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>" );
MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>" );
MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>" );
MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver" );
MODULE_LICENSE("GPL v2" );
Messung V0.5 in Prozent C=93 H=94 G=93