1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2014 NVIDIA Corporation |
4 | */ |
5 | |
6 | #include <linux/delay.h> |
7 | #include <linux/gpio/consumer.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of.h> |
10 | #include <linux/regulator/consumer.h> |
11 | |
12 | #include <video/mipi_display.h> |
13 | |
14 | #include <drm/drm_crtc.h> |
15 | #include <drm/drm_device.h> |
16 | #include <drm/drm_mipi_dsi.h> |
17 | #include <drm/drm_panel.h> |
18 | |
19 | struct sharp_panel { |
20 | struct drm_panel base; |
21 | /* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */ |
22 | struct mipi_dsi_device *link1; |
23 | struct mipi_dsi_device *link2; |
24 | |
25 | struct regulator *supply; |
26 | |
27 | bool prepared; |
28 | bool enabled; |
29 | |
30 | const struct drm_display_mode *mode; |
31 | }; |
32 | |
33 | static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel) |
34 | { |
35 | return container_of(panel, struct sharp_panel, base); |
36 | } |
37 | |
38 | static void sharp_wait_frames(struct sharp_panel *sharp, unsigned int frames) |
39 | { |
40 | unsigned int refresh = drm_mode_vrefresh(mode: sharp->mode); |
41 | |
42 | if (WARN_ON(frames > refresh)) |
43 | return; |
44 | |
45 | msleep(msecs: 1000 / (refresh / frames)); |
46 | } |
47 | |
48 | static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value) |
49 | { |
50 | u8 payload[3] = { offset >> 8, offset & 0xff, value }; |
51 | struct mipi_dsi_device *dsi = sharp->link1; |
52 | ssize_t err; |
53 | |
54 | err = mipi_dsi_generic_write(dsi, payload, size: sizeof(payload)); |
55 | if (err < 0) { |
56 | dev_err(&dsi->dev, "failed to write %02x to %04x: %zd\n" , |
57 | value, offset, err); |
58 | return err; |
59 | } |
60 | |
61 | err = mipi_dsi_dcs_nop(dsi); |
62 | if (err < 0) { |
63 | dev_err(&dsi->dev, "failed to send DCS nop: %zd\n" , err); |
64 | return err; |
65 | } |
66 | |
67 | usleep_range(min: 10, max: 20); |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | static __maybe_unused int sharp_panel_read(struct sharp_panel *sharp, |
73 | u16 offset, u8 *value) |
74 | { |
75 | ssize_t err; |
76 | |
77 | cpu_to_be16s(&offset); |
78 | |
79 | err = mipi_dsi_generic_read(dsi: sharp->link1, params: &offset, num_params: sizeof(offset), |
80 | data: value, size: sizeof(*value)); |
81 | if (err < 0) |
82 | dev_err(&sharp->link1->dev, "failed to read from %04x: %zd\n" , |
83 | offset, err); |
84 | |
85 | return err; |
86 | } |
87 | |
88 | static int sharp_panel_disable(struct drm_panel *panel) |
89 | { |
90 | struct sharp_panel *sharp = to_sharp_panel(panel); |
91 | |
92 | if (!sharp->enabled) |
93 | return 0; |
94 | |
95 | sharp->enabled = false; |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | static int sharp_panel_unprepare(struct drm_panel *panel) |
101 | { |
102 | struct sharp_panel *sharp = to_sharp_panel(panel); |
103 | int err; |
104 | |
105 | if (!sharp->prepared) |
106 | return 0; |
107 | |
108 | sharp_wait_frames(sharp, frames: 4); |
109 | |
110 | err = mipi_dsi_dcs_set_display_off(dsi: sharp->link1); |
111 | if (err < 0) |
112 | dev_err(panel->dev, "failed to set display off: %d\n" , err); |
113 | |
114 | err = mipi_dsi_dcs_enter_sleep_mode(dsi: sharp->link1); |
115 | if (err < 0) |
116 | dev_err(panel->dev, "failed to enter sleep mode: %d\n" , err); |
117 | |
118 | msleep(msecs: 120); |
119 | |
120 | regulator_disable(regulator: sharp->supply); |
121 | |
122 | sharp->prepared = false; |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left, |
128 | struct mipi_dsi_device *right, |
129 | const struct drm_display_mode *mode) |
130 | { |
131 | int err; |
132 | |
133 | err = mipi_dsi_dcs_set_column_address(dsi: left, start: 0, end: mode->hdisplay / 2 - 1); |
134 | if (err < 0) { |
135 | dev_err(&left->dev, "failed to set column address: %d\n" , err); |
136 | return err; |
137 | } |
138 | |
139 | err = mipi_dsi_dcs_set_page_address(dsi: left, start: 0, end: mode->vdisplay - 1); |
140 | if (err < 0) { |
141 | dev_err(&left->dev, "failed to set page address: %d\n" , err); |
142 | return err; |
143 | } |
144 | |
145 | err = mipi_dsi_dcs_set_column_address(dsi: right, start: mode->hdisplay / 2, |
146 | end: mode->hdisplay - 1); |
147 | if (err < 0) { |
148 | dev_err(&right->dev, "failed to set column address: %d\n" , err); |
149 | return err; |
150 | } |
151 | |
152 | err = mipi_dsi_dcs_set_page_address(dsi: right, start: 0, end: mode->vdisplay - 1); |
153 | if (err < 0) { |
154 | dev_err(&right->dev, "failed to set page address: %d\n" , err); |
155 | return err; |
156 | } |
157 | |
158 | return 0; |
159 | } |
160 | |
161 | static int sharp_panel_prepare(struct drm_panel *panel) |
162 | { |
163 | struct sharp_panel *sharp = to_sharp_panel(panel); |
164 | u8 format = MIPI_DCS_PIXEL_FMT_24BIT; |
165 | int err; |
166 | |
167 | if (sharp->prepared) |
168 | return 0; |
169 | |
170 | err = regulator_enable(regulator: sharp->supply); |
171 | if (err < 0) |
172 | return err; |
173 | |
174 | /* |
175 | * According to the datasheet, the panel needs around 10 ms to fully |
176 | * power up. At least another 120 ms is required before exiting sleep |
177 | * mode to make sure the panel is ready. Throw in another 20 ms for |
178 | * good measure. |
179 | */ |
180 | msleep(msecs: 150); |
181 | |
182 | err = mipi_dsi_dcs_exit_sleep_mode(dsi: sharp->link1); |
183 | if (err < 0) { |
184 | dev_err(panel->dev, "failed to exit sleep mode: %d\n" , err); |
185 | goto poweroff; |
186 | } |
187 | |
188 | /* |
189 | * The MIPI DCS specification mandates this delay only between the |
190 | * exit_sleep_mode and enter_sleep_mode commands, so it isn't strictly |
191 | * necessary here. |
192 | */ |
193 | /* |
194 | msleep(120); |
195 | */ |
196 | |
197 | /* set left-right mode */ |
198 | err = sharp_panel_write(sharp, offset: 0x1000, value: 0x2a); |
199 | if (err < 0) { |
200 | dev_err(panel->dev, "failed to set left-right mode: %d\n" , err); |
201 | goto poweroff; |
202 | } |
203 | |
204 | /* enable command mode */ |
205 | err = sharp_panel_write(sharp, offset: 0x1001, value: 0x01); |
206 | if (err < 0) { |
207 | dev_err(panel->dev, "failed to enable command mode: %d\n" , err); |
208 | goto poweroff; |
209 | } |
210 | |
211 | err = mipi_dsi_dcs_set_pixel_format(dsi: sharp->link1, format); |
212 | if (err < 0) { |
213 | dev_err(panel->dev, "failed to set pixel format: %d\n" , err); |
214 | goto poweroff; |
215 | } |
216 | |
217 | /* |
218 | * TODO: The device supports both left-right and even-odd split |
219 | * configurations, but this driver currently supports only the left- |
220 | * right split. To support a different mode a mechanism needs to be |
221 | * put in place to communicate the configuration back to the DSI host |
222 | * controller. |
223 | */ |
224 | err = sharp_setup_symmetrical_split(left: sharp->link1, right: sharp->link2, |
225 | mode: sharp->mode); |
226 | if (err < 0) { |
227 | dev_err(panel->dev, "failed to set up symmetrical split: %d\n" , |
228 | err); |
229 | goto poweroff; |
230 | } |
231 | |
232 | err = mipi_dsi_dcs_set_display_on(dsi: sharp->link1); |
233 | if (err < 0) { |
234 | dev_err(panel->dev, "failed to set display on: %d\n" , err); |
235 | goto poweroff; |
236 | } |
237 | |
238 | sharp->prepared = true; |
239 | |
240 | /* wait for 6 frames before continuing */ |
241 | sharp_wait_frames(sharp, frames: 6); |
242 | |
243 | return 0; |
244 | |
245 | poweroff: |
246 | regulator_disable(regulator: sharp->supply); |
247 | return err; |
248 | } |
249 | |
250 | static int sharp_panel_enable(struct drm_panel *panel) |
251 | { |
252 | struct sharp_panel *sharp = to_sharp_panel(panel); |
253 | |
254 | if (sharp->enabled) |
255 | return 0; |
256 | |
257 | sharp->enabled = true; |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static const struct drm_display_mode default_mode = { |
263 | .clock = 278000, |
264 | .hdisplay = 2560, |
265 | .hsync_start = 2560 + 128, |
266 | .hsync_end = 2560 + 128 + 64, |
267 | .htotal = 2560 + 128 + 64 + 64, |
268 | .vdisplay = 1600, |
269 | .vsync_start = 1600 + 4, |
270 | .vsync_end = 1600 + 4 + 8, |
271 | .vtotal = 1600 + 4 + 8 + 32, |
272 | }; |
273 | |
274 | static int sharp_panel_get_modes(struct drm_panel *panel, |
275 | struct drm_connector *connector) |
276 | { |
277 | struct drm_display_mode *mode; |
278 | |
279 | mode = drm_mode_duplicate(dev: connector->dev, mode: &default_mode); |
280 | if (!mode) { |
281 | dev_err(panel->dev, "failed to add mode %ux%ux@%u\n" , |
282 | default_mode.hdisplay, default_mode.vdisplay, |
283 | drm_mode_vrefresh(&default_mode)); |
284 | return -ENOMEM; |
285 | } |
286 | |
287 | drm_mode_set_name(mode); |
288 | |
289 | drm_mode_probed_add(connector, mode); |
290 | |
291 | connector->display_info.width_mm = 217; |
292 | connector->display_info.height_mm = 136; |
293 | |
294 | return 1; |
295 | } |
296 | |
297 | static const struct drm_panel_funcs sharp_panel_funcs = { |
298 | .disable = sharp_panel_disable, |
299 | .unprepare = sharp_panel_unprepare, |
300 | .prepare = sharp_panel_prepare, |
301 | .enable = sharp_panel_enable, |
302 | .get_modes = sharp_panel_get_modes, |
303 | }; |
304 | |
305 | static const struct of_device_id sharp_of_match[] = { |
306 | { .compatible = "sharp,lq101r1sx01" , }, |
307 | { } |
308 | }; |
309 | MODULE_DEVICE_TABLE(of, sharp_of_match); |
310 | |
311 | static int sharp_panel_add(struct sharp_panel *sharp) |
312 | { |
313 | int ret; |
314 | |
315 | sharp->mode = &default_mode; |
316 | |
317 | sharp->supply = devm_regulator_get(dev: &sharp->link1->dev, id: "power" ); |
318 | if (IS_ERR(ptr: sharp->supply)) |
319 | return PTR_ERR(ptr: sharp->supply); |
320 | |
321 | drm_panel_init(panel: &sharp->base, dev: &sharp->link1->dev, funcs: &sharp_panel_funcs, |
322 | DRM_MODE_CONNECTOR_DSI); |
323 | |
324 | ret = drm_panel_of_backlight(panel: &sharp->base); |
325 | if (ret) |
326 | return ret; |
327 | |
328 | drm_panel_add(panel: &sharp->base); |
329 | |
330 | return 0; |
331 | } |
332 | |
333 | static void sharp_panel_del(struct sharp_panel *sharp) |
334 | { |
335 | if (sharp->base.dev) |
336 | drm_panel_remove(panel: &sharp->base); |
337 | |
338 | if (sharp->link2) |
339 | put_device(dev: &sharp->link2->dev); |
340 | } |
341 | |
342 | static int sharp_panel_probe(struct mipi_dsi_device *dsi) |
343 | { |
344 | struct mipi_dsi_device *secondary = NULL; |
345 | struct sharp_panel *sharp; |
346 | struct device_node *np; |
347 | int err; |
348 | |
349 | dsi->lanes = 4; |
350 | dsi->format = MIPI_DSI_FMT_RGB888; |
351 | dsi->mode_flags = MIPI_DSI_MODE_LPM; |
352 | |
353 | /* Find DSI-LINK1 */ |
354 | np = of_parse_phandle(np: dsi->dev.of_node, phandle_name: "link2" , index: 0); |
355 | if (np) { |
356 | secondary = of_find_mipi_dsi_device_by_node(np); |
357 | of_node_put(node: np); |
358 | |
359 | if (!secondary) |
360 | return -EPROBE_DEFER; |
361 | } |
362 | |
363 | /* register a panel for only the DSI-LINK1 interface */ |
364 | if (secondary) { |
365 | sharp = devm_kzalloc(dev: &dsi->dev, size: sizeof(*sharp), GFP_KERNEL); |
366 | if (!sharp) { |
367 | put_device(dev: &secondary->dev); |
368 | return -ENOMEM; |
369 | } |
370 | |
371 | mipi_dsi_set_drvdata(dsi, data: sharp); |
372 | |
373 | sharp->link2 = secondary; |
374 | sharp->link1 = dsi; |
375 | |
376 | err = sharp_panel_add(sharp); |
377 | if (err < 0) { |
378 | put_device(dev: &secondary->dev); |
379 | return err; |
380 | } |
381 | } |
382 | |
383 | err = mipi_dsi_attach(dsi); |
384 | if (err < 0) { |
385 | if (secondary) |
386 | sharp_panel_del(sharp); |
387 | |
388 | return err; |
389 | } |
390 | |
391 | return 0; |
392 | } |
393 | |
394 | static void sharp_panel_remove(struct mipi_dsi_device *dsi) |
395 | { |
396 | struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); |
397 | int err; |
398 | |
399 | /* only detach from host for the DSI-LINK2 interface */ |
400 | if (!sharp) { |
401 | mipi_dsi_detach(dsi); |
402 | return; |
403 | } |
404 | |
405 | err = drm_panel_disable(panel: &sharp->base); |
406 | if (err < 0) |
407 | dev_err(&dsi->dev, "failed to disable panel: %d\n" , err); |
408 | |
409 | err = mipi_dsi_detach(dsi); |
410 | if (err < 0) |
411 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n" , err); |
412 | |
413 | sharp_panel_del(sharp); |
414 | } |
415 | |
416 | static void sharp_panel_shutdown(struct mipi_dsi_device *dsi) |
417 | { |
418 | struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); |
419 | |
420 | /* nothing to do for DSI-LINK2 */ |
421 | if (!sharp) |
422 | return; |
423 | |
424 | drm_panel_disable(panel: &sharp->base); |
425 | } |
426 | |
427 | static struct mipi_dsi_driver sharp_panel_driver = { |
428 | .driver = { |
429 | .name = "panel-sharp-lq101r1sx01" , |
430 | .of_match_table = sharp_of_match, |
431 | }, |
432 | .probe = sharp_panel_probe, |
433 | .remove = sharp_panel_remove, |
434 | .shutdown = sharp_panel_shutdown, |
435 | }; |
436 | module_mipi_dsi_driver(sharp_panel_driver); |
437 | |
438 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>" ); |
439 | MODULE_DESCRIPTION("Sharp LQ101R1SX01 panel driver" ); |
440 | MODULE_LICENSE("GPL v2" ); |
441 | |