diff options
Diffstat (limited to 'drivers/video/omap2/displays/panel-taal.c')
-rw-r--r-- | drivers/video/omap2/displays/panel-taal.c | 567 |
1 files changed, 447 insertions, 120 deletions
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index aaf5d308a04..e1c765d1141 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -28,12 +28,13 @@ | |||
28 | #include <linux/fb.h> | 28 | #include <linux/fb.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/gpio.h> | 30 | #include <linux/gpio.h> |
31 | #include <linux/completion.h> | ||
32 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
33 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
35 | 35 | ||
36 | #include <plat/display.h> | 36 | #include <plat/display.h> |
37 | #include <plat/nokia-dsi-panel.h> | ||
37 | 38 | ||
38 | /* DSI Virtual channel. Hardcoded for now. */ | 39 | /* DSI Virtual channel. Hardcoded for now. */ |
39 | #define TCH 0 | 40 | #define TCH 0 |
@@ -62,11 +63,136 @@ | |||
62 | #define DCS_GET_ID2 0xdb | 63 | #define DCS_GET_ID2 0xdb |
63 | #define DCS_GET_ID3 0xdc | 64 | #define DCS_GET_ID3 0xdc |
64 | 65 | ||
65 | /* #define TAAL_USE_ESD_CHECK */ | ||
66 | #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) | 66 | #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) |
67 | 67 | ||
68 | static irqreturn_t taal_te_isr(int irq, void *data); | ||
69 | static void taal_te_timeout_work_callback(struct work_struct *work); | ||
68 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); | 70 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); |
69 | 71 | ||
72 | struct panel_regulator { | ||
73 | struct regulator *regulator; | ||
74 | const char *name; | ||
75 | int min_uV; | ||
76 | int max_uV; | ||
77 | }; | ||
78 | |||
79 | static void free_regulators(struct panel_regulator *regulators, int n) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | for (i = 0; i < n; i++) { | ||
84 | /* disable/put in reverse order */ | ||
85 | regulator_disable(regulators[n - i - 1].regulator); | ||
86 | regulator_put(regulators[n - i - 1].regulator); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static int init_regulators(struct omap_dss_device *dssdev, | ||
91 | struct panel_regulator *regulators, int n) | ||
92 | { | ||
93 | int r, i, v; | ||
94 | |||
95 | for (i = 0; i < n; i++) { | ||
96 | struct regulator *reg; | ||
97 | |||
98 | reg = regulator_get(&dssdev->dev, regulators[i].name); | ||
99 | if (IS_ERR(reg)) { | ||
100 | dev_err(&dssdev->dev, "failed to get regulator %s\n", | ||
101 | regulators[i].name); | ||
102 | r = PTR_ERR(reg); | ||
103 | goto err; | ||
104 | } | ||
105 | |||
106 | /* FIXME: better handling of fixed vs. variable regulators */ | ||
107 | v = regulator_get_voltage(reg); | ||
108 | if (v < regulators[i].min_uV || v > regulators[i].max_uV) { | ||
109 | r = regulator_set_voltage(reg, regulators[i].min_uV, | ||
110 | regulators[i].max_uV); | ||
111 | if (r) { | ||
112 | dev_err(&dssdev->dev, | ||
113 | "failed to set regulator %s voltage\n", | ||
114 | regulators[i].name); | ||
115 | regulator_put(reg); | ||
116 | goto err; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | r = regulator_enable(reg); | ||
121 | if (r) { | ||
122 | dev_err(&dssdev->dev, "failed to enable regulator %s\n", | ||
123 | regulators[i].name); | ||
124 | regulator_put(reg); | ||
125 | goto err; | ||
126 | } | ||
127 | |||
128 | regulators[i].regulator = reg; | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | |||
133 | err: | ||
134 | free_regulators(regulators, i); | ||
135 | |||
136 | return r; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * struct panel_config - panel configuration | ||
141 | * @name: panel name | ||
142 | * @type: panel type | ||
143 | * @timings: panel resolution | ||
144 | * @sleep: various panel specific delays, passed to msleep() if non-zero | ||
145 | * @reset_sequence: reset sequence timings, passed to udelay() if non-zero | ||
146 | * @regulators: array of panel regulators | ||
147 | * @num_regulators: number of regulators in the array | ||
148 | */ | ||
149 | struct panel_config { | ||
150 | const char *name; | ||
151 | int type; | ||
152 | |||
153 | struct omap_video_timings timings; | ||
154 | |||
155 | struct { | ||
156 | unsigned int sleep_in; | ||
157 | unsigned int sleep_out; | ||
158 | unsigned int hw_reset; | ||
159 | unsigned int enable_te; | ||
160 | } sleep; | ||
161 | |||
162 | struct { | ||
163 | unsigned int high; | ||
164 | unsigned int low; | ||
165 | } reset_sequence; | ||
166 | |||
167 | struct panel_regulator *regulators; | ||
168 | int num_regulators; | ||
169 | }; | ||
170 | |||
171 | enum { | ||
172 | PANEL_TAAL, | ||
173 | }; | ||
174 | |||
175 | static struct panel_config panel_configs[] = { | ||
176 | { | ||
177 | .name = "taal", | ||
178 | .type = PANEL_TAAL, | ||
179 | .timings = { | ||
180 | .x_res = 864, | ||
181 | .y_res = 480, | ||
182 | }, | ||
183 | .sleep = { | ||
184 | .sleep_in = 5, | ||
185 | .sleep_out = 5, | ||
186 | .hw_reset = 5, | ||
187 | .enable_te = 100, /* possible panel bug */ | ||
188 | }, | ||
189 | .reset_sequence = { | ||
190 | .high = 10, | ||
191 | .low = 10, | ||
192 | }, | ||
193 | }, | ||
194 | }; | ||
195 | |||
70 | struct taal_data { | 196 | struct taal_data { |
71 | struct mutex lock; | 197 | struct mutex lock; |
72 | 198 | ||
@@ -84,8 +210,15 @@ struct taal_data { | |||
84 | bool mirror; | 210 | bool mirror; |
85 | 211 | ||
86 | bool te_enabled; | 212 | bool te_enabled; |
87 | bool use_ext_te; | 213 | |
88 | struct completion te_completion; | 214 | atomic_t do_update; |
215 | struct { | ||
216 | u16 x; | ||
217 | u16 y; | ||
218 | u16 w; | ||
219 | u16 h; | ||
220 | } update_region; | ||
221 | struct delayed_work te_timeout_work; | ||
89 | 222 | ||
90 | bool use_dsi_bl; | 223 | bool use_dsi_bl; |
91 | 224 | ||
@@ -96,8 +229,16 @@ struct taal_data { | |||
96 | 229 | ||
97 | struct workqueue_struct *esd_wq; | 230 | struct workqueue_struct *esd_wq; |
98 | struct delayed_work esd_work; | 231 | struct delayed_work esd_work; |
232 | |||
233 | struct panel_config *panel_config; | ||
99 | }; | 234 | }; |
100 | 235 | ||
236 | static inline struct nokia_dsi_panel_data | ||
237 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
238 | { | ||
239 | return (struct nokia_dsi_panel_data *) dssdev->data; | ||
240 | } | ||
241 | |||
101 | static void taal_esd_work(struct work_struct *work); | 242 | static void taal_esd_work(struct work_struct *work); |
102 | 243 | ||
103 | static void hw_guard_start(struct taal_data *td, int guard_msec) | 244 | static void hw_guard_start(struct taal_data *td, int guard_msec) |
@@ -159,7 +300,8 @@ static int taal_sleep_in(struct taal_data *td) | |||
159 | 300 | ||
160 | hw_guard_start(td, 120); | 301 | hw_guard_start(td, 120); |
161 | 302 | ||
162 | msleep(5); | 303 | if (td->panel_config->sleep.sleep_in) |
304 | msleep(td->panel_config->sleep.sleep_in); | ||
163 | 305 | ||
164 | return 0; | 306 | return 0; |
165 | } | 307 | } |
@@ -176,7 +318,8 @@ static int taal_sleep_out(struct taal_data *td) | |||
176 | 318 | ||
177 | hw_guard_start(td, 120); | 319 | hw_guard_start(td, 120); |
178 | 320 | ||
179 | msleep(5); | 321 | if (td->panel_config->sleep.sleep_out) |
322 | msleep(td->panel_config->sleep.sleep_out); | ||
180 | 323 | ||
181 | return 0; | 324 | return 0; |
182 | } | 325 | } |
@@ -279,6 +422,7 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
279 | { | 422 | { |
280 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | 423 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); |
281 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 424 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
425 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
282 | int r; | 426 | int r; |
283 | int level; | 427 | int level; |
284 | 428 | ||
@@ -290,24 +434,26 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
290 | 434 | ||
291 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); | 435 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); |
292 | 436 | ||
437 | mutex_lock(&td->lock); | ||
438 | |||
293 | if (td->use_dsi_bl) { | 439 | if (td->use_dsi_bl) { |
294 | if (td->enabled) { | 440 | if (td->enabled) { |
295 | dsi_bus_lock(); | 441 | dsi_bus_lock(); |
296 | r = taal_dcs_write_1(DCS_BRIGHTNESS, level); | 442 | r = taal_dcs_write_1(DCS_BRIGHTNESS, level); |
297 | dsi_bus_unlock(); | 443 | dsi_bus_unlock(); |
298 | if (r) | 444 | } else { |
299 | return r; | 445 | r = 0; |
300 | } | 446 | } |
301 | } else { | 447 | } else { |
302 | if (!dssdev->set_backlight) | 448 | if (!panel_data->set_backlight) |
303 | return -EINVAL; | 449 | r = -EINVAL; |
304 | 450 | else | |
305 | r = dssdev->set_backlight(dssdev, level); | 451 | r = panel_data->set_backlight(dssdev, level); |
306 | if (r) | ||
307 | return r; | ||
308 | } | 452 | } |
309 | 453 | ||
310 | return 0; | 454 | mutex_unlock(&td->lock); |
455 | |||
456 | return r; | ||
311 | } | 457 | } |
312 | 458 | ||
313 | static int taal_bl_get_intensity(struct backlight_device *dev) | 459 | static int taal_bl_get_intensity(struct backlight_device *dev) |
@@ -344,16 +490,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev, | |||
344 | } | 490 | } |
345 | } | 491 | } |
346 | 492 | ||
347 | static irqreturn_t taal_te_isr(int irq, void *data) | ||
348 | { | ||
349 | struct omap_dss_device *dssdev = data; | ||
350 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
351 | |||
352 | complete_all(&td->te_completion); | ||
353 | |||
354 | return IRQ_HANDLED; | ||
355 | } | ||
356 | |||
357 | static ssize_t taal_num_errors_show(struct device *dev, | 493 | static ssize_t taal_num_errors_show(struct device *dev, |
358 | struct device_attribute *attr, char *buf) | 494 | struct device_attribute *attr, char *buf) |
359 | { | 495 | { |
@@ -362,6 +498,8 @@ static ssize_t taal_num_errors_show(struct device *dev, | |||
362 | u8 errors; | 498 | u8 errors; |
363 | int r; | 499 | int r; |
364 | 500 | ||
501 | mutex_lock(&td->lock); | ||
502 | |||
365 | if (td->enabled) { | 503 | if (td->enabled) { |
366 | dsi_bus_lock(); | 504 | dsi_bus_lock(); |
367 | r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); | 505 | r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); |
@@ -370,6 +508,8 @@ static ssize_t taal_num_errors_show(struct device *dev, | |||
370 | r = -ENODEV; | 508 | r = -ENODEV; |
371 | } | 509 | } |
372 | 510 | ||
511 | mutex_unlock(&td->lock); | ||
512 | |||
373 | if (r) | 513 | if (r) |
374 | return r; | 514 | return r; |
375 | 515 | ||
@@ -384,6 +524,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, | |||
384 | u8 id1, id2, id3; | 524 | u8 id1, id2, id3; |
385 | int r; | 525 | int r; |
386 | 526 | ||
527 | mutex_lock(&td->lock); | ||
528 | |||
387 | if (td->enabled) { | 529 | if (td->enabled) { |
388 | dsi_bus_lock(); | 530 | dsi_bus_lock(); |
389 | r = taal_get_id(&id1, &id2, &id3); | 531 | r = taal_get_id(&id1, &id2, &id3); |
@@ -392,6 +534,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, | |||
392 | r = -ENODEV; | 534 | r = -ENODEV; |
393 | } | 535 | } |
394 | 536 | ||
537 | mutex_unlock(&td->lock); | ||
538 | |||
395 | if (r) | 539 | if (r) |
396 | return r; | 540 | return r; |
397 | 541 | ||
@@ -441,6 +585,8 @@ static ssize_t store_cabc_mode(struct device *dev, | |||
441 | if (i == ARRAY_SIZE(cabc_modes)) | 585 | if (i == ARRAY_SIZE(cabc_modes)) |
442 | return -EINVAL; | 586 | return -EINVAL; |
443 | 587 | ||
588 | mutex_lock(&td->lock); | ||
589 | |||
444 | if (td->enabled) { | 590 | if (td->enabled) { |
445 | dsi_bus_lock(); | 591 | dsi_bus_lock(); |
446 | if (!td->cabc_broken) | 592 | if (!td->cabc_broken) |
@@ -450,6 +596,8 @@ static ssize_t store_cabc_mode(struct device *dev, | |||
450 | 596 | ||
451 | td->cabc_mode = i; | 597 | td->cabc_mode = i; |
452 | 598 | ||
599 | mutex_unlock(&td->lock); | ||
600 | |||
453 | return count; | 601 | return count; |
454 | } | 602 | } |
455 | 603 | ||
@@ -488,47 +636,93 @@ static struct attribute_group taal_attr_group = { | |||
488 | .attrs = taal_attrs, | 636 | .attrs = taal_attrs, |
489 | }; | 637 | }; |
490 | 638 | ||
639 | static void taal_hw_reset(struct omap_dss_device *dssdev) | ||
640 | { | ||
641 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
642 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
643 | |||
644 | if (panel_data->reset_gpio == -1) | ||
645 | return; | ||
646 | |||
647 | gpio_set_value(panel_data->reset_gpio, 1); | ||
648 | if (td->panel_config->reset_sequence.high) | ||
649 | udelay(td->panel_config->reset_sequence.high); | ||
650 | /* reset the panel */ | ||
651 | gpio_set_value(panel_data->reset_gpio, 0); | ||
652 | /* assert reset */ | ||
653 | if (td->panel_config->reset_sequence.low) | ||
654 | udelay(td->panel_config->reset_sequence.low); | ||
655 | gpio_set_value(panel_data->reset_gpio, 1); | ||
656 | /* wait after releasing reset */ | ||
657 | if (td->panel_config->sleep.hw_reset) | ||
658 | msleep(td->panel_config->sleep.hw_reset); | ||
659 | } | ||
660 | |||
491 | static int taal_probe(struct omap_dss_device *dssdev) | 661 | static int taal_probe(struct omap_dss_device *dssdev) |
492 | { | 662 | { |
493 | struct backlight_properties props; | 663 | struct backlight_properties props; |
494 | struct taal_data *td; | 664 | struct taal_data *td; |
495 | struct backlight_device *bldev; | 665 | struct backlight_device *bldev; |
496 | int r; | 666 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); |
497 | 667 | struct panel_config *panel_config = NULL; | |
498 | const struct omap_video_timings taal_panel_timings = { | 668 | int r, i; |
499 | .x_res = 864, | ||
500 | .y_res = 480, | ||
501 | }; | ||
502 | 669 | ||
503 | dev_dbg(&dssdev->dev, "probe\n"); | 670 | dev_dbg(&dssdev->dev, "probe\n"); |
504 | 671 | ||
672 | if (!panel_data || !panel_data->name) { | ||
673 | r = -EINVAL; | ||
674 | goto err; | ||
675 | } | ||
676 | |||
677 | for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { | ||
678 | if (strcmp(panel_data->name, panel_configs[i].name) == 0) { | ||
679 | panel_config = &panel_configs[i]; | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | |||
684 | if (!panel_config) { | ||
685 | r = -EINVAL; | ||
686 | goto err; | ||
687 | } | ||
688 | |||
505 | dssdev->panel.config = OMAP_DSS_LCD_TFT; | 689 | dssdev->panel.config = OMAP_DSS_LCD_TFT; |
506 | dssdev->panel.timings = taal_panel_timings; | 690 | dssdev->panel.timings = panel_config->timings; |
507 | dssdev->ctrl.pixel_size = 24; | 691 | dssdev->ctrl.pixel_size = 24; |
508 | 692 | ||
509 | td = kzalloc(sizeof(*td), GFP_KERNEL); | 693 | td = kzalloc(sizeof(*td), GFP_KERNEL); |
510 | if (!td) { | 694 | if (!td) { |
511 | r = -ENOMEM; | 695 | r = -ENOMEM; |
512 | goto err0; | 696 | goto err; |
513 | } | 697 | } |
514 | td->dssdev = dssdev; | 698 | td->dssdev = dssdev; |
699 | td->panel_config = panel_config; | ||
515 | 700 | ||
516 | mutex_init(&td->lock); | 701 | mutex_init(&td->lock); |
517 | 702 | ||
703 | atomic_set(&td->do_update, 0); | ||
704 | |||
705 | r = init_regulators(dssdev, panel_config->regulators, | ||
706 | panel_config->num_regulators); | ||
707 | if (r) | ||
708 | goto err_reg; | ||
709 | |||
518 | td->esd_wq = create_singlethread_workqueue("taal_esd"); | 710 | td->esd_wq = create_singlethread_workqueue("taal_esd"); |
519 | if (td->esd_wq == NULL) { | 711 | if (td->esd_wq == NULL) { |
520 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); | 712 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); |
521 | r = -ENOMEM; | 713 | r = -ENOMEM; |
522 | goto err1; | 714 | goto err_wq; |
523 | } | 715 | } |
524 | INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); | 716 | INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); |
525 | 717 | ||
526 | dev_set_drvdata(&dssdev->dev, td); | 718 | dev_set_drvdata(&dssdev->dev, td); |
527 | 719 | ||
720 | taal_hw_reset(dssdev); | ||
721 | |||
528 | /* if no platform set_backlight() defined, presume DSI backlight | 722 | /* if no platform set_backlight() defined, presume DSI backlight |
529 | * control */ | 723 | * control */ |
530 | memset(&props, 0, sizeof(struct backlight_properties)); | 724 | memset(&props, 0, sizeof(struct backlight_properties)); |
531 | if (!dssdev->set_backlight) | 725 | if (!panel_data->set_backlight) |
532 | td->use_dsi_bl = true; | 726 | td->use_dsi_bl = true; |
533 | 727 | ||
534 | if (td->use_dsi_bl) | 728 | if (td->use_dsi_bl) |
@@ -539,7 +733,7 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
539 | &taal_bl_ops, &props); | 733 | &taal_bl_ops, &props); |
540 | if (IS_ERR(bldev)) { | 734 | if (IS_ERR(bldev)) { |
541 | r = PTR_ERR(bldev); | 735 | r = PTR_ERR(bldev); |
542 | goto err2; | 736 | goto err_bl; |
543 | } | 737 | } |
544 | 738 | ||
545 | td->bldev = bldev; | 739 | td->bldev = bldev; |
@@ -553,13 +747,13 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
553 | 747 | ||
554 | taal_bl_update_status(bldev); | 748 | taal_bl_update_status(bldev); |
555 | 749 | ||
556 | if (dssdev->phy.dsi.ext_te) { | 750 | if (panel_data->use_ext_te) { |
557 | int gpio = dssdev->phy.dsi.ext_te_gpio; | 751 | int gpio = panel_data->ext_te_gpio; |
558 | 752 | ||
559 | r = gpio_request(gpio, "taal irq"); | 753 | r = gpio_request(gpio, "taal irq"); |
560 | if (r) { | 754 | if (r) { |
561 | dev_err(&dssdev->dev, "GPIO request failed\n"); | 755 | dev_err(&dssdev->dev, "GPIO request failed\n"); |
562 | goto err3; | 756 | goto err_gpio; |
563 | } | 757 | } |
564 | 758 | ||
565 | gpio_direction_input(gpio); | 759 | gpio_direction_input(gpio); |
@@ -571,49 +765,52 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
571 | if (r) { | 765 | if (r) { |
572 | dev_err(&dssdev->dev, "IRQ request failed\n"); | 766 | dev_err(&dssdev->dev, "IRQ request failed\n"); |
573 | gpio_free(gpio); | 767 | gpio_free(gpio); |
574 | goto err3; | 768 | goto err_irq; |
575 | } | 769 | } |
576 | 770 | ||
577 | init_completion(&td->te_completion); | 771 | INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, |
772 | taal_te_timeout_work_callback); | ||
578 | 773 | ||
579 | td->use_ext_te = true; | 774 | dev_dbg(&dssdev->dev, "Using GPIO TE\n"); |
580 | } | 775 | } |
581 | 776 | ||
582 | r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); | 777 | r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); |
583 | if (r) { | 778 | if (r) { |
584 | dev_err(&dssdev->dev, "failed to create sysfs files\n"); | 779 | dev_err(&dssdev->dev, "failed to create sysfs files\n"); |
585 | goto err4; | 780 | goto err_sysfs; |
586 | } | 781 | } |
587 | 782 | ||
588 | return 0; | 783 | return 0; |
589 | err4: | 784 | err_sysfs: |
590 | if (td->use_ext_te) { | 785 | if (panel_data->use_ext_te) |
591 | int gpio = dssdev->phy.dsi.ext_te_gpio; | 786 | free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); |
592 | free_irq(gpio_to_irq(gpio), dssdev); | 787 | err_irq: |
593 | gpio_free(gpio); | 788 | if (panel_data->use_ext_te) |
594 | } | 789 | gpio_free(panel_data->ext_te_gpio); |
595 | err3: | 790 | err_gpio: |
596 | backlight_device_unregister(bldev); | 791 | backlight_device_unregister(bldev); |
597 | err2: | 792 | err_bl: |
598 | cancel_delayed_work_sync(&td->esd_work); | ||
599 | destroy_workqueue(td->esd_wq); | 793 | destroy_workqueue(td->esd_wq); |
600 | err1: | 794 | err_wq: |
795 | free_regulators(panel_config->regulators, panel_config->num_regulators); | ||
796 | err_reg: | ||
601 | kfree(td); | 797 | kfree(td); |
602 | err0: | 798 | err: |
603 | return r; | 799 | return r; |
604 | } | 800 | } |
605 | 801 | ||
606 | static void taal_remove(struct omap_dss_device *dssdev) | 802 | static void taal_remove(struct omap_dss_device *dssdev) |
607 | { | 803 | { |
608 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 804 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
805 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
609 | struct backlight_device *bldev; | 806 | struct backlight_device *bldev; |
610 | 807 | ||
611 | dev_dbg(&dssdev->dev, "remove\n"); | 808 | dev_dbg(&dssdev->dev, "remove\n"); |
612 | 809 | ||
613 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); | 810 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); |
614 | 811 | ||
615 | if (td->use_ext_te) { | 812 | if (panel_data->use_ext_te) { |
616 | int gpio = dssdev->phy.dsi.ext_te_gpio; | 813 | int gpio = panel_data->ext_te_gpio; |
617 | free_irq(gpio_to_irq(gpio), dssdev); | 814 | free_irq(gpio_to_irq(gpio), dssdev); |
618 | gpio_free(gpio); | 815 | gpio_free(gpio); |
619 | } | 816 | } |
@@ -623,9 +820,15 @@ static void taal_remove(struct omap_dss_device *dssdev) | |||
623 | taal_bl_update_status(bldev); | 820 | taal_bl_update_status(bldev); |
624 | backlight_device_unregister(bldev); | 821 | backlight_device_unregister(bldev); |
625 | 822 | ||
626 | cancel_delayed_work_sync(&td->esd_work); | 823 | cancel_delayed_work(&td->esd_work); |
627 | destroy_workqueue(td->esd_wq); | 824 | destroy_workqueue(td->esd_wq); |
628 | 825 | ||
826 | /* reset, to be sure that the panel is in a valid state */ | ||
827 | taal_hw_reset(dssdev); | ||
828 | |||
829 | free_regulators(td->panel_config->regulators, | ||
830 | td->panel_config->num_regulators); | ||
831 | |||
629 | kfree(td); | 832 | kfree(td); |
630 | } | 833 | } |
631 | 834 | ||
@@ -635,23 +838,14 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
635 | u8 id1, id2, id3; | 838 | u8 id1, id2, id3; |
636 | int r; | 839 | int r; |
637 | 840 | ||
638 | if (dssdev->platform_enable) { | ||
639 | r = dssdev->platform_enable(dssdev); | ||
640 | if (r) | ||
641 | return r; | ||
642 | } | ||
643 | |||
644 | /* it seems we have to wait a bit until taal is ready */ | ||
645 | msleep(5); | ||
646 | |||
647 | dsi_bus_lock(); | ||
648 | |||
649 | r = omapdss_dsi_display_enable(dssdev); | 841 | r = omapdss_dsi_display_enable(dssdev); |
650 | if (r) { | 842 | if (r) { |
651 | dev_err(&dssdev->dev, "failed to enable DSI\n"); | 843 | dev_err(&dssdev->dev, "failed to enable DSI\n"); |
652 | goto err0; | 844 | goto err0; |
653 | } | 845 | } |
654 | 846 | ||
847 | taal_hw_reset(dssdev); | ||
848 | |||
655 | omapdss_dsi_vc_enable_hs(TCH, false); | 849 | omapdss_dsi_vc_enable_hs(TCH, false); |
656 | 850 | ||
657 | r = taal_sleep_out(td); | 851 | r = taal_sleep_out(td); |
@@ -662,34 +856,47 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
662 | if (r) | 856 | if (r) |
663 | goto err; | 857 | goto err; |
664 | 858 | ||
665 | /* on early revisions CABC is broken */ | 859 | /* on early Taal revisions CABC is broken */ |
666 | if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) | 860 | if (td->panel_config->type == PANEL_TAAL && |
861 | (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) | ||
667 | td->cabc_broken = true; | 862 | td->cabc_broken = true; |
668 | 863 | ||
669 | taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); | 864 | r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); |
670 | taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */ | 865 | if (r) |
866 | goto err; | ||
867 | |||
868 | r = taal_dcs_write_1(DCS_CTRL_DISPLAY, | ||
869 | (1<<2) | (1<<5)); /* BL | BCTRL */ | ||
870 | if (r) | ||
871 | goto err; | ||
872 | |||
873 | r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ | ||
874 | if (r) | ||
875 | goto err; | ||
671 | 876 | ||
672 | taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ | 877 | r = taal_set_addr_mode(td->rotate, td->mirror); |
878 | if (r) | ||
879 | goto err; | ||
673 | 880 | ||
674 | taal_set_addr_mode(td->rotate, td->mirror); | 881 | if (!td->cabc_broken) { |
675 | if (!td->cabc_broken) | 882 | r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); |
676 | taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); | 883 | if (r) |
884 | goto err; | ||
885 | } | ||
677 | 886 | ||
678 | taal_dcs_write_0(DCS_DISPLAY_ON); | 887 | r = taal_dcs_write_0(DCS_DISPLAY_ON); |
888 | if (r) | ||
889 | goto err; | ||
679 | 890 | ||
680 | r = _taal_enable_te(dssdev, td->te_enabled); | 891 | r = _taal_enable_te(dssdev, td->te_enabled); |
681 | if (r) | 892 | if (r) |
682 | goto err; | 893 | goto err; |
683 | 894 | ||
684 | #ifdef TAAL_USE_ESD_CHECK | ||
685 | queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); | ||
686 | #endif | ||
687 | |||
688 | td->enabled = 1; | 895 | td->enabled = 1; |
689 | 896 | ||
690 | if (!td->intro_printed) { | 897 | if (!td->intro_printed) { |
691 | dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n", | 898 | dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", |
692 | id1, id2, id3); | 899 | td->panel_config->name, id1, id2, id3); |
693 | if (td->cabc_broken) | 900 | if (td->cabc_broken) |
694 | dev_info(&dssdev->dev, | 901 | dev_info(&dssdev->dev, |
695 | "old Taal version, CABC disabled\n"); | 902 | "old Taal version, CABC disabled\n"); |
@@ -698,46 +905,44 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
698 | 905 | ||
699 | omapdss_dsi_vc_enable_hs(TCH, true); | 906 | omapdss_dsi_vc_enable_hs(TCH, true); |
700 | 907 | ||
701 | dsi_bus_unlock(); | ||
702 | |||
703 | return 0; | 908 | return 0; |
704 | err: | 909 | err: |
910 | dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); | ||
911 | |||
912 | taal_hw_reset(dssdev); | ||
913 | |||
705 | omapdss_dsi_display_disable(dssdev); | 914 | omapdss_dsi_display_disable(dssdev); |
706 | err0: | 915 | err0: |
707 | dsi_bus_unlock(); | ||
708 | if (dssdev->platform_disable) | ||
709 | dssdev->platform_disable(dssdev); | ||
710 | |||
711 | return r; | 916 | return r; |
712 | } | 917 | } |
713 | 918 | ||
714 | static void taal_power_off(struct omap_dss_device *dssdev) | 919 | static void taal_power_off(struct omap_dss_device *dssdev) |
715 | { | 920 | { |
716 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 921 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
922 | int r; | ||
717 | 923 | ||
718 | dsi_bus_lock(); | 924 | r = taal_dcs_write_0(DCS_DISPLAY_OFF); |
719 | 925 | if (!r) { | |
720 | cancel_delayed_work(&td->esd_work); | 926 | r = taal_sleep_in(td); |
721 | 927 | /* HACK: wait a bit so that the message goes through */ | |
722 | taal_dcs_write_0(DCS_DISPLAY_OFF); | 928 | msleep(10); |
723 | taal_sleep_in(td); | 929 | } |
724 | 930 | ||
725 | /* wait a bit so that the message goes through */ | 931 | if (r) { |
726 | msleep(10); | 932 | dev_err(&dssdev->dev, |
933 | "error disabling panel, issuing HW reset\n"); | ||
934 | taal_hw_reset(dssdev); | ||
935 | } | ||
727 | 936 | ||
728 | omapdss_dsi_display_disable(dssdev); | 937 | omapdss_dsi_display_disable(dssdev); |
729 | 938 | ||
730 | if (dssdev->platform_disable) | ||
731 | dssdev->platform_disable(dssdev); | ||
732 | |||
733 | td->enabled = 0; | 939 | td->enabled = 0; |
734 | |||
735 | dsi_bus_unlock(); | ||
736 | } | 940 | } |
737 | 941 | ||
738 | static int taal_enable(struct omap_dss_device *dssdev) | 942 | static int taal_enable(struct omap_dss_device *dssdev) |
739 | { | 943 | { |
740 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 944 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
945 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
741 | int r; | 946 | int r; |
742 | 947 | ||
743 | dev_dbg(&dssdev->dev, "enable\n"); | 948 | dev_dbg(&dssdev->dev, "enable\n"); |
@@ -749,10 +954,19 @@ static int taal_enable(struct omap_dss_device *dssdev) | |||
749 | goto err; | 954 | goto err; |
750 | } | 955 | } |
751 | 956 | ||
957 | dsi_bus_lock(); | ||
958 | |||
752 | r = taal_power_on(dssdev); | 959 | r = taal_power_on(dssdev); |
960 | |||
961 | dsi_bus_unlock(); | ||
962 | |||
753 | if (r) | 963 | if (r) |
754 | goto err; | 964 | goto err; |
755 | 965 | ||
966 | if (panel_data->use_esd_check) | ||
967 | queue_delayed_work(td->esd_wq, &td->esd_work, | ||
968 | TAAL_ESD_CHECK_PERIOD); | ||
969 | |||
756 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 970 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
757 | 971 | ||
758 | mutex_unlock(&td->lock); | 972 | mutex_unlock(&td->lock); |
@@ -772,9 +986,15 @@ static void taal_disable(struct omap_dss_device *dssdev) | |||
772 | 986 | ||
773 | mutex_lock(&td->lock); | 987 | mutex_lock(&td->lock); |
774 | 988 | ||
989 | cancel_delayed_work(&td->esd_work); | ||
990 | |||
991 | dsi_bus_lock(); | ||
992 | |||
775 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 993 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
776 | taal_power_off(dssdev); | 994 | taal_power_off(dssdev); |
777 | 995 | ||
996 | dsi_bus_unlock(); | ||
997 | |||
778 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 998 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
779 | 999 | ||
780 | mutex_unlock(&td->lock); | 1000 | mutex_unlock(&td->lock); |
@@ -794,7 +1014,14 @@ static int taal_suspend(struct omap_dss_device *dssdev) | |||
794 | goto err; | 1014 | goto err; |
795 | } | 1015 | } |
796 | 1016 | ||
1017 | cancel_delayed_work(&td->esd_work); | ||
1018 | |||
1019 | dsi_bus_lock(); | ||
1020 | |||
797 | taal_power_off(dssdev); | 1021 | taal_power_off(dssdev); |
1022 | |||
1023 | dsi_bus_unlock(); | ||
1024 | |||
798 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | 1025 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; |
799 | 1026 | ||
800 | mutex_unlock(&td->lock); | 1027 | mutex_unlock(&td->lock); |
@@ -808,6 +1035,7 @@ err: | |||
808 | static int taal_resume(struct omap_dss_device *dssdev) | 1035 | static int taal_resume(struct omap_dss_device *dssdev) |
809 | { | 1036 | { |
810 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1037 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1038 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
811 | int r; | 1039 | int r; |
812 | 1040 | ||
813 | dev_dbg(&dssdev->dev, "resume\n"); | 1041 | dev_dbg(&dssdev->dev, "resume\n"); |
@@ -819,8 +1047,20 @@ static int taal_resume(struct omap_dss_device *dssdev) | |||
819 | goto err; | 1047 | goto err; |
820 | } | 1048 | } |
821 | 1049 | ||
1050 | dsi_bus_lock(); | ||
1051 | |||
822 | r = taal_power_on(dssdev); | 1052 | r = taal_power_on(dssdev); |
823 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 1053 | |
1054 | dsi_bus_unlock(); | ||
1055 | |||
1056 | if (r) { | ||
1057 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
1058 | } else { | ||
1059 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
1060 | if (panel_data->use_esd_check) | ||
1061 | queue_delayed_work(td->esd_wq, &td->esd_work, | ||
1062 | TAAL_ESD_CHECK_PERIOD); | ||
1063 | } | ||
824 | 1064 | ||
825 | mutex_unlock(&td->lock); | 1065 | mutex_unlock(&td->lock); |
826 | 1066 | ||
@@ -837,10 +1077,52 @@ static void taal_framedone_cb(int err, void *data) | |||
837 | dsi_bus_unlock(); | 1077 | dsi_bus_unlock(); |
838 | } | 1078 | } |
839 | 1079 | ||
1080 | static irqreturn_t taal_te_isr(int irq, void *data) | ||
1081 | { | ||
1082 | struct omap_dss_device *dssdev = data; | ||
1083 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1084 | int old; | ||
1085 | int r; | ||
1086 | |||
1087 | old = atomic_cmpxchg(&td->do_update, 1, 0); | ||
1088 | |||
1089 | if (old) { | ||
1090 | cancel_delayed_work(&td->te_timeout_work); | ||
1091 | |||
1092 | r = omap_dsi_update(dssdev, TCH, | ||
1093 | td->update_region.x, | ||
1094 | td->update_region.y, | ||
1095 | td->update_region.w, | ||
1096 | td->update_region.h, | ||
1097 | taal_framedone_cb, dssdev); | ||
1098 | if (r) | ||
1099 | goto err; | ||
1100 | } | ||
1101 | |||
1102 | return IRQ_HANDLED; | ||
1103 | err: | ||
1104 | dev_err(&dssdev->dev, "start update failed\n"); | ||
1105 | dsi_bus_unlock(); | ||
1106 | return IRQ_HANDLED; | ||
1107 | } | ||
1108 | |||
1109 | static void taal_te_timeout_work_callback(struct work_struct *work) | ||
1110 | { | ||
1111 | struct taal_data *td = container_of(work, struct taal_data, | ||
1112 | te_timeout_work.work); | ||
1113 | struct omap_dss_device *dssdev = td->dssdev; | ||
1114 | |||
1115 | dev_err(&dssdev->dev, "TE not received for 250ms!\n"); | ||
1116 | |||
1117 | atomic_set(&td->do_update, 0); | ||
1118 | dsi_bus_unlock(); | ||
1119 | } | ||
1120 | |||
840 | static int taal_update(struct omap_dss_device *dssdev, | 1121 | static int taal_update(struct omap_dss_device *dssdev, |
841 | u16 x, u16 y, u16 w, u16 h) | 1122 | u16 x, u16 y, u16 w, u16 h) |
842 | { | 1123 | { |
843 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1124 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1125 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
844 | int r; | 1126 | int r; |
845 | 1127 | ||
846 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | 1128 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); |
@@ -853,7 +1135,7 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
853 | goto err; | 1135 | goto err; |
854 | } | 1136 | } |
855 | 1137 | ||
856 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h); | 1138 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); |
857 | if (r) | 1139 | if (r) |
858 | goto err; | 1140 | goto err; |
859 | 1141 | ||
@@ -861,10 +1143,21 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
861 | if (r) | 1143 | if (r) |
862 | goto err; | 1144 | goto err; |
863 | 1145 | ||
864 | r = omap_dsi_update(dssdev, TCH, x, y, w, h, | 1146 | if (td->te_enabled && panel_data->use_ext_te) { |
865 | taal_framedone_cb, dssdev); | 1147 | td->update_region.x = x; |
866 | if (r) | 1148 | td->update_region.y = y; |
867 | goto err; | 1149 | td->update_region.w = w; |
1150 | td->update_region.h = h; | ||
1151 | barrier(); | ||
1152 | schedule_delayed_work(&td->te_timeout_work, | ||
1153 | msecs_to_jiffies(250)); | ||
1154 | atomic_set(&td->do_update, 1); | ||
1155 | } else { | ||
1156 | r = omap_dsi_update(dssdev, TCH, x, y, w, h, | ||
1157 | taal_framedone_cb, dssdev); | ||
1158 | if (r) | ||
1159 | goto err; | ||
1160 | } | ||
868 | 1161 | ||
869 | /* note: no bus_unlock here. unlock is in framedone_cb */ | 1162 | /* note: no bus_unlock here. unlock is in framedone_cb */ |
870 | mutex_unlock(&td->lock); | 1163 | mutex_unlock(&td->lock); |
@@ -894,20 +1187,19 @@ static int taal_sync(struct omap_dss_device *dssdev) | |||
894 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | 1187 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) |
895 | { | 1188 | { |
896 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1189 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1190 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
897 | int r; | 1191 | int r; |
898 | 1192 | ||
899 | td->te_enabled = enable; | ||
900 | |||
901 | if (enable) | 1193 | if (enable) |
902 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); | 1194 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); |
903 | else | 1195 | else |
904 | r = taal_dcs_write_0(DCS_TEAR_OFF); | 1196 | r = taal_dcs_write_0(DCS_TEAR_OFF); |
905 | 1197 | ||
906 | omapdss_dsi_enable_te(dssdev, enable); | 1198 | if (!panel_data->use_ext_te) |
1199 | omapdss_dsi_enable_te(dssdev, enable); | ||
907 | 1200 | ||
908 | /* XXX for some reason, DSI TE breaks if we don't wait here. | 1201 | if (td->panel_config->sleep.enable_te) |
909 | * Panel bug? Needs more studying */ | 1202 | msleep(td->panel_config->sleep.enable_te); |
910 | msleep(100); | ||
911 | 1203 | ||
912 | return r; | 1204 | return r; |
913 | } | 1205 | } |
@@ -918,10 +1210,26 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
918 | int r; | 1210 | int r; |
919 | 1211 | ||
920 | mutex_lock(&td->lock); | 1212 | mutex_lock(&td->lock); |
1213 | |||
1214 | if (td->te_enabled == enable) | ||
1215 | goto end; | ||
1216 | |||
921 | dsi_bus_lock(); | 1217 | dsi_bus_lock(); |
922 | 1218 | ||
923 | r = _taal_enable_te(dssdev, enable); | 1219 | if (td->enabled) { |
1220 | r = _taal_enable_te(dssdev, enable); | ||
1221 | if (r) | ||
1222 | goto err; | ||
1223 | } | ||
1224 | |||
1225 | td->te_enabled = enable; | ||
1226 | |||
1227 | dsi_bus_unlock(); | ||
1228 | end: | ||
1229 | mutex_unlock(&td->lock); | ||
924 | 1230 | ||
1231 | return 0; | ||
1232 | err: | ||
925 | dsi_bus_unlock(); | 1233 | dsi_bus_unlock(); |
926 | mutex_unlock(&td->lock); | 1234 | mutex_unlock(&td->lock); |
927 | 1235 | ||
@@ -948,6 +1256,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | |||
948 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); | 1256 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); |
949 | 1257 | ||
950 | mutex_lock(&td->lock); | 1258 | mutex_lock(&td->lock); |
1259 | |||
1260 | if (td->rotate == rotate) | ||
1261 | goto end; | ||
1262 | |||
951 | dsi_bus_lock(); | 1263 | dsi_bus_lock(); |
952 | 1264 | ||
953 | if (td->enabled) { | 1265 | if (td->enabled) { |
@@ -959,6 +1271,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | |||
959 | td->rotate = rotate; | 1271 | td->rotate = rotate; |
960 | 1272 | ||
961 | dsi_bus_unlock(); | 1273 | dsi_bus_unlock(); |
1274 | end: | ||
962 | mutex_unlock(&td->lock); | 1275 | mutex_unlock(&td->lock); |
963 | return 0; | 1276 | return 0; |
964 | err: | 1277 | err: |
@@ -987,6 +1300,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) | |||
987 | dev_dbg(&dssdev->dev, "mirror %d\n", enable); | 1300 | dev_dbg(&dssdev->dev, "mirror %d\n", enable); |
988 | 1301 | ||
989 | mutex_lock(&td->lock); | 1302 | mutex_lock(&td->lock); |
1303 | |||
1304 | if (td->mirror == enable) | ||
1305 | goto end; | ||
1306 | |||
990 | dsi_bus_lock(); | 1307 | dsi_bus_lock(); |
991 | if (td->enabled) { | 1308 | if (td->enabled) { |
992 | r = taal_set_addr_mode(td->rotate, enable); | 1309 | r = taal_set_addr_mode(td->rotate, enable); |
@@ -997,6 +1314,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) | |||
997 | td->mirror = enable; | 1314 | td->mirror = enable; |
998 | 1315 | ||
999 | dsi_bus_unlock(); | 1316 | dsi_bus_unlock(); |
1317 | end: | ||
1000 | mutex_unlock(&td->lock); | 1318 | mutex_unlock(&td->lock); |
1001 | return 0; | 1319 | return 0; |
1002 | err: | 1320 | err: |
@@ -1024,23 +1342,30 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num) | |||
1024 | int r; | 1342 | int r; |
1025 | 1343 | ||
1026 | mutex_lock(&td->lock); | 1344 | mutex_lock(&td->lock); |
1345 | |||
1346 | if (!td->enabled) { | ||
1347 | r = -ENODEV; | ||
1348 | goto err1; | ||
1349 | } | ||
1350 | |||
1027 | dsi_bus_lock(); | 1351 | dsi_bus_lock(); |
1028 | 1352 | ||
1029 | r = taal_dcs_read_1(DCS_GET_ID1, &id1); | 1353 | r = taal_dcs_read_1(DCS_GET_ID1, &id1); |
1030 | if (r) | 1354 | if (r) |
1031 | goto err; | 1355 | goto err2; |
1032 | r = taal_dcs_read_1(DCS_GET_ID2, &id2); | 1356 | r = taal_dcs_read_1(DCS_GET_ID2, &id2); |
1033 | if (r) | 1357 | if (r) |
1034 | goto err; | 1358 | goto err2; |
1035 | r = taal_dcs_read_1(DCS_GET_ID3, &id3); | 1359 | r = taal_dcs_read_1(DCS_GET_ID3, &id3); |
1036 | if (r) | 1360 | if (r) |
1037 | goto err; | 1361 | goto err2; |
1038 | 1362 | ||
1039 | dsi_bus_unlock(); | 1363 | dsi_bus_unlock(); |
1040 | mutex_unlock(&td->lock); | 1364 | mutex_unlock(&td->lock); |
1041 | return 0; | 1365 | return 0; |
1042 | err: | 1366 | err2: |
1043 | dsi_bus_unlock(); | 1367 | dsi_bus_unlock(); |
1368 | err1: | ||
1044 | mutex_unlock(&td->lock); | 1369 | mutex_unlock(&td->lock); |
1045 | return r; | 1370 | return r; |
1046 | } | 1371 | } |
@@ -1128,6 +1453,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1128 | struct taal_data *td = container_of(work, struct taal_data, | 1453 | struct taal_data *td = container_of(work, struct taal_data, |
1129 | esd_work.work); | 1454 | esd_work.work); |
1130 | struct omap_dss_device *dssdev = td->dssdev; | 1455 | struct omap_dss_device *dssdev = td->dssdev; |
1456 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
1131 | u8 state1, state2; | 1457 | u8 state1, state2; |
1132 | int r; | 1458 | int r; |
1133 | 1459 | ||
@@ -1168,7 +1494,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1168 | } | 1494 | } |
1169 | /* Self-diagnostics result is also shown on TE GPIO line. We need | 1495 | /* Self-diagnostics result is also shown on TE GPIO line. We need |
1170 | * to re-enable TE after self diagnostics */ | 1496 | * to re-enable TE after self diagnostics */ |
1171 | if (td->use_ext_te && td->te_enabled) { | 1497 | if (td->te_enabled && panel_data->use_ext_te) { |
1172 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); | 1498 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); |
1173 | if (r) | 1499 | if (r) |
1174 | goto err; | 1500 | goto err; |
@@ -1184,6 +1510,7 @@ err: | |||
1184 | dev_err(&dssdev->dev, "performing LCD reset\n"); | 1510 | dev_err(&dssdev->dev, "performing LCD reset\n"); |
1185 | 1511 | ||
1186 | taal_power_off(dssdev); | 1512 | taal_power_off(dssdev); |
1513 | taal_hw_reset(dssdev); | ||
1187 | taal_power_on(dssdev); | 1514 | taal_power_on(dssdev); |
1188 | 1515 | ||
1189 | dsi_bus_unlock(); | 1516 | dsi_bus_unlock(); |