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