aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/omap2/displays-new/Kconfig5
-rw-r--r--drivers/video/omap2/displays-new/Makefile1
-rw-r--r--drivers/video/omap2/displays-new/panel-dsi-cm.c1336
-rw-r--r--include/video/omap-panel-data.h28
4 files changed, 1370 insertions, 0 deletions
diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
index cc62a7614f7f..efb72b352efd 100644
--- a/drivers/video/omap2/displays-new/Kconfig
+++ b/drivers/video/omap2/displays-new/Kconfig
@@ -33,4 +33,9 @@ config DISPLAY_PANEL_DPI
33 help 33 help
34 Driver for generic DPI panels. 34 Driver for generic DPI panels.
35 35
36config DISPLAY_PANEL_DSI_CM
37 tristate "Generic DSI Command Mode Panel"
38 help
39 Driver for generic DSI command mode panels.
40
36endmenu 41endmenu
diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
index 45a8037b6909..557c48226296 100644
--- a/drivers/video/omap2/displays-new/Makefile
+++ b/drivers/video/omap2/displays-new/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
4obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o 4obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o
5obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o 5obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
6obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o 6obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o
7obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o
diff --git a/drivers/video/omap2/displays-new/panel-dsi-cm.c b/drivers/video/omap2/displays-new/panel-dsi-cm.c
new file mode 100644
index 000000000000..aaaea6469cd9
--- /dev/null
+++ b/drivers/video/omap2/displays-new/panel-dsi-cm.c
@@ -0,0 +1,1336 @@
1/*
2 * Generic DSI Command Mode panel driver
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11
12/* #define DEBUG */
13
14#include <linux/backlight.h>
15#include <linux/delay.h>
16#include <linux/fb.h>
17#include <linux/gpio.h>
18#include <linux/interrupt.h>
19#include <linux/jiffies.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/sched.h>
23#include <linux/slab.h>
24#include <linux/workqueue.h>
25
26#include <video/omapdss.h>
27#include <video/omap-panel-data.h>
28#include <video/mipi_display.h>
29
30/* DSI Virtual channel. Hardcoded for now. */
31#define TCH 0
32
33#define DCS_READ_NUM_ERRORS 0x05
34#define DCS_BRIGHTNESS 0x51
35#define DCS_CTRL_DISPLAY 0x53
36#define DCS_GET_ID1 0xda
37#define DCS_GET_ID2 0xdb
38#define DCS_GET_ID3 0xdc
39
40struct panel_drv_data {
41 struct omap_dss_device dssdev;
42 struct omap_dss_device *in;
43
44 struct omap_video_timings timings;
45
46 struct platform_device *pdev;
47
48 struct mutex lock;
49
50 struct backlight_device *bldev;
51
52 unsigned long hw_guard_end; /* next value of jiffies when we can
53 * issue the next sleep in/out command
54 */
55 unsigned long hw_guard_wait; /* max guard time in jiffies */
56
57 /* panel HW configuration from DT or platform data */
58 int reset_gpio;
59 int ext_te_gpio;
60
61 bool use_dsi_backlight;
62
63 struct omap_dsi_pin_config pin_config;
64
65 /* runtime variables */
66 bool enabled;
67
68 bool te_enabled;
69
70 atomic_t do_update;
71 int channel;
72
73 struct delayed_work te_timeout_work;
74
75 bool intro_printed;
76
77 struct workqueue_struct *workqueue;
78
79 bool ulps_enabled;
80 unsigned ulps_timeout;
81 struct delayed_work ulps_work;
82};
83
84#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
85
86static irqreturn_t dsicm_te_isr(int irq, void *data);
87static void dsicm_te_timeout_work_callback(struct work_struct *work);
88static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);
89
90static int dsicm_panel_reset(struct panel_drv_data *ddata);
91
92static void dsicm_ulps_work(struct work_struct *work);
93
94static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec)
95{
96 ddata->hw_guard_wait = msecs_to_jiffies(guard_msec);
97 ddata->hw_guard_end = jiffies + ddata->hw_guard_wait;
98}
99
100static void hw_guard_wait(struct panel_drv_data *ddata)
101{
102 unsigned long wait = ddata->hw_guard_end - jiffies;
103
104 if ((long)wait > 0 && wait <= ddata->hw_guard_wait) {
105 set_current_state(TASK_UNINTERRUPTIBLE);
106 schedule_timeout(wait);
107 }
108}
109
110static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
111{
112 struct omap_dss_device *in = ddata->in;
113 int r;
114 u8 buf[1];
115
116 r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);
117
118 if (r < 0)
119 return r;
120
121 *data = buf[0];
122
123 return 0;
124}
125
126static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
127{
128 struct omap_dss_device *in = ddata->in;
129 return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);
130}
131
132static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
133{
134 struct omap_dss_device *in = ddata->in;
135 u8 buf[2] = { dcs_cmd, param };
136
137 return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);
138}
139
140static int dsicm_sleep_in(struct panel_drv_data *ddata)
141
142{
143 struct omap_dss_device *in = ddata->in;
144 u8 cmd;
145 int r;
146
147 hw_guard_wait(ddata);
148
149 cmd = MIPI_DCS_ENTER_SLEEP_MODE;
150 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);
151 if (r)
152 return r;
153
154 hw_guard_start(ddata, 120);
155
156 usleep_range(5000, 10000);
157
158 return 0;
159}
160
161static int dsicm_sleep_out(struct panel_drv_data *ddata)
162{
163 int r;
164
165 hw_guard_wait(ddata);
166
167 r = dsicm_dcs_write_0(ddata, MIPI_DCS_EXIT_SLEEP_MODE);
168 if (r)
169 return r;
170
171 hw_guard_start(ddata, 120);
172
173 usleep_range(5000, 10000);
174
175 return 0;
176}
177
178static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
179{
180 int r;
181
182 r = dsicm_dcs_read_1(ddata, DCS_GET_ID1, id1);
183 if (r)
184 return r;
185 r = dsicm_dcs_read_1(ddata, DCS_GET_ID2, id2);
186 if (r)
187 return r;
188 r = dsicm_dcs_read_1(ddata, DCS_GET_ID3, id3);
189 if (r)
190 return r;
191
192 return 0;
193}
194
195static int dsicm_set_update_window(struct panel_drv_data *ddata,
196 u16 x, u16 y, u16 w, u16 h)
197{
198 struct omap_dss_device *in = ddata->in;
199 int r;
200 u16 x1 = x;
201 u16 x2 = x + w - 1;
202 u16 y1 = y;
203 u16 y2 = y + h - 1;
204
205 u8 buf[5];
206 buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
207 buf[1] = (x1 >> 8) & 0xff;
208 buf[2] = (x1 >> 0) & 0xff;
209 buf[3] = (x2 >> 8) & 0xff;
210 buf[4] = (x2 >> 0) & 0xff;
211
212 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
213 if (r)
214 return r;
215
216 buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
217 buf[1] = (y1 >> 8) & 0xff;
218 buf[2] = (y1 >> 0) & 0xff;
219 buf[3] = (y2 >> 8) & 0xff;
220 buf[4] = (y2 >> 0) & 0xff;
221
222 r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
223 if (r)
224 return r;
225
226 in->ops.dsi->bta_sync(in, ddata->channel);
227
228 return r;
229}
230
231static void dsicm_queue_ulps_work(struct panel_drv_data *ddata)
232{
233 if (ddata->ulps_timeout > 0)
234 queue_delayed_work(ddata->workqueue, &ddata->ulps_work,
235 msecs_to_jiffies(ddata->ulps_timeout));
236}
237
238static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)
239{
240 cancel_delayed_work(&ddata->ulps_work);
241}
242
243static int dsicm_enter_ulps(struct panel_drv_data *ddata)
244{
245 struct omap_dss_device *in = ddata->in;
246 int r;
247
248 if (ddata->ulps_enabled)
249 return 0;
250
251 dsicm_cancel_ulps_work(ddata);
252
253 r = _dsicm_enable_te(ddata, false);
254 if (r)
255 goto err;
256
257 if (gpio_is_valid(ddata->ext_te_gpio))
258 disable_irq(gpio_to_irq(ddata->ext_te_gpio));
259
260 in->ops.dsi->disable(in, false, true);
261
262 ddata->ulps_enabled = true;
263
264 return 0;
265
266err:
267 dev_err(&ddata->pdev->dev, "enter ULPS failed");
268 dsicm_panel_reset(ddata);
269
270 ddata->ulps_enabled = false;
271
272 dsicm_queue_ulps_work(ddata);
273
274 return r;
275}
276
277static int dsicm_exit_ulps(struct panel_drv_data *ddata)
278{
279 struct omap_dss_device *in = ddata->in;
280 int r;
281
282 if (!ddata->ulps_enabled)
283 return 0;
284
285 r = in->ops.dsi->enable(in);
286 if (r) {
287 dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
288 goto err1;
289 }
290
291 in->ops.dsi->enable_hs(in, ddata->channel, true);
292
293 r = _dsicm_enable_te(ddata, true);
294 if (r) {
295 dev_err(&ddata->pdev->dev, "failed to re-enable TE");
296 goto err2;
297 }
298
299 if (gpio_is_valid(ddata->ext_te_gpio))
300 enable_irq(gpio_to_irq(ddata->ext_te_gpio));
301
302 dsicm_queue_ulps_work(ddata);
303
304 ddata->ulps_enabled = false;
305
306 return 0;
307
308err2:
309 dev_err(&ddata->pdev->dev, "failed to exit ULPS");
310
311 r = dsicm_panel_reset(ddata);
312 if (!r) {
313 if (gpio_is_valid(ddata->ext_te_gpio))
314 enable_irq(gpio_to_irq(ddata->ext_te_gpio));
315 ddata->ulps_enabled = false;
316 }
317err1:
318 dsicm_queue_ulps_work(ddata);
319
320 return r;
321}
322
323static int dsicm_wake_up(struct panel_drv_data *ddata)
324{
325 if (ddata->ulps_enabled)
326 return dsicm_exit_ulps(ddata);
327
328 dsicm_cancel_ulps_work(ddata);
329 dsicm_queue_ulps_work(ddata);
330 return 0;
331}
332
333static int dsicm_bl_update_status(struct backlight_device *dev)
334{
335 struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
336 struct omap_dss_device *in = ddata->in;
337 int r;
338 int level;
339
340 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
341 dev->props.power == FB_BLANK_UNBLANK)
342 level = dev->props.brightness;
343 else
344 level = 0;
345
346 dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level);
347
348 mutex_lock(&ddata->lock);
349
350 if (ddata->enabled) {
351 in->ops.dsi->bus_lock(in);
352
353 r = dsicm_wake_up(ddata);
354 if (!r)
355 r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);
356
357 in->ops.dsi->bus_unlock(in);
358 } else {
359 r = 0;
360 }
361
362 mutex_unlock(&ddata->lock);
363
364 return r;
365}
366
367static int dsicm_bl_get_intensity(struct backlight_device *dev)
368{
369 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
370 dev->props.power == FB_BLANK_UNBLANK)
371 return dev->props.brightness;
372
373 return 0;
374}
375
376static const struct backlight_ops dsicm_bl_ops = {
377 .get_brightness = dsicm_bl_get_intensity,
378 .update_status = dsicm_bl_update_status,
379};
380
381static void dsicm_get_resolution(struct omap_dss_device *dssdev,
382 u16 *xres, u16 *yres)
383{
384 *xres = dssdev->panel.timings.x_res;
385 *yres = dssdev->panel.timings.y_res;
386}
387
388static ssize_t dsicm_num_errors_show(struct device *dev,
389 struct device_attribute *attr, char *buf)
390{
391 struct platform_device *pdev = to_platform_device(dev);
392 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
393 struct omap_dss_device *in = ddata->in;
394 u8 errors = 0;
395 int r;
396
397 mutex_lock(&ddata->lock);
398
399 if (ddata->enabled) {
400 in->ops.dsi->bus_lock(in);
401
402 r = dsicm_wake_up(ddata);
403 if (!r)
404 r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,
405 &errors);
406
407 in->ops.dsi->bus_unlock(in);
408 } else {
409 r = -ENODEV;
410 }
411
412 mutex_unlock(&ddata->lock);
413
414 if (r)
415 return r;
416
417 return snprintf(buf, PAGE_SIZE, "%d\n", errors);
418}
419
420static ssize_t dsicm_hw_revision_show(struct device *dev,
421 struct device_attribute *attr, char *buf)
422{
423 struct platform_device *pdev = to_platform_device(dev);
424 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
425 struct omap_dss_device *in = ddata->in;
426 u8 id1, id2, id3;
427 int r;
428
429 mutex_lock(&ddata->lock);
430
431 if (ddata->enabled) {
432 in->ops.dsi->bus_lock(in);
433
434 r = dsicm_wake_up(ddata);
435 if (!r)
436 r = dsicm_get_id(ddata, &id1, &id2, &id3);
437
438 in->ops.dsi->bus_unlock(in);
439 } else {
440 r = -ENODEV;
441 }
442
443 mutex_unlock(&ddata->lock);
444
445 if (r)
446 return r;
447
448 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
449}
450
451static ssize_t dsicm_store_ulps(struct device *dev,
452 struct device_attribute *attr,
453 const char *buf, size_t count)
454{
455 struct platform_device *pdev = to_platform_device(dev);
456 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
457 struct omap_dss_device *in = ddata->in;
458 unsigned long t;
459 int r;
460
461 r = kstrtoul(buf, 0, &t);
462 if (r)
463 return r;
464
465 mutex_lock(&ddata->lock);
466
467 if (ddata->enabled) {
468 in->ops.dsi->bus_lock(in);
469
470 if (t)
471 r = dsicm_enter_ulps(ddata);
472 else
473 r = dsicm_wake_up(ddata);
474
475 in->ops.dsi->bus_unlock(in);
476 }
477
478 mutex_unlock(&ddata->lock);
479
480 if (r)
481 return r;
482
483 return count;
484}
485
486static ssize_t dsicm_show_ulps(struct device *dev,
487 struct device_attribute *attr,
488 char *buf)
489{
490 struct platform_device *pdev = to_platform_device(dev);
491 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
492 unsigned t;
493
494 mutex_lock(&ddata->lock);
495 t = ddata->ulps_enabled;
496 mutex_unlock(&ddata->lock);
497
498 return snprintf(buf, PAGE_SIZE, "%u\n", t);
499}
500
501static ssize_t dsicm_store_ulps_timeout(struct device *dev,
502 struct device_attribute *attr,
503 const char *buf, size_t count)
504{
505 struct platform_device *pdev = to_platform_device(dev);
506 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
507 struct omap_dss_device *in = ddata->in;
508 unsigned long t;
509 int r;
510
511 r = kstrtoul(buf, 0, &t);
512 if (r)
513 return r;
514
515 mutex_lock(&ddata->lock);
516 ddata->ulps_timeout = t;
517
518 if (ddata->enabled) {
519 /* dsicm_wake_up will restart the timer */
520 in->ops.dsi->bus_lock(in);
521 r = dsicm_wake_up(ddata);
522 in->ops.dsi->bus_unlock(in);
523 }
524
525 mutex_unlock(&ddata->lock);
526
527 if (r)
528 return r;
529
530 return count;
531}
532
533static ssize_t dsicm_show_ulps_timeout(struct device *dev,
534 struct device_attribute *attr,
535 char *buf)
536{
537 struct platform_device *pdev = to_platform_device(dev);
538 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
539 unsigned t;
540
541 mutex_lock(&ddata->lock);
542 t = ddata->ulps_timeout;
543 mutex_unlock(&ddata->lock);
544
545 return snprintf(buf, PAGE_SIZE, "%u\n", t);
546}
547
548static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL);
549static DEVICE_ATTR(hw_revision, S_IRUGO, dsicm_hw_revision_show, NULL);
550static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
551 dsicm_show_ulps, dsicm_store_ulps);
552static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
553 dsicm_show_ulps_timeout, dsicm_store_ulps_timeout);
554
555static struct attribute *dsicm_attrs[] = {
556 &dev_attr_num_dsi_errors.attr,
557 &dev_attr_hw_revision.attr,
558 &dev_attr_ulps.attr,
559 &dev_attr_ulps_timeout.attr,
560 NULL,
561};
562
563static struct attribute_group dsicm_attr_group = {
564 .attrs = dsicm_attrs,
565};
566
567static void dsicm_hw_reset(struct panel_drv_data *ddata)
568{
569 if (!gpio_is_valid(ddata->reset_gpio))
570 return;
571
572 gpio_set_value(ddata->reset_gpio, 1);
573 udelay(10);
574 /* reset the panel */
575 gpio_set_value(ddata->reset_gpio, 0);
576 /* assert reset */
577 udelay(10);
578 gpio_set_value(ddata->reset_gpio, 1);
579 /* wait after releasing reset */
580 usleep_range(5000, 10000);
581}
582
583static int dsicm_power_on(struct panel_drv_data *ddata)
584{
585 struct omap_dss_device *in = ddata->in;
586 u8 id1, id2, id3;
587 int r;
588 struct omap_dss_dsi_config dsi_config = {
589 .mode = OMAP_DSS_DSI_CMD_MODE,
590 .pixel_format = OMAP_DSS_DSI_FMT_RGB888,
591 .timings = &ddata->timings,
592 .hs_clk_min = 150000000,
593 .hs_clk_max = 300000000,
594 .lp_clk_min = 7000000,
595 .lp_clk_max = 10000000,
596 };
597
598 r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
599 if (r) {
600 dev_err(&ddata->pdev->dev, "failed to configure DSI pins\n");
601 goto err0;
602 };
603
604 r = in->ops.dsi->set_config(in, &dsi_config);
605 if (r) {
606 dev_err(&ddata->pdev->dev, "failed to configure DSI\n");
607 goto err0;
608 }
609
610 r = in->ops.dsi->enable(in);
611 if (r) {
612 dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
613 goto err0;
614 }
615
616 dsicm_hw_reset(ddata);
617
618 in->ops.dsi->enable_hs(in, ddata->channel, false);
619
620 r = dsicm_sleep_out(ddata);
621 if (r)
622 goto err;
623
624 r = dsicm_get_id(ddata, &id1, &id2, &id3);
625 if (r)
626 goto err;
627
628 r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, 0xff);
629 if (r)
630 goto err;
631
632 r = dsicm_dcs_write_1(ddata, DCS_CTRL_DISPLAY,
633 (1<<2) | (1<<5)); /* BL | BCTRL */
634 if (r)
635 goto err;
636
637 r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_PIXEL_FORMAT,
638 MIPI_DCS_PIXEL_FMT_24BIT);
639 if (r)
640 goto err;
641
642 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_ON);
643 if (r)
644 goto err;
645
646 r = _dsicm_enable_te(ddata, ddata->te_enabled);
647 if (r)
648 goto err;
649
650 r = in->ops.dsi->enable_video_output(in, ddata->channel);
651 if (r)
652 goto err;
653
654 ddata->enabled = 1;
655
656 if (!ddata->intro_printed) {
657 dev_info(&ddata->pdev->dev, "panel revision %02x.%02x.%02x\n",
658 id1, id2, id3);
659 ddata->intro_printed = true;
660 }
661
662 in->ops.dsi->enable_hs(in, ddata->channel, true);
663
664 return 0;
665err:
666 dev_err(&ddata->pdev->dev, "error while enabling panel, issuing HW reset\n");
667
668 dsicm_hw_reset(ddata);
669
670 in->ops.dsi->disable(in, true, false);
671err0:
672 return r;
673}
674
675static void dsicm_power_off(struct panel_drv_data *ddata)
676{
677 struct omap_dss_device *in = ddata->in;
678 int r;
679
680 in->ops.dsi->disable_video_output(in, ddata->channel);
681
682 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);
683 if (!r)
684 r = dsicm_sleep_in(ddata);
685
686 if (r) {
687 dev_err(&ddata->pdev->dev,
688 "error disabling panel, issuing HW reset\n");
689 dsicm_hw_reset(ddata);
690 }
691
692 in->ops.dsi->disable(in, true, false);
693
694 ddata->enabled = 0;
695}
696
697static int dsicm_panel_reset(struct panel_drv_data *ddata)
698{
699 dev_err(&ddata->pdev->dev, "performing LCD reset\n");
700
701 dsicm_power_off(ddata);
702 dsicm_hw_reset(ddata);
703 return dsicm_power_on(ddata);
704}
705
706static int dsicm_connect(struct omap_dss_device *dssdev)
707{
708 struct panel_drv_data *ddata = to_panel_data(dssdev);
709 struct omap_dss_device *in = ddata->in;
710 struct device *dev = &ddata->pdev->dev;
711 int r;
712
713 if (omapdss_device_is_connected(dssdev))
714 return 0;
715
716 r = in->ops.dsi->connect(in, dssdev);
717 if (r) {
718 dev_err(dev, "Failed to connect to video source\n");
719 return r;
720 }
721
722 r = in->ops.dsi->request_vc(ddata->in, &ddata->channel);
723 if (r) {
724 dev_err(dev, "failed to get virtual channel\n");
725 goto err_req_vc;
726 }
727
728 r = in->ops.dsi->set_vc_id(ddata->in, ddata->channel, TCH);
729 if (r) {
730 dev_err(dev, "failed to set VC_ID\n");
731 goto err_vc_id;
732 }
733
734 return 0;
735
736err_vc_id:
737 in->ops.dsi->release_vc(ddata->in, ddata->channel);
738err_req_vc:
739 in->ops.dsi->disconnect(in, dssdev);
740 return r;
741}
742
743static void dsicm_disconnect(struct omap_dss_device *dssdev)
744{
745 struct panel_drv_data *ddata = to_panel_data(dssdev);
746 struct omap_dss_device *in = ddata->in;
747
748 if (!omapdss_device_is_connected(dssdev))
749 return;
750
751 in->ops.dsi->release_vc(in, ddata->channel);
752 in->ops.dsi->disconnect(in, dssdev);
753}
754
755static int dsicm_enable(struct omap_dss_device *dssdev)
756{
757 struct panel_drv_data *ddata = to_panel_data(dssdev);
758 struct omap_dss_device *in = ddata->in;
759 int r;
760
761 dev_dbg(&ddata->pdev->dev, "enable\n");
762
763 mutex_lock(&ddata->lock);
764
765 if (!omapdss_device_is_connected(dssdev)) {
766 r = -ENODEV;
767 goto err;
768 }
769
770 if (omapdss_device_is_enabled(dssdev)) {
771 r = 0;
772 goto err;
773 }
774
775 in->ops.dsi->bus_lock(in);
776
777 r = dsicm_power_on(ddata);
778
779 in->ops.dsi->bus_unlock(in);
780
781 if (r)
782 goto err;
783
784 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
785
786 mutex_unlock(&ddata->lock);
787
788 return 0;
789err:
790 dev_dbg(&ddata->pdev->dev, "enable failed\n");
791 mutex_unlock(&ddata->lock);
792 return r;
793}
794
795static void dsicm_disable(struct omap_dss_device *dssdev)
796{
797 struct panel_drv_data *ddata = to_panel_data(dssdev);
798 struct omap_dss_device *in = ddata->in;
799 int r;
800
801 dev_dbg(&ddata->pdev->dev, "disable\n");
802
803 mutex_lock(&ddata->lock);
804
805 dsicm_cancel_ulps_work(ddata);
806
807 in->ops.dsi->bus_lock(in);
808
809 if (omapdss_device_is_enabled(dssdev)) {
810 r = dsicm_wake_up(ddata);
811 if (!r)
812 dsicm_power_off(ddata);
813 }
814
815 in->ops.dsi->bus_unlock(in);
816
817 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
818
819 mutex_unlock(&ddata->lock);
820}
821
822static void dsicm_framedone_cb(int err, void *data)
823{
824 struct panel_drv_data *ddata = data;
825 struct omap_dss_device *in = ddata->in;
826
827 dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);
828 in->ops.dsi->bus_unlock(ddata->in);
829}
830
831static irqreturn_t dsicm_te_isr(int irq, void *data)
832{
833 struct panel_drv_data *ddata = data;
834 struct omap_dss_device *in = ddata->in;
835 int old;
836 int r;
837
838 old = atomic_cmpxchg(&ddata->do_update, 1, 0);
839
840 if (old) {
841 cancel_delayed_work(&ddata->te_timeout_work);
842
843 r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
844 ddata);
845 if (r)
846 goto err;
847 }
848
849 return IRQ_HANDLED;
850err:
851 dev_err(&ddata->pdev->dev, "start update failed\n");
852 in->ops.dsi->bus_unlock(in);
853 return IRQ_HANDLED;
854}
855
856static void dsicm_te_timeout_work_callback(struct work_struct *work)
857{
858 struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
859 te_timeout_work.work);
860 struct omap_dss_device *in = ddata->in;
861
862 dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");
863
864 atomic_set(&ddata->do_update, 0);
865 in->ops.dsi->bus_unlock(in);
866}
867
868static int dsicm_update(struct omap_dss_device *dssdev,
869 u16 x, u16 y, u16 w, u16 h)
870{
871 struct panel_drv_data *ddata = to_panel_data(dssdev);
872 struct omap_dss_device *in = ddata->in;
873 int r;
874
875 dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
876
877 mutex_lock(&ddata->lock);
878 in->ops.dsi->bus_lock(in);
879
880 r = dsicm_wake_up(ddata);
881 if (r)
882 goto err;
883
884 if (!ddata->enabled) {
885 r = 0;
886 goto err;
887 }
888
889 /* XXX no need to send this every frame, but dsi break if not done */
890 r = dsicm_set_update_window(ddata, 0, 0,
891 dssdev->panel.timings.x_res,
892 dssdev->panel.timings.y_res);
893 if (r)
894 goto err;
895
896 if (ddata->te_enabled && gpio_is_valid(ddata->ext_te_gpio)) {
897 schedule_delayed_work(&ddata->te_timeout_work,
898 msecs_to_jiffies(250));
899 atomic_set(&ddata->do_update, 1);
900 } else {
901 r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
902 ddata);
903 if (r)
904 goto err;
905 }
906
907 /* note: no bus_unlock here. unlock is in framedone_cb */
908 mutex_unlock(&ddata->lock);
909 return 0;
910err:
911 in->ops.dsi->bus_unlock(in);
912 mutex_unlock(&ddata->lock);
913 return r;
914}
915
916static int dsicm_sync(struct omap_dss_device *dssdev)
917{
918 struct panel_drv_data *ddata = to_panel_data(dssdev);
919 struct omap_dss_device *in = ddata->in;
920
921 dev_dbg(&ddata->pdev->dev, "sync\n");
922
923 mutex_lock(&ddata->lock);
924 in->ops.dsi->bus_lock(in);
925 in->ops.dsi->bus_unlock(in);
926 mutex_unlock(&ddata->lock);
927
928 dev_dbg(&ddata->pdev->dev, "sync done\n");
929
930 return 0;
931}
932
933static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
934{
935 struct omap_dss_device *in = ddata->in;
936 int r;
937
938 if (enable)
939 r = dsicm_dcs_write_1(ddata, MIPI_DCS_SET_TEAR_ON, 0);
940 else
941 r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);
942
943 if (!gpio_is_valid(ddata->ext_te_gpio))
944 in->ops.dsi->enable_te(in, enable);
945
946 /* possible panel bug */
947 msleep(100);
948
949 return r;
950}
951
952static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
953{
954 struct panel_drv_data *ddata = to_panel_data(dssdev);
955 struct omap_dss_device *in = ddata->in;
956 int r;
957
958 mutex_lock(&ddata->lock);
959
960 if (ddata->te_enabled == enable)
961 goto end;
962
963 in->ops.dsi->bus_lock(in);
964
965 if (ddata->enabled) {
966 r = dsicm_wake_up(ddata);
967 if (r)
968 goto err;
969
970 r = _dsicm_enable_te(ddata, enable);
971 if (r)
972 goto err;
973 }
974
975 ddata->te_enabled = enable;
976
977 in->ops.dsi->bus_unlock(in);
978end:
979 mutex_unlock(&ddata->lock);
980
981 return 0;
982err:
983 in->ops.dsi->bus_unlock(in);
984 mutex_unlock(&ddata->lock);
985
986 return r;
987}
988
989static int dsicm_get_te(struct omap_dss_device *dssdev)
990{
991 struct panel_drv_data *ddata = to_panel_data(dssdev);
992 int r;
993
994 mutex_lock(&ddata->lock);
995 r = ddata->te_enabled;
996 mutex_unlock(&ddata->lock);
997
998 return r;
999}
1000
1001static int dsicm_memory_read(struct omap_dss_device *dssdev,
1002 void *buf, size_t size,
1003 u16 x, u16 y, u16 w, u16 h)
1004{
1005 struct panel_drv_data *ddata = to_panel_data(dssdev);
1006 struct omap_dss_device *in = ddata->in;
1007 int r;
1008 int first = 1;
1009 int plen;
1010 unsigned buf_used = 0;
1011
1012 if (size < w * h * 3)
1013 return -ENOMEM;
1014
1015 mutex_lock(&ddata->lock);
1016
1017 if (!ddata->enabled) {
1018 r = -ENODEV;
1019 goto err1;
1020 }
1021
1022 size = min(w * h * 3,
1023 dssdev->panel.timings.x_res *
1024 dssdev->panel.timings.y_res * 3);
1025
1026 in->ops.dsi->bus_lock(in);
1027
1028 r = dsicm_wake_up(ddata);
1029 if (r)
1030 goto err2;
1031
1032 /* plen 1 or 2 goes into short packet. until checksum error is fixed,
1033 * use short packets. plen 32 works, but bigger packets seem to cause
1034 * an error. */
1035 if (size % 2)
1036 plen = 1;
1037 else
1038 plen = 2;
1039
1040 dsicm_set_update_window(ddata, x, y, w, h);
1041
1042 r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);
1043 if (r)
1044 goto err2;
1045
1046 while (buf_used < size) {
1047 u8 dcs_cmd = first ? 0x2e : 0x3e;
1048 first = 0;
1049
1050 r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,
1051 buf + buf_used, size - buf_used);
1052
1053 if (r < 0) {
1054 dev_err(dssdev->dev, "read error\n");
1055 goto err3;
1056 }
1057
1058 buf_used += r;
1059
1060 if (r < plen) {
1061 dev_err(&ddata->pdev->dev, "short read\n");
1062 break;
1063 }
1064
1065 if (signal_pending(current)) {
1066 dev_err(&ddata->pdev->dev, "signal pending, "
1067 "aborting memory read\n");
1068 r = -ERESTARTSYS;
1069 goto err3;
1070 }
1071 }
1072
1073 r = buf_used;
1074
1075err3:
1076 in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);
1077err2:
1078 in->ops.dsi->bus_unlock(in);
1079err1:
1080 mutex_unlock(&ddata->lock);
1081 return r;
1082}
1083
1084static void dsicm_ulps_work(struct work_struct *work)
1085{
1086 struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
1087 ulps_work.work);
1088 struct omap_dss_device *dssdev = &ddata->dssdev;
1089 struct omap_dss_device *in = ddata->in;
1090
1091 mutex_lock(&ddata->lock);
1092
1093 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !ddata->enabled) {
1094 mutex_unlock(&ddata->lock);
1095 return;
1096 }
1097
1098 in->ops.dsi->bus_lock(in);
1099
1100 dsicm_enter_ulps(ddata);
1101
1102 in->ops.dsi->bus_unlock(in);
1103 mutex_unlock(&ddata->lock);
1104}
1105
1106static struct omap_dss_driver dsicm_ops = {
1107 .connect = dsicm_connect,
1108 .disconnect = dsicm_disconnect,
1109
1110 .enable = dsicm_enable,
1111 .disable = dsicm_disable,
1112
1113 .update = dsicm_update,
1114 .sync = dsicm_sync,
1115
1116 .get_resolution = dsicm_get_resolution,
1117 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
1118
1119 .enable_te = dsicm_enable_te,
1120 .get_te = dsicm_get_te,
1121
1122 .memory_read = dsicm_memory_read,
1123};
1124
1125static int dsicm_probe_pdata(struct platform_device *pdev)
1126{
1127 const struct panel_dsicm_platform_data *pdata;
1128 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
1129 struct omap_dss_device *dssdev, *in;
1130
1131 pdata = dev_get_platdata(&pdev->dev);
1132
1133 in = omap_dss_find_output(pdata->source);
1134 if (in == NULL) {
1135 dev_err(&pdev->dev, "failed to find video source\n");
1136 return -EPROBE_DEFER;
1137 }
1138 ddata->in = in;
1139
1140 ddata->reset_gpio = pdata->reset_gpio;
1141
1142 if (pdata->use_ext_te)
1143 ddata->ext_te_gpio = pdata->ext_te_gpio;
1144 else
1145 ddata->ext_te_gpio = -1;
1146
1147 ddata->ulps_timeout = pdata->ulps_timeout;
1148
1149 ddata->use_dsi_backlight = pdata->use_dsi_backlight;
1150
1151 ddata->pin_config = pdata->pin_config;
1152
1153 dssdev = &ddata->dssdev;
1154 dssdev->name = pdata->name;
1155
1156 return 0;
1157}
1158
1159static int dsicm_probe(struct platform_device *pdev)
1160{
1161 struct backlight_properties props;
1162 struct panel_drv_data *ddata;
1163 struct backlight_device *bldev = NULL;
1164 struct device *dev = &pdev->dev;
1165 struct omap_dss_device *dssdev;
1166 int r;
1167
1168 dev_dbg(dev, "probe\n");
1169
1170 ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
1171 if (!ddata)
1172 return -ENOMEM;
1173
1174 platform_set_drvdata(pdev, ddata);
1175 ddata->pdev = pdev;
1176
1177 if (dev_get_platdata(dev)) {
1178 r = dsicm_probe_pdata(pdev);
1179 if (r)
1180 return r;
1181 } else {
1182 return -ENODEV;
1183 }
1184
1185 ddata->timings.x_res = 864;
1186 ddata->timings.y_res = 480;
1187 ddata->timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000);
1188
1189 dssdev = &ddata->dssdev;
1190 dssdev->dev = dev;
1191 dssdev->driver = &dsicm_ops;
1192 dssdev->panel.timings = ddata->timings;
1193 dssdev->type = OMAP_DISPLAY_TYPE_DSI;
1194 dssdev->owner = THIS_MODULE;
1195
1196 dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
1197 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
1198 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
1199
1200 r = omapdss_register_display(dssdev);
1201 if (r) {
1202 dev_err(dev, "Failed to register panel\n");
1203 goto err_reg;
1204 }
1205
1206 mutex_init(&ddata->lock);
1207
1208 atomic_set(&ddata->do_update, 0);
1209
1210 if (gpio_is_valid(ddata->reset_gpio)) {
1211 r = devm_gpio_request_one(dev, ddata->reset_gpio,
1212 GPIOF_OUT_INIT_LOW, "taal rst");
1213 if (r) {
1214 dev_err(dev, "failed to request reset gpio\n");
1215 return r;
1216 }
1217 }
1218
1219 if (gpio_is_valid(ddata->ext_te_gpio)) {
1220 r = devm_gpio_request_one(dev, ddata->ext_te_gpio,
1221 GPIOF_IN, "taal irq");
1222 if (r) {
1223 dev_err(dev, "GPIO request failed\n");
1224 return r;
1225 }
1226
1227 r = devm_request_irq(dev, gpio_to_irq(ddata->ext_te_gpio),
1228 dsicm_te_isr,
1229 IRQF_TRIGGER_RISING,
1230 "taal vsync", ddata);
1231
1232 if (r) {
1233 dev_err(dev, "IRQ request failed\n");
1234 return r;
1235 }
1236
1237 INIT_DEFERRABLE_WORK(&ddata->te_timeout_work,
1238 dsicm_te_timeout_work_callback);
1239
1240 dev_dbg(dev, "Using GPIO TE\n");
1241 }
1242
1243 ddata->workqueue = create_singlethread_workqueue("dsicm_wq");
1244 if (ddata->workqueue == NULL) {
1245 dev_err(dev, "can't create workqueue\n");
1246 return -ENOMEM;
1247 }
1248 INIT_DELAYED_WORK(&ddata->ulps_work, dsicm_ulps_work);
1249
1250 dsicm_hw_reset(ddata);
1251
1252 if (ddata->use_dsi_backlight) {
1253 memset(&props, 0, sizeof(struct backlight_properties));
1254 props.max_brightness = 255;
1255
1256 props.type = BACKLIGHT_RAW;
1257 bldev = backlight_device_register(dev_name(dev),
1258 dev, ddata, &dsicm_bl_ops, &props);
1259 if (IS_ERR(bldev)) {
1260 r = PTR_ERR(bldev);
1261 goto err_bl;
1262 }
1263
1264 ddata->bldev = bldev;
1265
1266 bldev->props.fb_blank = FB_BLANK_UNBLANK;
1267 bldev->props.power = FB_BLANK_UNBLANK;
1268 bldev->props.brightness = 255;
1269
1270 dsicm_bl_update_status(bldev);
1271 }
1272
1273 r = sysfs_create_group(&dev->kobj, &dsicm_attr_group);
1274 if (r) {
1275 dev_err(dev, "failed to create sysfs files\n");
1276 goto err_sysfs_create;
1277 }
1278
1279 return 0;
1280
1281err_sysfs_create:
1282 if (bldev != NULL)
1283 backlight_device_unregister(bldev);
1284err_bl:
1285 destroy_workqueue(ddata->workqueue);
1286err_reg:
1287 return r;
1288}
1289
1290static int __exit dsicm_remove(struct platform_device *pdev)
1291{
1292 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
1293 struct omap_dss_device *dssdev = &ddata->dssdev;
1294 struct backlight_device *bldev;
1295
1296 dev_dbg(&pdev->dev, "remove\n");
1297
1298 omapdss_unregister_display(dssdev);
1299
1300 dsicm_disable(dssdev);
1301 dsicm_disconnect(dssdev);
1302
1303 sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);
1304
1305 bldev = ddata->bldev;
1306 if (bldev != NULL) {
1307 bldev->props.power = FB_BLANK_POWERDOWN;
1308 dsicm_bl_update_status(bldev);
1309 backlight_device_unregister(bldev);
1310 }
1311
1312 omap_dss_put_device(ddata->in);
1313
1314 dsicm_cancel_ulps_work(ddata);
1315 destroy_workqueue(ddata->workqueue);
1316
1317 /* reset, to be sure that the panel is in a valid state */
1318 dsicm_hw_reset(ddata);
1319
1320 return 0;
1321}
1322
1323static struct platform_driver dsicm_driver = {
1324 .probe = dsicm_probe,
1325 .remove = __exit_p(dsicm_remove),
1326 .driver = {
1327 .name = "panel-dsi-cm",
1328 .owner = THIS_MODULE,
1329 },
1330};
1331
1332module_platform_driver(dsicm_driver);
1333
1334MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
1335MODULE_DESCRIPTION("Generic DSI Command Mode Panel Driver");
1336MODULE_LICENSE("GPL");
diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h
index 4e0fc1a8c843..d4d93a900709 100644
--- a/include/video/omap-panel-data.h
+++ b/include/video/omap-panel-data.h
@@ -27,6 +27,7 @@
27#ifndef __OMAP_PANEL_DATA_H 27#ifndef __OMAP_PANEL_DATA_H
28#define __OMAP_PANEL_DATA_H 28#define __OMAP_PANEL_DATA_H
29 29
30#include <video/omapdss.h>
30#include <video/display_timing.h> 31#include <video/display_timing.h>
31 32
32struct omap_dss_device; 33struct omap_dss_device;
@@ -236,4 +237,31 @@ struct panel_dpi_platform_data {
236 int enable_gpio; 237 int enable_gpio;
237}; 238};
238 239
240/**
241 * panel_dsicm platform data
242 * @name: name for this display entity
243 * @source: name of the display entity used as a video source
244 * @reset_gpio: gpio to reset the panel (or -1)
245 * @use_ext_te: use external TE GPIO
246 * @ext_te_gpio: external TE GPIO
247 * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
248 * @use_dsi_backlight: true if panel uses DSI command to control backlight
249 * @pin_config: DSI pin configuration
250 */
251struct panel_dsicm_platform_data {
252 const char *name;
253 const char *source;
254
255 int reset_gpio;
256
257 bool use_ext_te;
258 int ext_te_gpio;
259
260 unsigned ulps_timeout;
261
262 bool use_dsi_backlight;
263
264 struct omap_dsi_pin_config pin_config;
265};
266
239#endif /* __OMAP_PANEL_DATA_H */ 267#endif /* __OMAP_PANEL_DATA_H */