1 // SPDX-License-Identifier: GPL-2.0-only
3 * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
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>
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>
18 #include <drm/drm_mipi_dsi.h>
19 #include <drm/drm_modes.h>
20 #include <drm/drm_panel.h>
22 #define S6E3HA2_MIN_BRIGHTNESS 0
23 #define S6E3HA2_MAX_BRIGHTNESS 100
24 #define S6E3HA2_DEFAULT_BRIGHTNESS 80
26 #define S6E3HA2_NUM_GAMMA_STEPS 46
27 #define S6E3HA2_GAMMA_CMD_CNT 35
28 #define S6E3HA2_VINT_STATUS_MAX 10
30 static 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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
217 static const unsigned char vint_table
[S6E3HA2_VINT_STATUS_MAX
] = {
218 0x18, 0x19, 0x1a, 0x1b, 0x1c,
219 0x1d, 0x1e, 0x1f, 0x20, 0x21
227 struct s6e3ha2_panel_desc
{
228 const struct drm_display_mode
*mode
;
229 enum s6e3ha2_type type
;
234 struct drm_panel panel
;
235 struct backlight_device
*bl_dev
;
237 struct regulator_bulk_data supplies
[2];
238 struct gpio_desc
*reset_gpio
;
239 struct gpio_desc
*enable_gpio
;
241 const struct s6e3ha2_panel_desc
*desc
;
244 static int s6e3ha2_dcs_write(struct s6e3ha2
*ctx
, const void *data
, size_t len
)
246 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
248 return mipi_dsi_dcs_write_buffer(dsi
, data
, len
);
251 #define s6e3ha2_dcs_write_seq_static(ctx, seq...) do { \
252 static const u8 d[] = { seq }; \
254 ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d)); \
259 #define s6e3ha2_call_write_func(ret, func) do { \
265 static int s6e3ha2_test_key_on_f0(struct s6e3ha2
*ctx
)
267 s6e3ha2_dcs_write_seq_static(ctx
, 0xf0, 0x5a, 0x5a);
271 static int s6e3ha2_test_key_off_f0(struct s6e3ha2
*ctx
)
273 s6e3ha2_dcs_write_seq_static(ctx
, 0xf0, 0xa5, 0xa5);
277 static int s6e3ha2_test_key_on_fc(struct s6e3ha2
*ctx
)
279 s6e3ha2_dcs_write_seq_static(ctx
, 0xfc, 0x5a, 0x5a);
283 static int s6e3ha2_test_key_off_fc(struct s6e3ha2
*ctx
)
285 s6e3ha2_dcs_write_seq_static(ctx
, 0xfc, 0xa5, 0xa5);
289 static int s6e3ha2_single_dsi_set(struct s6e3ha2
*ctx
)
291 s6e3ha2_dcs_write_seq_static(ctx
, 0xf2, 0x67);
292 s6e3ha2_dcs_write_seq_static(ctx
, 0xf9, 0x09);
296 static int s6e3ha2_freq_calibration(struct s6e3ha2
*ctx
)
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);
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);
310 s6e3ha2_dcs_write_seq_static(ctx
, 0xce, 0x03, 0x3b, 0x14, 0x6d,
311 0x40, 0x80, 0xc0, 0x28, 0x28,
312 0x28, 0x28, 0x39, 0xc5);
317 static int s6e3ha2_aor_control(struct s6e3ha2
*ctx
)
319 s6e3ha2_dcs_write_seq_static(ctx
, 0xb2, 0x03, 0x10);
323 static int s6e3ha2_caps_elvss_set(struct s6e3ha2
*ctx
)
325 s6e3ha2_dcs_write_seq_static(ctx
, 0xb6, 0x9c, 0x0a);
329 static int s6e3ha2_acl_off(struct s6e3ha2
*ctx
)
331 s6e3ha2_dcs_write_seq_static(ctx
, 0x55, 0x00);
335 static int s6e3ha2_acl_off_opr(struct s6e3ha2
*ctx
)
337 s6e3ha2_dcs_write_seq_static(ctx
, 0xb5, 0x40);
341 static int s6e3ha2_test_global(struct s6e3ha2
*ctx
)
343 s6e3ha2_dcs_write_seq_static(ctx
, 0xb0, 0x07);
347 static int s6e3ha2_test(struct s6e3ha2
*ctx
)
349 s6e3ha2_dcs_write_seq_static(ctx
, 0xb8, 0x19);
353 static int s6e3ha2_touch_hsync_on1(struct s6e3ha2
*ctx
)
355 s6e3ha2_dcs_write_seq_static(ctx
, 0xbd, 0x33, 0x11, 0x02,
360 static int s6e3ha2_pentile_control(struct s6e3ha2
*ctx
)
362 s6e3ha2_dcs_write_seq_static(ctx
, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
366 static int s6e3ha2_poc_global(struct s6e3ha2
*ctx
)
368 s6e3ha2_dcs_write_seq_static(ctx
, 0xb0, 0x20);
372 static int s6e3ha2_poc_setting(struct s6e3ha2
*ctx
)
374 s6e3ha2_dcs_write_seq_static(ctx
, 0xfe, 0x08);
378 static int s6e3ha2_pcd_set_off(struct s6e3ha2
*ctx
)
380 s6e3ha2_dcs_write_seq_static(ctx
, 0xcc, 0x40, 0x51);
384 static int s6e3ha2_err_fg_set(struct s6e3ha2
*ctx
)
386 s6e3ha2_dcs_write_seq_static(ctx
, 0xed, 0x44);
390 static int s6e3ha2_hbm_off(struct s6e3ha2
*ctx
)
392 s6e3ha2_dcs_write_seq_static(ctx
, 0x53, 0x00);
396 static int s6e3ha2_te_start_setting(struct s6e3ha2
*ctx
)
398 s6e3ha2_dcs_write_seq_static(ctx
, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
402 static int s6e3ha2_gamma_update(struct s6e3ha2
*ctx
)
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);
410 static int s6e3ha2_get_brightness(struct backlight_device
*bl_dev
)
412 return bl_dev
->props
.brightness
;
415 static int s6e3ha2_set_vint(struct s6e3ha2
*ctx
)
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
] };
423 return s6e3ha2_dcs_write(ctx
, data
, ARRAY_SIZE(data
));
426 static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness
)
428 return (brightness
* (S6E3HA2_NUM_GAMMA_STEPS
- 1)) /
429 S6E3HA2_MAX_BRIGHTNESS
;
432 static int s6e3ha2_update_gamma(struct s6e3ha2
*ctx
, unsigned int brightness
)
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, };
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
)));
443 s6e3ha2_call_write_func(ret
, s6e3ha2_gamma_update(ctx
));
444 bl_dev
->props
.brightness
= brightness
;
449 static int s6e3ha2_set_brightness(struct backlight_device
*bl_dev
)
451 struct s6e3ha2
*ctx
= bl_get_data(bl_dev
);
452 unsigned int brightness
= bl_dev
->props
.brightness
;
455 if (brightness
< S6E3HA2_MIN_BRIGHTNESS
||
456 brightness
> bl_dev
->props
.max_brightness
) {
457 dev_err(ctx
->dev
, "Invalid brightness: %u\n", brightness
);
461 if (bl_dev
->props
.power
> FB_BLANK_NORMAL
)
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
));
473 static const struct backlight_ops s6e3ha2_bl_ops
= {
474 .get_brightness
= s6e3ha2_get_brightness
,
475 .update_status
= s6e3ha2_set_brightness
,
478 static int s6e3ha2_panel_init(struct s6e3ha2
*ctx
)
480 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
483 s6e3ha2_call_write_func(ret
, mipi_dsi_dcs_exit_sleep_mode(dsi
));
484 usleep_range(5000, 6000);
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
));
496 static int s6e3ha2_power_off(struct s6e3ha2
*ctx
)
498 return regulator_bulk_disable(ARRAY_SIZE(ctx
->supplies
), ctx
->supplies
);
501 static int s6e3ha2_disable(struct drm_panel
*panel
)
503 struct s6e3ha2
*ctx
= container_of(panel
, struct s6e3ha2
, panel
);
504 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
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
));
511 ctx
->bl_dev
->props
.power
= FB_BLANK_NORMAL
;
516 static int s6e3ha2_unprepare(struct drm_panel
*panel
)
518 struct s6e3ha2
*ctx
= container_of(panel
, struct s6e3ha2
, panel
);
520 return s6e3ha2_power_off(ctx
);
523 static int s6e3ha2_power_on(struct s6e3ha2
*ctx
)
527 ret
= regulator_bulk_enable(ARRAY_SIZE(ctx
->supplies
), ctx
->supplies
);
533 gpiod_set_value(ctx
->enable_gpio
, 0);
534 usleep_range(5000, 6000);
535 gpiod_set_value(ctx
->enable_gpio
, 1);
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);
544 static int s6e3ha2_prepare(struct drm_panel
*panel
)
546 struct s6e3ha2
*ctx
= container_of(panel
, struct s6e3ha2
, panel
);
549 ret
= s6e3ha2_power_on(ctx
);
553 ret
= s6e3ha2_panel_init(ctx
);
557 ctx
->bl_dev
->props
.power
= FB_BLANK_NORMAL
;
562 s6e3ha2_power_off(ctx
);
566 static int s6e3ha2_enable(struct drm_panel
*panel
)
568 struct s6e3ha2
*ctx
= container_of(panel
, struct s6e3ha2
, panel
);
569 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
573 s6e3ha2_call_write_func(ret
,
574 mipi_dsi_dcs_set_tear_on(dsi
, MIPI_DSI_DCS_TEAR_MODE_VBLANK
));
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
));
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
));
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
));
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
));
603 s6e3ha2_call_write_func(ret
, mipi_dsi_dcs_set_display_on(dsi
));
604 ctx
->bl_dev
->props
.power
= FB_BLANK_UNBLANK
;
609 static const struct drm_display_mode s6e3ha2_mode
= {
612 .hsync_start
= 1440 + 1,
613 .hsync_end
= 1440 + 1 + 1,
614 .htotal
= 1440 + 1 + 1 + 1,
616 .vsync_start
= 2560 + 1,
617 .vsync_end
= 2560 + 1 + 1,
618 .vtotal
= 2560 + 1 + 1 + 15,
622 static const struct s6e3ha2_panel_desc samsung_s6e3ha2
= {
623 .mode
= &s6e3ha2_mode
,
627 static const struct drm_display_mode s6e3hf2_mode
= {
630 .hsync_start
= 1600 + 1,
631 .hsync_end
= 1600 + 1 + 1,
632 .htotal
= 1600 + 1 + 1 + 1,
634 .vsync_start
= 2560 + 1,
635 .vsync_end
= 2560 + 1 + 1,
636 .vtotal
= 2560 + 1 + 1 + 15,
640 static const struct s6e3ha2_panel_desc samsung_s6e3hf2
= {
641 .mode
= &s6e3hf2_mode
,
645 static int s6e3ha2_get_modes(struct drm_panel
*panel
,
646 struct drm_connector
*connector
)
648 struct s6e3ha2
*ctx
= container_of(panel
, struct s6e3ha2
, panel
);
649 struct drm_display_mode
*mode
;
651 mode
= drm_mode_duplicate(connector
->dev
, ctx
->desc
->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
));
659 drm_mode_set_name(mode
);
661 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
662 drm_mode_probed_add(connector
, mode
);
664 connector
->display_info
.width_mm
= 71;
665 connector
->display_info
.height_mm
= 125;
670 static 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
,
678 static int s6e3ha2_probe(struct mipi_dsi_device
*dsi
)
680 struct device
*dev
= &dsi
->dev
;
684 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
688 mipi_dsi_set_drvdata(dsi
, ctx
);
691 ctx
->desc
= of_device_get_match_data(dev
);
694 dsi
->format
= MIPI_DSI_FMT_RGB888
;
695 dsi
->mode_flags
= MIPI_DSI_CLOCK_NON_CONTINUOUS
;
697 ctx
->supplies
[0].supply
= "vdd3";
698 ctx
->supplies
[1].supply
= "vci";
700 ret
= devm_regulator_bulk_get(dev
, ARRAY_SIZE(ctx
->supplies
),
703 dev_err(dev
, "failed to get regulators: %d\n", ret
);
707 ctx
->reset_gpio
= devm_gpiod_get(dev
, "reset", GPIOD_OUT_LOW
);
708 if (IS_ERR(ctx
->reset_gpio
)) {
709 dev_err(dev
, "cannot get reset-gpios %ld\n",
710 PTR_ERR(ctx
->reset_gpio
));
711 return PTR_ERR(ctx
->reset_gpio
);
714 ctx
->enable_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_HIGH
);
715 if (IS_ERR(ctx
->enable_gpio
)) {
716 dev_err(dev
, "cannot get enable-gpios %ld\n",
717 PTR_ERR(ctx
->enable_gpio
));
718 return PTR_ERR(ctx
->enable_gpio
);
721 ctx
->bl_dev
= backlight_device_register("s6e3ha2", dev
, ctx
,
722 &s6e3ha2_bl_ops
, NULL
);
723 if (IS_ERR(ctx
->bl_dev
)) {
724 dev_err(dev
, "failed to register backlight device\n");
725 return PTR_ERR(ctx
->bl_dev
);
728 ctx
->bl_dev
->props
.max_brightness
= S6E3HA2_MAX_BRIGHTNESS
;
729 ctx
->bl_dev
->props
.brightness
= S6E3HA2_DEFAULT_BRIGHTNESS
;
730 ctx
->bl_dev
->props
.power
= FB_BLANK_POWERDOWN
;
732 drm_panel_init(&ctx
->panel
, dev
, &s6e3ha2_drm_funcs
,
733 DRM_MODE_CONNECTOR_DSI
);
735 drm_panel_add(&ctx
->panel
);
737 ret
= mipi_dsi_attach(dsi
);
744 drm_panel_remove(&ctx
->panel
);
745 backlight_device_unregister(ctx
->bl_dev
);
750 static int s6e3ha2_remove(struct mipi_dsi_device
*dsi
)
752 struct s6e3ha2
*ctx
= mipi_dsi_get_drvdata(dsi
);
754 mipi_dsi_detach(dsi
);
755 drm_panel_remove(&ctx
->panel
);
756 backlight_device_unregister(ctx
->bl_dev
);
761 static const struct of_device_id s6e3ha2_of_match
[] = {
762 { .compatible
= "samsung,s6e3ha2", .data
= &samsung_s6e3ha2
},
763 { .compatible
= "samsung,s6e3hf2", .data
= &samsung_s6e3hf2
},
766 MODULE_DEVICE_TABLE(of
, s6e3ha2_of_match
);
768 static struct mipi_dsi_driver s6e3ha2_driver
= {
769 .probe
= s6e3ha2_probe
,
770 .remove
= s6e3ha2_remove
,
772 .name
= "panel-samsung-s6e3ha2",
773 .of_match_table
= s6e3ha2_of_match
,
776 module_mipi_dsi_driver(s6e3ha2_driver
);
778 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
779 MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>");
780 MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
781 MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
782 MODULE_LICENSE("GPL v2");