1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2021, Linaro Limited |
4 | * |
5 | * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: |
6 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. |
7 | */ |
8 | |
9 | #include <linux/backlight.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/regulator/consumer.h> |
15 | |
16 | #include <drm/drm_mipi_dsi.h> |
17 | #include <drm/drm_modes.h> |
18 | #include <drm/drm_panel.h> |
19 | |
20 | struct truly_nt35521 { |
21 | struct drm_panel panel; |
22 | struct mipi_dsi_device *dsi; |
23 | struct regulator_bulk_data supplies[2]; |
24 | struct gpio_desc *reset_gpio; |
25 | struct gpio_desc *blen_gpio; |
26 | }; |
27 | |
28 | static inline |
29 | struct truly_nt35521 *to_truly_nt35521(struct drm_panel *panel) |
30 | { |
31 | return container_of(panel, struct truly_nt35521, panel); |
32 | } |
33 | |
34 | static void truly_nt35521_reset(struct truly_nt35521 *ctx) |
35 | { |
36 | gpiod_set_value_cansleep(desc: ctx->reset_gpio, value: 1); |
37 | usleep_range(min: 1000, max: 2000); |
38 | gpiod_set_value_cansleep(desc: ctx->reset_gpio, value: 1); |
39 | usleep_range(min: 10000, max: 11000); |
40 | gpiod_set_value_cansleep(desc: ctx->reset_gpio, value: 0); |
41 | msleep(msecs: 150); |
42 | } |
43 | |
44 | static int truly_nt35521_on(struct truly_nt35521 *ctx) |
45 | { |
46 | struct mipi_dsi_device *dsi = ctx->dsi; |
47 | struct device *dev = &dsi->dev; |
48 | int ret; |
49 | |
50 | dsi->mode_flags |= MIPI_DSI_MODE_LPM; |
51 | |
52 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00); |
53 | mipi_dsi_generic_write_seq(dsi, 0xff, 0xaa, 0x55, 0xa5, 0x80); |
54 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11, 0x00); |
55 | mipi_dsi_generic_write_seq(dsi, 0xf7, 0x20, 0x00); |
56 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01); |
57 | mipi_dsi_generic_write_seq(dsi, 0xb1, 0x21); |
58 | mipi_dsi_generic_write_seq(dsi, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01); |
59 | mipi_dsi_generic_write_seq(dsi, 0xb8, 0x01, 0x02, 0x0c, 0x02); |
60 | mipi_dsi_generic_write_seq(dsi, 0xbb, 0x11, 0x11); |
61 | mipi_dsi_generic_write_seq(dsi, 0xbc, 0x00, 0x00); |
62 | mipi_dsi_generic_write_seq(dsi, 0xb6, 0x02); |
63 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01); |
64 | mipi_dsi_generic_write_seq(dsi, 0xb0, 0x09, 0x09); |
65 | mipi_dsi_generic_write_seq(dsi, 0xb1, 0x09, 0x09); |
66 | mipi_dsi_generic_write_seq(dsi, 0xbc, 0x8c, 0x00); |
67 | mipi_dsi_generic_write_seq(dsi, 0xbd, 0x8c, 0x00); |
68 | mipi_dsi_generic_write_seq(dsi, 0xca, 0x00); |
69 | mipi_dsi_generic_write_seq(dsi, 0xc0, 0x04); |
70 | mipi_dsi_generic_write_seq(dsi, 0xbe, 0xb5); |
71 | mipi_dsi_generic_write_seq(dsi, 0xb3, 0x35, 0x35); |
72 | mipi_dsi_generic_write_seq(dsi, 0xb4, 0x25, 0x25); |
73 | mipi_dsi_generic_write_seq(dsi, 0xb9, 0x43, 0x43); |
74 | mipi_dsi_generic_write_seq(dsi, 0xba, 0x24, 0x24); |
75 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02); |
76 | mipi_dsi_generic_write_seq(dsi, 0xee, 0x03); |
77 | mipi_dsi_generic_write_seq(dsi, 0xb0, |
78 | 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3, |
79 | 0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11); |
80 | mipi_dsi_generic_write_seq(dsi, 0xb1, |
81 | 0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3, |
82 | 0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77); |
83 | mipi_dsi_generic_write_seq(dsi, 0xb2, |
84 | 0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c, |
85 | 0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90); |
86 | mipi_dsi_generic_write_seq(dsi, 0xb3, 0x03, 0x96, 0x03, 0x98); |
87 | mipi_dsi_generic_write_seq(dsi, 0xb4, |
88 | 0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9, |
89 | 0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02); |
90 | mipi_dsi_generic_write_seq(dsi, 0xb5, |
91 | 0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf, |
92 | 0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76); |
93 | mipi_dsi_generic_write_seq(dsi, 0xb6, |
94 | 0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c, |
95 | 0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2); |
96 | mipi_dsi_generic_write_seq(dsi, 0xb7, 0x03, 0xb8, 0x03, 0xba); |
97 | mipi_dsi_generic_write_seq(dsi, 0xb8, |
98 | 0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a, |
99 | 0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9); |
100 | mipi_dsi_generic_write_seq(dsi, 0xb9, |
101 | 0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3, |
102 | 0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67); |
103 | mipi_dsi_generic_write_seq(dsi, 0xba, |
104 | 0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31, |
105 | 0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4); |
106 | mipi_dsi_generic_write_seq(dsi, 0xbb, 0x03, 0xf6, 0x03, 0xf7); |
107 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03); |
108 | mipi_dsi_generic_write_seq(dsi, 0xb0, 0x22, 0x00); |
109 | mipi_dsi_generic_write_seq(dsi, 0xb1, 0x22, 0x00); |
110 | mipi_dsi_generic_write_seq(dsi, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00); |
111 | mipi_dsi_generic_write_seq(dsi, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00); |
112 | mipi_dsi_generic_write_seq(dsi, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00); |
113 | mipi_dsi_generic_write_seq(dsi, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00); |
114 | mipi_dsi_generic_write_seq(dsi, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00); |
115 | mipi_dsi_generic_write_seq(dsi, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00); |
116 | mipi_dsi_generic_write_seq(dsi, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00); |
117 | mipi_dsi_generic_write_seq(dsi, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00); |
118 | mipi_dsi_generic_write_seq(dsi, 0xc0, 0x00, 0x34, 0x00, 0x00); |
119 | mipi_dsi_generic_write_seq(dsi, 0xc1, 0x00, 0x00, 0x34, 0x00); |
120 | mipi_dsi_generic_write_seq(dsi, 0xc2, 0x00, 0x00, 0x34, 0x00); |
121 | mipi_dsi_generic_write_seq(dsi, 0xc3, 0x00, 0x00, 0x34, 0x00); |
122 | mipi_dsi_generic_write_seq(dsi, 0xc4, 0x60); |
123 | mipi_dsi_generic_write_seq(dsi, 0xc5, 0xc0); |
124 | mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00); |
125 | mipi_dsi_generic_write_seq(dsi, 0xc7, 0x00); |
126 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05); |
127 | mipi_dsi_generic_write_seq(dsi, 0xb0, 0x17, 0x06); |
128 | mipi_dsi_generic_write_seq(dsi, 0xb1, 0x17, 0x06); |
129 | mipi_dsi_generic_write_seq(dsi, 0xb2, 0x17, 0x06); |
130 | mipi_dsi_generic_write_seq(dsi, 0xb3, 0x17, 0x06); |
131 | mipi_dsi_generic_write_seq(dsi, 0xb4, 0x17, 0x06); |
132 | mipi_dsi_generic_write_seq(dsi, 0xb5, 0x17, 0x06); |
133 | mipi_dsi_generic_write_seq(dsi, 0xb6, 0x17, 0x06); |
134 | mipi_dsi_generic_write_seq(dsi, 0xb7, 0x17, 0x06); |
135 | mipi_dsi_generic_write_seq(dsi, 0xb8, 0x00); |
136 | mipi_dsi_generic_write_seq(dsi, 0xb9, 0x00, 0x03); |
137 | mipi_dsi_generic_write_seq(dsi, 0xba, 0x00, 0x00); |
138 | mipi_dsi_generic_write_seq(dsi, 0xbb, 0x02, 0x03); |
139 | mipi_dsi_generic_write_seq(dsi, 0xbc, 0x02, 0x03); |
140 | mipi_dsi_generic_write_seq(dsi, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03); |
141 | mipi_dsi_generic_write_seq(dsi, 0xc0, 0x0b); |
142 | mipi_dsi_generic_write_seq(dsi, 0xc1, 0x09); |
143 | mipi_dsi_generic_write_seq(dsi, 0xc2, 0xa6); |
144 | mipi_dsi_generic_write_seq(dsi, 0xc3, 0x05); |
145 | mipi_dsi_generic_write_seq(dsi, 0xc4, 0x00); |
146 | mipi_dsi_generic_write_seq(dsi, 0xc5, 0x02); |
147 | mipi_dsi_generic_write_seq(dsi, 0xc6, 0x22); |
148 | mipi_dsi_generic_write_seq(dsi, 0xc7, 0x03); |
149 | mipi_dsi_generic_write_seq(dsi, 0xc8, 0x07, 0x20); |
150 | mipi_dsi_generic_write_seq(dsi, 0xc9, 0x03, 0x20); |
151 | mipi_dsi_generic_write_seq(dsi, 0xca, 0x01, 0x60); |
152 | mipi_dsi_generic_write_seq(dsi, 0xcb, 0x01, 0x60); |
153 | mipi_dsi_generic_write_seq(dsi, 0xcc, 0x00, 0x00, 0x02); |
154 | mipi_dsi_generic_write_seq(dsi, 0xcd, 0x00, 0x00, 0x02); |
155 | mipi_dsi_generic_write_seq(dsi, 0xce, 0x00, 0x00, 0x02); |
156 | mipi_dsi_generic_write_seq(dsi, 0xcf, 0x00, 0x00, 0x02); |
157 | mipi_dsi_generic_write_seq(dsi, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10); |
158 | mipi_dsi_generic_write_seq(dsi, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10); |
159 | mipi_dsi_generic_write_seq(dsi, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10); |
160 | mipi_dsi_generic_write_seq(dsi, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10); |
161 | mipi_dsi_generic_write_seq(dsi, 0xd0, |
162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
163 | mipi_dsi_generic_write_seq(dsi, 0xd5, |
164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
165 | 0x00, 0x00, 0x00); |
166 | mipi_dsi_generic_write_seq(dsi, 0xd6, |
167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
168 | 0x00, 0x00, 0x00); |
169 | mipi_dsi_generic_write_seq(dsi, 0xd7, |
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
171 | 0x00, 0x00, 0x00); |
172 | mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00); |
173 | mipi_dsi_generic_write_seq(dsi, 0xe5, 0x06); |
174 | mipi_dsi_generic_write_seq(dsi, 0xe6, 0x06); |
175 | mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00); |
176 | mipi_dsi_generic_write_seq(dsi, 0xe8, 0x06); |
177 | mipi_dsi_generic_write_seq(dsi, 0xe9, 0x06); |
178 | mipi_dsi_generic_write_seq(dsi, 0xea, 0x06); |
179 | mipi_dsi_generic_write_seq(dsi, 0xeb, 0x00); |
180 | mipi_dsi_generic_write_seq(dsi, 0xec, 0x00); |
181 | mipi_dsi_generic_write_seq(dsi, 0xed, 0x30); |
182 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06); |
183 | mipi_dsi_generic_write_seq(dsi, 0xb0, 0x31, 0x31); |
184 | mipi_dsi_generic_write_seq(dsi, 0xb1, 0x31, 0x31); |
185 | mipi_dsi_generic_write_seq(dsi, 0xb2, 0x2d, 0x2e); |
186 | mipi_dsi_generic_write_seq(dsi, 0xb3, 0x31, 0x34); |
187 | mipi_dsi_generic_write_seq(dsi, 0xb4, 0x29, 0x2a); |
188 | mipi_dsi_generic_write_seq(dsi, 0xb5, 0x12, 0x10); |
189 | mipi_dsi_generic_write_seq(dsi, 0xb6, 0x18, 0x16); |
190 | mipi_dsi_generic_write_seq(dsi, 0xb7, 0x00, 0x02); |
191 | mipi_dsi_generic_write_seq(dsi, 0xb8, 0x08, 0x31); |
192 | mipi_dsi_generic_write_seq(dsi, 0xb9, 0x31, 0x31); |
193 | mipi_dsi_generic_write_seq(dsi, 0xba, 0x31, 0x31); |
194 | mipi_dsi_generic_write_seq(dsi, 0xbb, 0x31, 0x08); |
195 | mipi_dsi_generic_write_seq(dsi, 0xbc, 0x03, 0x01); |
196 | mipi_dsi_generic_write_seq(dsi, 0xbd, 0x17, 0x19); |
197 | mipi_dsi_generic_write_seq(dsi, 0xbe, 0x11, 0x13); |
198 | mipi_dsi_generic_write_seq(dsi, 0xbf, 0x2a, 0x29); |
199 | mipi_dsi_generic_write_seq(dsi, 0xc0, 0x34, 0x31); |
200 | mipi_dsi_generic_write_seq(dsi, 0xc1, 0x2e, 0x2d); |
201 | mipi_dsi_generic_write_seq(dsi, 0xc2, 0x31, 0x31); |
202 | mipi_dsi_generic_write_seq(dsi, 0xc3, 0x31, 0x31); |
203 | mipi_dsi_generic_write_seq(dsi, 0xc4, 0x31, 0x31); |
204 | mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31, 0x31); |
205 | mipi_dsi_generic_write_seq(dsi, 0xc6, 0x2e, 0x2d); |
206 | mipi_dsi_generic_write_seq(dsi, 0xc7, 0x31, 0x34); |
207 | mipi_dsi_generic_write_seq(dsi, 0xc8, 0x29, 0x2a); |
208 | mipi_dsi_generic_write_seq(dsi, 0xc9, 0x17, 0x19); |
209 | mipi_dsi_generic_write_seq(dsi, 0xca, 0x11, 0x13); |
210 | mipi_dsi_generic_write_seq(dsi, 0xcb, 0x03, 0x01); |
211 | mipi_dsi_generic_write_seq(dsi, 0xcc, 0x08, 0x31); |
212 | mipi_dsi_generic_write_seq(dsi, 0xcd, 0x31, 0x31); |
213 | mipi_dsi_generic_write_seq(dsi, 0xce, 0x31, 0x31); |
214 | mipi_dsi_generic_write_seq(dsi, 0xcf, 0x31, 0x08); |
215 | mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00, 0x02); |
216 | mipi_dsi_generic_write_seq(dsi, 0xd1, 0x12, 0x10); |
217 | mipi_dsi_generic_write_seq(dsi, 0xd2, 0x18, 0x16); |
218 | mipi_dsi_generic_write_seq(dsi, 0xd3, 0x2a, 0x29); |
219 | mipi_dsi_generic_write_seq(dsi, 0xd4, 0x34, 0x31); |
220 | mipi_dsi_generic_write_seq(dsi, 0xd5, 0x2d, 0x2e); |
221 | mipi_dsi_generic_write_seq(dsi, 0xd6, 0x31, 0x31); |
222 | mipi_dsi_generic_write_seq(dsi, 0xd7, 0x31, 0x31); |
223 | mipi_dsi_generic_write_seq(dsi, 0xe5, 0x31, 0x31); |
224 | mipi_dsi_generic_write_seq(dsi, 0xe6, 0x31, 0x31); |
225 | mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00); |
226 | mipi_dsi_generic_write_seq(dsi, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00); |
227 | mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00); |
228 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x02); |
229 | mipi_dsi_generic_write_seq(dsi, 0xf7, 0x47); |
230 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x0a); |
231 | mipi_dsi_generic_write_seq(dsi, 0xf7, 0x02); |
232 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x17); |
233 | mipi_dsi_generic_write_seq(dsi, 0xf4, 0x60); |
234 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01); |
235 | mipi_dsi_generic_write_seq(dsi, 0xf9, 0x46); |
236 | mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11); |
237 | mipi_dsi_generic_write_seq(dsi, 0xf3, 0x01); |
238 | mipi_dsi_generic_write_seq(dsi, 0x35, 0x00); |
239 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00); |
240 | mipi_dsi_generic_write_seq(dsi, 0xd9, 0x02, 0x03, 0x00); |
241 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00); |
242 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00); |
243 | mipi_dsi_generic_write_seq(dsi, 0xb1, 0x6c, 0x21); |
244 | mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00); |
245 | mipi_dsi_generic_write_seq(dsi, 0x35, 0x00); |
246 | |
247 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
248 | if (ret < 0) { |
249 | dev_err(dev, "Failed to exit sleep mode: %d\n" , ret); |
250 | return ret; |
251 | } |
252 | msleep(msecs: 120); |
253 | |
254 | ret = mipi_dsi_dcs_set_display_on(dsi); |
255 | if (ret < 0) { |
256 | dev_err(dev, "Failed to set display on: %d\n" , ret); |
257 | return ret; |
258 | } |
259 | usleep_range(min: 1000, max: 2000); |
260 | |
261 | mipi_dsi_generic_write_seq(dsi, 0x53, 0x24); |
262 | |
263 | return 0; |
264 | } |
265 | |
266 | static int truly_nt35521_off(struct truly_nt35521 *ctx) |
267 | { |
268 | struct mipi_dsi_device *dsi = ctx->dsi; |
269 | struct device *dev = &dsi->dev; |
270 | int ret; |
271 | |
272 | dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; |
273 | |
274 | ret = mipi_dsi_dcs_set_display_off(dsi); |
275 | if (ret < 0) { |
276 | dev_err(dev, "Failed to set display off: %d\n" , ret); |
277 | return ret; |
278 | } |
279 | msleep(msecs: 50); |
280 | |
281 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
282 | if (ret < 0) { |
283 | dev_err(dev, "Failed to enter sleep mode: %d\n" , ret); |
284 | return ret; |
285 | } |
286 | msleep(msecs: 150); |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | static int truly_nt35521_prepare(struct drm_panel *panel) |
292 | { |
293 | struct truly_nt35521 *ctx = to_truly_nt35521(panel); |
294 | struct device *dev = &ctx->dsi->dev; |
295 | int ret; |
296 | |
297 | ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), consumers: ctx->supplies); |
298 | if (ret < 0) { |
299 | dev_err(dev, "Failed to enable regulators: %d\n" , ret); |
300 | return ret; |
301 | } |
302 | |
303 | truly_nt35521_reset(ctx); |
304 | |
305 | ret = truly_nt35521_on(ctx); |
306 | if (ret < 0) { |
307 | dev_err(dev, "Failed to initialize panel: %d\n" , ret); |
308 | gpiod_set_value_cansleep(desc: ctx->reset_gpio, value: 1); |
309 | return ret; |
310 | } |
311 | |
312 | return 0; |
313 | } |
314 | |
315 | static int truly_nt35521_unprepare(struct drm_panel *panel) |
316 | { |
317 | struct truly_nt35521 *ctx = to_truly_nt35521(panel); |
318 | struct device *dev = &ctx->dsi->dev; |
319 | int ret; |
320 | |
321 | ret = truly_nt35521_off(ctx); |
322 | if (ret < 0) |
323 | dev_err(dev, "Failed to un-initialize panel: %d\n" , ret); |
324 | |
325 | gpiod_set_value_cansleep(desc: ctx->reset_gpio, value: 1); |
326 | regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), |
327 | consumers: ctx->supplies); |
328 | |
329 | return 0; |
330 | } |
331 | |
332 | static int truly_nt35521_enable(struct drm_panel *panel) |
333 | { |
334 | struct truly_nt35521 *ctx = to_truly_nt35521(panel); |
335 | |
336 | gpiod_set_value_cansleep(desc: ctx->blen_gpio, value: 1); |
337 | |
338 | return 0; |
339 | } |
340 | |
341 | static int truly_nt35521_disable(struct drm_panel *panel) |
342 | { |
343 | struct truly_nt35521 *ctx = to_truly_nt35521(panel); |
344 | |
345 | gpiod_set_value_cansleep(desc: ctx->blen_gpio, value: 0); |
346 | |
347 | return 0; |
348 | } |
349 | |
350 | static const struct drm_display_mode truly_nt35521_mode = { |
351 | .clock = (720 + 232 + 20 + 112) * (1280 + 18 + 1 + 18) * 60 / 1000, |
352 | .hdisplay = 720, |
353 | .hsync_start = 720 + 232, |
354 | .hsync_end = 720 + 232 + 20, |
355 | .htotal = 720 + 232 + 20 + 112, |
356 | .vdisplay = 1280, |
357 | .vsync_start = 1280 + 18, |
358 | .vsync_end = 1280 + 18 + 1, |
359 | .vtotal = 1280 + 18 + 1 + 18, |
360 | .width_mm = 65, |
361 | .height_mm = 116, |
362 | }; |
363 | |
364 | static int truly_nt35521_get_modes(struct drm_panel *panel, |
365 | struct drm_connector *connector) |
366 | { |
367 | struct drm_display_mode *mode; |
368 | |
369 | mode = drm_mode_duplicate(dev: connector->dev, mode: &truly_nt35521_mode); |
370 | if (!mode) |
371 | return -ENOMEM; |
372 | |
373 | drm_mode_set_name(mode); |
374 | |
375 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; |
376 | connector->display_info.width_mm = mode->width_mm; |
377 | connector->display_info.height_mm = mode->height_mm; |
378 | drm_mode_probed_add(connector, mode); |
379 | |
380 | return 1; |
381 | } |
382 | |
383 | static const struct drm_panel_funcs truly_nt35521_panel_funcs = { |
384 | .prepare = truly_nt35521_prepare, |
385 | .unprepare = truly_nt35521_unprepare, |
386 | .enable = truly_nt35521_enable, |
387 | .disable = truly_nt35521_disable, |
388 | .get_modes = truly_nt35521_get_modes, |
389 | }; |
390 | |
391 | static int truly_nt35521_bl_update_status(struct backlight_device *bl) |
392 | { |
393 | struct mipi_dsi_device *dsi = bl_get_data(bl_dev: bl); |
394 | u16 brightness = backlight_get_brightness(bd: bl); |
395 | int ret; |
396 | |
397 | ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); |
398 | if (ret < 0) |
399 | return ret; |
400 | |
401 | return 0; |
402 | } |
403 | |
404 | static int truly_nt35521_bl_get_brightness(struct backlight_device *bl) |
405 | { |
406 | struct mipi_dsi_device *dsi = bl_get_data(bl_dev: bl); |
407 | u16 brightness; |
408 | int ret; |
409 | |
410 | ret = mipi_dsi_dcs_get_display_brightness(dsi, brightness: &brightness); |
411 | if (ret < 0) |
412 | return ret; |
413 | |
414 | return brightness & 0xff; |
415 | } |
416 | |
417 | static const struct backlight_ops truly_nt35521_bl_ops = { |
418 | .update_status = truly_nt35521_bl_update_status, |
419 | .get_brightness = truly_nt35521_bl_get_brightness, |
420 | }; |
421 | |
422 | static struct backlight_device * |
423 | truly_nt35521_create_backlight(struct mipi_dsi_device *dsi) |
424 | { |
425 | struct device *dev = &dsi->dev; |
426 | const struct backlight_properties props = { |
427 | .type = BACKLIGHT_RAW, |
428 | .brightness = 255, |
429 | .max_brightness = 255, |
430 | }; |
431 | |
432 | return devm_backlight_device_register(dev, name: dev_name(dev), parent: dev, devdata: dsi, |
433 | ops: &truly_nt35521_bl_ops, props: &props); |
434 | } |
435 | |
436 | static int truly_nt35521_probe(struct mipi_dsi_device *dsi) |
437 | { |
438 | struct device *dev = &dsi->dev; |
439 | struct truly_nt35521 *ctx; |
440 | int ret; |
441 | |
442 | ctx = devm_kzalloc(dev, size: sizeof(*ctx), GFP_KERNEL); |
443 | if (!ctx) |
444 | return -ENOMEM; |
445 | |
446 | ctx->supplies[0].supply = "positive5" ; |
447 | ctx->supplies[1].supply = "negative5" ; |
448 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), |
449 | consumers: ctx->supplies); |
450 | if (ret < 0) { |
451 | dev_err(dev, "Failed to get regulators: %d\n" , ret); |
452 | return ret; |
453 | } |
454 | |
455 | ctx->reset_gpio = devm_gpiod_get(dev, con_id: "reset" , flags: GPIOD_OUT_HIGH); |
456 | if (IS_ERR(ptr: ctx->reset_gpio)) |
457 | return dev_err_probe(dev, err: PTR_ERR(ptr: ctx->reset_gpio), |
458 | fmt: "Failed to get reset-gpios\n" ); |
459 | |
460 | ctx->blen_gpio = devm_gpiod_get(dev, con_id: "backlight" , flags: GPIOD_OUT_LOW); |
461 | if (IS_ERR(ptr: ctx->blen_gpio)) |
462 | return dev_err_probe(dev, err: PTR_ERR(ptr: ctx->blen_gpio), |
463 | fmt: "Failed to get backlight-gpios\n" ); |
464 | |
465 | ctx->dsi = dsi; |
466 | mipi_dsi_set_drvdata(dsi, data: ctx); |
467 | |
468 | dsi->lanes = 4; |
469 | dsi->format = MIPI_DSI_FMT_RGB888; |
470 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | |
471 | MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_NO_EOT_PACKET | |
472 | MIPI_DSI_CLOCK_NON_CONTINUOUS; |
473 | |
474 | drm_panel_init(panel: &ctx->panel, dev, funcs: &truly_nt35521_panel_funcs, |
475 | DRM_MODE_CONNECTOR_DSI); |
476 | |
477 | ctx->panel.backlight = truly_nt35521_create_backlight(dsi); |
478 | if (IS_ERR(ptr: ctx->panel.backlight)) |
479 | return dev_err_probe(dev, err: PTR_ERR(ptr: ctx->panel.backlight), |
480 | fmt: "Failed to create backlight\n" ); |
481 | |
482 | drm_panel_add(panel: &ctx->panel); |
483 | |
484 | ret = mipi_dsi_attach(dsi); |
485 | if (ret < 0) { |
486 | dev_err(dev, "Failed to attach to DSI host: %d\n" , ret); |
487 | drm_panel_remove(panel: &ctx->panel); |
488 | return ret; |
489 | } |
490 | |
491 | return 0; |
492 | } |
493 | |
494 | static void truly_nt35521_remove(struct mipi_dsi_device *dsi) |
495 | { |
496 | struct truly_nt35521 *ctx = mipi_dsi_get_drvdata(dsi); |
497 | int ret; |
498 | |
499 | ret = mipi_dsi_detach(dsi); |
500 | if (ret < 0) |
501 | dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n" , ret); |
502 | |
503 | drm_panel_remove(panel: &ctx->panel); |
504 | } |
505 | |
506 | static const struct of_device_id truly_nt35521_of_match[] = { |
507 | { .compatible = "sony,tulip-truly-nt35521" }, |
508 | { /* sentinel */ } |
509 | }; |
510 | MODULE_DEVICE_TABLE(of, truly_nt35521_of_match); |
511 | |
512 | static struct mipi_dsi_driver truly_nt35521_driver = { |
513 | .probe = truly_nt35521_probe, |
514 | .remove = truly_nt35521_remove, |
515 | .driver = { |
516 | .name = "panel-truly-nt35521" , |
517 | .of_match_table = truly_nt35521_of_match, |
518 | }, |
519 | }; |
520 | module_mipi_dsi_driver(truly_nt35521_driver); |
521 | |
522 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>" ); |
523 | MODULE_DESCRIPTION("DRM driver for Sony Tulip Truly NT35521 panel" ); |
524 | MODULE_LICENSE("GPL v2" ); |
525 | |