1
2
3
4
5
6
7
8
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.h>
16#include <linux/regulator/consumer.h>
17
18#include <video/mipi_display.h>
19
20#include <drm/drm_mipi_dsi.h>
21#include <drm/drm_modes.h>
22#include <drm/drm_panel.h>
23#include <drm/drm_print.h>
24
25#define ACX424_DCS_READ_ID1 0xDA
26#define ACX424_DCS_READ_ID2 0xDB
27#define ACX424_DCS_READ_ID3 0xDC
28#define ACX424_DCS_SET_MDDI 0xAE
29
30
31
32
33#define DISPLAY_SONY_ACX424AKP_ID1 0x811b
34#define DISPLAY_SONY_ACX424AKP_ID2 0x811a
35
36
37
38
39#define DISPLAY_SONY_ACX424AKP_ID3 0x8000
40
41struct acx424akp {
42 struct drm_panel panel;
43 struct device *dev;
44 struct backlight_device *bl;
45 struct regulator *supply;
46 struct gpio_desc *reset_gpio;
47 bool video_mode;
48};
49
50static const struct drm_display_mode sony_acx424akp_vid_mode = {
51 .clock = 27234,
52 .hdisplay = 480,
53 .hsync_start = 480 + 15,
54 .hsync_end = 480 + 15 + 0,
55 .htotal = 480 + 15 + 0 + 15,
56 .vdisplay = 864,
57 .vsync_start = 864 + 14,
58 .vsync_end = 864 + 14 + 1,
59 .vtotal = 864 + 14 + 1 + 11,
60 .vrefresh = 60,
61 .width_mm = 48,
62 .height_mm = 84,
63 .flags = DRM_MODE_FLAG_PVSYNC,
64};
65
66
67
68
69
70static const struct drm_display_mode sony_acx424akp_cmd_mode = {
71 .clock = 35478,
72 .hdisplay = 480,
73 .hsync_start = 480 + 154,
74 .hsync_end = 480 + 154 + 16,
75 .htotal = 480 + 154 + 16 + 32,
76 .vdisplay = 864,
77 .vsync_start = 864 + 1,
78 .vsync_end = 864 + 1 + 1,
79 .vtotal = 864 + 1 + 1 + 1,
80
81
82
83
84 .vrefresh = 60,
85 .width_mm = 48,
86 .height_mm = 84,
87};
88
89static inline struct acx424akp *panel_to_acx424akp(struct drm_panel *panel)
90{
91 return container_of(panel, struct acx424akp, panel);
92}
93
94#define FOSC 20
95#define SCALE_FACTOR_NS_DIV_MHZ 1000
96
97static int acx424akp_set_brightness(struct backlight_device *bl)
98{
99 struct acx424akp *acx = bl_get_data(bl);
100 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev);
101 int period_ns = 1023;
102 int duty_ns = bl->props.brightness;
103 u8 pwm_ratio;
104 u8 pwm_div;
105 u8 par;
106 int ret;
107
108
109 pwm_ratio = max(((duty_ns * 256) / period_ns) - 1, 1);
110 pwm_div = max(1,
111 ((FOSC * period_ns) / 256) /
112 SCALE_FACTOR_NS_DIV_MHZ);
113
114
115 DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio);
116 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
117 &pwm_ratio, 1);
118 if (ret < 0) {
119 DRM_DEV_ERROR(acx->dev,
120 "failed to set display PWM ratio (%d)\n",
121 ret);
122 return ret;
123 }
124
125
126
127
128
129
130
131
132
133
134 par = 0xaa;
135 ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1);
136 if (ret < 0) {
137 DRM_DEV_ERROR(acx->dev,
138 "failed to unlock CMD 2 (%d)\n",
139 ret);
140 return ret;
141 }
142 par = 0x01;
143 ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1);
144 if (ret < 0) {
145 DRM_DEV_ERROR(acx->dev,
146 "failed to enter page 1 (%d)\n",
147 ret);
148 return ret;
149 }
150 par = 0x01;
151 ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1);
152 if (ret < 0) {
153 DRM_DEV_ERROR(acx->dev,
154 "failed to disable MTP reload (%d)\n",
155 ret);
156 return ret;
157 }
158 ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1);
159 if (ret < 0) {
160 DRM_DEV_ERROR(acx->dev,
161 "failed to set PWM divisor (%d)\n",
162 ret);
163 return ret;
164 }
165 par = 0xaa;
166 ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1);
167 if (ret < 0) {
168 DRM_DEV_ERROR(acx->dev,
169 "failed to lock CMD 2 (%d)\n",
170 ret);
171 return ret;
172 }
173
174
175 par = 0x24;
176 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
177 &par, 1);
178 if (ret < 0) {
179 DRM_DEV_ERROR(acx->dev,
180 "failed to enable display backlight (%d)\n",
181 ret);
182 return ret;
183 }
184
185 return 0;
186}
187
188static const struct backlight_ops acx424akp_bl_ops = {
189 .update_status = acx424akp_set_brightness,
190};
191
192static int acx424akp_read_id(struct acx424akp *acx)
193{
194 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev);
195 u8 vendor, version, panel;
196 u16 val;
197 int ret;
198
199 ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1);
200 if (ret < 0) {
201 DRM_DEV_ERROR(acx->dev, "could not vendor ID byte\n");
202 return ret;
203 }
204 ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1);
205 if (ret < 0) {
206 DRM_DEV_ERROR(acx->dev, "could not read device version byte\n");
207 return ret;
208 }
209 ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1);
210 if (ret < 0) {
211 DRM_DEV_ERROR(acx->dev, "could not read panel ID byte\n");
212 return ret;
213 }
214
215 if (vendor == 0x00) {
216 DRM_DEV_ERROR(acx->dev, "device vendor ID is zero\n");
217 return -ENODEV;
218 }
219
220 val = (vendor << 8) | panel;
221 switch (val) {
222 case DISPLAY_SONY_ACX424AKP_ID1:
223 case DISPLAY_SONY_ACX424AKP_ID2:
224 case DISPLAY_SONY_ACX424AKP_ID3:
225 DRM_DEV_INFO(acx->dev,
226 "MTP vendor: %02x, version: %02x, panel: %02x\n",
227 vendor, version, panel);
228 break;
229 default:
230 DRM_DEV_INFO(acx->dev,
231 "unknown vendor: %02x, version: %02x, panel: %02x\n",
232 vendor, version, panel);
233 break;
234 }
235
236 return 0;
237}
238
239static int acx424akp_power_on(struct acx424akp *acx)
240{
241 int ret;
242
243 ret = regulator_enable(acx->supply);
244 if (ret) {
245 DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret);
246 return ret;
247 }
248
249
250 gpiod_set_value_cansleep(acx->reset_gpio, 1);
251 udelay(20);
252
253 gpiod_set_value_cansleep(acx->reset_gpio, 0);
254 usleep_range(11000, 20000);
255
256 return 0;
257}
258
259static void acx424akp_power_off(struct acx424akp *acx)
260{
261
262 gpiod_set_value_cansleep(acx->reset_gpio, 1);
263 usleep_range(11000, 20000);
264
265 regulator_disable(acx->supply);
266}
267
268static int acx424akp_prepare(struct drm_panel *panel)
269{
270 struct acx424akp *acx = panel_to_acx424akp(panel);
271 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev);
272 const u8 mddi = 3;
273 int ret;
274
275 ret = acx424akp_power_on(acx);
276 if (ret)
277 return ret;
278
279 ret = acx424akp_read_id(acx);
280 if (ret) {
281 DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret);
282 goto err_power_off;
283 }
284
285
286 ret = mipi_dsi_dcs_set_tear_on(dsi,
287 MIPI_DSI_DCS_TEAR_MODE_VBLANK);
288 if (ret) {
289 DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n",
290 ret);
291 goto err_power_off;
292 }
293
294
295
296
297
298
299
300
301
302
303
304 ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI,
305 &mddi, sizeof(mddi));
306 if (ret < 0) {
307 DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret);
308 goto err_power_off;
309 }
310
311
312 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
313 if (ret) {
314 DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n",
315 ret);
316 goto err_power_off;
317 }
318 msleep(140);
319
320 ret = mipi_dsi_dcs_set_display_on(dsi);
321 if (ret) {
322 DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n",
323 ret);
324 goto err_power_off;
325 }
326 if (acx->video_mode) {
327
328 ret = mipi_dsi_turn_on_peripheral(dsi);
329 if (ret) {
330 dev_err(acx->dev, "failed to turn on peripheral\n");
331 goto err_power_off;
332 }
333 }
334
335 acx->bl->props.power = FB_BLANK_NORMAL;
336
337 return 0;
338
339err_power_off:
340 acx424akp_power_off(acx);
341 return ret;
342}
343
344static int acx424akp_unprepare(struct drm_panel *panel)
345{
346 struct acx424akp *acx = panel_to_acx424akp(panel);
347 struct mipi_dsi_device *dsi = to_mipi_dsi_device(acx->dev);
348 u8 par;
349 int ret;
350
351
352 par = 0x00;
353 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
354 &par, 1);
355 if (ret) {
356 DRM_DEV_ERROR(acx->dev,
357 "failed to disable display backlight (%d)\n",
358 ret);
359 return ret;
360 }
361
362 ret = mipi_dsi_dcs_set_display_off(dsi);
363 if (ret) {
364 DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n",
365 ret);
366 return ret;
367 }
368
369
370 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
371 if (ret) {
372 DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n",
373 ret);
374 return ret;
375 }
376 msleep(85);
377
378 acx424akp_power_off(acx);
379 acx->bl->props.power = FB_BLANK_POWERDOWN;
380
381 return 0;
382}
383
384static int acx424akp_enable(struct drm_panel *panel)
385{
386 struct acx424akp *acx = panel_to_acx424akp(panel);
387
388
389
390
391
392 acx->bl->props.power = FB_BLANK_UNBLANK;
393
394 return 0;
395}
396
397static int acx424akp_disable(struct drm_panel *panel)
398{
399 struct acx424akp *acx = panel_to_acx424akp(panel);
400
401
402
403
404
405 acx->bl->props.power = FB_BLANK_NORMAL;
406
407 return 0;
408}
409
410static int acx424akp_get_modes(struct drm_panel *panel,
411 struct drm_connector *connector)
412{
413 struct acx424akp *acx = panel_to_acx424akp(panel);
414 struct drm_display_mode *mode;
415
416 if (acx->video_mode)
417 mode = drm_mode_duplicate(connector->dev,
418 &sony_acx424akp_vid_mode);
419 else
420 mode = drm_mode_duplicate(connector->dev,
421 &sony_acx424akp_cmd_mode);
422 if (!mode) {
423 DRM_ERROR("bad mode or failed to add mode\n");
424 return -EINVAL;
425 }
426 drm_mode_set_name(mode);
427 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
428
429 connector->display_info.width_mm = mode->width_mm;
430 connector->display_info.height_mm = mode->height_mm;
431
432 drm_mode_probed_add(connector, mode);
433
434 return 1;
435}
436
437static const struct drm_panel_funcs acx424akp_drm_funcs = {
438 .disable = acx424akp_disable,
439 .unprepare = acx424akp_unprepare,
440 .prepare = acx424akp_prepare,
441 .enable = acx424akp_enable,
442 .get_modes = acx424akp_get_modes,
443};
444
445static int acx424akp_probe(struct mipi_dsi_device *dsi)
446{
447 struct device *dev = &dsi->dev;
448 struct acx424akp *acx;
449 int ret;
450
451 acx = devm_kzalloc(dev, sizeof(struct acx424akp), GFP_KERNEL);
452 if (!acx)
453 return -ENOMEM;
454 acx->video_mode = of_property_read_bool(dev->of_node,
455 "enforce-video-mode");
456
457 mipi_dsi_set_drvdata(dsi, acx);
458 acx->dev = dev;
459
460 dsi->lanes = 2;
461 dsi->format = MIPI_DSI_FMT_RGB888;
462
463
464
465
466
467
468 dsi->lp_rate = 19200000;
469 dsi->hs_rate = 420160000;
470
471 if (acx->video_mode)
472
473 dsi->mode_flags =
474 MIPI_DSI_MODE_VIDEO |
475 MIPI_DSI_MODE_VIDEO_BURST;
476 else
477 dsi->mode_flags =
478 MIPI_DSI_CLOCK_NON_CONTINUOUS |
479 MIPI_DSI_MODE_EOT_PACKET;
480
481 acx->supply = devm_regulator_get(dev, "vddi");
482 if (IS_ERR(acx->supply))
483 return PTR_ERR(acx->supply);
484
485
486 acx->reset_gpio = devm_gpiod_get_optional(dev, "reset",
487 GPIOD_OUT_HIGH);
488 if (IS_ERR(acx->reset_gpio)) {
489 ret = PTR_ERR(acx->reset_gpio);
490 if (ret != -EPROBE_DEFER)
491 DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n",
492 ret);
493 return ret;
494 }
495
496 drm_panel_init(&acx->panel, dev, &acx424akp_drm_funcs,
497 DRM_MODE_CONNECTOR_DSI);
498
499 acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx,
500 &acx424akp_bl_ops, NULL);
501 if (IS_ERR(acx->bl)) {
502 DRM_DEV_ERROR(dev, "failed to register backlight device\n");
503 return PTR_ERR(acx->bl);
504 }
505 acx->bl->props.max_brightness = 1023;
506 acx->bl->props.brightness = 512;
507 acx->bl->props.power = FB_BLANK_POWERDOWN;
508
509 ret = drm_panel_add(&acx->panel);
510 if (ret < 0)
511 return ret;
512
513 ret = mipi_dsi_attach(dsi);
514 if (ret < 0) {
515 drm_panel_remove(&acx->panel);
516 return ret;
517 }
518
519 return 0;
520}
521
522static int acx424akp_remove(struct mipi_dsi_device *dsi)
523{
524 struct acx424akp *acx = mipi_dsi_get_drvdata(dsi);
525
526 mipi_dsi_detach(dsi);
527 drm_panel_remove(&acx->panel);
528
529 return 0;
530}
531
532static const struct of_device_id acx424akp_of_match[] = {
533 { .compatible = "sony,acx424akp" },
534 { }
535};
536MODULE_DEVICE_TABLE(of, acx424akp_of_match);
537
538static struct mipi_dsi_driver acx424akp_driver = {
539 .probe = acx424akp_probe,
540 .remove = acx424akp_remove,
541 .driver = {
542 .name = "panel-sony-acx424akp",
543 .of_match_table = acx424akp_of_match,
544 },
545};
546module_mipi_dsi_driver(acx424akp_driver);
547
548MODULE_AUTHOR("Linus Wallei <linus.walleij@linaro.org>");
549MODULE_DESCRIPTION("MIPI-DSI Sony acx424akp Panel Driver");
550MODULE_LICENSE("GPL v2");
551