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