]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/video/omap2/displays/panel-taal.c
ARM/OMAP: Remove the +x bit from a couple of source files
[mv-sheeva.git] / drivers / video / omap2 / displays / panel-taal.c
1 /*
2  * Taal DSI command mode panel
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /*#define DEBUG*/
21
22 #include <linux/module.h>
23 #include <linux/delay.h>
24 #include <linux/err.h>
25 #include <linux/jiffies.h>
26 #include <linux/sched.h>
27 #include <linux/backlight.h>
28 #include <linux/fb.h>
29 #include <linux/interrupt.h>
30 #include <linux/gpio.h>
31 #include <linux/completion.h>
32 #include <linux/workqueue.h>
33
34 #include <plat/display.h>
35
36 /* DSI Virtual channel. Hardcoded for now. */
37 #define TCH 0
38
39 #define DCS_READ_NUM_ERRORS     0x05
40 #define DCS_READ_POWER_MODE     0x0a
41 #define DCS_READ_MADCTL         0x0b
42 #define DCS_READ_PIXEL_FORMAT   0x0c
43 #define DCS_RDDSDR              0x0f
44 #define DCS_SLEEP_IN            0x10
45 #define DCS_SLEEP_OUT           0x11
46 #define DCS_DISPLAY_OFF         0x28
47 #define DCS_DISPLAY_ON          0x29
48 #define DCS_COLUMN_ADDR         0x2a
49 #define DCS_PAGE_ADDR           0x2b
50 #define DCS_MEMORY_WRITE        0x2c
51 #define DCS_TEAR_OFF            0x34
52 #define DCS_TEAR_ON             0x35
53 #define DCS_MEM_ACC_CTRL        0x36
54 #define DCS_PIXEL_FORMAT        0x3a
55 #define DCS_BRIGHTNESS          0x51
56 #define DCS_CTRL_DISPLAY        0x53
57 #define DCS_WRITE_CABC          0x55
58 #define DCS_READ_CABC           0x56
59 #define DCS_GET_ID1             0xda
60 #define DCS_GET_ID2             0xdb
61 #define DCS_GET_ID3             0xdc
62
63 /* #define TAAL_USE_ESD_CHECK */
64 #define TAAL_ESD_CHECK_PERIOD   msecs_to_jiffies(5000)
65
66 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
67
68 struct taal_data {
69         struct backlight_device *bldev;
70
71         unsigned long   hw_guard_end;   /* next value of jiffies when we can
72                                          * issue the next sleep in/out command
73                                          */
74         unsigned long   hw_guard_wait;  /* max guard time in jiffies */
75
76         struct omap_dss_device *dssdev;
77
78         bool enabled;
79         u8 rotate;
80         bool mirror;
81
82         bool te_enabled;
83         bool use_ext_te;
84         struct completion te_completion;
85
86         bool use_dsi_bl;
87
88         bool cabc_broken;
89         unsigned cabc_mode;
90
91         bool intro_printed;
92
93         struct workqueue_struct *esd_wq;
94         struct delayed_work esd_work;
95 };
96
97 static void taal_esd_work(struct work_struct *work);
98
99 static void hw_guard_start(struct taal_data *td, int guard_msec)
100 {
101         td->hw_guard_wait = msecs_to_jiffies(guard_msec);
102         td->hw_guard_end = jiffies + td->hw_guard_wait;
103 }
104
105 static void hw_guard_wait(struct taal_data *td)
106 {
107         unsigned long wait = td->hw_guard_end - jiffies;
108
109         if ((long)wait > 0 && wait <= td->hw_guard_wait) {
110                 set_current_state(TASK_UNINTERRUPTIBLE);
111                 schedule_timeout(wait);
112         }
113 }
114
115 static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
116 {
117         int r;
118         u8 buf[1];
119
120         r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
121
122         if (r < 0)
123                 return r;
124
125         *data = buf[0];
126
127         return 0;
128 }
129
130 static int taal_dcs_write_0(u8 dcs_cmd)
131 {
132         return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
133 }
134
135 static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
136 {
137         u8 buf[2];
138         buf[0] = dcs_cmd;
139         buf[1] = param;
140         return dsi_vc_dcs_write(TCH, buf, 2);
141 }
142
143 static int taal_sleep_in(struct taal_data *td)
144
145 {
146         u8 cmd;
147         int r;
148
149         hw_guard_wait(td);
150
151         cmd = DCS_SLEEP_IN;
152         r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
153         if (r)
154                 return r;
155
156         hw_guard_start(td, 120);
157
158         msleep(5);
159
160         return 0;
161 }
162
163 static int taal_sleep_out(struct taal_data *td)
164 {
165         int r;
166
167         hw_guard_wait(td);
168
169         r = taal_dcs_write_0(DCS_SLEEP_OUT);
170         if (r)
171                 return r;
172
173         hw_guard_start(td, 120);
174
175         msleep(5);
176
177         return 0;
178 }
179
180 static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
181 {
182         int r;
183
184         r = taal_dcs_read_1(DCS_GET_ID1, id1);
185         if (r)
186                 return r;
187         r = taal_dcs_read_1(DCS_GET_ID2, id2);
188         if (r)
189                 return r;
190         r = taal_dcs_read_1(DCS_GET_ID3, id3);
191         if (r)
192                 return r;
193
194         return 0;
195 }
196
197 static int taal_set_addr_mode(u8 rotate, bool mirror)
198 {
199         int r;
200         u8 mode;
201         int b5, b6, b7;
202
203         r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
204         if (r)
205                 return r;
206
207         switch (rotate) {
208         default:
209         case 0:
210                 b7 = 0;
211                 b6 = 0;
212                 b5 = 0;
213                 break;
214         case 1:
215                 b7 = 0;
216                 b6 = 1;
217                 b5 = 1;
218                 break;
219         case 2:
220                 b7 = 1;
221                 b6 = 1;
222                 b5 = 0;
223                 break;
224         case 3:
225                 b7 = 1;
226                 b6 = 0;
227                 b5 = 1;
228                 break;
229         }
230
231         if (mirror)
232                 b6 = !b6;
233
234         mode &= ~((1<<7) | (1<<6) | (1<<5));
235         mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
236
237         return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
238 }
239
240 static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
241 {
242         int r;
243         u16 x1 = x;
244         u16 x2 = x + w - 1;
245         u16 y1 = y;
246         u16 y2 = y + h - 1;
247
248         u8 buf[5];
249         buf[0] = DCS_COLUMN_ADDR;
250         buf[1] = (x1 >> 8) & 0xff;
251         buf[2] = (x1 >> 0) & 0xff;
252         buf[3] = (x2 >> 8) & 0xff;
253         buf[4] = (x2 >> 0) & 0xff;
254
255         r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
256         if (r)
257                 return r;
258
259         buf[0] = DCS_PAGE_ADDR;
260         buf[1] = (y1 >> 8) & 0xff;
261         buf[2] = (y1 >> 0) & 0xff;
262         buf[3] = (y2 >> 8) & 0xff;
263         buf[4] = (y2 >> 0) & 0xff;
264
265         r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
266         if (r)
267                 return r;
268
269         dsi_vc_send_bta_sync(TCH);
270
271         return r;
272 }
273
274 static int taal_bl_update_status(struct backlight_device *dev)
275 {
276         struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
277         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
278         int r;
279         int level;
280
281         if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
282                         dev->props.power == FB_BLANK_UNBLANK)
283                 level = dev->props.brightness;
284         else
285                 level = 0;
286
287         dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
288
289         if (td->use_dsi_bl) {
290                 if (td->enabled) {
291                         dsi_bus_lock();
292                         r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
293                         dsi_bus_unlock();
294                         if (r)
295                                 return r;
296                 }
297         } else {
298                 if (!dssdev->set_backlight)
299                         return -EINVAL;
300
301                 r = dssdev->set_backlight(dssdev, level);
302                 if (r)
303                         return r;
304         }
305
306         return 0;
307 }
308
309 static int taal_bl_get_intensity(struct backlight_device *dev)
310 {
311         if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
312                         dev->props.power == FB_BLANK_UNBLANK)
313                 return dev->props.brightness;
314
315         return 0;
316 }
317
318 static struct backlight_ops taal_bl_ops = {
319         .get_brightness = taal_bl_get_intensity,
320         .update_status  = taal_bl_update_status,
321 };
322
323 static void taal_get_timings(struct omap_dss_device *dssdev,
324                         struct omap_video_timings *timings)
325 {
326         *timings = dssdev->panel.timings;
327 }
328
329 static void taal_get_resolution(struct omap_dss_device *dssdev,
330                 u16 *xres, u16 *yres)
331 {
332         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
333
334         if (td->rotate == 0 || td->rotate == 2) {
335                 *xres = dssdev->panel.timings.x_res;
336                 *yres = dssdev->panel.timings.y_res;
337         } else {
338                 *yres = dssdev->panel.timings.x_res;
339                 *xres = dssdev->panel.timings.y_res;
340         }
341 }
342
343 static irqreturn_t taal_te_isr(int irq, void *data)
344 {
345         struct omap_dss_device *dssdev = data;
346         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
347
348         complete_all(&td->te_completion);
349
350         return IRQ_HANDLED;
351 }
352
353 static ssize_t taal_num_errors_show(struct device *dev,
354                 struct device_attribute *attr, char *buf)
355 {
356         struct omap_dss_device *dssdev = to_dss_device(dev);
357         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
358         u8 errors;
359         int r;
360
361         if (td->enabled) {
362                 dsi_bus_lock();
363                 r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
364                 dsi_bus_unlock();
365         } else {
366                 r = -ENODEV;
367         }
368
369         if (r)
370                 return r;
371
372         return snprintf(buf, PAGE_SIZE, "%d\n", errors);
373 }
374
375 static ssize_t taal_hw_revision_show(struct device *dev,
376                 struct device_attribute *attr, char *buf)
377 {
378         struct omap_dss_device *dssdev = to_dss_device(dev);
379         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
380         u8 id1, id2, id3;
381         int r;
382
383         if (td->enabled) {
384                 dsi_bus_lock();
385                 r = taal_get_id(&id1, &id2, &id3);
386                 dsi_bus_unlock();
387         } else {
388                 r = -ENODEV;
389         }
390
391         if (r)
392                 return r;
393
394         return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
395 }
396
397 static const char *cabc_modes[] = {
398         "off",          /* used also always when CABC is not supported */
399         "ui",
400         "still-image",
401         "moving-image",
402 };
403
404 static ssize_t show_cabc_mode(struct device *dev,
405                 struct device_attribute *attr,
406                 char *buf)
407 {
408         struct omap_dss_device *dssdev = to_dss_device(dev);
409         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
410         const char *mode_str;
411         int mode;
412         int len;
413
414         mode = td->cabc_mode;
415
416         mode_str = "unknown";
417         if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
418                 mode_str = cabc_modes[mode];
419         len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
420
421         return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
422 }
423
424 static ssize_t store_cabc_mode(struct device *dev,
425                 struct device_attribute *attr,
426                 const char *buf, size_t count)
427 {
428         struct omap_dss_device *dssdev = to_dss_device(dev);
429         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
430         int i;
431
432         for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
433                 if (sysfs_streq(cabc_modes[i], buf))
434                         break;
435         }
436
437         if (i == ARRAY_SIZE(cabc_modes))
438                 return -EINVAL;
439
440         if (td->enabled) {
441                 dsi_bus_lock();
442                 if (!td->cabc_broken)
443                         taal_dcs_write_1(DCS_WRITE_CABC, i);
444                 dsi_bus_unlock();
445         }
446
447         td->cabc_mode = i;
448
449         return count;
450 }
451
452 static ssize_t show_cabc_available_modes(struct device *dev,
453                 struct device_attribute *attr,
454                 char *buf)
455 {
456         int len;
457         int i;
458
459         for (i = 0, len = 0;
460              len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
461                 len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
462                         i ? " " : "", cabc_modes[i],
463                         i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
464
465         return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
466 }
467
468 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
469 static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
470 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
471                 show_cabc_mode, store_cabc_mode);
472 static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
473                 show_cabc_available_modes, NULL);
474
475 static struct attribute *taal_attrs[] = {
476         &dev_attr_num_dsi_errors.attr,
477         &dev_attr_hw_revision.attr,
478         &dev_attr_cabc_mode.attr,
479         &dev_attr_cabc_available_modes.attr,
480         NULL,
481 };
482
483 static struct attribute_group taal_attr_group = {
484         .attrs = taal_attrs,
485 };
486
487 static int taal_probe(struct omap_dss_device *dssdev)
488 {
489         struct taal_data *td;
490         struct backlight_device *bldev;
491         int r;
492
493         const struct omap_video_timings taal_panel_timings = {
494                 .x_res          = 864,
495                 .y_res          = 480,
496         };
497
498         dev_dbg(&dssdev->dev, "probe\n");
499
500         dssdev->panel.config = OMAP_DSS_LCD_TFT;
501         dssdev->panel.timings = taal_panel_timings;
502         dssdev->ctrl.pixel_size = 24;
503
504         td = kzalloc(sizeof(*td), GFP_KERNEL);
505         if (!td) {
506                 r = -ENOMEM;
507                 goto err0;
508         }
509         td->dssdev = dssdev;
510
511         td->esd_wq = create_singlethread_workqueue("taal_esd");
512         if (td->esd_wq == NULL) {
513                 dev_err(&dssdev->dev, "can't create ESD workqueue\n");
514                 r = -ENOMEM;
515                 goto err1;
516         }
517         INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
518
519         dev_set_drvdata(&dssdev->dev, td);
520
521         /* if no platform set_backlight() defined, presume DSI backlight
522          * control */
523         if (!dssdev->set_backlight)
524                 td->use_dsi_bl = true;
525
526         bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
527                         &taal_bl_ops);
528         if (IS_ERR(bldev)) {
529                 r = PTR_ERR(bldev);
530                 goto err2;
531         }
532
533         td->bldev = bldev;
534
535         bldev->props.fb_blank = FB_BLANK_UNBLANK;
536         bldev->props.power = FB_BLANK_UNBLANK;
537         if (td->use_dsi_bl) {
538                 bldev->props.max_brightness = 255;
539                 bldev->props.brightness = 255;
540         } else {
541                 bldev->props.max_brightness = 127;
542                 bldev->props.brightness = 127;
543         }
544
545         taal_bl_update_status(bldev);
546
547         if (dssdev->phy.dsi.ext_te) {
548                 int gpio = dssdev->phy.dsi.ext_te_gpio;
549
550                 r = gpio_request(gpio, "taal irq");
551                 if (r) {
552                         dev_err(&dssdev->dev, "GPIO request failed\n");
553                         goto err3;
554                 }
555
556                 gpio_direction_input(gpio);
557
558                 r = request_irq(gpio_to_irq(gpio), taal_te_isr,
559                                 IRQF_DISABLED | IRQF_TRIGGER_RISING,
560                                 "taal vsync", dssdev);
561
562                 if (r) {
563                         dev_err(&dssdev->dev, "IRQ request failed\n");
564                         gpio_free(gpio);
565                         goto err3;
566                 }
567
568                 init_completion(&td->te_completion);
569
570                 td->use_ext_te = true;
571         }
572
573         r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
574         if (r) {
575                 dev_err(&dssdev->dev, "failed to create sysfs files\n");
576                 goto err4;
577         }
578
579         return 0;
580 err4:
581         if (td->use_ext_te) {
582                 int gpio = dssdev->phy.dsi.ext_te_gpio;
583                 free_irq(gpio_to_irq(gpio), dssdev);
584                 gpio_free(gpio);
585         }
586 err3:
587         backlight_device_unregister(bldev);
588 err2:
589         cancel_delayed_work_sync(&td->esd_work);
590         destroy_workqueue(td->esd_wq);
591 err1:
592         kfree(td);
593 err0:
594         return r;
595 }
596
597 static void taal_remove(struct omap_dss_device *dssdev)
598 {
599         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
600         struct backlight_device *bldev;
601
602         dev_dbg(&dssdev->dev, "remove\n");
603
604         sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
605
606         if (td->use_ext_te) {
607                 int gpio = dssdev->phy.dsi.ext_te_gpio;
608                 free_irq(gpio_to_irq(gpio), dssdev);
609                 gpio_free(gpio);
610         }
611
612         bldev = td->bldev;
613         bldev->props.power = FB_BLANK_POWERDOWN;
614         taal_bl_update_status(bldev);
615         backlight_device_unregister(bldev);
616
617         cancel_delayed_work_sync(&td->esd_work);
618         destroy_workqueue(td->esd_wq);
619
620         kfree(td);
621 }
622
623 static int taal_power_on(struct omap_dss_device *dssdev)
624 {
625         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
626         u8 id1, id2, id3;
627         int r;
628
629         if (dssdev->platform_enable) {
630                 r = dssdev->platform_enable(dssdev);
631                 if (r)
632                         return r;
633         }
634
635         /* it seems we have to wait a bit until taal is ready */
636         msleep(5);
637
638         dsi_bus_lock();
639
640         r = omapdss_dsi_display_enable(dssdev);
641         if (r) {
642                 dev_err(&dssdev->dev, "failed to enable DSI\n");
643                 goto err0;
644         }
645
646         omapdss_dsi_vc_enable_hs(TCH, false);
647
648         r = taal_sleep_out(td);
649         if (r)
650                 goto err;
651
652         r = taal_get_id(&id1, &id2, &id3);
653         if (r)
654                 goto err;
655
656         /* on early revisions CABC is broken */
657         if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
658                 td->cabc_broken = true;
659
660         taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
661         taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
662
663         taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
664
665         taal_set_addr_mode(td->rotate, td->mirror);
666         if (!td->cabc_broken)
667                 taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
668
669         taal_dcs_write_0(DCS_DISPLAY_ON);
670
671         r = _taal_enable_te(dssdev, td->te_enabled);
672         if (r)
673                 goto err;
674
675 #ifdef TAAL_USE_ESD_CHECK
676         queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
677 #endif
678
679         td->enabled = 1;
680
681         if (!td->intro_printed) {
682                 dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
683                                 id1, id2, id3);
684                 if (td->cabc_broken)
685                         dev_info(&dssdev->dev,
686                                         "old Taal version, CABC disabled\n");
687                 td->intro_printed = true;
688         }
689
690         omapdss_dsi_vc_enable_hs(TCH, true);
691
692         dsi_bus_unlock();
693
694         return 0;
695 err:
696         dsi_bus_unlock();
697
698         omapdss_dsi_display_disable(dssdev);
699 err0:
700         if (dssdev->platform_disable)
701                 dssdev->platform_disable(dssdev);
702
703         return r;
704 }
705
706 static void taal_power_off(struct omap_dss_device *dssdev)
707 {
708         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
709
710         dsi_bus_lock();
711
712         cancel_delayed_work(&td->esd_work);
713
714         taal_dcs_write_0(DCS_DISPLAY_OFF);
715         taal_sleep_in(td);
716
717         /* wait a bit so that the message goes through */
718         msleep(10);
719
720         omapdss_dsi_display_disable(dssdev);
721
722         if (dssdev->platform_disable)
723                 dssdev->platform_disable(dssdev);
724
725         td->enabled = 0;
726
727         dsi_bus_unlock();
728 }
729
730 static int taal_enable(struct omap_dss_device *dssdev)
731 {
732         int r;
733         dev_dbg(&dssdev->dev, "enable\n");
734
735         if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
736                 return -EINVAL;
737
738         r = taal_power_on(dssdev);
739         if (r)
740                 return r;
741
742         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
743
744         return r;
745 }
746
747 static void taal_disable(struct omap_dss_device *dssdev)
748 {
749         dev_dbg(&dssdev->dev, "disable\n");
750
751         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
752                 taal_power_off(dssdev);
753
754         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
755 }
756
757 static int taal_suspend(struct omap_dss_device *dssdev)
758 {
759         dev_dbg(&dssdev->dev, "suspend\n");
760
761         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
762                 return -EINVAL;
763
764         taal_power_off(dssdev);
765         dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
766
767         return 0;
768 }
769
770 static int taal_resume(struct omap_dss_device *dssdev)
771 {
772         int r;
773         dev_dbg(&dssdev->dev, "resume\n");
774
775         if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
776                 return -EINVAL;
777
778         r = taal_power_on(dssdev);
779         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
780         return r;
781 }
782
783 static void taal_framedone_cb(int err, void *data)
784 {
785         struct omap_dss_device *dssdev = data;
786         dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
787         dsi_bus_unlock();
788 }
789
790 static int taal_update(struct omap_dss_device *dssdev,
791                                     u16 x, u16 y, u16 w, u16 h)
792 {
793         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
794         int r;
795
796         dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
797
798         dsi_bus_lock();
799
800         if (!td->enabled) {
801                 r = 0;
802                 goto err;
803         }
804
805         r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
806         if (r)
807                 goto err;
808
809         r = taal_set_update_window(x, y, w, h);
810         if (r)
811                 goto err;
812
813         r = omap_dsi_update(dssdev, TCH, x, y, w, h,
814                         taal_framedone_cb, dssdev);
815         if (r)
816                 goto err;
817
818         /* note: no bus_unlock here. unlock is in framedone_cb */
819         return 0;
820 err:
821         dsi_bus_unlock();
822         return r;
823 }
824
825 static int taal_sync(struct omap_dss_device *dssdev)
826 {
827         dev_dbg(&dssdev->dev, "sync\n");
828
829         dsi_bus_lock();
830         dsi_bus_unlock();
831
832         dev_dbg(&dssdev->dev, "sync done\n");
833
834         return 0;
835 }
836
837 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
838 {
839         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
840         int r;
841
842         td->te_enabled = enable;
843
844         if (enable)
845                 r = taal_dcs_write_1(DCS_TEAR_ON, 0);
846         else
847                 r = taal_dcs_write_0(DCS_TEAR_OFF);
848
849         omapdss_dsi_enable_te(dssdev, enable);
850
851         /* XXX for some reason, DSI TE breaks if we don't wait here.
852          * Panel bug? Needs more studying */
853         msleep(100);
854
855         return r;
856 }
857
858 static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
859 {
860         int r;
861
862         dsi_bus_lock();
863
864         r = _taal_enable_te(dssdev, enable);
865
866         dsi_bus_unlock();
867
868         return r;
869 }
870
871 static int taal_get_te(struct omap_dss_device *dssdev)
872 {
873         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
874         return td->te_enabled;
875 }
876
877 static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
878 {
879         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
880         int r;
881
882         dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
883
884         dsi_bus_lock();
885
886         if (td->enabled) {
887                 r = taal_set_addr_mode(rotate, td->mirror);
888                 if (r)
889                         goto err;
890         }
891
892         td->rotate = rotate;
893
894         dsi_bus_unlock();
895         return 0;
896 err:
897         dsi_bus_unlock();
898         return r;
899 }
900
901 static u8 taal_get_rotate(struct omap_dss_device *dssdev)
902 {
903         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
904         return td->rotate;
905 }
906
907 static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
908 {
909         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
910         int r;
911
912         dev_dbg(&dssdev->dev, "mirror %d\n", enable);
913
914         dsi_bus_lock();
915         if (td->enabled) {
916                 r = taal_set_addr_mode(td->rotate, enable);
917                 if (r)
918                         goto err;
919         }
920
921         td->mirror = enable;
922
923         dsi_bus_unlock();
924         return 0;
925 err:
926         dsi_bus_unlock();
927         return r;
928 }
929
930 static bool taal_get_mirror(struct omap_dss_device *dssdev)
931 {
932         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
933         return td->mirror;
934 }
935
936 static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
937 {
938         u8 id1, id2, id3;
939         int r;
940
941         dsi_bus_lock();
942
943         r = taal_dcs_read_1(DCS_GET_ID1, &id1);
944         if (r)
945                 goto err;
946         r = taal_dcs_read_1(DCS_GET_ID2, &id2);
947         if (r)
948                 goto err;
949         r = taal_dcs_read_1(DCS_GET_ID3, &id3);
950         if (r)
951                 goto err;
952
953         dsi_bus_unlock();
954         return 0;
955 err:
956         dsi_bus_unlock();
957         return r;
958 }
959
960 static int taal_memory_read(struct omap_dss_device *dssdev,
961                 void *buf, size_t size,
962                 u16 x, u16 y, u16 w, u16 h)
963 {
964         int r;
965         int first = 1;
966         int plen;
967         unsigned buf_used = 0;
968         struct taal_data *td = dev_get_drvdata(&dssdev->dev);
969
970         if (!td->enabled)
971                 return -ENODEV;
972
973         if (size < w * h * 3)
974                 return -ENOMEM;
975
976         size = min(w * h * 3,
977                         dssdev->panel.timings.x_res *
978                         dssdev->panel.timings.y_res * 3);
979
980         dsi_bus_lock();
981
982         /* plen 1 or 2 goes into short packet. until checksum error is fixed,
983          * use short packets. plen 32 works, but bigger packets seem to cause
984          * an error. */
985         if (size % 2)
986                 plen = 1;
987         else
988                 plen = 2;
989
990         taal_set_update_window(x, y, w, h);
991
992         r = dsi_vc_set_max_rx_packet_size(TCH, plen);
993         if (r)
994                 goto err0;
995
996         while (buf_used < size) {
997                 u8 dcs_cmd = first ? 0x2e : 0x3e;
998                 first = 0;
999
1000                 r = dsi_vc_dcs_read(TCH, dcs_cmd,
1001                                 buf + buf_used, size - buf_used);
1002
1003                 if (r < 0) {
1004                         dev_err(&dssdev->dev, "read error\n");
1005                         goto err;
1006                 }
1007
1008                 buf_used += r;
1009
1010                 if (r < plen) {
1011                         dev_err(&dssdev->dev, "short read\n");
1012                         break;
1013                 }
1014
1015                 if (signal_pending(current)) {
1016                         dev_err(&dssdev->dev, "signal pending, "
1017                                         "aborting memory read\n");
1018                         r = -ERESTARTSYS;
1019                         goto err;
1020                 }
1021         }
1022
1023         r = buf_used;
1024
1025 err:
1026         dsi_vc_set_max_rx_packet_size(TCH, 1);
1027 err0:
1028         dsi_bus_unlock();
1029         return r;
1030 }
1031
1032 static void taal_esd_work(struct work_struct *work)
1033 {
1034         struct taal_data *td = container_of(work, struct taal_data,
1035                         esd_work.work);
1036         struct omap_dss_device *dssdev = td->dssdev;
1037         u8 state1, state2;
1038         int r;
1039
1040         if (!td->enabled)
1041                 return;
1042
1043         dsi_bus_lock();
1044
1045         r = taal_dcs_read_1(DCS_RDDSDR, &state1);
1046         if (r) {
1047                 dev_err(&dssdev->dev, "failed to read Taal status\n");
1048                 goto err;
1049         }
1050
1051         /* Run self diagnostics */
1052         r = taal_sleep_out(td);
1053         if (r) {
1054                 dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n");
1055                 goto err;
1056         }
1057
1058         r = taal_dcs_read_1(DCS_RDDSDR, &state2);
1059         if (r) {
1060                 dev_err(&dssdev->dev, "failed to read Taal status\n");
1061                 goto err;
1062         }
1063
1064         /* Each sleep out command will trigger a self diagnostic and flip
1065          * Bit6 if the test passes.
1066          */
1067         if (!((state1 ^ state2) & (1 << 6))) {
1068                 dev_err(&dssdev->dev, "LCD self diagnostics failed\n");
1069                 goto err;
1070         }
1071         /* Self-diagnostics result is also shown on TE GPIO line. We need
1072          * to re-enable TE after self diagnostics */
1073         if (td->use_ext_te && td->te_enabled) {
1074                 r = taal_dcs_write_1(DCS_TEAR_ON, 0);
1075                 if (r)
1076                         goto err;
1077         }
1078
1079         dsi_bus_unlock();
1080
1081         queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
1082
1083         return;
1084 err:
1085         dev_err(&dssdev->dev, "performing LCD reset\n");
1086
1087         taal_disable(dssdev);
1088         taal_enable(dssdev);
1089
1090         dsi_bus_unlock();
1091
1092         queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
1093 }
1094
1095 static int taal_set_update_mode(struct omap_dss_device *dssdev,
1096                 enum omap_dss_update_mode mode)
1097 {
1098         if (mode != OMAP_DSS_UPDATE_MANUAL)
1099                 return -EINVAL;
1100         return 0;
1101 }
1102
1103 static enum omap_dss_update_mode taal_get_update_mode(
1104                 struct omap_dss_device *dssdev)
1105 {
1106         return OMAP_DSS_UPDATE_MANUAL;
1107 }
1108
1109 static struct omap_dss_driver taal_driver = {
1110         .probe          = taal_probe,
1111         .remove         = taal_remove,
1112
1113         .enable         = taal_enable,
1114         .disable        = taal_disable,
1115         .suspend        = taal_suspend,
1116         .resume         = taal_resume,
1117
1118         .set_update_mode = taal_set_update_mode,
1119         .get_update_mode = taal_get_update_mode,
1120
1121         .update         = taal_update,
1122         .sync           = taal_sync,
1123
1124         .get_resolution = taal_get_resolution,
1125         .get_recommended_bpp = omapdss_default_get_recommended_bpp,
1126
1127         .enable_te      = taal_enable_te,
1128         .get_te         = taal_get_te,
1129
1130         .set_rotate     = taal_rotate,
1131         .get_rotate     = taal_get_rotate,
1132         .set_mirror     = taal_mirror,
1133         .get_mirror     = taal_get_mirror,
1134         .run_test       = taal_run_test,
1135         .memory_read    = taal_memory_read,
1136
1137         .get_timings    = taal_get_timings,
1138
1139         .driver         = {
1140                 .name   = "taal",
1141                 .owner  = THIS_MODULE,
1142         },
1143 };
1144
1145 static int __init taal_init(void)
1146 {
1147         omap_dss_register_driver(&taal_driver);
1148
1149         return 0;
1150 }
1151
1152 static void __exit taal_exit(void)
1153 {
1154         omap_dss_unregister_driver(&taal_driver);
1155 }
1156
1157 module_init(taal_init);
1158 module_exit(taal_exit);
1159
1160 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
1161 MODULE_DESCRIPTION("Taal Driver");
1162 MODULE_LICENSE("GPL");