1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
4 *
5 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
6 * Donghwa Lee <dh09.lee@samsung.com>
7 * Hyungwon Hwang <human.hwang@samsung.com>
8 * Hoegeun Kwon <hoegeun.kwon@samsung.com>
9 */
10
11#include <linux/backlight.h>
12#include <linux/delay.h>
13#include <linux/gpio/consumer.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/regulator/consumer.h>
17
18#include <drm/drm_mipi_dsi.h>
19#include <drm/drm_modes.h>
20#include <drm/drm_panel.h>
21
22#define S6E3HA2_MIN_BRIGHTNESS		0
23#define S6E3HA2_MAX_BRIGHTNESS		100
24#define S6E3HA2_DEFAULT_BRIGHTNESS	80
25
26#define S6E3HA2_NUM_GAMMA_STEPS		46
27#define S6E3HA2_GAMMA_CMD_CNT		35
28#define S6E3HA2_VINT_STATUS_MAX		10
29
30static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
31	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83,
32	  0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c,
33	  0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00,
34	  0x00, 0x00 },
35	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84,
36	  0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a,
37	  0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00,
38	  0x00, 0x00 },
39	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
40	  0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a,
41	  0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00,
42	  0x00, 0x00 },
43	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
44	  0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a,
45	  0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00,
46	  0x00, 0x00 },
47	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85,
48	  0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b,
49	  0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00,
50	  0x00, 0x00 },
51	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
52	  0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b,
53	  0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00,
54	  0x00, 0x00 },
55	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
56	  0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89,
57	  0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00,
58	  0x00, 0x00 },
59	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
60	  0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c,
61	  0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
62	  0x00, 0x00 },
63	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
64	  0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88,
65	  0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
66	  0x00, 0x00 },
67	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
68	  0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a,
69	  0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00,
70	  0x00, 0x00 },
71	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
72	  0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b,
73	  0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00,
74	  0x00, 0x00 },
75	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
76	  0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c,
77	  0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00,
78	  0x00, 0x00 },
79	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
80	  0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c,
81	  0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00,
82	  0x00, 0x00 },
83	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
84	  0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
85	  0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00,
86	  0x00, 0x00 },
87	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
88	  0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
89	  0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00,
90	  0x00, 0x00 },
91	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
92	  0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b,
93	  0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
94	  0x00, 0x00 },
95	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
96	  0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e,
97	  0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
98	  0x00, 0x00 },
99	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
100	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e,
101	  0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00,
102	  0x00, 0x00 },
103	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
104	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d,
105	  0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
106	  0x00, 0x00 },
107	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
108	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c,
109	  0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
110	  0x00, 0x00 },
111	{ 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83,
112	  0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a,
113	  0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
114	  0x00, 0x00 },
115	{ 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83,
116	  0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a,
117	  0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
118	  0x00, 0x00 },
119	{ 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83,
120	  0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89,
121	  0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
122	  0x00, 0x00 },
123	{ 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83,
124	  0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a,
125	  0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00,
126	  0x00, 0x00 },
127	{ 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82,
128	  0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87,
129	  0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
130	  0x00, 0x00 },
131	{ 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82,
132	  0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88,
133	  0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
134	  0x00, 0x00 },
135	{ 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83,
136	  0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89,
137	  0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
138	  0x00, 0x00 },
139	{ 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82,
140	  0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86,
141	  0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
142	  0x00, 0x00 },
143	{ 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82,
144	  0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87,
145	  0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00,
146	  0x00, 0x00 },
147	{ 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81,
148	  0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86,
149	  0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
150	  0x00, 0x00 },
151	{ 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82,
152	  0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83,
153	  0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00,
154	  0x00, 0x00 },
155	{ 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82,
156	  0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82,
157	  0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
158	  0x00, 0x00 },
159	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
160	  0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80,
161	  0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
162	  0x00, 0x00 },
163	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81,
164	  0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
165	  0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
166	  0x00, 0x00 },
167	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
168	  0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
169	  0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
170	  0x00, 0x00 },
171	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
172	  0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82,
173	  0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
174	  0x00, 0x00 },
175	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
176	  0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83,
177	  0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
178	  0x00, 0x00 },
179	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
180	  0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83,
181	  0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
182	  0x00, 0x00 },
183	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80,
184	  0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81,
185	  0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00,
186	  0x00, 0x00 },
187	{ 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81,
188	  0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83,
189	  0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00,
190	  0x00, 0x00 },
191	{ 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80,
192	  0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80,
193	  0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
194	  0x00, 0x00 },
195	{ 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80,
196	  0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d,
197	  0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
198	  0x00, 0x00 },
199	{ 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80,
200	  0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82,
201	  0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
202	  0x00, 0x00 },
203	{ 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80,
204	  0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
205	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
206	  0x00, 0x00 },
207	{ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
208	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
209	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
210	  0x00, 0x00 },
211	{ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
212	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
213	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
214	  0x00, 0x00 }
215};
216
217static const unsigned char vint_table[S6E3HA2_VINT_STATUS_MAX] = {
218	0x18, 0x19, 0x1a, 0x1b, 0x1c,
219	0x1d, 0x1e, 0x1f, 0x20, 0x21
220};
221
222enum s6e3ha2_type {
223	HA2_TYPE,
224	HF2_TYPE,
225};
226
227struct s6e3ha2_panel_desc {
228	const struct drm_display_mode *mode;
229	enum s6e3ha2_type type;
230};
231
232struct s6e3ha2 {
233	struct device *dev;
234	struct drm_panel panel;
235	struct backlight_device *bl_dev;
236
237	struct regulator_bulk_data supplies[2];
238	struct gpio_desc *reset_gpio;
239	struct gpio_desc *enable_gpio;
240
241	const struct s6e3ha2_panel_desc *desc;
242};
243
244static int s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
245{
246	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
247
248	return mipi_dsi_dcs_write_buffer(dsi, data, len);
249}
250
251#define s6e3ha2_dcs_write_seq_static(ctx, seq...) do {	\
252	static const u8 d[] = { seq };			\
253	int ret;					\
254	ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d));	\
255	if (ret < 0)					\
256		return ret;				\
257} while (0)
258
259#define s6e3ha2_call_write_func(ret, func) do {	\
260	ret = (func);				\
261	if (ret < 0)				\
262		return ret;			\
263} while (0)
264
265static int s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
266{
267	s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
268	return 0;
269}
270
271static int s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
272{
273	s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5);
274	return 0;
275}
276
277static int s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
278{
279	s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
280	return 0;
281}
282
283static int s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
284{
285	s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5);
286	return 0;
287}
288
289static int s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
290{
291	s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67);
292	s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09);
293	return 0;
294}
295
296static int s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
297{
298	s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c);
299	if (ctx->desc->type == HF2_TYPE)
300		s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67, 0x40, 0xc5);
301	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39);
302	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0);
303	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20);
304
305	if (ctx->desc->type == HA2_TYPE)
306		s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62,
307						  0x40, 0x80, 0xc0, 0x28, 0x28,
308						  0x28, 0x28, 0x39, 0xc5);
309	else
310		s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x14, 0x6d,
311						  0x40, 0x80, 0xc0, 0x28, 0x28,
312						  0x28, 0x28, 0x39, 0xc5);
313
314	return 0;
315}
316
317static int s6e3ha2_aor_control(struct s6e3ha2 *ctx)
318{
319	s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10);
320	return 0;
321}
322
323static int s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
324{
325	s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a);
326	return 0;
327}
328
329static int s6e3ha2_acl_off(struct s6e3ha2 *ctx)
330{
331	s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00);
332	return 0;
333}
334
335static int s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
336{
337	s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40);
338	return 0;
339}
340
341static int s6e3ha2_test_global(struct s6e3ha2 *ctx)
342{
343	s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07);
344	return 0;
345}
346
347static int s6e3ha2_test(struct s6e3ha2 *ctx)
348{
349	s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19);
350	return 0;
351}
352
353static int s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx)
354{
355	s6e3ha2_dcs_write_seq_static(ctx, 0xbd, 0x33, 0x11, 0x02,
356					0x16, 0x02, 0x16);
357	return 0;
358}
359
360static int s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
361{
362	s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
363	return 0;
364}
365
366static int s6e3ha2_poc_global(struct s6e3ha2 *ctx)
367{
368	s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20);
369	return 0;
370}
371
372static int s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
373{
374	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08);
375	return 0;
376}
377
378static int s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
379{
380	s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51);
381	return 0;
382}
383
384static int s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
385{
386	s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44);
387	return 0;
388}
389
390static int s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
391{
392	s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00);
393	return 0;
394}
395
396static int s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
397{
398	s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
399	return 0;
400}
401
402static int s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
403{
404	s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03);
405	ndelay(100); /* need for 100ns delay */
406	s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00);
407	return 0;
408}
409
410static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
411{
412	return bl_dev->props.brightness;
413}
414
415static int s6e3ha2_set_vint(struct s6e3ha2 *ctx)
416{
417	struct backlight_device *bl_dev = ctx->bl_dev;
418	unsigned int brightness = bl_dev->props.brightness;
419	unsigned char data[] = { 0xf4, 0x8b,
420			vint_table[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) /
421			S6E3HA2_MAX_BRIGHTNESS] };
422
423	return s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
424}
425
426static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
427{
428	return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) /
429		S6E3HA2_MAX_BRIGHTNESS;
430}
431
432static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
433{
434	struct backlight_device *bl_dev = ctx->bl_dev;
435	unsigned int index = s6e3ha2_get_brightness_index(brightness);
436	u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, };
437	int ret;
438
439	memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
440	s6e3ha2_call_write_func(ret,
441				s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data)));
442
443	s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
444	bl_dev->props.brightness = brightness;
445
446	return 0;
447}
448
449static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
450{
451	struct s6e3ha2 *ctx = bl_get_data(bl_dev);
452	unsigned int brightness = bl_dev->props.brightness;
453	int ret;
454
455	if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
456		brightness > bl_dev->props.max_brightness) {
457		dev_err(ctx->dev, "Invalid brightness: %u\n", brightness);
458		return -EINVAL;
459	}
460
461	if (bl_dev->props.power > FB_BLANK_NORMAL)
462		return -EPERM;
463
464	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
465	s6e3ha2_call_write_func(ret, s6e3ha2_update_gamma(ctx, brightness));
466	s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
467	s6e3ha2_call_write_func(ret, s6e3ha2_set_vint(ctx));
468	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
469
470	return 0;
471}
472
473static const struct backlight_ops s6e3ha2_bl_ops = {
474	.get_brightness = s6e3ha2_get_brightness,
475	.update_status = s6e3ha2_set_brightness,
476};
477
478static int s6e3ha2_panel_init(struct s6e3ha2 *ctx)
479{
480	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
481	int ret;
482
483	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_exit_sleep_mode(dsi));
484	usleep_range(5000, 6000);
485
486	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
487	s6e3ha2_call_write_func(ret, s6e3ha2_single_dsi_set(ctx));
488	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
489	s6e3ha2_call_write_func(ret, s6e3ha2_freq_calibration(ctx));
490	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
491	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
492
493	return 0;
494}
495
496static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
497{
498	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
499}
500
501static int s6e3ha2_disable(struct drm_panel *panel)
502{
503	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
504	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
505	int ret;
506
507	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_enter_sleep_mode(dsi));
508	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_off(dsi));
509
510	msleep(40);
511	ctx->bl_dev->props.power = FB_BLANK_NORMAL;
512
513	return 0;
514}
515
516static int s6e3ha2_unprepare(struct drm_panel *panel)
517{
518	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
519
520	return s6e3ha2_power_off(ctx);
521}
522
523static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
524{
525	int ret;
526
527	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
528	if (ret < 0)
529		return ret;
530
531	msleep(120);
532
533	gpiod_set_value(ctx->enable_gpio, 0);
534	usleep_range(5000, 6000);
535	gpiod_set_value(ctx->enable_gpio, 1);
536
537	gpiod_set_value(ctx->reset_gpio, 1);
538	usleep_range(5000, 6000);
539	gpiod_set_value(ctx->reset_gpio, 0);
540	usleep_range(5000, 6000);
541
542	return 0;
543}
544static int s6e3ha2_prepare(struct drm_panel *panel)
545{
546	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
547	int ret;
548
549	ret = s6e3ha2_power_on(ctx);
550	if (ret < 0)
551		return ret;
552
553	ret = s6e3ha2_panel_init(ctx);
554	if (ret < 0)
555		goto err;
556
557	ctx->bl_dev->props.power = FB_BLANK_NORMAL;
558
559	return 0;
560
561err:
562	s6e3ha2_power_off(ctx);
563	return ret;
564}
565
566static int s6e3ha2_enable(struct drm_panel *panel)
567{
568	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
569	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
570	int ret;
571
572	/* common setting */
573	s6e3ha2_call_write_func(ret,
574		mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK));
575
576	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx));
577	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx));
578	s6e3ha2_call_write_func(ret, s6e3ha2_touch_hsync_on1(ctx));
579	s6e3ha2_call_write_func(ret, s6e3ha2_pentile_control(ctx));
580	s6e3ha2_call_write_func(ret, s6e3ha2_poc_global(ctx));
581	s6e3ha2_call_write_func(ret, s6e3ha2_poc_setting(ctx));
582	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx));
583
584	/* pcd setting off for TB */
585	s6e3ha2_call_write_func(ret, s6e3ha2_pcd_set_off(ctx));
586	s6e3ha2_call_write_func(ret, s6e3ha2_err_fg_set(ctx));
587	s6e3ha2_call_write_func(ret, s6e3ha2_te_start_setting(ctx));
588
589	/* brightness setting */
590	s6e3ha2_call_write_func(ret, s6e3ha2_set_brightness(ctx->bl_dev));
591	s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx));
592	s6e3ha2_call_write_func(ret, s6e3ha2_caps_elvss_set(ctx));
593	s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx));
594	s6e3ha2_call_write_func(ret, s6e3ha2_acl_off(ctx));
595	s6e3ha2_call_write_func(ret, s6e3ha2_acl_off_opr(ctx));
596	s6e3ha2_call_write_func(ret, s6e3ha2_hbm_off(ctx));
597
598	/* elvss temp compensation */
599	s6e3ha2_call_write_func(ret, s6e3ha2_test_global(ctx));
600	s6e3ha2_call_write_func(ret, s6e3ha2_test(ctx));
601	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx));
602
603	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_on(dsi));
604	ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
605
606	return 0;
607}
608
609static const struct drm_display_mode s6e3ha2_mode = {
610	.clock = 222372,
611	.hdisplay = 1440,
612	.hsync_start = 1440 + 1,
613	.hsync_end = 1440 + 1 + 1,
614	.htotal = 1440 + 1 + 1 + 1,
615	.vdisplay = 2560,
616	.vsync_start = 2560 + 1,
617	.vsync_end = 2560 + 1 + 1,
618	.vtotal = 2560 + 1 + 1 + 15,
619	.flags = 0,
620};
621
622static const struct s6e3ha2_panel_desc samsung_s6e3ha2 = {
623	.mode = &s6e3ha2_mode,
624	.type = HA2_TYPE,
625};
626
627static const struct drm_display_mode s6e3hf2_mode = {
628	.clock = 247856,
629	.hdisplay = 1600,
630	.hsync_start = 1600 + 1,
631	.hsync_end = 1600 + 1 + 1,
632	.htotal = 1600 + 1 + 1 + 1,
633	.vdisplay = 2560,
634	.vsync_start = 2560 + 1,
635	.vsync_end = 2560 + 1 + 1,
636	.vtotal = 2560 + 1 + 1 + 15,
637	.flags = 0,
638};
639
640static const struct s6e3ha2_panel_desc samsung_s6e3hf2 = {
641	.mode = &s6e3hf2_mode,
642	.type = HF2_TYPE,
643};
644
645static int s6e3ha2_get_modes(struct drm_panel *panel,
646			     struct drm_connector *connector)
647{
648	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
649	struct drm_display_mode *mode;
650
651	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
652	if (!mode) {
653		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
654			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
655			drm_mode_vrefresh(ctx->desc->mode));
656		return -ENOMEM;
657	}
658
659	drm_mode_set_name(mode);
660
661	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
662	drm_mode_probed_add(connector, mode);
663
664	connector->display_info.width_mm = 71;
665	connector->display_info.height_mm = 125;
666
667	return 1;
668}
669
670static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
671	.disable = s6e3ha2_disable,
672	.unprepare = s6e3ha2_unprepare,
673	.prepare = s6e3ha2_prepare,
674	.enable = s6e3ha2_enable,
675	.get_modes = s6e3ha2_get_modes,
676};
677
678static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
679{
680	struct device *dev = &dsi->dev;
681	struct s6e3ha2 *ctx;
682	int ret;
683
684	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
685	if (!ctx)
686		return -ENOMEM;
687
688	mipi_dsi_set_drvdata(dsi, ctx);
689
690	ctx->dev = dev;
691	ctx->desc = of_device_get_match_data(dev);
692
693	dsi->lanes = 4;
694	dsi->format = MIPI_DSI_FMT_RGB888;
695	dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
696		MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP |
697		MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET;
698
699	ctx->supplies[0].supply = "vdd3";
700	ctx->supplies[1].supply = "vci";
701
702	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
703				      ctx->supplies);
704	if (ret < 0) {
705		dev_err(dev, "failed to get regulators: %d\n", ret);
706		return ret;
707	}
708
709	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
710	if (IS_ERR(ctx->reset_gpio)) {
711		dev_err(dev, "cannot get reset-gpios %ld\n",
712			PTR_ERR(ctx->reset_gpio));
713		return PTR_ERR(ctx->reset_gpio);
714	}
715
716	ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
717	if (IS_ERR(ctx->enable_gpio)) {
718		dev_err(dev, "cannot get enable-gpios %ld\n",
719			PTR_ERR(ctx->enable_gpio));
720		return PTR_ERR(ctx->enable_gpio);
721	}
722
723	ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx,
724						&s6e3ha2_bl_ops, NULL);
725	if (IS_ERR(ctx->bl_dev)) {
726		dev_err(dev, "failed to register backlight device\n");
727		return PTR_ERR(ctx->bl_dev);
728	}
729
730	ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS;
731	ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
732	ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
733
734	drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs,
735		       DRM_MODE_CONNECTOR_DSI);
736	ctx->panel.prepare_prev_first = true;
737
738	drm_panel_add(&ctx->panel);
739
740	ret = mipi_dsi_attach(dsi);
741	if (ret < 0)
742		goto remove_panel;
743
744	return ret;
745
746remove_panel:
747	drm_panel_remove(&ctx->panel);
748	backlight_device_unregister(ctx->bl_dev);
749
750	return ret;
751}
752
753static void s6e3ha2_remove(struct mipi_dsi_device *dsi)
754{
755	struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
756
757	mipi_dsi_detach(dsi);
758	drm_panel_remove(&ctx->panel);
759	backlight_device_unregister(ctx->bl_dev);
760}
761
762static const struct of_device_id s6e3ha2_of_match[] = {
763	{ .compatible = "samsung,s6e3ha2", .data = &samsung_s6e3ha2 },
764	{ .compatible = "samsung,s6e3hf2", .data = &samsung_s6e3hf2 },
765	{ }
766};
767MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
768
769static struct mipi_dsi_driver s6e3ha2_driver = {
770	.probe = s6e3ha2_probe,
771	.remove = s6e3ha2_remove,
772	.driver = {
773		.name = "panel-samsung-s6e3ha2",
774		.of_match_table = s6e3ha2_of_match,
775	},
776};
777module_mipi_dsi_driver(s6e3ha2_driver);
778
779MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
780MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>");
781MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
782MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
783MODULE_LICENSE("GPL v2");
784