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