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