diff options
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r-- | drivers/video/omap2/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/omap2/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/omap2/displays/Kconfig | 75 | ||||
-rw-r--r-- | drivers/video/omap2/displays/Makefile | 11 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-acx565akm.c | 798 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-generic-dpi.c | 744 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-lgphilips-lb035q02.c | 262 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-n8x0.c | 616 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | 290 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-picodlp.c | 559 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-picodlp.h | 288 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c | 198 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-taal.c | 1551 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-tfp410.c | 353 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-tpo-td043mtea1.c | 596 |
15 files changed, 0 insertions, 6343 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig index 56cad0f5386c..63b23f87081d 100644 --- a/drivers/video/omap2/Kconfig +++ b/drivers/video/omap2/Kconfig | |||
@@ -5,7 +5,6 @@ if ARCH_OMAP2PLUS | |||
5 | 5 | ||
6 | source "drivers/video/omap2/dss/Kconfig" | 6 | source "drivers/video/omap2/dss/Kconfig" |
7 | source "drivers/video/omap2/omapfb/Kconfig" | 7 | source "drivers/video/omap2/omapfb/Kconfig" |
8 | source "drivers/video/omap2/displays/Kconfig" | ||
9 | source "drivers/video/omap2/displays-new/Kconfig" | 8 | source "drivers/video/omap2/displays-new/Kconfig" |
10 | 9 | ||
11 | endif | 10 | endif |
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 86873c2fbb27..bf8127df8c71 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o | 1 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o |
2 | 2 | ||
3 | obj-$(CONFIG_OMAP2_DSS) += dss/ | 3 | obj-$(CONFIG_OMAP2_DSS) += dss/ |
4 | obj-y += displays/ | ||
5 | obj-y += displays-new/ | 4 | obj-y += displays-new/ |
6 | obj-$(CONFIG_FB_OMAP2) += omapfb/ | 5 | obj-$(CONFIG_FB_OMAP2) += omapfb/ |
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig deleted file mode 100644 index e80ac1c79561..000000000000 --- a/drivers/video/omap2/displays/Kconfig +++ /dev/null | |||
@@ -1,75 +0,0 @@ | |||
1 | menu "OMAP2/3 Display Device Drivers (old device model)" | ||
2 | depends on OMAP2_DSS | ||
3 | |||
4 | config PANEL_GENERIC_DPI | ||
5 | tristate "Generic DPI Panel" | ||
6 | depends on OMAP2_DSS_DPI | ||
7 | help | ||
8 | Generic DPI panel driver. | ||
9 | Supports DVI output for Beagle and OMAP3 SDP. | ||
10 | Supports LCD Panel used in TI SDP3430 and EVM boards, | ||
11 | OMAP3517 EVM boards and CM-T35. | ||
12 | |||
13 | config PANEL_TFP410 | ||
14 | tristate "TFP410 DPI-to-DVI chip" | ||
15 | depends on OMAP2_DSS_DPI && I2C | ||
16 | help | ||
17 | Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID | ||
18 | information from the monitor. | ||
19 | |||
20 | config PANEL_LGPHILIPS_LB035Q02 | ||
21 | tristate "LG.Philips LB035Q02 LCD Panel" | ||
22 | depends on OMAP2_DSS_DPI && SPI | ||
23 | help | ||
24 | LCD Panel used on the Gumstix Overo Palo35 | ||
25 | |||
26 | config PANEL_SHARP_LS037V7DW01 | ||
27 | tristate "Sharp LS037V7DW01 LCD Panel" | ||
28 | depends on OMAP2_DSS_DPI | ||
29 | depends on BACKLIGHT_CLASS_DEVICE | ||
30 | help | ||
31 | LCD Panel used in TI's SDP3430 and EVM boards | ||
32 | |||
33 | config PANEL_NEC_NL8048HL11_01B | ||
34 | tristate "NEC NL8048HL11-01B Panel" | ||
35 | depends on OMAP2_DSS_DPI | ||
36 | depends on SPI | ||
37 | depends on BACKLIGHT_CLASS_DEVICE | ||
38 | help | ||
39 | This NEC NL8048HL11-01B panel is TFT LCD | ||
40 | used in the Zoom2/3/3630 sdp boards. | ||
41 | |||
42 | config PANEL_PICODLP | ||
43 | tristate "TI PICO DLP mini-projector" | ||
44 | depends on OMAP2_DSS_DPI && I2C | ||
45 | help | ||
46 | A mini-projector used in TI's SDP4430 and EVM boards | ||
47 | For more info please visit http://www.dlp.com/projector/ | ||
48 | |||
49 | config PANEL_TAAL | ||
50 | tristate "Taal DSI Panel" | ||
51 | depends on OMAP2_DSS_DSI | ||
52 | depends on BACKLIGHT_CLASS_DEVICE | ||
53 | help | ||
54 | Taal DSI command mode panel from TPO. | ||
55 | |||
56 | config PANEL_TPO_TD043MTEA1 | ||
57 | tristate "TPO TD043MTEA1 LCD Panel" | ||
58 | depends on OMAP2_DSS_DPI && SPI | ||
59 | help | ||
60 | LCD Panel used in OMAP3 Pandora | ||
61 | |||
62 | config PANEL_ACX565AKM | ||
63 | tristate "ACX565AKM Panel" | ||
64 | depends on OMAP2_DSS_SDI && SPI | ||
65 | depends on BACKLIGHT_CLASS_DEVICE | ||
66 | help | ||
67 | This is the LCD panel used on Nokia N900 | ||
68 | |||
69 | config PANEL_N8X0 | ||
70 | tristate "N8X0 Panel" | ||
71 | depends on OMAP2_DSS_RFBI && SPI | ||
72 | depends on BACKLIGHT_CLASS_DEVICE | ||
73 | help | ||
74 | This is the LCD panel used on Nokia N8x0 | ||
75 | endmenu | ||
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile deleted file mode 100644 index 58a5176b07b0..000000000000 --- a/drivers/video/omap2/displays/Makefile +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o | ||
2 | obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o | ||
3 | obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o | ||
4 | obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o | ||
5 | obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o | ||
6 | |||
7 | obj-$(CONFIG_PANEL_TAAL) += panel-taal.o | ||
8 | obj-$(CONFIG_PANEL_PICODLP) += panel-picodlp.o | ||
9 | obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o | ||
10 | obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o | ||
11 | obj-$(CONFIG_PANEL_N8X0) += panel-n8x0.o | ||
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c deleted file mode 100644 index 3fd100fc853e..000000000000 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ /dev/null | |||
@@ -1,798 +0,0 @@ | |||
1 | /* | ||
2 | * Support for ACX565AKM LCD Panel used on Nokia N900 | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Original Driver Author: Imre Deak <imre.deak@nokia.com> | ||
7 | * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
8 | * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/backlight.h> | ||
31 | #include <linux/fb.h> | ||
32 | #include <linux/gpio.h> | ||
33 | |||
34 | #include <video/omapdss.h> | ||
35 | #include <video/omap-panel-data.h> | ||
36 | |||
37 | #define MIPID_CMD_READ_DISP_ID 0x04 | ||
38 | #define MIPID_CMD_READ_RED 0x06 | ||
39 | #define MIPID_CMD_READ_GREEN 0x07 | ||
40 | #define MIPID_CMD_READ_BLUE 0x08 | ||
41 | #define MIPID_CMD_READ_DISP_STATUS 0x09 | ||
42 | #define MIPID_CMD_RDDSDR 0x0F | ||
43 | #define MIPID_CMD_SLEEP_IN 0x10 | ||
44 | #define MIPID_CMD_SLEEP_OUT 0x11 | ||
45 | #define MIPID_CMD_DISP_OFF 0x28 | ||
46 | #define MIPID_CMD_DISP_ON 0x29 | ||
47 | #define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51 | ||
48 | #define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52 | ||
49 | #define MIPID_CMD_WRITE_CTRL_DISP 0x53 | ||
50 | |||
51 | #define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5) | ||
52 | #define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4) | ||
53 | #define CTRL_DISP_BACKLIGHT_ON (1 << 2) | ||
54 | #define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1) | ||
55 | |||
56 | #define MIPID_CMD_READ_CTRL_DISP 0x54 | ||
57 | #define MIPID_CMD_WRITE_CABC 0x55 | ||
58 | #define MIPID_CMD_READ_CABC 0x56 | ||
59 | |||
60 | #define MIPID_VER_LPH8923 3 | ||
61 | #define MIPID_VER_LS041Y3 4 | ||
62 | #define MIPID_VER_L4F00311 8 | ||
63 | #define MIPID_VER_ACX565AKM 9 | ||
64 | |||
65 | struct acx565akm_device { | ||
66 | char *name; | ||
67 | int enabled; | ||
68 | int model; | ||
69 | int revision; | ||
70 | u8 display_id[3]; | ||
71 | unsigned has_bc:1; | ||
72 | unsigned has_cabc:1; | ||
73 | unsigned cabc_mode; | ||
74 | unsigned long hw_guard_end; /* next value of jiffies | ||
75 | when we can issue the | ||
76 | next sleep in/out command */ | ||
77 | unsigned long hw_guard_wait; /* max guard time in jiffies */ | ||
78 | |||
79 | struct spi_device *spi; | ||
80 | struct mutex mutex; | ||
81 | |||
82 | struct omap_dss_device *dssdev; | ||
83 | struct backlight_device *bl_dev; | ||
84 | }; | ||
85 | |||
86 | static struct acx565akm_device acx_dev; | ||
87 | static int acx565akm_bl_update_status(struct backlight_device *dev); | ||
88 | |||
89 | /*--------------------MIPID interface-----------------------------*/ | ||
90 | |||
91 | static void acx565akm_transfer(struct acx565akm_device *md, int cmd, | ||
92 | const u8 *wbuf, int wlen, u8 *rbuf, int rlen) | ||
93 | { | ||
94 | struct spi_message m; | ||
95 | struct spi_transfer *x, xfer[5]; | ||
96 | int r; | ||
97 | |||
98 | BUG_ON(md->spi == NULL); | ||
99 | |||
100 | spi_message_init(&m); | ||
101 | |||
102 | memset(xfer, 0, sizeof(xfer)); | ||
103 | x = &xfer[0]; | ||
104 | |||
105 | cmd &= 0xff; | ||
106 | x->tx_buf = &cmd; | ||
107 | x->bits_per_word = 9; | ||
108 | x->len = 2; | ||
109 | |||
110 | if (rlen > 1 && wlen == 0) { | ||
111 | /* | ||
112 | * Between the command and the response data there is a | ||
113 | * dummy clock cycle. Add an extra bit after the command | ||
114 | * word to account for this. | ||
115 | */ | ||
116 | x->bits_per_word = 10; | ||
117 | cmd <<= 1; | ||
118 | } | ||
119 | spi_message_add_tail(x, &m); | ||
120 | |||
121 | if (wlen) { | ||
122 | x++; | ||
123 | x->tx_buf = wbuf; | ||
124 | x->len = wlen; | ||
125 | x->bits_per_word = 9; | ||
126 | spi_message_add_tail(x, &m); | ||
127 | } | ||
128 | |||
129 | if (rlen) { | ||
130 | x++; | ||
131 | x->rx_buf = rbuf; | ||
132 | x->len = rlen; | ||
133 | spi_message_add_tail(x, &m); | ||
134 | } | ||
135 | |||
136 | r = spi_sync(md->spi, &m); | ||
137 | if (r < 0) | ||
138 | dev_dbg(&md->spi->dev, "spi_sync %d\n", r); | ||
139 | } | ||
140 | |||
141 | static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd) | ||
142 | { | ||
143 | acx565akm_transfer(md, cmd, NULL, 0, NULL, 0); | ||
144 | } | ||
145 | |||
146 | static inline void acx565akm_write(struct acx565akm_device *md, | ||
147 | int reg, const u8 *buf, int len) | ||
148 | { | ||
149 | acx565akm_transfer(md, reg, buf, len, NULL, 0); | ||
150 | } | ||
151 | |||
152 | static inline void acx565akm_read(struct acx565akm_device *md, | ||
153 | int reg, u8 *buf, int len) | ||
154 | { | ||
155 | acx565akm_transfer(md, reg, NULL, 0, buf, len); | ||
156 | } | ||
157 | |||
158 | static void hw_guard_start(struct acx565akm_device *md, int guard_msec) | ||
159 | { | ||
160 | md->hw_guard_wait = msecs_to_jiffies(guard_msec); | ||
161 | md->hw_guard_end = jiffies + md->hw_guard_wait; | ||
162 | } | ||
163 | |||
164 | static void hw_guard_wait(struct acx565akm_device *md) | ||
165 | { | ||
166 | unsigned long wait = md->hw_guard_end - jiffies; | ||
167 | |||
168 | if ((long)wait > 0 && wait <= md->hw_guard_wait) { | ||
169 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
170 | schedule_timeout(wait); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /*----------------------MIPID wrappers----------------------------*/ | ||
175 | |||
176 | static void set_sleep_mode(struct acx565akm_device *md, int on) | ||
177 | { | ||
178 | int cmd; | ||
179 | |||
180 | if (on) | ||
181 | cmd = MIPID_CMD_SLEEP_IN; | ||
182 | else | ||
183 | cmd = MIPID_CMD_SLEEP_OUT; | ||
184 | /* | ||
185 | * We have to keep 120msec between sleep in/out commands. | ||
186 | * (8.2.15, 8.2.16). | ||
187 | */ | ||
188 | hw_guard_wait(md); | ||
189 | acx565akm_cmd(md, cmd); | ||
190 | hw_guard_start(md, 120); | ||
191 | } | ||
192 | |||
193 | static void set_display_state(struct acx565akm_device *md, int enabled) | ||
194 | { | ||
195 | int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF; | ||
196 | |||
197 | acx565akm_cmd(md, cmd); | ||
198 | } | ||
199 | |||
200 | static int panel_enabled(struct acx565akm_device *md) | ||
201 | { | ||
202 | u32 disp_status; | ||
203 | int enabled; | ||
204 | |||
205 | acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4); | ||
206 | disp_status = __be32_to_cpu(disp_status); | ||
207 | enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); | ||
208 | dev_dbg(&md->spi->dev, | ||
209 | "LCD panel %senabled by bootloader (status 0x%04x)\n", | ||
210 | enabled ? "" : "not ", disp_status); | ||
211 | return enabled; | ||
212 | } | ||
213 | |||
214 | static int panel_detect(struct acx565akm_device *md) | ||
215 | { | ||
216 | acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3); | ||
217 | dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n", | ||
218 | md->display_id[0], md->display_id[1], md->display_id[2]); | ||
219 | |||
220 | switch (md->display_id[0]) { | ||
221 | case 0x10: | ||
222 | md->model = MIPID_VER_ACX565AKM; | ||
223 | md->name = "acx565akm"; | ||
224 | md->has_bc = 1; | ||
225 | md->has_cabc = 1; | ||
226 | break; | ||
227 | case 0x29: | ||
228 | md->model = MIPID_VER_L4F00311; | ||
229 | md->name = "l4f00311"; | ||
230 | break; | ||
231 | case 0x45: | ||
232 | md->model = MIPID_VER_LPH8923; | ||
233 | md->name = "lph8923"; | ||
234 | break; | ||
235 | case 0x83: | ||
236 | md->model = MIPID_VER_LS041Y3; | ||
237 | md->name = "ls041y3"; | ||
238 | break; | ||
239 | default: | ||
240 | md->name = "unknown"; | ||
241 | dev_err(&md->spi->dev, "invalid display ID\n"); | ||
242 | return -ENODEV; | ||
243 | } | ||
244 | |||
245 | md->revision = md->display_id[1]; | ||
246 | |||
247 | dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n", | ||
248 | md->name, md->revision); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | /*----------------------Backlight Control-------------------------*/ | ||
254 | |||
255 | static void enable_backlight_ctrl(struct acx565akm_device *md, int enable) | ||
256 | { | ||
257 | u16 ctrl; | ||
258 | |||
259 | acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1); | ||
260 | if (enable) { | ||
261 | ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON | | ||
262 | CTRL_DISP_BACKLIGHT_ON; | ||
263 | } else { | ||
264 | ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON | | ||
265 | CTRL_DISP_BACKLIGHT_ON); | ||
266 | } | ||
267 | |||
268 | ctrl |= 1 << 8; | ||
269 | acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); | ||
270 | } | ||
271 | |||
272 | static void set_cabc_mode(struct acx565akm_device *md, unsigned mode) | ||
273 | { | ||
274 | u16 cabc_ctrl; | ||
275 | |||
276 | md->cabc_mode = mode; | ||
277 | if (!md->enabled) | ||
278 | return; | ||
279 | cabc_ctrl = 0; | ||
280 | acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1); | ||
281 | cabc_ctrl &= ~3; | ||
282 | cabc_ctrl |= (1 << 8) | (mode & 3); | ||
283 | acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); | ||
284 | } | ||
285 | |||
286 | static unsigned get_cabc_mode(struct acx565akm_device *md) | ||
287 | { | ||
288 | return md->cabc_mode; | ||
289 | } | ||
290 | |||
291 | static unsigned get_hw_cabc_mode(struct acx565akm_device *md) | ||
292 | { | ||
293 | u8 cabc_ctrl; | ||
294 | |||
295 | acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1); | ||
296 | return cabc_ctrl & 3; | ||
297 | } | ||
298 | |||
299 | static void acx565akm_set_brightness(struct acx565akm_device *md, int level) | ||
300 | { | ||
301 | int bv; | ||
302 | |||
303 | bv = level | (1 << 8); | ||
304 | acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2); | ||
305 | |||
306 | if (level) | ||
307 | enable_backlight_ctrl(md, 1); | ||
308 | else | ||
309 | enable_backlight_ctrl(md, 0); | ||
310 | } | ||
311 | |||
312 | static int acx565akm_get_actual_brightness(struct acx565akm_device *md) | ||
313 | { | ||
314 | u8 bv; | ||
315 | |||
316 | acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1); | ||
317 | |||
318 | return bv; | ||
319 | } | ||
320 | |||
321 | |||
322 | static int acx565akm_bl_update_status(struct backlight_device *dev) | ||
323 | { | ||
324 | struct acx565akm_device *md = dev_get_drvdata(&dev->dev); | ||
325 | int r; | ||
326 | int level; | ||
327 | |||
328 | dev_dbg(&md->spi->dev, "%s\n", __func__); | ||
329 | |||
330 | mutex_lock(&md->mutex); | ||
331 | |||
332 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
333 | dev->props.power == FB_BLANK_UNBLANK) | ||
334 | level = dev->props.brightness; | ||
335 | else | ||
336 | level = 0; | ||
337 | |||
338 | r = 0; | ||
339 | if (md->has_bc) | ||
340 | acx565akm_set_brightness(md, level); | ||
341 | else | ||
342 | r = -ENODEV; | ||
343 | |||
344 | mutex_unlock(&md->mutex); | ||
345 | |||
346 | return r; | ||
347 | } | ||
348 | |||
349 | static int acx565akm_bl_get_intensity(struct backlight_device *dev) | ||
350 | { | ||
351 | struct acx565akm_device *md = dev_get_drvdata(&dev->dev); | ||
352 | |||
353 | dev_dbg(&dev->dev, "%s\n", __func__); | ||
354 | |||
355 | if (!md->has_bc) | ||
356 | return -ENODEV; | ||
357 | |||
358 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
359 | dev->props.power == FB_BLANK_UNBLANK) { | ||
360 | if (md->has_bc) | ||
361 | return acx565akm_get_actual_brightness(md); | ||
362 | else | ||
363 | return dev->props.brightness; | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static const struct backlight_ops acx565akm_bl_ops = { | ||
370 | .get_brightness = acx565akm_bl_get_intensity, | ||
371 | .update_status = acx565akm_bl_update_status, | ||
372 | }; | ||
373 | |||
374 | /*--------------------Auto Brightness control via Sysfs---------------------*/ | ||
375 | |||
376 | static const char *cabc_modes[] = { | ||
377 | "off", /* always used when CABC is not supported */ | ||
378 | "ui", | ||
379 | "still-image", | ||
380 | "moving-image", | ||
381 | }; | ||
382 | |||
383 | static ssize_t show_cabc_mode(struct device *dev, | ||
384 | struct device_attribute *attr, | ||
385 | char *buf) | ||
386 | { | ||
387 | struct acx565akm_device *md = dev_get_drvdata(dev); | ||
388 | const char *mode_str; | ||
389 | int mode; | ||
390 | int len; | ||
391 | |||
392 | if (!md->has_cabc) | ||
393 | mode = 0; | ||
394 | else | ||
395 | mode = get_cabc_mode(md); | ||
396 | mode_str = "unknown"; | ||
397 | if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) | ||
398 | mode_str = cabc_modes[mode]; | ||
399 | len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); | ||
400 | |||
401 | return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; | ||
402 | } | ||
403 | |||
404 | static ssize_t store_cabc_mode(struct device *dev, | ||
405 | struct device_attribute *attr, | ||
406 | const char *buf, size_t count) | ||
407 | { | ||
408 | struct acx565akm_device *md = dev_get_drvdata(dev); | ||
409 | int i; | ||
410 | |||
411 | for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { | ||
412 | const char *mode_str = cabc_modes[i]; | ||
413 | int cmp_len = strlen(mode_str); | ||
414 | |||
415 | if (count > 0 && buf[count - 1] == '\n') | ||
416 | count--; | ||
417 | if (count != cmp_len) | ||
418 | continue; | ||
419 | |||
420 | if (strncmp(buf, mode_str, cmp_len) == 0) | ||
421 | break; | ||
422 | } | ||
423 | |||
424 | if (i == ARRAY_SIZE(cabc_modes)) | ||
425 | return -EINVAL; | ||
426 | |||
427 | if (!md->has_cabc && i != 0) | ||
428 | return -EINVAL; | ||
429 | |||
430 | mutex_lock(&md->mutex); | ||
431 | set_cabc_mode(md, i); | ||
432 | mutex_unlock(&md->mutex); | ||
433 | |||
434 | return count; | ||
435 | } | ||
436 | |||
437 | static ssize_t show_cabc_available_modes(struct device *dev, | ||
438 | struct device_attribute *attr, | ||
439 | char *buf) | ||
440 | { | ||
441 | struct acx565akm_device *md = dev_get_drvdata(dev); | ||
442 | int len; | ||
443 | int i; | ||
444 | |||
445 | if (!md->has_cabc) | ||
446 | return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); | ||
447 | |||
448 | for (i = 0, len = 0; | ||
449 | len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) | ||
450 | len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", | ||
451 | i ? " " : "", cabc_modes[i], | ||
452 | i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); | ||
453 | |||
454 | return len < PAGE_SIZE ? len : PAGE_SIZE - 1; | ||
455 | } | ||
456 | |||
457 | static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, | ||
458 | show_cabc_mode, store_cabc_mode); | ||
459 | static DEVICE_ATTR(cabc_available_modes, S_IRUGO, | ||
460 | show_cabc_available_modes, NULL); | ||
461 | |||
462 | static struct attribute *bldev_attrs[] = { | ||
463 | &dev_attr_cabc_mode.attr, | ||
464 | &dev_attr_cabc_available_modes.attr, | ||
465 | NULL, | ||
466 | }; | ||
467 | |||
468 | static struct attribute_group bldev_attr_group = { | ||
469 | .attrs = bldev_attrs, | ||
470 | }; | ||
471 | |||
472 | |||
473 | /*---------------------------ACX Panel----------------------------*/ | ||
474 | |||
475 | static int acx_get_recommended_bpp(struct omap_dss_device *dssdev) | ||
476 | { | ||
477 | return 16; | ||
478 | } | ||
479 | |||
480 | static struct omap_video_timings acx_panel_timings = { | ||
481 | .x_res = 800, | ||
482 | .y_res = 480, | ||
483 | .pixel_clock = 24000, | ||
484 | .hfp = 28, | ||
485 | .hsw = 4, | ||
486 | .hbp = 24, | ||
487 | .vfp = 3, | ||
488 | .vsw = 3, | ||
489 | .vbp = 4, | ||
490 | |||
491 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
492 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
493 | |||
494 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
495 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
496 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
497 | }; | ||
498 | |||
499 | static struct panel_acx565akm_data *get_panel_data(struct omap_dss_device *dssdev) | ||
500 | { | ||
501 | return (struct panel_acx565akm_data *) dssdev->data; | ||
502 | } | ||
503 | |||
504 | static int acx_panel_probe(struct omap_dss_device *dssdev) | ||
505 | { | ||
506 | int r; | ||
507 | struct acx565akm_device *md = &acx_dev; | ||
508 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | ||
509 | struct backlight_device *bldev; | ||
510 | int max_brightness, brightness; | ||
511 | struct backlight_properties props; | ||
512 | |||
513 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
514 | |||
515 | if (!panel_data) | ||
516 | return -EINVAL; | ||
517 | |||
518 | /* FIXME AC bias ? */ | ||
519 | dssdev->panel.timings = acx_panel_timings; | ||
520 | |||
521 | if (gpio_is_valid(panel_data->reset_gpio)) { | ||
522 | r = devm_gpio_request_one(dssdev->dev, panel_data->reset_gpio, | ||
523 | GPIOF_OUT_INIT_LOW, "lcd reset"); | ||
524 | if (r) | ||
525 | return r; | ||
526 | } | ||
527 | |||
528 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
529 | gpio_set_value(panel_data->reset_gpio, 1); | ||
530 | |||
531 | /* | ||
532 | * After reset we have to wait 5 msec before the first | ||
533 | * command can be sent. | ||
534 | */ | ||
535 | msleep(5); | ||
536 | |||
537 | md->enabled = panel_enabled(md); | ||
538 | |||
539 | r = panel_detect(md); | ||
540 | if (r) { | ||
541 | dev_err(dssdev->dev, "%s panel detect error\n", __func__); | ||
542 | if (!md->enabled && gpio_is_valid(panel_data->reset_gpio)) | ||
543 | gpio_set_value(panel_data->reset_gpio, 0); | ||
544 | |||
545 | return r; | ||
546 | } | ||
547 | |||
548 | mutex_lock(&acx_dev.mutex); | ||
549 | acx_dev.dssdev = dssdev; | ||
550 | mutex_unlock(&acx_dev.mutex); | ||
551 | |||
552 | if (!md->enabled) { | ||
553 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
554 | gpio_set_value(panel_data->reset_gpio, 0); | ||
555 | } | ||
556 | |||
557 | /*------- Backlight control --------*/ | ||
558 | |||
559 | memset(&props, 0, sizeof(props)); | ||
560 | props.fb_blank = FB_BLANK_UNBLANK; | ||
561 | props.power = FB_BLANK_UNBLANK; | ||
562 | props.type = BACKLIGHT_RAW; | ||
563 | |||
564 | bldev = backlight_device_register("acx565akm", &md->spi->dev, | ||
565 | md, &acx565akm_bl_ops, &props); | ||
566 | md->bl_dev = bldev; | ||
567 | if (md->has_cabc) { | ||
568 | r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group); | ||
569 | if (r) { | ||
570 | dev_err(&bldev->dev, | ||
571 | "%s failed to create sysfs files\n", __func__); | ||
572 | backlight_device_unregister(bldev); | ||
573 | return r; | ||
574 | } | ||
575 | md->cabc_mode = get_hw_cabc_mode(md); | ||
576 | } | ||
577 | |||
578 | max_brightness = 255; | ||
579 | |||
580 | if (md->has_bc) | ||
581 | brightness = acx565akm_get_actual_brightness(md); | ||
582 | else | ||
583 | brightness = 0; | ||
584 | |||
585 | bldev->props.max_brightness = max_brightness; | ||
586 | bldev->props.brightness = brightness; | ||
587 | |||
588 | acx565akm_bl_update_status(bldev); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static void acx_panel_remove(struct omap_dss_device *dssdev) | ||
593 | { | ||
594 | struct acx565akm_device *md = &acx_dev; | ||
595 | |||
596 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
597 | sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group); | ||
598 | backlight_device_unregister(md->bl_dev); | ||
599 | mutex_lock(&acx_dev.mutex); | ||
600 | acx_dev.dssdev = NULL; | ||
601 | mutex_unlock(&acx_dev.mutex); | ||
602 | } | ||
603 | |||
604 | static int acx_panel_power_on(struct omap_dss_device *dssdev) | ||
605 | { | ||
606 | struct acx565akm_device *md = &acx_dev; | ||
607 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | ||
608 | int r; | ||
609 | |||
610 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
611 | |||
612 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
613 | return 0; | ||
614 | |||
615 | mutex_lock(&md->mutex); | ||
616 | |||
617 | omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings); | ||
618 | omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs); | ||
619 | |||
620 | r = omapdss_sdi_display_enable(dssdev); | ||
621 | if (r) { | ||
622 | pr_err("%s sdi enable failed\n", __func__); | ||
623 | goto fail_unlock; | ||
624 | } | ||
625 | |||
626 | /*FIXME tweak me */ | ||
627 | msleep(50); | ||
628 | |||
629 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
630 | gpio_set_value(panel_data->reset_gpio, 1); | ||
631 | |||
632 | if (md->enabled) { | ||
633 | dev_dbg(&md->spi->dev, "panel already enabled\n"); | ||
634 | mutex_unlock(&md->mutex); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /* | ||
639 | * We have to meet all the following delay requirements: | ||
640 | * 1. tRW: reset pulse width 10usec (7.12.1) | ||
641 | * 2. tRT: reset cancel time 5msec (7.12.1) | ||
642 | * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst | ||
643 | * case (7.6.2) | ||
644 | * 4. 120msec before the sleep out command (7.12.1) | ||
645 | */ | ||
646 | msleep(120); | ||
647 | |||
648 | set_sleep_mode(md, 0); | ||
649 | md->enabled = 1; | ||
650 | |||
651 | /* 5msec between sleep out and the next command. (8.2.16) */ | ||
652 | msleep(5); | ||
653 | set_display_state(md, 1); | ||
654 | set_cabc_mode(md, md->cabc_mode); | ||
655 | |||
656 | mutex_unlock(&md->mutex); | ||
657 | |||
658 | return acx565akm_bl_update_status(md->bl_dev); | ||
659 | |||
660 | fail_unlock: | ||
661 | mutex_unlock(&md->mutex); | ||
662 | return r; | ||
663 | } | ||
664 | |||
665 | static void acx_panel_power_off(struct omap_dss_device *dssdev) | ||
666 | { | ||
667 | struct acx565akm_device *md = &acx_dev; | ||
668 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | ||
669 | |||
670 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
671 | |||
672 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
673 | return; | ||
674 | |||
675 | mutex_lock(&md->mutex); | ||
676 | |||
677 | if (!md->enabled) { | ||
678 | mutex_unlock(&md->mutex); | ||
679 | return; | ||
680 | } | ||
681 | set_display_state(md, 0); | ||
682 | set_sleep_mode(md, 1); | ||
683 | md->enabled = 0; | ||
684 | /* | ||
685 | * We have to provide PCLK,HS,VS signals for 2 frames (worst case | ||
686 | * ~50msec) after sending the sleep in command and asserting the | ||
687 | * reset signal. We probably could assert the reset w/o the delay | ||
688 | * but we still delay to avoid possible artifacts. (7.6.1) | ||
689 | */ | ||
690 | msleep(50); | ||
691 | |||
692 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
693 | gpio_set_value(panel_data->reset_gpio, 0); | ||
694 | |||
695 | /* FIXME need to tweak this delay */ | ||
696 | msleep(100); | ||
697 | |||
698 | omapdss_sdi_display_disable(dssdev); | ||
699 | |||
700 | mutex_unlock(&md->mutex); | ||
701 | } | ||
702 | |||
703 | static int acx_panel_enable(struct omap_dss_device *dssdev) | ||
704 | { | ||
705 | int r; | ||
706 | |||
707 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
708 | r = acx_panel_power_on(dssdev); | ||
709 | |||
710 | if (r) | ||
711 | return r; | ||
712 | |||
713 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static void acx_panel_disable(struct omap_dss_device *dssdev) | ||
718 | { | ||
719 | dev_dbg(dssdev->dev, "%s\n", __func__); | ||
720 | acx_panel_power_off(dssdev); | ||
721 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
722 | } | ||
723 | |||
724 | static void acx_panel_set_timings(struct omap_dss_device *dssdev, | ||
725 | struct omap_video_timings *timings) | ||
726 | { | ||
727 | omapdss_sdi_set_timings(dssdev, timings); | ||
728 | |||
729 | dssdev->panel.timings = *timings; | ||
730 | } | ||
731 | |||
732 | static int acx_panel_check_timings(struct omap_dss_device *dssdev, | ||
733 | struct omap_video_timings *timings) | ||
734 | { | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | |||
739 | static struct omap_dss_driver acx_panel_driver = { | ||
740 | .probe = acx_panel_probe, | ||
741 | .remove = acx_panel_remove, | ||
742 | |||
743 | .enable = acx_panel_enable, | ||
744 | .disable = acx_panel_disable, | ||
745 | |||
746 | .set_timings = acx_panel_set_timings, | ||
747 | .check_timings = acx_panel_check_timings, | ||
748 | |||
749 | .get_recommended_bpp = acx_get_recommended_bpp, | ||
750 | |||
751 | .driver = { | ||
752 | .name = "panel-acx565akm", | ||
753 | .owner = THIS_MODULE, | ||
754 | }, | ||
755 | }; | ||
756 | |||
757 | /*--------------------SPI probe-------------------------*/ | ||
758 | |||
759 | static int acx565akm_spi_probe(struct spi_device *spi) | ||
760 | { | ||
761 | struct acx565akm_device *md = &acx_dev; | ||
762 | |||
763 | dev_dbg(&spi->dev, "%s\n", __func__); | ||
764 | |||
765 | spi->mode = SPI_MODE_3; | ||
766 | md->spi = spi; | ||
767 | mutex_init(&md->mutex); | ||
768 | dev_set_drvdata(&spi->dev, md); | ||
769 | |||
770 | omap_dss_register_driver(&acx_panel_driver); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int acx565akm_spi_remove(struct spi_device *spi) | ||
776 | { | ||
777 | struct acx565akm_device *md = dev_get_drvdata(&spi->dev); | ||
778 | |||
779 | dev_dbg(&md->spi->dev, "%s\n", __func__); | ||
780 | omap_dss_unregister_driver(&acx_panel_driver); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static struct spi_driver acx565akm_spi_driver = { | ||
786 | .driver = { | ||
787 | .name = "acx565akm", | ||
788 | .owner = THIS_MODULE, | ||
789 | }, | ||
790 | .probe = acx565akm_spi_probe, | ||
791 | .remove = acx565akm_spi_remove, | ||
792 | }; | ||
793 | |||
794 | module_spi_driver(acx565akm_spi_driver); | ||
795 | |||
796 | MODULE_AUTHOR("Nokia Corporation"); | ||
797 | MODULE_DESCRIPTION("acx565akm LCD Driver"); | ||
798 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c deleted file mode 100644 index bebebd45847f..000000000000 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ /dev/null | |||
@@ -1,744 +0,0 @@ | |||
1 | /* | ||
2 | * Generic DPI Panels support | ||
3 | * | ||
4 | * Copyright (C) 2010 Canonical Ltd. | ||
5 | * Author: Bryan Wu <bryan.wu@canonical.com> | ||
6 | * | ||
7 | * LCD panel driver for Sharp LQ043T1DG01 | ||
8 | * | ||
9 | * Copyright (C) 2009 Texas Instruments Inc | ||
10 | * Author: Vaibhav Hiremath <hvaibhav@ti.com> | ||
11 | * | ||
12 | * LCD panel driver for Toppoly TDO35S | ||
13 | * | ||
14 | * Copyright (C) 2009 CompuLab, Ltd. | ||
15 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
16 | * | ||
17 | * Copyright (C) 2008 Nokia Corporation | ||
18 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify it | ||
21 | * under the terms of the GNU General Public License version 2 as published by | ||
22 | * the Free Software Foundation. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
25 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
26 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
27 | * more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License along with | ||
30 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/gpio.h> | ||
37 | #include <video/omapdss.h> | ||
38 | |||
39 | #include <video/omap-panel-data.h> | ||
40 | |||
41 | struct panel_config { | ||
42 | struct omap_video_timings timings; | ||
43 | |||
44 | int power_on_delay; | ||
45 | int power_off_delay; | ||
46 | |||
47 | /* | ||
48 | * Used to match device to panel configuration | ||
49 | * when use generic panel driver | ||
50 | */ | ||
51 | const char *name; | ||
52 | }; | ||
53 | |||
54 | /* Panel configurations */ | ||
55 | static struct panel_config generic_dpi_panels[] = { | ||
56 | /* Sharp LQ043T1DG01 */ | ||
57 | { | ||
58 | { | ||
59 | .x_res = 480, | ||
60 | .y_res = 272, | ||
61 | |||
62 | .pixel_clock = 9000, | ||
63 | |||
64 | .hsw = 42, | ||
65 | .hfp = 3, | ||
66 | .hbp = 2, | ||
67 | |||
68 | .vsw = 11, | ||
69 | .vfp = 3, | ||
70 | .vbp = 2, | ||
71 | |||
72 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
73 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
74 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
75 | .de_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
76 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
77 | }, | ||
78 | .power_on_delay = 50, | ||
79 | .power_off_delay = 100, | ||
80 | .name = "sharp_lq", | ||
81 | }, | ||
82 | |||
83 | /* Sharp LS037V7DW01 */ | ||
84 | { | ||
85 | { | ||
86 | .x_res = 480, | ||
87 | .y_res = 640, | ||
88 | |||
89 | .pixel_clock = 19200, | ||
90 | |||
91 | .hsw = 2, | ||
92 | .hfp = 1, | ||
93 | .hbp = 28, | ||
94 | |||
95 | .vsw = 1, | ||
96 | .vfp = 1, | ||
97 | .vbp = 1, | ||
98 | |||
99 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
100 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
101 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
102 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
103 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
104 | }, | ||
105 | .power_on_delay = 50, | ||
106 | .power_off_delay = 100, | ||
107 | .name = "sharp_ls", | ||
108 | }, | ||
109 | |||
110 | /* Toppoly TDO35S */ | ||
111 | { | ||
112 | { | ||
113 | .x_res = 480, | ||
114 | .y_res = 640, | ||
115 | |||
116 | .pixel_clock = 26000, | ||
117 | |||
118 | .hfp = 104, | ||
119 | .hsw = 8, | ||
120 | .hbp = 8, | ||
121 | |||
122 | .vfp = 4, | ||
123 | .vsw = 2, | ||
124 | .vbp = 2, | ||
125 | |||
126 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
127 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
128 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
129 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
130 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
131 | }, | ||
132 | .power_on_delay = 0, | ||
133 | .power_off_delay = 0, | ||
134 | .name = "toppoly_tdo35s", | ||
135 | }, | ||
136 | |||
137 | /* Samsung LTE430WQ-F0C */ | ||
138 | { | ||
139 | { | ||
140 | .x_res = 480, | ||
141 | .y_res = 272, | ||
142 | |||
143 | .pixel_clock = 9200, | ||
144 | |||
145 | .hfp = 8, | ||
146 | .hsw = 41, | ||
147 | .hbp = 45 - 41, | ||
148 | |||
149 | .vfp = 4, | ||
150 | .vsw = 10, | ||
151 | .vbp = 12 - 10, | ||
152 | |||
153 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
154 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
155 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
156 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
157 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
158 | }, | ||
159 | .power_on_delay = 0, | ||
160 | .power_off_delay = 0, | ||
161 | .name = "samsung_lte430wq_f0c", | ||
162 | }, | ||
163 | |||
164 | /* Seiko 70WVW1TZ3Z3 */ | ||
165 | { | ||
166 | { | ||
167 | .x_res = 800, | ||
168 | .y_res = 480, | ||
169 | |||
170 | .pixel_clock = 33000, | ||
171 | |||
172 | .hsw = 128, | ||
173 | .hfp = 10, | ||
174 | .hbp = 10, | ||
175 | |||
176 | .vsw = 2, | ||
177 | .vfp = 4, | ||
178 | .vbp = 11, | ||
179 | |||
180 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
181 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
182 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
183 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
184 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
185 | }, | ||
186 | .power_on_delay = 0, | ||
187 | .power_off_delay = 0, | ||
188 | .name = "seiko_70wvw1tz3", | ||
189 | }, | ||
190 | |||
191 | /* Powertip PH480272T */ | ||
192 | { | ||
193 | { | ||
194 | .x_res = 480, | ||
195 | .y_res = 272, | ||
196 | |||
197 | .pixel_clock = 9000, | ||
198 | |||
199 | .hsw = 40, | ||
200 | .hfp = 2, | ||
201 | .hbp = 2, | ||
202 | |||
203 | .vsw = 10, | ||
204 | .vfp = 2, | ||
205 | .vbp = 2, | ||
206 | |||
207 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
208 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
209 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
210 | .de_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
211 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
212 | }, | ||
213 | .power_on_delay = 0, | ||
214 | .power_off_delay = 0, | ||
215 | .name = "powertip_ph480272t", | ||
216 | }, | ||
217 | |||
218 | /* Innolux AT070TN83 */ | ||
219 | { | ||
220 | { | ||
221 | .x_res = 800, | ||
222 | .y_res = 480, | ||
223 | |||
224 | .pixel_clock = 40000, | ||
225 | |||
226 | .hsw = 48, | ||
227 | .hfp = 1, | ||
228 | .hbp = 1, | ||
229 | |||
230 | .vsw = 3, | ||
231 | .vfp = 12, | ||
232 | .vbp = 25, | ||
233 | |||
234 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
235 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
236 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
237 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
238 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
239 | }, | ||
240 | .power_on_delay = 0, | ||
241 | .power_off_delay = 0, | ||
242 | .name = "innolux_at070tn83", | ||
243 | }, | ||
244 | |||
245 | /* NEC NL2432DR22-11B */ | ||
246 | { | ||
247 | { | ||
248 | .x_res = 240, | ||
249 | .y_res = 320, | ||
250 | |||
251 | .pixel_clock = 5400, | ||
252 | |||
253 | .hsw = 3, | ||
254 | .hfp = 3, | ||
255 | .hbp = 39, | ||
256 | |||
257 | .vsw = 1, | ||
258 | .vfp = 2, | ||
259 | .vbp = 7, | ||
260 | |||
261 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
262 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
263 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
264 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
265 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
266 | }, | ||
267 | .name = "nec_nl2432dr22-11b", | ||
268 | }, | ||
269 | |||
270 | /* Unknown panel used in OMAP H4 */ | ||
271 | { | ||
272 | { | ||
273 | .x_res = 240, | ||
274 | .y_res = 320, | ||
275 | |||
276 | .pixel_clock = 6250, | ||
277 | |||
278 | .hsw = 15, | ||
279 | .hfp = 15, | ||
280 | .hbp = 60, | ||
281 | |||
282 | .vsw = 1, | ||
283 | .vfp = 1, | ||
284 | .vbp = 1, | ||
285 | |||
286 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
287 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
288 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
289 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
290 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
291 | }, | ||
292 | .name = "h4", | ||
293 | }, | ||
294 | |||
295 | /* FocalTech ETM070003DH6 */ | ||
296 | { | ||
297 | { | ||
298 | .x_res = 800, | ||
299 | .y_res = 480, | ||
300 | |||
301 | .pixel_clock = 28000, | ||
302 | |||
303 | .hsw = 48, | ||
304 | .hfp = 40, | ||
305 | .hbp = 40, | ||
306 | |||
307 | .vsw = 3, | ||
308 | .vfp = 13, | ||
309 | .vbp = 29, | ||
310 | |||
311 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
312 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
313 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
314 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
315 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
316 | }, | ||
317 | .name = "focaltech_etm070003dh6", | ||
318 | }, | ||
319 | |||
320 | /* Microtips Technologies - UMSH-8173MD */ | ||
321 | { | ||
322 | { | ||
323 | .x_res = 800, | ||
324 | .y_res = 480, | ||
325 | |||
326 | .pixel_clock = 34560, | ||
327 | |||
328 | .hsw = 13, | ||
329 | .hfp = 101, | ||
330 | .hbp = 101, | ||
331 | |||
332 | .vsw = 23, | ||
333 | .vfp = 1, | ||
334 | .vbp = 1, | ||
335 | |||
336 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
337 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
338 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
339 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
340 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
341 | }, | ||
342 | .power_on_delay = 0, | ||
343 | .power_off_delay = 0, | ||
344 | .name = "microtips_umsh_8173md", | ||
345 | }, | ||
346 | |||
347 | /* OrtusTech COM43H4M10XTC */ | ||
348 | { | ||
349 | { | ||
350 | .x_res = 480, | ||
351 | .y_res = 272, | ||
352 | |||
353 | .pixel_clock = 8000, | ||
354 | |||
355 | .hsw = 41, | ||
356 | .hfp = 8, | ||
357 | .hbp = 4, | ||
358 | |||
359 | .vsw = 10, | ||
360 | .vfp = 4, | ||
361 | .vbp = 2, | ||
362 | |||
363 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
364 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
365 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
366 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
367 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
368 | }, | ||
369 | .name = "ortustech_com43h4m10xtc", | ||
370 | }, | ||
371 | |||
372 | /* Innolux AT080TN52 */ | ||
373 | { | ||
374 | { | ||
375 | .x_res = 800, | ||
376 | .y_res = 600, | ||
377 | |||
378 | .pixel_clock = 41142, | ||
379 | |||
380 | .hsw = 20, | ||
381 | .hfp = 210, | ||
382 | .hbp = 46, | ||
383 | |||
384 | .vsw = 10, | ||
385 | .vfp = 12, | ||
386 | .vbp = 23, | ||
387 | |||
388 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
389 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
390 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
391 | .de_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
392 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
393 | }, | ||
394 | .name = "innolux_at080tn52", | ||
395 | }, | ||
396 | |||
397 | /* Mitsubishi AA084SB01 */ | ||
398 | { | ||
399 | { | ||
400 | .x_res = 800, | ||
401 | .y_res = 600, | ||
402 | .pixel_clock = 40000, | ||
403 | |||
404 | .hsw = 1, | ||
405 | .hfp = 254, | ||
406 | .hbp = 1, | ||
407 | |||
408 | .vsw = 1, | ||
409 | .vfp = 26, | ||
410 | .vbp = 1, | ||
411 | |||
412 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
413 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
414 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
415 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
416 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
417 | }, | ||
418 | .name = "mitsubishi_aa084sb01", | ||
419 | }, | ||
420 | /* EDT ET0500G0DH6 */ | ||
421 | { | ||
422 | { | ||
423 | .x_res = 800, | ||
424 | .y_res = 480, | ||
425 | .pixel_clock = 33260, | ||
426 | |||
427 | .hsw = 128, | ||
428 | .hfp = 216, | ||
429 | .hbp = 40, | ||
430 | |||
431 | .vsw = 2, | ||
432 | .vfp = 35, | ||
433 | .vbp = 10, | ||
434 | |||
435 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
436 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
437 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
438 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
439 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
440 | }, | ||
441 | .name = "edt_et0500g0dh6", | ||
442 | }, | ||
443 | |||
444 | /* Prime-View PD050VL1 */ | ||
445 | { | ||
446 | { | ||
447 | .x_res = 640, | ||
448 | .y_res = 480, | ||
449 | |||
450 | .pixel_clock = 25000, | ||
451 | |||
452 | .hsw = 96, | ||
453 | .hfp = 18, | ||
454 | .hbp = 46, | ||
455 | |||
456 | .vsw = 2, | ||
457 | .vfp = 10, | ||
458 | .vbp = 33, | ||
459 | |||
460 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
461 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
462 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
463 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
464 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
465 | }, | ||
466 | .name = "primeview_pd050vl1", | ||
467 | }, | ||
468 | |||
469 | /* Prime-View PM070WL4 */ | ||
470 | { | ||
471 | { | ||
472 | .x_res = 800, | ||
473 | .y_res = 480, | ||
474 | |||
475 | .pixel_clock = 32000, | ||
476 | |||
477 | .hsw = 128, | ||
478 | .hfp = 42, | ||
479 | .hbp = 86, | ||
480 | |||
481 | .vsw = 2, | ||
482 | .vfp = 10, | ||
483 | .vbp = 33, | ||
484 | |||
485 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
486 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
487 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
488 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
489 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
490 | }, | ||
491 | .name = "primeview_pm070wl4", | ||
492 | }, | ||
493 | |||
494 | /* Prime-View PD104SLF */ | ||
495 | { | ||
496 | { | ||
497 | .x_res = 800, | ||
498 | .y_res = 600, | ||
499 | |||
500 | .pixel_clock = 40000, | ||
501 | |||
502 | .hsw = 128, | ||
503 | .hfp = 42, | ||
504 | .hbp = 86, | ||
505 | |||
506 | .vsw = 4, | ||
507 | .vfp = 1, | ||
508 | .vbp = 23, | ||
509 | |||
510 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
511 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
512 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
513 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
514 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
515 | }, | ||
516 | .name = "primeview_pd104slf", | ||
517 | }, | ||
518 | }; | ||
519 | |||
520 | struct panel_drv_data { | ||
521 | |||
522 | struct omap_dss_device *dssdev; | ||
523 | |||
524 | struct panel_config *panel_config; | ||
525 | |||
526 | struct mutex lock; | ||
527 | }; | ||
528 | |||
529 | static inline struct panel_generic_dpi_data | ||
530 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
531 | { | ||
532 | return (struct panel_generic_dpi_data *) dssdev->data; | ||
533 | } | ||
534 | |||
535 | static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) | ||
536 | { | ||
537 | int r, i; | ||
538 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
539 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
540 | struct panel_config *panel_config = drv_data->panel_config; | ||
541 | |||
542 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
543 | return 0; | ||
544 | |||
545 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
546 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
547 | |||
548 | r = omapdss_dpi_display_enable(dssdev); | ||
549 | if (r) | ||
550 | goto err0; | ||
551 | |||
552 | /* wait couple of vsyncs until enabling the LCD */ | ||
553 | if (panel_config->power_on_delay) | ||
554 | msleep(panel_config->power_on_delay); | ||
555 | |||
556 | for (i = 0; i < panel_data->num_gpios; ++i) { | ||
557 | gpio_set_value_cansleep(panel_data->gpios[i], | ||
558 | panel_data->gpio_invert[i] ? 0 : 1); | ||
559 | } | ||
560 | |||
561 | return 0; | ||
562 | |||
563 | err0: | ||
564 | return r; | ||
565 | } | ||
566 | |||
567 | static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) | ||
568 | { | ||
569 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
570 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
571 | struct panel_config *panel_config = drv_data->panel_config; | ||
572 | int i; | ||
573 | |||
574 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
575 | return; | ||
576 | |||
577 | for (i = panel_data->num_gpios - 1; i >= 0; --i) { | ||
578 | gpio_set_value_cansleep(panel_data->gpios[i], | ||
579 | panel_data->gpio_invert[i] ? 1 : 0); | ||
580 | } | ||
581 | |||
582 | /* wait couple of vsyncs after disabling the LCD */ | ||
583 | if (panel_config->power_off_delay) | ||
584 | msleep(panel_config->power_off_delay); | ||
585 | |||
586 | omapdss_dpi_display_disable(dssdev); | ||
587 | } | ||
588 | |||
589 | static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | ||
590 | { | ||
591 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
592 | struct panel_config *panel_config = NULL; | ||
593 | struct panel_drv_data *drv_data = NULL; | ||
594 | int i, r; | ||
595 | |||
596 | dev_dbg(dssdev->dev, "probe\n"); | ||
597 | |||
598 | if (!panel_data || !panel_data->name) | ||
599 | return -EINVAL; | ||
600 | |||
601 | for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) { | ||
602 | if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) { | ||
603 | panel_config = &generic_dpi_panels[i]; | ||
604 | break; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | if (!panel_config) | ||
609 | return -EINVAL; | ||
610 | |||
611 | for (i = 0; i < panel_data->num_gpios; ++i) { | ||
612 | r = devm_gpio_request_one(dssdev->dev, panel_data->gpios[i], | ||
613 | panel_data->gpio_invert[i] ? | ||
614 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | ||
615 | "panel gpio"); | ||
616 | if (r) | ||
617 | return r; | ||
618 | } | ||
619 | |||
620 | dssdev->panel.timings = panel_config->timings; | ||
621 | |||
622 | drv_data = devm_kzalloc(dssdev->dev, sizeof(*drv_data), GFP_KERNEL); | ||
623 | if (!drv_data) | ||
624 | return -ENOMEM; | ||
625 | |||
626 | drv_data->dssdev = dssdev; | ||
627 | drv_data->panel_config = panel_config; | ||
628 | |||
629 | mutex_init(&drv_data->lock); | ||
630 | |||
631 | dev_set_drvdata(dssdev->dev, drv_data); | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) | ||
637 | { | ||
638 | dev_dbg(dssdev->dev, "remove\n"); | ||
639 | |||
640 | dev_set_drvdata(dssdev->dev, NULL); | ||
641 | } | ||
642 | |||
643 | static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) | ||
644 | { | ||
645 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
646 | int r; | ||
647 | |||
648 | mutex_lock(&drv_data->lock); | ||
649 | |||
650 | r = generic_dpi_panel_power_on(dssdev); | ||
651 | if (r) | ||
652 | goto err; | ||
653 | |||
654 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
655 | err: | ||
656 | mutex_unlock(&drv_data->lock); | ||
657 | |||
658 | return r; | ||
659 | } | ||
660 | |||
661 | static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) | ||
662 | { | ||
663 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
664 | |||
665 | mutex_lock(&drv_data->lock); | ||
666 | |||
667 | generic_dpi_panel_power_off(dssdev); | ||
668 | |||
669 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
670 | |||
671 | mutex_unlock(&drv_data->lock); | ||
672 | } | ||
673 | |||
674 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | ||
675 | struct omap_video_timings *timings) | ||
676 | { | ||
677 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
678 | |||
679 | mutex_lock(&drv_data->lock); | ||
680 | |||
681 | omapdss_dpi_set_timings(dssdev, timings); | ||
682 | |||
683 | dssdev->panel.timings = *timings; | ||
684 | |||
685 | mutex_unlock(&drv_data->lock); | ||
686 | } | ||
687 | |||
688 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, | ||
689 | struct omap_video_timings *timings) | ||
690 | { | ||
691 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
692 | |||
693 | mutex_lock(&drv_data->lock); | ||
694 | |||
695 | *timings = dssdev->panel.timings; | ||
696 | |||
697 | mutex_unlock(&drv_data->lock); | ||
698 | } | ||
699 | |||
700 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, | ||
701 | struct omap_video_timings *timings) | ||
702 | { | ||
703 | struct panel_drv_data *drv_data = dev_get_drvdata(dssdev->dev); | ||
704 | int r; | ||
705 | |||
706 | mutex_lock(&drv_data->lock); | ||
707 | |||
708 | r = dpi_check_timings(dssdev, timings); | ||
709 | |||
710 | mutex_unlock(&drv_data->lock); | ||
711 | |||
712 | return r; | ||
713 | } | ||
714 | |||
715 | static struct omap_dss_driver dpi_driver = { | ||
716 | .probe = generic_dpi_panel_probe, | ||
717 | .remove = __exit_p(generic_dpi_panel_remove), | ||
718 | |||
719 | .enable = generic_dpi_panel_enable, | ||
720 | .disable = generic_dpi_panel_disable, | ||
721 | |||
722 | .set_timings = generic_dpi_panel_set_timings, | ||
723 | .get_timings = generic_dpi_panel_get_timings, | ||
724 | .check_timings = generic_dpi_panel_check_timings, | ||
725 | |||
726 | .driver = { | ||
727 | .name = "generic_dpi_panel", | ||
728 | .owner = THIS_MODULE, | ||
729 | }, | ||
730 | }; | ||
731 | |||
732 | static int __init generic_dpi_panel_drv_init(void) | ||
733 | { | ||
734 | return omap_dss_register_driver(&dpi_driver); | ||
735 | } | ||
736 | |||
737 | static void __exit generic_dpi_panel_drv_exit(void) | ||
738 | { | ||
739 | omap_dss_unregister_driver(&dpi_driver); | ||
740 | } | ||
741 | |||
742 | module_init(generic_dpi_panel_drv_init); | ||
743 | module_exit(generic_dpi_panel_drv_exit); | ||
744 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c deleted file mode 100644 index 6c51430ddb37..000000000000 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | /* | ||
2 | * LCD panel driver for LG.Philips LB035Q02 | ||
3 | * | ||
4 | * Author: Steve Sakoman <steve@sakoman.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/gpio.h> | ||
24 | |||
25 | #include <video/omapdss.h> | ||
26 | #include <video/omap-panel-data.h> | ||
27 | |||
28 | struct lb035q02_data { | ||
29 | struct mutex lock; | ||
30 | }; | ||
31 | |||
32 | static struct omap_video_timings lb035q02_timings = { | ||
33 | .x_res = 320, | ||
34 | .y_res = 240, | ||
35 | |||
36 | .pixel_clock = 6500, | ||
37 | |||
38 | .hsw = 2, | ||
39 | .hfp = 20, | ||
40 | .hbp = 68, | ||
41 | |||
42 | .vsw = 2, | ||
43 | .vfp = 4, | ||
44 | .vbp = 18, | ||
45 | |||
46 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
47 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
48 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
49 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
50 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
51 | }; | ||
52 | |||
53 | static inline struct panel_generic_dpi_data | ||
54 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
55 | { | ||
56 | return (struct panel_generic_dpi_data *) dssdev->data; | ||
57 | } | ||
58 | |||
59 | static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) | ||
60 | { | ||
61 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
62 | int r, i; | ||
63 | |||
64 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
65 | return 0; | ||
66 | |||
67 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
68 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
69 | |||
70 | r = omapdss_dpi_display_enable(dssdev); | ||
71 | if (r) | ||
72 | goto err0; | ||
73 | |||
74 | for (i = 0; i < panel_data->num_gpios; ++i) { | ||
75 | gpio_set_value_cansleep(panel_data->gpios[i], | ||
76 | panel_data->gpio_invert[i] ? 0 : 1); | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | |||
81 | err0: | ||
82 | return r; | ||
83 | } | ||
84 | |||
85 | static void lb035q02_panel_power_off(struct omap_dss_device *dssdev) | ||
86 | { | ||
87 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
88 | int i; | ||
89 | |||
90 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
91 | return; | ||
92 | |||
93 | for (i = panel_data->num_gpios - 1; i >= 0; --i) { | ||
94 | gpio_set_value_cansleep(panel_data->gpios[i], | ||
95 | panel_data->gpio_invert[i] ? 1 : 0); | ||
96 | } | ||
97 | |||
98 | omapdss_dpi_display_disable(dssdev); | ||
99 | } | ||
100 | |||
101 | static int lb035q02_panel_probe(struct omap_dss_device *dssdev) | ||
102 | { | ||
103 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
104 | struct lb035q02_data *ld; | ||
105 | int r, i; | ||
106 | |||
107 | if (!panel_data) | ||
108 | return -EINVAL; | ||
109 | |||
110 | dssdev->panel.timings = lb035q02_timings; | ||
111 | |||
112 | ld = devm_kzalloc(dssdev->dev, sizeof(*ld), GFP_KERNEL); | ||
113 | if (!ld) | ||
114 | return -ENOMEM; | ||
115 | |||
116 | for (i = 0; i < panel_data->num_gpios; ++i) { | ||
117 | r = devm_gpio_request_one(dssdev->dev, panel_data->gpios[i], | ||
118 | panel_data->gpio_invert[i] ? | ||
119 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | ||
120 | "panel gpio"); | ||
121 | if (r) | ||
122 | return r; | ||
123 | } | ||
124 | |||
125 | mutex_init(&ld->lock); | ||
126 | dev_set_drvdata(dssdev->dev, ld); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void lb035q02_panel_remove(struct omap_dss_device *dssdev) | ||
132 | { | ||
133 | } | ||
134 | |||
135 | static int lb035q02_panel_enable(struct omap_dss_device *dssdev) | ||
136 | { | ||
137 | struct lb035q02_data *ld = dev_get_drvdata(dssdev->dev); | ||
138 | int r; | ||
139 | |||
140 | mutex_lock(&ld->lock); | ||
141 | |||
142 | r = lb035q02_panel_power_on(dssdev); | ||
143 | if (r) | ||
144 | goto err; | ||
145 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
146 | |||
147 | mutex_unlock(&ld->lock); | ||
148 | return 0; | ||
149 | err: | ||
150 | mutex_unlock(&ld->lock); | ||
151 | return r; | ||
152 | } | ||
153 | |||
154 | static void lb035q02_panel_disable(struct omap_dss_device *dssdev) | ||
155 | { | ||
156 | struct lb035q02_data *ld = dev_get_drvdata(dssdev->dev); | ||
157 | |||
158 | mutex_lock(&ld->lock); | ||
159 | |||
160 | lb035q02_panel_power_off(dssdev); | ||
161 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
162 | |||
163 | mutex_unlock(&ld->lock); | ||
164 | } | ||
165 | |||
166 | static struct omap_dss_driver lb035q02_driver = { | ||
167 | .probe = lb035q02_panel_probe, | ||
168 | .remove = lb035q02_panel_remove, | ||
169 | |||
170 | .enable = lb035q02_panel_enable, | ||
171 | .disable = lb035q02_panel_disable, | ||
172 | |||
173 | .driver = { | ||
174 | .name = "lgphilips_lb035q02_panel", | ||
175 | .owner = THIS_MODULE, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val) | ||
180 | { | ||
181 | struct spi_message msg; | ||
182 | struct spi_transfer index_xfer = { | ||
183 | .len = 3, | ||
184 | .cs_change = 1, | ||
185 | }; | ||
186 | struct spi_transfer value_xfer = { | ||
187 | .len = 3, | ||
188 | }; | ||
189 | u8 buffer[16]; | ||
190 | |||
191 | spi_message_init(&msg); | ||
192 | |||
193 | /* register index */ | ||
194 | buffer[0] = 0x70; | ||
195 | buffer[1] = 0x00; | ||
196 | buffer[2] = reg & 0x7f; | ||
197 | index_xfer.tx_buf = buffer; | ||
198 | spi_message_add_tail(&index_xfer, &msg); | ||
199 | |||
200 | /* register value */ | ||
201 | buffer[4] = 0x72; | ||
202 | buffer[5] = val >> 8; | ||
203 | buffer[6] = val; | ||
204 | value_xfer.tx_buf = buffer + 4; | ||
205 | spi_message_add_tail(&value_xfer, &msg); | ||
206 | |||
207 | return spi_sync(spi, &msg); | ||
208 | } | ||
209 | |||
210 | static void init_lb035q02_panel(struct spi_device *spi) | ||
211 | { | ||
212 | /* Init sequence from page 28 of the lb035q02 spec */ | ||
213 | lb035q02_write_reg(spi, 0x01, 0x6300); | ||
214 | lb035q02_write_reg(spi, 0x02, 0x0200); | ||
215 | lb035q02_write_reg(spi, 0x03, 0x0177); | ||
216 | lb035q02_write_reg(spi, 0x04, 0x04c7); | ||
217 | lb035q02_write_reg(spi, 0x05, 0xffc0); | ||
218 | lb035q02_write_reg(spi, 0x06, 0xe806); | ||
219 | lb035q02_write_reg(spi, 0x0a, 0x4008); | ||
220 | lb035q02_write_reg(spi, 0x0b, 0x0000); | ||
221 | lb035q02_write_reg(spi, 0x0d, 0x0030); | ||
222 | lb035q02_write_reg(spi, 0x0e, 0x2800); | ||
223 | lb035q02_write_reg(spi, 0x0f, 0x0000); | ||
224 | lb035q02_write_reg(spi, 0x16, 0x9f80); | ||
225 | lb035q02_write_reg(spi, 0x17, 0x0a0f); | ||
226 | lb035q02_write_reg(spi, 0x1e, 0x00c1); | ||
227 | lb035q02_write_reg(spi, 0x30, 0x0300); | ||
228 | lb035q02_write_reg(spi, 0x31, 0x0007); | ||
229 | lb035q02_write_reg(spi, 0x32, 0x0000); | ||
230 | lb035q02_write_reg(spi, 0x33, 0x0000); | ||
231 | lb035q02_write_reg(spi, 0x34, 0x0707); | ||
232 | lb035q02_write_reg(spi, 0x35, 0x0004); | ||
233 | lb035q02_write_reg(spi, 0x36, 0x0302); | ||
234 | lb035q02_write_reg(spi, 0x37, 0x0202); | ||
235 | lb035q02_write_reg(spi, 0x3a, 0x0a0d); | ||
236 | lb035q02_write_reg(spi, 0x3b, 0x0806); | ||
237 | } | ||
238 | |||
239 | static int lb035q02_panel_spi_probe(struct spi_device *spi) | ||
240 | { | ||
241 | init_lb035q02_panel(spi); | ||
242 | return omap_dss_register_driver(&lb035q02_driver); | ||
243 | } | ||
244 | |||
245 | static int lb035q02_panel_spi_remove(struct spi_device *spi) | ||
246 | { | ||
247 | omap_dss_unregister_driver(&lb035q02_driver); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static struct spi_driver lb035q02_spi_driver = { | ||
252 | .driver = { | ||
253 | .name = "lgphilips_lb035q02_panel-spi", | ||
254 | .owner = THIS_MODULE, | ||
255 | }, | ||
256 | .probe = lb035q02_panel_spi_probe, | ||
257 | .remove = lb035q02_panel_spi_remove, | ||
258 | }; | ||
259 | |||
260 | module_spi_driver(lb035q02_spi_driver); | ||
261 | |||
262 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c deleted file mode 100644 index 1d525fc84db9..000000000000 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ /dev/null | |||
@@ -1,616 +0,0 @@ | |||
1 | /* #define DEBUG */ | ||
2 | |||
3 | #include <linux/module.h> | ||
4 | #include <linux/delay.h> | ||
5 | #include <linux/slab.h> | ||
6 | #include <linux/gpio.h> | ||
7 | #include <linux/spi/spi.h> | ||
8 | #include <linux/fb.h> | ||
9 | |||
10 | #include <video/omapdss.h> | ||
11 | #include <video/omap-panel-data.h> | ||
12 | |||
13 | #define BLIZZARD_REV_CODE 0x00 | ||
14 | #define BLIZZARD_CONFIG 0x02 | ||
15 | #define BLIZZARD_PLL_DIV 0x04 | ||
16 | #define BLIZZARD_PLL_LOCK_RANGE 0x06 | ||
17 | #define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08 | ||
18 | #define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a | ||
19 | #define BLIZZARD_PLL_MODE 0x0c | ||
20 | #define BLIZZARD_CLK_SRC 0x0e | ||
21 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 | ||
22 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 | ||
23 | #define BLIZZARD_PANEL_CONFIGURATION 0x28 | ||
24 | #define BLIZZARD_HDISP 0x2a | ||
25 | #define BLIZZARD_HNDP 0x2c | ||
26 | #define BLIZZARD_VDISP0 0x2e | ||
27 | #define BLIZZARD_VDISP1 0x30 | ||
28 | #define BLIZZARD_VNDP 0x32 | ||
29 | #define BLIZZARD_HSW 0x34 | ||
30 | #define BLIZZARD_VSW 0x38 | ||
31 | #define BLIZZARD_DISPLAY_MODE 0x68 | ||
32 | #define BLIZZARD_INPUT_WIN_X_START_0 0x6c | ||
33 | #define BLIZZARD_DATA_SOURCE_SELECT 0x8e | ||
34 | #define BLIZZARD_DISP_MEM_DATA_PORT 0x90 | ||
35 | #define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 | ||
36 | #define BLIZZARD_POWER_SAVE 0xE6 | ||
37 | #define BLIZZARD_NDISP_CTRL_STATUS 0xE8 | ||
38 | |||
39 | /* Data source select */ | ||
40 | /* For S1D13745 */ | ||
41 | #define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 | ||
42 | #define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 | ||
43 | #define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 | ||
44 | #define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 | ||
45 | /* For S1D13744 */ | ||
46 | #define BLIZZARD_SRC_WRITE_LCD 0x00 | ||
47 | #define BLIZZARD_SRC_BLT_LCD 0x06 | ||
48 | |||
49 | #define BLIZZARD_COLOR_RGB565 0x01 | ||
50 | #define BLIZZARD_COLOR_YUV420 0x09 | ||
51 | |||
52 | #define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ | ||
53 | #define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ | ||
54 | |||
55 | #define MIPID_CMD_READ_DISP_ID 0x04 | ||
56 | #define MIPID_CMD_READ_RED 0x06 | ||
57 | #define MIPID_CMD_READ_GREEN 0x07 | ||
58 | #define MIPID_CMD_READ_BLUE 0x08 | ||
59 | #define MIPID_CMD_READ_DISP_STATUS 0x09 | ||
60 | #define MIPID_CMD_RDDSDR 0x0F | ||
61 | #define MIPID_CMD_SLEEP_IN 0x10 | ||
62 | #define MIPID_CMD_SLEEP_OUT 0x11 | ||
63 | #define MIPID_CMD_DISP_OFF 0x28 | ||
64 | #define MIPID_CMD_DISP_ON 0x29 | ||
65 | |||
66 | static struct panel_drv_data { | ||
67 | struct mutex lock; | ||
68 | |||
69 | struct omap_dss_device *dssdev; | ||
70 | struct spi_device *spidev; | ||
71 | |||
72 | int blizzard_ver; | ||
73 | } s_drv_data; | ||
74 | |||
75 | |||
76 | static inline | ||
77 | struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev) | ||
78 | { | ||
79 | return dssdev->data; | ||
80 | } | ||
81 | |||
82 | static inline | ||
83 | struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev) | ||
84 | { | ||
85 | return &s_drv_data; | ||
86 | } | ||
87 | |||
88 | |||
89 | static inline void blizzard_cmd(u8 cmd) | ||
90 | { | ||
91 | omap_rfbi_write_command(&cmd, 1); | ||
92 | } | ||
93 | |||
94 | static inline void blizzard_write(u8 cmd, const u8 *buf, int len) | ||
95 | { | ||
96 | omap_rfbi_write_command(&cmd, 1); | ||
97 | omap_rfbi_write_data(buf, len); | ||
98 | } | ||
99 | |||
100 | static inline void blizzard_read(u8 cmd, u8 *buf, int len) | ||
101 | { | ||
102 | omap_rfbi_write_command(&cmd, 1); | ||
103 | omap_rfbi_read_data(buf, len); | ||
104 | } | ||
105 | |||
106 | static u8 blizzard_read_reg(u8 cmd) | ||
107 | { | ||
108 | u8 data; | ||
109 | blizzard_read(cmd, &data, 1); | ||
110 | return data; | ||
111 | } | ||
112 | |||
113 | static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev, | ||
114 | int x, int y, int w, int h) | ||
115 | { | ||
116 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
117 | u8 tmp[18]; | ||
118 | int x_end, y_end; | ||
119 | |||
120 | x_end = x + w - 1; | ||
121 | y_end = y + h - 1; | ||
122 | |||
123 | tmp[0] = x; | ||
124 | tmp[1] = x >> 8; | ||
125 | tmp[2] = y; | ||
126 | tmp[3] = y >> 8; | ||
127 | tmp[4] = x_end; | ||
128 | tmp[5] = x_end >> 8; | ||
129 | tmp[6] = y_end; | ||
130 | tmp[7] = y_end >> 8; | ||
131 | |||
132 | /* scaling? */ | ||
133 | tmp[8] = x; | ||
134 | tmp[9] = x >> 8; | ||
135 | tmp[10] = y; | ||
136 | tmp[11] = y >> 8; | ||
137 | tmp[12] = x_end; | ||
138 | tmp[13] = x_end >> 8; | ||
139 | tmp[14] = y_end; | ||
140 | tmp[15] = y_end >> 8; | ||
141 | |||
142 | tmp[16] = BLIZZARD_COLOR_RGB565; | ||
143 | |||
144 | if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745) | ||
145 | tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; | ||
146 | else | ||
147 | tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ? | ||
148 | BLIZZARD_SRC_WRITE_LCD : | ||
149 | BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; | ||
150 | |||
151 | omapdss_rfbi_set_pixel_size(dssdev, 16); | ||
152 | omapdss_rfbi_set_data_lines(dssdev, 8); | ||
153 | |||
154 | omap_rfbi_configure(dssdev); | ||
155 | |||
156 | blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18); | ||
157 | |||
158 | omapdss_rfbi_set_pixel_size(dssdev, 16); | ||
159 | omapdss_rfbi_set_data_lines(dssdev, 16); | ||
160 | |||
161 | omap_rfbi_configure(dssdev); | ||
162 | } | ||
163 | |||
164 | static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf, | ||
165 | int wlen, u8 *rbuf, int rlen) | ||
166 | { | ||
167 | struct spi_message m; | ||
168 | struct spi_transfer *x, xfer[4]; | ||
169 | u16 w; | ||
170 | int r; | ||
171 | |||
172 | spi_message_init(&m); | ||
173 | |||
174 | memset(xfer, 0, sizeof(xfer)); | ||
175 | x = &xfer[0]; | ||
176 | |||
177 | cmd &= 0xff; | ||
178 | x->tx_buf = &cmd; | ||
179 | x->bits_per_word = 9; | ||
180 | x->len = 2; | ||
181 | spi_message_add_tail(x, &m); | ||
182 | |||
183 | if (wlen) { | ||
184 | x++; | ||
185 | x->tx_buf = wbuf; | ||
186 | x->len = wlen; | ||
187 | x->bits_per_word = 9; | ||
188 | spi_message_add_tail(x, &m); | ||
189 | } | ||
190 | |||
191 | if (rlen) { | ||
192 | x++; | ||
193 | x->rx_buf = &w; | ||
194 | x->len = 1; | ||
195 | spi_message_add_tail(x, &m); | ||
196 | |||
197 | if (rlen > 1) { | ||
198 | /* Arrange for the extra clock before the first | ||
199 | * data bit. | ||
200 | */ | ||
201 | x->bits_per_word = 9; | ||
202 | x->len = 2; | ||
203 | |||
204 | x++; | ||
205 | x->rx_buf = &rbuf[1]; | ||
206 | x->len = rlen - 1; | ||
207 | spi_message_add_tail(x, &m); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | r = spi_sync(spi, &m); | ||
212 | if (r < 0) | ||
213 | dev_dbg(&spi->dev, "spi_sync %d\n", r); | ||
214 | |||
215 | if (rlen) | ||
216 | rbuf[0] = w & 0xff; | ||
217 | } | ||
218 | |||
219 | static inline void mipid_cmd(struct spi_device *spi, int cmd) | ||
220 | { | ||
221 | mipid_transfer(spi, cmd, NULL, 0, NULL, 0); | ||
222 | } | ||
223 | |||
224 | static inline void mipid_write(struct spi_device *spi, | ||
225 | int reg, const u8 *buf, int len) | ||
226 | { | ||
227 | mipid_transfer(spi, reg, buf, len, NULL, 0); | ||
228 | } | ||
229 | |||
230 | static inline void mipid_read(struct spi_device *spi, | ||
231 | int reg, u8 *buf, int len) | ||
232 | { | ||
233 | mipid_transfer(spi, reg, NULL, 0, buf, len); | ||
234 | } | ||
235 | |||
236 | static void set_data_lines(struct spi_device *spi, int data_lines) | ||
237 | { | ||
238 | u16 par; | ||
239 | |||
240 | switch (data_lines) { | ||
241 | case 16: | ||
242 | par = 0x150; | ||
243 | break; | ||
244 | case 18: | ||
245 | par = 0x160; | ||
246 | break; | ||
247 | case 24: | ||
248 | par = 0x170; | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | mipid_write(spi, 0x3a, (u8 *)&par, 2); | ||
253 | } | ||
254 | |||
255 | static void send_init_string(struct spi_device *spi) | ||
256 | { | ||
257 | u16 initpar[] = { 0x0102, 0x0100, 0x0100 }; | ||
258 | mipid_write(spi, 0xc2, (u8 *)initpar, sizeof(initpar)); | ||
259 | } | ||
260 | |||
261 | static void send_display_on(struct spi_device *spi) | ||
262 | { | ||
263 | mipid_cmd(spi, MIPID_CMD_DISP_ON); | ||
264 | } | ||
265 | |||
266 | static void send_display_off(struct spi_device *spi) | ||
267 | { | ||
268 | mipid_cmd(spi, MIPID_CMD_DISP_OFF); | ||
269 | } | ||
270 | |||
271 | static void send_sleep_out(struct spi_device *spi) | ||
272 | { | ||
273 | mipid_cmd(spi, MIPID_CMD_SLEEP_OUT); | ||
274 | msleep(120); | ||
275 | } | ||
276 | |||
277 | static void send_sleep_in(struct spi_device *spi) | ||
278 | { | ||
279 | mipid_cmd(spi, MIPID_CMD_SLEEP_IN); | ||
280 | msleep(50); | ||
281 | } | ||
282 | |||
283 | static int n8x0_panel_power_on(struct omap_dss_device *dssdev) | ||
284 | { | ||
285 | int r; | ||
286 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
287 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
288 | struct spi_device *spi = ddata->spidev; | ||
289 | u8 rev, conf; | ||
290 | u8 display_id[3]; | ||
291 | const char *panel_name; | ||
292 | |||
293 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
294 | return 0; | ||
295 | |||
296 | gpio_direction_output(bdata->ctrl_pwrdown, 1); | ||
297 | |||
298 | omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, | ||
299 | dssdev->panel.timings.y_res); | ||
300 | omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); | ||
301 | omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines); | ||
302 | omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings); | ||
303 | |||
304 | r = omapdss_rfbi_display_enable(dssdev); | ||
305 | if (r) | ||
306 | goto err_rfbi_en; | ||
307 | |||
308 | rev = blizzard_read_reg(BLIZZARD_REV_CODE); | ||
309 | conf = blizzard_read_reg(BLIZZARD_CONFIG); | ||
310 | |||
311 | switch (rev & 0xfc) { | ||
312 | case 0x9c: | ||
313 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744; | ||
314 | dev_info(dssdev->dev, "s1d13744 LCD controller rev %d " | ||
315 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
316 | break; | ||
317 | case 0xa4: | ||
318 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745; | ||
319 | dev_info(dssdev->dev, "s1d13745 LCD controller rev %d " | ||
320 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
321 | break; | ||
322 | default: | ||
323 | dev_err(dssdev->dev, "invalid s1d1374x revision %02x\n", rev); | ||
324 | r = -ENODEV; | ||
325 | goto err_inv_chip; | ||
326 | } | ||
327 | |||
328 | /* panel */ | ||
329 | |||
330 | gpio_direction_output(bdata->panel_reset, 1); | ||
331 | |||
332 | mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3); | ||
333 | dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n", | ||
334 | display_id[0], display_id[1], display_id[2]); | ||
335 | |||
336 | switch (display_id[0]) { | ||
337 | case 0x45: | ||
338 | panel_name = "lph8923"; | ||
339 | break; | ||
340 | case 0x83: | ||
341 | panel_name = "ls041y3"; | ||
342 | break; | ||
343 | default: | ||
344 | dev_err(dssdev->dev, "invalid display ID 0x%x\n", | ||
345 | display_id[0]); | ||
346 | r = -ENODEV; | ||
347 | goto err_inv_panel; | ||
348 | } | ||
349 | |||
350 | dev_info(dssdev->dev, "%s rev %02x LCD detected\n", | ||
351 | panel_name, display_id[1]); | ||
352 | |||
353 | send_sleep_out(spi); | ||
354 | send_init_string(spi); | ||
355 | set_data_lines(spi, 24); | ||
356 | send_display_on(spi); | ||
357 | |||
358 | return 0; | ||
359 | |||
360 | err_inv_panel: | ||
361 | /* | ||
362 | * HACK: we should turn off the panel here, but there is some problem | ||
363 | * with the initialization sequence, and we fail to init the panel if we | ||
364 | * have turned it off | ||
365 | */ | ||
366 | /* gpio_direction_output(bdata->panel_reset, 0); */ | ||
367 | err_inv_chip: | ||
368 | omapdss_rfbi_display_disable(dssdev); | ||
369 | err_rfbi_en: | ||
370 | gpio_direction_output(bdata->ctrl_pwrdown, 0); | ||
371 | return r; | ||
372 | } | ||
373 | |||
374 | static void n8x0_panel_power_off(struct omap_dss_device *dssdev) | ||
375 | { | ||
376 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
377 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
378 | struct spi_device *spi = ddata->spidev; | ||
379 | |||
380 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
381 | return; | ||
382 | |||
383 | send_display_off(spi); | ||
384 | send_sleep_in(spi); | ||
385 | |||
386 | /* | ||
387 | * HACK: we should turn off the panel here, but there is some problem | ||
388 | * with the initialization sequence, and we fail to init the panel if we | ||
389 | * have turned it off | ||
390 | */ | ||
391 | /* gpio_direction_output(bdata->panel_reset, 0); */ | ||
392 | gpio_direction_output(bdata->ctrl_pwrdown, 0); | ||
393 | omapdss_rfbi_display_disable(dssdev); | ||
394 | } | ||
395 | |||
396 | static const struct rfbi_timings n8x0_panel_timings = { | ||
397 | .cs_on_time = 0, | ||
398 | |||
399 | .we_on_time = 9000, | ||
400 | .we_off_time = 18000, | ||
401 | .we_cycle_time = 36000, | ||
402 | |||
403 | .re_on_time = 9000, | ||
404 | .re_off_time = 27000, | ||
405 | .re_cycle_time = 36000, | ||
406 | |||
407 | .access_time = 27000, | ||
408 | .cs_off_time = 36000, | ||
409 | |||
410 | .cs_pulse_width = 0, | ||
411 | }; | ||
412 | |||
413 | static int n8x0_panel_probe(struct omap_dss_device *dssdev) | ||
414 | { | ||
415 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
416 | struct panel_drv_data *ddata; | ||
417 | int r; | ||
418 | |||
419 | dev_dbg(dssdev->dev, "probe\n"); | ||
420 | |||
421 | if (!bdata) | ||
422 | return -EINVAL; | ||
423 | |||
424 | s_drv_data.dssdev = dssdev; | ||
425 | |||
426 | ddata = &s_drv_data; | ||
427 | |||
428 | mutex_init(&ddata->lock); | ||
429 | |||
430 | dssdev->panel.timings.x_res = 800; | ||
431 | dssdev->panel.timings.y_res = 480; | ||
432 | dssdev->ctrl.pixel_size = 16; | ||
433 | dssdev->ctrl.rfbi_timings = n8x0_panel_timings; | ||
434 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
435 | |||
436 | if (gpio_is_valid(bdata->panel_reset)) { | ||
437 | r = devm_gpio_request_one(dssdev->dev, bdata->panel_reset, | ||
438 | GPIOF_OUT_INIT_LOW, "PANEL RESET"); | ||
439 | if (r) | ||
440 | return r; | ||
441 | } | ||
442 | |||
443 | if (gpio_is_valid(bdata->ctrl_pwrdown)) { | ||
444 | r = devm_gpio_request_one(dssdev->dev, bdata->ctrl_pwrdown, | ||
445 | GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN"); | ||
446 | if (r) | ||
447 | return r; | ||
448 | } | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static void n8x0_panel_remove(struct omap_dss_device *dssdev) | ||
454 | { | ||
455 | dev_dbg(dssdev->dev, "remove\n"); | ||
456 | |||
457 | dev_set_drvdata(dssdev->dev, NULL); | ||
458 | } | ||
459 | |||
460 | static int n8x0_panel_enable(struct omap_dss_device *dssdev) | ||
461 | { | ||
462 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
463 | int r; | ||
464 | |||
465 | dev_dbg(dssdev->dev, "enable\n"); | ||
466 | |||
467 | mutex_lock(&ddata->lock); | ||
468 | |||
469 | rfbi_bus_lock(); | ||
470 | |||
471 | r = n8x0_panel_power_on(dssdev); | ||
472 | |||
473 | rfbi_bus_unlock(); | ||
474 | |||
475 | if (r) { | ||
476 | mutex_unlock(&ddata->lock); | ||
477 | return r; | ||
478 | } | ||
479 | |||
480 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
481 | |||
482 | mutex_unlock(&ddata->lock); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static void n8x0_panel_disable(struct omap_dss_device *dssdev) | ||
488 | { | ||
489 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
490 | |||
491 | dev_dbg(dssdev->dev, "disable\n"); | ||
492 | |||
493 | mutex_lock(&ddata->lock); | ||
494 | |||
495 | rfbi_bus_lock(); | ||
496 | |||
497 | n8x0_panel_power_off(dssdev); | ||
498 | |||
499 | rfbi_bus_unlock(); | ||
500 | |||
501 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
502 | |||
503 | mutex_unlock(&ddata->lock); | ||
504 | } | ||
505 | |||
506 | static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, | ||
507 | u16 *xres, u16 *yres) | ||
508 | { | ||
509 | *xres = dssdev->panel.timings.x_res; | ||
510 | *yres = dssdev->panel.timings.y_res; | ||
511 | } | ||
512 | |||
513 | static void update_done(void *data) | ||
514 | { | ||
515 | rfbi_bus_unlock(); | ||
516 | } | ||
517 | |||
518 | static int n8x0_panel_update(struct omap_dss_device *dssdev, | ||
519 | u16 x, u16 y, u16 w, u16 h) | ||
520 | { | ||
521 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
522 | u16 dw, dh; | ||
523 | |||
524 | dev_dbg(dssdev->dev, "update\n"); | ||
525 | |||
526 | dw = dssdev->panel.timings.x_res; | ||
527 | dh = dssdev->panel.timings.y_res; | ||
528 | |||
529 | if (x != 0 || y != 0 || w != dw || h != dh) { | ||
530 | dev_err(dssdev->dev, "invalid update region %d, %d, %d, %d\n", | ||
531 | x, y, w, h); | ||
532 | return -EINVAL; | ||
533 | } | ||
534 | |||
535 | mutex_lock(&ddata->lock); | ||
536 | rfbi_bus_lock(); | ||
537 | |||
538 | blizzard_ctrl_setup_update(dssdev, x, y, w, h); | ||
539 | |||
540 | omap_rfbi_update(dssdev, update_done, NULL); | ||
541 | |||
542 | mutex_unlock(&ddata->lock); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int n8x0_panel_sync(struct omap_dss_device *dssdev) | ||
548 | { | ||
549 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
550 | |||
551 | dev_dbg(dssdev->dev, "sync\n"); | ||
552 | |||
553 | mutex_lock(&ddata->lock); | ||
554 | rfbi_bus_lock(); | ||
555 | rfbi_bus_unlock(); | ||
556 | mutex_unlock(&ddata->lock); | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static struct omap_dss_driver n8x0_panel_driver = { | ||
562 | .probe = n8x0_panel_probe, | ||
563 | .remove = n8x0_panel_remove, | ||
564 | |||
565 | .enable = n8x0_panel_enable, | ||
566 | .disable = n8x0_panel_disable, | ||
567 | |||
568 | .update = n8x0_panel_update, | ||
569 | .sync = n8x0_panel_sync, | ||
570 | |||
571 | .get_resolution = n8x0_panel_get_resolution, | ||
572 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
573 | |||
574 | .driver = { | ||
575 | .name = "n8x0_panel", | ||
576 | .owner = THIS_MODULE, | ||
577 | }, | ||
578 | }; | ||
579 | |||
580 | /* PANEL */ | ||
581 | |||
582 | static int mipid_spi_probe(struct spi_device *spi) | ||
583 | { | ||
584 | int r; | ||
585 | |||
586 | dev_dbg(&spi->dev, "mipid_spi_probe\n"); | ||
587 | |||
588 | spi->mode = SPI_MODE_0; | ||
589 | |||
590 | s_drv_data.spidev = spi; | ||
591 | |||
592 | r = omap_dss_register_driver(&n8x0_panel_driver); | ||
593 | if (r) | ||
594 | pr_err("n8x0_panel: dss driver registration failed\n"); | ||
595 | |||
596 | return r; | ||
597 | } | ||
598 | |||
599 | static int mipid_spi_remove(struct spi_device *spi) | ||
600 | { | ||
601 | dev_dbg(&spi->dev, "mipid_spi_remove\n"); | ||
602 | omap_dss_unregister_driver(&n8x0_panel_driver); | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static struct spi_driver mipid_spi_driver = { | ||
607 | .driver = { | ||
608 | .name = "lcd_mipid", | ||
609 | .owner = THIS_MODULE, | ||
610 | }, | ||
611 | .probe = mipid_spi_probe, | ||
612 | .remove = mipid_spi_remove, | ||
613 | }; | ||
614 | module_spi_driver(mipid_spi_driver); | ||
615 | |||
616 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c deleted file mode 100644 index 6b9f7925e918..000000000000 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ /dev/null | |||
@@ -1,290 +0,0 @@ | |||
1 | /* | ||
2 | * Support for NEC-nl8048hl11-01b panel driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along with | ||
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/fb.h> | ||
23 | #include <linux/gpio.h> | ||
24 | |||
25 | #include <video/omapdss.h> | ||
26 | #include <video/omap-panel-data.h> | ||
27 | |||
28 | #define LCD_XRES 800 | ||
29 | #define LCD_YRES 480 | ||
30 | /* | ||
31 | * NEC PIX Clock Ratings | ||
32 | * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz | ||
33 | */ | ||
34 | #define LCD_PIXEL_CLOCK 23800 | ||
35 | |||
36 | static const struct { | ||
37 | unsigned char addr; | ||
38 | unsigned char dat; | ||
39 | } nec_8048_init_seq[] = { | ||
40 | { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 }, | ||
41 | { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 }, | ||
42 | { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 }, | ||
43 | { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F }, | ||
44 | { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F }, | ||
45 | { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F }, | ||
46 | { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F }, | ||
47 | { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, | ||
48 | { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 }, | ||
49 | { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C }, | ||
50 | { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, | ||
51 | { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 }, | ||
52 | { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 }, | ||
53 | { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 }, | ||
54 | { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC }, | ||
55 | { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, | ||
56 | { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 }, | ||
57 | { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 }, | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * NEC NL8048HL11-01B Manual | ||
62 | * defines HFB, HSW, HBP, VFP, VSW, VBP as shown below | ||
63 | */ | ||
64 | |||
65 | static struct omap_video_timings nec_8048_panel_timings = { | ||
66 | /* 800 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ | ||
67 | .x_res = LCD_XRES, | ||
68 | .y_res = LCD_YRES, | ||
69 | .pixel_clock = LCD_PIXEL_CLOCK, | ||
70 | .hfp = 6, | ||
71 | .hsw = 1, | ||
72 | .hbp = 4, | ||
73 | .vfp = 3, | ||
74 | .vsw = 1, | ||
75 | .vbp = 4, | ||
76 | |||
77 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
78 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
79 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
80 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
81 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
82 | }; | ||
83 | |||
84 | static inline struct panel_nec_nl8048_data | ||
85 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
86 | { | ||
87 | return (struct panel_nec_nl8048_data *) dssdev->data; | ||
88 | } | ||
89 | |||
90 | static int nec_8048_panel_probe(struct omap_dss_device *dssdev) | ||
91 | { | ||
92 | struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); | ||
93 | int r; | ||
94 | |||
95 | if (!pd) | ||
96 | return -EINVAL; | ||
97 | |||
98 | dssdev->panel.timings = nec_8048_panel_timings; | ||
99 | |||
100 | if (gpio_is_valid(pd->qvga_gpio)) { | ||
101 | r = devm_gpio_request_one(dssdev->dev, pd->qvga_gpio, | ||
102 | GPIOF_OUT_INIT_HIGH, "lcd QVGA"); | ||
103 | if (r) | ||
104 | return r; | ||
105 | } | ||
106 | |||
107 | if (gpio_is_valid(pd->res_gpio)) { | ||
108 | r = devm_gpio_request_one(dssdev->dev, pd->res_gpio, | ||
109 | GPIOF_OUT_INIT_LOW, "lcd RES"); | ||
110 | if (r) | ||
111 | return r; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static void nec_8048_panel_remove(struct omap_dss_device *dssdev) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) | ||
122 | { | ||
123 | struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); | ||
124 | int r; | ||
125 | |||
126 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
127 | return 0; | ||
128 | |||
129 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
130 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
131 | |||
132 | r = omapdss_dpi_display_enable(dssdev); | ||
133 | if (r) | ||
134 | goto err0; | ||
135 | |||
136 | if (gpio_is_valid(pd->res_gpio)) | ||
137 | gpio_set_value_cansleep(pd->res_gpio, 1); | ||
138 | |||
139 | return 0; | ||
140 | |||
141 | err0: | ||
142 | return r; | ||
143 | } | ||
144 | |||
145 | static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) | ||
146 | { | ||
147 | struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); | ||
148 | |||
149 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
150 | return; | ||
151 | |||
152 | if (gpio_is_valid(pd->res_gpio)) | ||
153 | gpio_set_value_cansleep(pd->res_gpio, 0); | ||
154 | |||
155 | omapdss_dpi_display_disable(dssdev); | ||
156 | } | ||
157 | |||
158 | static int nec_8048_panel_enable(struct omap_dss_device *dssdev) | ||
159 | { | ||
160 | int r; | ||
161 | |||
162 | r = nec_8048_panel_power_on(dssdev); | ||
163 | if (r) | ||
164 | return r; | ||
165 | |||
166 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void nec_8048_panel_disable(struct omap_dss_device *dssdev) | ||
172 | { | ||
173 | nec_8048_panel_power_off(dssdev); | ||
174 | |||
175 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
176 | } | ||
177 | |||
178 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) | ||
179 | { | ||
180 | return 16; | ||
181 | } | ||
182 | |||
183 | static struct omap_dss_driver nec_8048_driver = { | ||
184 | .probe = nec_8048_panel_probe, | ||
185 | .remove = nec_8048_panel_remove, | ||
186 | .enable = nec_8048_panel_enable, | ||
187 | .disable = nec_8048_panel_disable, | ||
188 | .get_recommended_bpp = nec_8048_recommended_bpp, | ||
189 | |||
190 | .driver = { | ||
191 | .name = "NEC_8048_panel", | ||
192 | .owner = THIS_MODULE, | ||
193 | }, | ||
194 | }; | ||
195 | |||
196 | static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr, | ||
197 | unsigned char reg_data) | ||
198 | { | ||
199 | int ret = 0; | ||
200 | unsigned int cmd = 0, data = 0; | ||
201 | |||
202 | cmd = 0x0000 | reg_addr; /* register address write */ | ||
203 | data = 0x0100 | reg_data ; /* register data write */ | ||
204 | data = (cmd << 16) | data; | ||
205 | |||
206 | ret = spi_write(spi, (unsigned char *)&data, 4); | ||
207 | if (ret) | ||
208 | pr_err("error in spi_write %x\n", data); | ||
209 | |||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static int init_nec_8048_wvga_lcd(struct spi_device *spi) | ||
214 | { | ||
215 | unsigned int i; | ||
216 | /* Initialization Sequence */ | ||
217 | /* nec_8048_spi_send(spi, REG, VAL) */ | ||
218 | for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++) | ||
219 | nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, | ||
220 | nec_8048_init_seq[i].dat); | ||
221 | udelay(20); | ||
222 | nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, | ||
223 | nec_8048_init_seq[i].dat); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int nec_8048_spi_probe(struct spi_device *spi) | ||
228 | { | ||
229 | spi->mode = SPI_MODE_0; | ||
230 | spi->bits_per_word = 32; | ||
231 | spi_setup(spi); | ||
232 | |||
233 | init_nec_8048_wvga_lcd(spi); | ||
234 | |||
235 | return omap_dss_register_driver(&nec_8048_driver); | ||
236 | } | ||
237 | |||
238 | static int nec_8048_spi_remove(struct spi_device *spi) | ||
239 | { | ||
240 | omap_dss_unregister_driver(&nec_8048_driver); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | #ifdef CONFIG_PM_SLEEP | ||
246 | |||
247 | static int nec_8048_spi_suspend(struct device *dev) | ||
248 | { | ||
249 | struct spi_device *spi = to_spi_device(dev); | ||
250 | |||
251 | nec_8048_spi_send(spi, 2, 0x01); | ||
252 | mdelay(40); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int nec_8048_spi_resume(struct device *dev) | ||
258 | { | ||
259 | struct spi_device *spi = to_spi_device(dev); | ||
260 | |||
261 | /* reinitialize the panel */ | ||
262 | spi_setup(spi); | ||
263 | nec_8048_spi_send(spi, 2, 0x00); | ||
264 | init_nec_8048_wvga_lcd(spi); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static SIMPLE_DEV_PM_OPS(nec_8048_spi_pm_ops, nec_8048_spi_suspend, | ||
270 | nec_8048_spi_resume); | ||
271 | #define NEC_8048_SPI_PM_OPS (&nec_8048_spi_pm_ops) | ||
272 | #else | ||
273 | #define NEC_8048_SPI_PM_OPS NULL | ||
274 | #endif | ||
275 | |||
276 | static struct spi_driver nec_8048_spi_driver = { | ||
277 | .probe = nec_8048_spi_probe, | ||
278 | .remove = nec_8048_spi_remove, | ||
279 | .driver = { | ||
280 | .name = "nec_8048_spi", | ||
281 | .owner = THIS_MODULE, | ||
282 | .pm = NEC_8048_SPI_PM_OPS, | ||
283 | }, | ||
284 | }; | ||
285 | |||
286 | module_spi_driver(nec_8048_spi_driver); | ||
287 | |||
288 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); | ||
289 | MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); | ||
290 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c deleted file mode 100644 index 153e9bea0f6e..000000000000 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ /dev/null | |||
@@ -1,559 +0,0 @@ | |||
1 | /* | ||
2 | * picodlp panel driver | ||
3 | * picodlp_i2c_driver: i2c_client driver | ||
4 | * | ||
5 | * Copyright (C) 2009-2011 Texas Instruments | ||
6 | * Author: Mythri P K <mythripk@ti.com> | ||
7 | * Mayuresh Janorkar <mayur@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/gpio.h> | ||
32 | |||
33 | #include <video/omapdss.h> | ||
34 | #include <video/omap-panel-data.h> | ||
35 | |||
36 | #include "panel-picodlp.h" | ||
37 | |||
38 | struct picodlp_data { | ||
39 | struct mutex lock; | ||
40 | struct i2c_client *picodlp_i2c_client; | ||
41 | }; | ||
42 | |||
43 | static struct i2c_board_info picodlp_i2c_board_info = { | ||
44 | I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b), | ||
45 | }; | ||
46 | |||
47 | struct picodlp_i2c_data { | ||
48 | struct mutex xfer_lock; | ||
49 | }; | ||
50 | |||
51 | static struct i2c_device_id picodlp_i2c_id[] = { | ||
52 | { "picodlp_i2c_driver", 0 }, | ||
53 | { } | ||
54 | }; | ||
55 | |||
56 | struct picodlp_i2c_command { | ||
57 | u8 reg; | ||
58 | u32 value; | ||
59 | }; | ||
60 | |||
61 | static struct omap_video_timings pico_ls_timings = { | ||
62 | .x_res = 864, | ||
63 | .y_res = 480, | ||
64 | .hsw = 7, | ||
65 | .hfp = 11, | ||
66 | .hbp = 7, | ||
67 | |||
68 | .pixel_clock = 19200, | ||
69 | |||
70 | .vsw = 2, | ||
71 | .vfp = 3, | ||
72 | .vbp = 14, | ||
73 | |||
74 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
75 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
76 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
77 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
78 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
79 | }; | ||
80 | |||
81 | static inline struct picodlp_panel_data | ||
82 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
83 | { | ||
84 | return (struct picodlp_panel_data *) dssdev->data; | ||
85 | } | ||
86 | |||
87 | static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg) | ||
88 | { | ||
89 | u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4]; | ||
90 | struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); | ||
91 | struct i2c_msg msg[2]; | ||
92 | |||
93 | mutex_lock(&picodlp_i2c_data->xfer_lock); | ||
94 | |||
95 | msg[0].addr = client->addr; | ||
96 | msg[0].flags = 0; | ||
97 | msg[0].len = 2; | ||
98 | msg[0].buf = read_cmd; | ||
99 | |||
100 | msg[1].addr = client->addr; | ||
101 | msg[1].flags = I2C_M_RD; | ||
102 | msg[1].len = 4; | ||
103 | msg[1].buf = data; | ||
104 | |||
105 | i2c_transfer(client->adapter, msg, 2); | ||
106 | mutex_unlock(&picodlp_i2c_data->xfer_lock); | ||
107 | return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24)); | ||
108 | } | ||
109 | |||
110 | static int picodlp_i2c_write_block(struct i2c_client *client, | ||
111 | u8 *data, int len) | ||
112 | { | ||
113 | struct i2c_msg msg; | ||
114 | int i, r, msg_count = 1; | ||
115 | |||
116 | struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); | ||
117 | |||
118 | if (len < 1 || len > 32) { | ||
119 | dev_err(&client->dev, | ||
120 | "too long syn_write_block len %d\n", len); | ||
121 | return -EIO; | ||
122 | } | ||
123 | mutex_lock(&picodlp_i2c_data->xfer_lock); | ||
124 | |||
125 | msg.addr = client->addr; | ||
126 | msg.flags = 0; | ||
127 | msg.len = len; | ||
128 | msg.buf = data; | ||
129 | r = i2c_transfer(client->adapter, &msg, msg_count); | ||
130 | mutex_unlock(&picodlp_i2c_data->xfer_lock); | ||
131 | |||
132 | /* | ||
133 | * i2c_transfer returns: | ||
134 | * number of messages sent in case of success | ||
135 | * a negative error number in case of failure | ||
136 | */ | ||
137 | if (r != msg_count) | ||
138 | goto err; | ||
139 | |||
140 | /* In case of success */ | ||
141 | for (i = 0; i < len; i++) | ||
142 | dev_dbg(&client->dev, | ||
143 | "addr %x bw 0x%02x[%d]: 0x%02x\n", | ||
144 | client->addr, data[0] + i, i, data[i]); | ||
145 | |||
146 | return 0; | ||
147 | err: | ||
148 | dev_err(&client->dev, "picodlp_i2c_write error\n"); | ||
149 | return r; | ||
150 | } | ||
151 | |||
152 | static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value) | ||
153 | { | ||
154 | u8 data[5]; | ||
155 | int i; | ||
156 | |||
157 | data[0] = reg; | ||
158 | for (i = 1; i < 5; i++) | ||
159 | data[i] = (value >> (32 - (i) * 8)) & 0xFF; | ||
160 | |||
161 | return picodlp_i2c_write_block(client, data, 5); | ||
162 | } | ||
163 | |||
164 | static int picodlp_i2c_write_array(struct i2c_client *client, | ||
165 | const struct picodlp_i2c_command commands[], | ||
166 | int count) | ||
167 | { | ||
168 | int i, r = 0; | ||
169 | for (i = 0; i < count; i++) { | ||
170 | r = picodlp_i2c_write(client, commands[i].reg, | ||
171 | commands[i].value); | ||
172 | if (r) | ||
173 | return r; | ||
174 | } | ||
175 | return r; | ||
176 | } | ||
177 | |||
178 | static int picodlp_wait_for_dma_done(struct i2c_client *client) | ||
179 | { | ||
180 | u8 trial = 100; | ||
181 | |||
182 | do { | ||
183 | msleep(1); | ||
184 | if (!trial--) | ||
185 | return -ETIMEDOUT; | ||
186 | } while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * picodlp_i2c_init: i2c_initialization routine | ||
193 | * client: i2c_client for communication | ||
194 | * | ||
195 | * return | ||
196 | * 0 : Success, no error | ||
197 | * error code : Failure | ||
198 | */ | ||
199 | static int picodlp_i2c_init(struct i2c_client *client) | ||
200 | { | ||
201 | int r; | ||
202 | static const struct picodlp_i2c_command init_cmd_set1[] = { | ||
203 | {SOFT_RESET, 1}, | ||
204 | {DMD_PARK_TRIGGER, 1}, | ||
205 | {MISC_REG, 5}, | ||
206 | {SEQ_CONTROL, 0}, | ||
207 | {SEQ_VECTOR, 0x100}, | ||
208 | {DMD_BLOCK_COUNT, 7}, | ||
209 | {DMD_VCC_CONTROL, 0x109}, | ||
210 | {DMD_PARK_PULSE_COUNT, 0xA}, | ||
211 | {DMD_PARK_PULSE_WIDTH, 0xB}, | ||
212 | {DMD_PARK_DELAY, 0x2ED}, | ||
213 | {DMD_SHADOW_ENABLE, 0}, | ||
214 | {FLASH_OPCODE, 0xB}, | ||
215 | {FLASH_DUMMY_BYTES, 1}, | ||
216 | {FLASH_ADDR_BYTES, 3}, | ||
217 | {PBC_CONTROL, 0}, | ||
218 | {FLASH_START_ADDR, CMT_LUT_0_START_ADDR}, | ||
219 | {FLASH_READ_BYTES, CMT_LUT_0_SIZE}, | ||
220 | {CMT_SPLASH_LUT_START_ADDR, 0}, | ||
221 | {CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL}, | ||
222 | {PBC_CONTROL, 1}, | ||
223 | }; | ||
224 | |||
225 | static const struct picodlp_i2c_command init_cmd_set2[] = { | ||
226 | {PBC_CONTROL, 0}, | ||
227 | {CMT_SPLASH_LUT_DEST_SELECT, 0}, | ||
228 | {PBC_CONTROL, 0}, | ||
229 | {FLASH_START_ADDR, SEQUENCE_0_START_ADDR}, | ||
230 | {FLASH_READ_BYTES, SEQUENCE_0_SIZE}, | ||
231 | {SEQ_RESET_LUT_START_ADDR, 0}, | ||
232 | {SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT}, | ||
233 | {PBC_CONTROL, 1}, | ||
234 | }; | ||
235 | |||
236 | static const struct picodlp_i2c_command init_cmd_set3[] = { | ||
237 | {PBC_CONTROL, 0}, | ||
238 | {SEQ_RESET_LUT_DEST_SELECT, 0}, | ||
239 | {PBC_CONTROL, 0}, | ||
240 | {FLASH_START_ADDR, DRC_TABLE_0_START_ADDR}, | ||
241 | {FLASH_READ_BYTES, DRC_TABLE_0_SIZE}, | ||
242 | {SEQ_RESET_LUT_START_ADDR, 0}, | ||
243 | {SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL}, | ||
244 | {PBC_CONTROL, 1}, | ||
245 | }; | ||
246 | |||
247 | static const struct picodlp_i2c_command init_cmd_set4[] = { | ||
248 | {PBC_CONTROL, 0}, | ||
249 | {SEQ_RESET_LUT_DEST_SELECT, 0}, | ||
250 | {SDC_ENABLE, 1}, | ||
251 | {AGC_CTRL, 7}, | ||
252 | {CCA_C1A, 0x100}, | ||
253 | {CCA_C1B, 0x0}, | ||
254 | {CCA_C1C, 0x0}, | ||
255 | {CCA_C2A, 0x0}, | ||
256 | {CCA_C2B, 0x100}, | ||
257 | {CCA_C2C, 0x0}, | ||
258 | {CCA_C3A, 0x0}, | ||
259 | {CCA_C3B, 0x0}, | ||
260 | {CCA_C3C, 0x100}, | ||
261 | {CCA_C7A, 0x100}, | ||
262 | {CCA_C7B, 0x100}, | ||
263 | {CCA_C7C, 0x100}, | ||
264 | {CCA_ENABLE, 1}, | ||
265 | {CPU_IF_MODE, 1}, | ||
266 | {SHORT_FLIP, 1}, | ||
267 | {CURTAIN_CONTROL, 0}, | ||
268 | {DMD_PARK_TRIGGER, 0}, | ||
269 | {R_DRIVE_CURRENT, 0x298}, | ||
270 | {G_DRIVE_CURRENT, 0x298}, | ||
271 | {B_DRIVE_CURRENT, 0x298}, | ||
272 | {RGB_DRIVER_ENABLE, 7}, | ||
273 | {SEQ_CONTROL, 0}, | ||
274 | {ACTGEN_CONTROL, 0x10}, | ||
275 | {SEQUENCE_MODE, SEQ_LOCK}, | ||
276 | {DATA_FORMAT, RGB888}, | ||
277 | {INPUT_RESOLUTION, WVGA_864_LANDSCAPE}, | ||
278 | {INPUT_SOURCE, PARALLEL_RGB}, | ||
279 | {CPU_IF_SYNC_METHOD, 1}, | ||
280 | {SEQ_CONTROL, 1} | ||
281 | }; | ||
282 | |||
283 | r = picodlp_i2c_write_array(client, init_cmd_set1, | ||
284 | ARRAY_SIZE(init_cmd_set1)); | ||
285 | if (r) | ||
286 | return r; | ||
287 | |||
288 | r = picodlp_wait_for_dma_done(client); | ||
289 | if (r) | ||
290 | return r; | ||
291 | |||
292 | r = picodlp_i2c_write_array(client, init_cmd_set2, | ||
293 | ARRAY_SIZE(init_cmd_set2)); | ||
294 | if (r) | ||
295 | return r; | ||
296 | |||
297 | r = picodlp_wait_for_dma_done(client); | ||
298 | if (r) | ||
299 | return r; | ||
300 | |||
301 | r = picodlp_i2c_write_array(client, init_cmd_set3, | ||
302 | ARRAY_SIZE(init_cmd_set3)); | ||
303 | if (r) | ||
304 | return r; | ||
305 | |||
306 | r = picodlp_wait_for_dma_done(client); | ||
307 | if (r) | ||
308 | return r; | ||
309 | |||
310 | r = picodlp_i2c_write_array(client, init_cmd_set4, | ||
311 | ARRAY_SIZE(init_cmd_set4)); | ||
312 | if (r) | ||
313 | return r; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int picodlp_i2c_probe(struct i2c_client *client, | ||
319 | const struct i2c_device_id *id) | ||
320 | { | ||
321 | struct picodlp_i2c_data *picodlp_i2c_data; | ||
322 | |||
323 | picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL); | ||
324 | |||
325 | if (!picodlp_i2c_data) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | mutex_init(&picodlp_i2c_data->xfer_lock); | ||
329 | i2c_set_clientdata(client, picodlp_i2c_data); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int picodlp_i2c_remove(struct i2c_client *client) | ||
335 | { | ||
336 | struct picodlp_i2c_data *picodlp_i2c_data = | ||
337 | i2c_get_clientdata(client); | ||
338 | kfree(picodlp_i2c_data); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static struct i2c_driver picodlp_i2c_driver = { | ||
343 | .driver = { | ||
344 | .name = "picodlp_i2c_driver", | ||
345 | }, | ||
346 | .probe = picodlp_i2c_probe, | ||
347 | .remove = picodlp_i2c_remove, | ||
348 | .id_table = picodlp_i2c_id, | ||
349 | }; | ||
350 | |||
351 | static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | ||
352 | { | ||
353 | int r, trial = 100; | ||
354 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); | ||
355 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | ||
356 | |||
357 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | ||
358 | msleep(1); | ||
359 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); | ||
360 | |||
361 | while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) { | ||
362 | if (!trial--) { | ||
363 | dev_err(dssdev->dev, "emu_done signal not" | ||
364 | " going high\n"); | ||
365 | return -ETIMEDOUT; | ||
366 | } | ||
367 | msleep(5); | ||
368 | } | ||
369 | /* | ||
370 | * As per dpp2600 programming guide, | ||
371 | * it is required to sleep for 1000ms after emu_done signal goes high | ||
372 | * then only i2c commands can be successfully sent to dpp2600 | ||
373 | */ | ||
374 | msleep(1000); | ||
375 | |||
376 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
377 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
378 | |||
379 | r = omapdss_dpi_display_enable(dssdev); | ||
380 | if (r) { | ||
381 | dev_err(dssdev->dev, "failed to enable DPI\n"); | ||
382 | goto err1; | ||
383 | } | ||
384 | |||
385 | r = picodlp_i2c_init(picod->picodlp_i2c_client); | ||
386 | if (r) | ||
387 | goto err; | ||
388 | |||
389 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
390 | |||
391 | return r; | ||
392 | err: | ||
393 | omapdss_dpi_display_disable(dssdev); | ||
394 | err1: | ||
395 | return r; | ||
396 | } | ||
397 | |||
398 | static void picodlp_panel_power_off(struct omap_dss_device *dssdev) | ||
399 | { | ||
400 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | ||
401 | |||
402 | omapdss_dpi_display_disable(dssdev); | ||
403 | |||
404 | gpio_set_value(picodlp_pdata->emu_done_gpio, 0); | ||
405 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | ||
406 | } | ||
407 | |||
408 | static int picodlp_panel_probe(struct omap_dss_device *dssdev) | ||
409 | { | ||
410 | struct picodlp_data *picod; | ||
411 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | ||
412 | struct i2c_adapter *adapter; | ||
413 | struct i2c_client *picodlp_i2c_client; | ||
414 | int r, picodlp_adapter_id; | ||
415 | |||
416 | dssdev->panel.timings = pico_ls_timings; | ||
417 | |||
418 | if (!picodlp_pdata) | ||
419 | return -EINVAL; | ||
420 | |||
421 | picod = devm_kzalloc(dssdev->dev, sizeof(*picod), GFP_KERNEL); | ||
422 | if (!picod) | ||
423 | return -ENOMEM; | ||
424 | |||
425 | mutex_init(&picod->lock); | ||
426 | |||
427 | picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id; | ||
428 | |||
429 | adapter = i2c_get_adapter(picodlp_adapter_id); | ||
430 | if (!adapter) { | ||
431 | dev_err(dssdev->dev, "can't get i2c adapter\n"); | ||
432 | return -ENODEV; | ||
433 | } | ||
434 | |||
435 | picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); | ||
436 | if (!picodlp_i2c_client) { | ||
437 | dev_err(dssdev->dev, "can't add i2c device::" | ||
438 | " picodlp_i2c_client is NULL\n"); | ||
439 | return -ENODEV; | ||
440 | } | ||
441 | |||
442 | picod->picodlp_i2c_client = picodlp_i2c_client; | ||
443 | |||
444 | dev_set_drvdata(dssdev->dev, picod); | ||
445 | |||
446 | if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) { | ||
447 | r = devm_gpio_request_one(dssdev->dev, | ||
448 | picodlp_pdata->emu_done_gpio, | ||
449 | GPIOF_IN, "DLP EMU DONE"); | ||
450 | if (r) | ||
451 | return r; | ||
452 | } | ||
453 | |||
454 | if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) { | ||
455 | r = devm_gpio_request_one(dssdev->dev, | ||
456 | picodlp_pdata->pwrgood_gpio, | ||
457 | GPIOF_OUT_INIT_LOW, "DLP PWRGOOD"); | ||
458 | if (r) | ||
459 | return r; | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static void picodlp_panel_remove(struct omap_dss_device *dssdev) | ||
466 | { | ||
467 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); | ||
468 | |||
469 | i2c_unregister_device(picod->picodlp_i2c_client); | ||
470 | dev_set_drvdata(dssdev->dev, NULL); | ||
471 | dev_dbg(dssdev->dev, "removing picodlp panel\n"); | ||
472 | } | ||
473 | |||
474 | static int picodlp_panel_enable(struct omap_dss_device *dssdev) | ||
475 | { | ||
476 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); | ||
477 | int r; | ||
478 | |||
479 | dev_dbg(dssdev->dev, "enabling picodlp panel\n"); | ||
480 | |||
481 | mutex_lock(&picod->lock); | ||
482 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
483 | mutex_unlock(&picod->lock); | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | r = picodlp_panel_power_on(dssdev); | ||
488 | mutex_unlock(&picod->lock); | ||
489 | |||
490 | return r; | ||
491 | } | ||
492 | |||
493 | static void picodlp_panel_disable(struct omap_dss_device *dssdev) | ||
494 | { | ||
495 | struct picodlp_data *picod = dev_get_drvdata(dssdev->dev); | ||
496 | |||
497 | mutex_lock(&picod->lock); | ||
498 | /* Turn off DLP Power */ | ||
499 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
500 | picodlp_panel_power_off(dssdev); | ||
501 | |||
502 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
503 | mutex_unlock(&picod->lock); | ||
504 | |||
505 | dev_dbg(dssdev->dev, "disabling picodlp panel\n"); | ||
506 | } | ||
507 | |||
508 | static void picodlp_get_resolution(struct omap_dss_device *dssdev, | ||
509 | u16 *xres, u16 *yres) | ||
510 | { | ||
511 | *xres = dssdev->panel.timings.x_res; | ||
512 | *yres = dssdev->panel.timings.y_res; | ||
513 | } | ||
514 | |||
515 | static struct omap_dss_driver picodlp_driver = { | ||
516 | .probe = picodlp_panel_probe, | ||
517 | .remove = picodlp_panel_remove, | ||
518 | |||
519 | .enable = picodlp_panel_enable, | ||
520 | .disable = picodlp_panel_disable, | ||
521 | |||
522 | .get_resolution = picodlp_get_resolution, | ||
523 | |||
524 | .driver = { | ||
525 | .name = "picodlp_panel", | ||
526 | .owner = THIS_MODULE, | ||
527 | }, | ||
528 | }; | ||
529 | |||
530 | static int __init picodlp_init(void) | ||
531 | { | ||
532 | int r = 0; | ||
533 | |||
534 | r = i2c_add_driver(&picodlp_i2c_driver); | ||
535 | if (r) { | ||
536 | printk(KERN_WARNING "picodlp_i2c_driver" \ | ||
537 | " registration failed\n"); | ||
538 | return r; | ||
539 | } | ||
540 | |||
541 | r = omap_dss_register_driver(&picodlp_driver); | ||
542 | if (r) | ||
543 | i2c_del_driver(&picodlp_i2c_driver); | ||
544 | |||
545 | return r; | ||
546 | } | ||
547 | |||
548 | static void __exit picodlp_exit(void) | ||
549 | { | ||
550 | i2c_del_driver(&picodlp_i2c_driver); | ||
551 | omap_dss_unregister_driver(&picodlp_driver); | ||
552 | } | ||
553 | |||
554 | module_init(picodlp_init); | ||
555 | module_exit(picodlp_exit); | ||
556 | |||
557 | MODULE_AUTHOR("Mythri P K <mythripk@ti.com>"); | ||
558 | MODULE_DESCRIPTION("picodlp driver"); | ||
559 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-picodlp.h b/drivers/video/omap2/displays/panel-picodlp.h deleted file mode 100644 index a34b431a7267..000000000000 --- a/drivers/video/omap2/displays/panel-picodlp.h +++ /dev/null | |||
@@ -1,288 +0,0 @@ | |||
1 | /* | ||
2 | * Header file required by picodlp panel driver | ||
3 | * | ||
4 | * Copyright (C) 2009-2011 Texas Instruments | ||
5 | * Author: Mythri P K <mythripk@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 | #ifndef __OMAP2_DISPLAY_PANEL_PICODLP_H | ||
21 | #define __OMAP2_DISPLAY_PANEL_PICODLP_H | ||
22 | |||
23 | /* Commands used for configuring picodlp panel */ | ||
24 | |||
25 | #define MAIN_STATUS 0x03 | ||
26 | #define PBC_CONTROL 0x08 | ||
27 | #define INPUT_SOURCE 0x0B | ||
28 | #define INPUT_RESOLUTION 0x0C | ||
29 | #define DATA_FORMAT 0x0D | ||
30 | #define IMG_ROTATION 0x0E | ||
31 | #define LONG_FLIP 0x0F | ||
32 | #define SHORT_FLIP 0x10 | ||
33 | #define TEST_PAT_SELECT 0x11 | ||
34 | #define R_DRIVE_CURRENT 0x12 | ||
35 | #define G_DRIVE_CURRENT 0x13 | ||
36 | #define B_DRIVE_CURRENT 0x14 | ||
37 | #define READ_REG_SELECT 0x15 | ||
38 | #define RGB_DRIVER_ENABLE 0x16 | ||
39 | |||
40 | #define CPU_IF_MODE 0x18 | ||
41 | #define FRAME_RATE 0x19 | ||
42 | #define CPU_IF_SYNC_METHOD 0x1A | ||
43 | #define CPU_IF_SOF 0x1B | ||
44 | #define CPU_IF_EOF 0x1C | ||
45 | #define CPU_IF_SLEEP 0x1D | ||
46 | |||
47 | #define SEQUENCE_MODE 0x1E | ||
48 | #define SOFT_RESET 0x1F | ||
49 | #define FRONT_END_RESET 0x21 | ||
50 | #define AUTO_PWR_ENABLE 0x22 | ||
51 | |||
52 | #define VSYNC_LINE_DELAY 0x23 | ||
53 | #define CPU_PI_HORIZ_START 0x24 | ||
54 | #define CPU_PI_VERT_START 0x25 | ||
55 | #define CPU_PI_HORIZ_WIDTH 0x26 | ||
56 | #define CPU_PI_VERT_HEIGHT 0x27 | ||
57 | |||
58 | #define PIXEL_MASK_CROP 0x28 | ||
59 | #define CROP_FIRST_LINE 0x29 | ||
60 | #define CROP_LAST_LINE 0x2A | ||
61 | #define CROP_FIRST_PIXEL 0x2B | ||
62 | #define CROP_LAST_PIXEL 0x2C | ||
63 | #define DMD_PARK_TRIGGER 0x2D | ||
64 | |||
65 | #define MISC_REG 0x30 | ||
66 | |||
67 | /* AGC registers */ | ||
68 | #define AGC_CTRL 0x50 | ||
69 | #define AGC_CLIPPED_PIXS 0x55 | ||
70 | #define AGC_BRIGHT_PIXS 0x56 | ||
71 | #define AGC_BG_PIXS 0x57 | ||
72 | #define AGC_SAFETY_MARGIN 0x17 | ||
73 | |||
74 | /* Color Coordinate Adjustment registers */ | ||
75 | #define CCA_ENABLE 0x5E | ||
76 | #define CCA_C1A 0x5F | ||
77 | #define CCA_C1B 0x60 | ||
78 | #define CCA_C1C 0x61 | ||
79 | #define CCA_C2A 0x62 | ||
80 | #define CCA_C2B 0x63 | ||
81 | #define CCA_C2C 0x64 | ||
82 | #define CCA_C3A 0x65 | ||
83 | #define CCA_C3B 0x66 | ||
84 | #define CCA_C3C 0x67 | ||
85 | #define CCA_C7A 0x71 | ||
86 | #define CCA_C7B 0x72 | ||
87 | #define CCA_C7C 0x73 | ||
88 | |||
89 | /** | ||
90 | * DLP Pico Processor 2600 comes with flash | ||
91 | * We can do DMA operations from flash for accessing Look Up Tables | ||
92 | */ | ||
93 | #define DMA_STATUS 0x100 | ||
94 | #define FLASH_ADDR_BYTES 0x74 | ||
95 | #define FLASH_DUMMY_BYTES 0x75 | ||
96 | #define FLASH_WRITE_BYTES 0x76 | ||
97 | #define FLASH_READ_BYTES 0x77 | ||
98 | #define FLASH_OPCODE 0x78 | ||
99 | #define FLASH_START_ADDR 0x79 | ||
100 | #define FLASH_DUMMY2 0x7A | ||
101 | #define FLASH_WRITE_DATA 0x7B | ||
102 | |||
103 | #define TEMPORAL_DITH_DISABLE 0x7E | ||
104 | #define SEQ_CONTROL 0x82 | ||
105 | #define SEQ_VECTOR 0x83 | ||
106 | |||
107 | /* DMD is Digital Micromirror Device */ | ||
108 | #define DMD_BLOCK_COUNT 0x84 | ||
109 | #define DMD_VCC_CONTROL 0x86 | ||
110 | #define DMD_PARK_PULSE_COUNT 0x87 | ||
111 | #define DMD_PARK_PULSE_WIDTH 0x88 | ||
112 | #define DMD_PARK_DELAY 0x89 | ||
113 | #define DMD_SHADOW_ENABLE 0x8E | ||
114 | #define SEQ_STATUS 0x8F | ||
115 | #define FLASH_CLOCK_CONTROL 0x98 | ||
116 | #define DMD_PARK 0x2D | ||
117 | |||
118 | #define SDRAM_BIST_ENABLE 0x46 | ||
119 | #define DDR_DRIVER_STRENGTH 0x9A | ||
120 | #define SDC_ENABLE 0x9D | ||
121 | #define SDC_BUFF_SWAP_DISABLE 0xA3 | ||
122 | #define CURTAIN_CONTROL 0xA6 | ||
123 | #define DDR_BUS_SWAP_ENABLE 0xA7 | ||
124 | #define DMD_TRC_ENABLE 0xA8 | ||
125 | #define DMD_BUS_SWAP_ENABLE 0xA9 | ||
126 | |||
127 | #define ACTGEN_ENABLE 0xAE | ||
128 | #define ACTGEN_CONTROL 0xAF | ||
129 | #define ACTGEN_HORIZ_BP 0xB0 | ||
130 | #define ACTGEN_VERT_BP 0xB1 | ||
131 | |||
132 | /* Look Up Table access */ | ||
133 | #define CMT_SPLASH_LUT_START_ADDR 0xFA | ||
134 | #define CMT_SPLASH_LUT_DEST_SELECT 0xFB | ||
135 | #define CMT_SPLASH_LUT_DATA 0xFC | ||
136 | #define SEQ_RESET_LUT_START_ADDR 0xFD | ||
137 | #define SEQ_RESET_LUT_DEST_SELECT 0xFE | ||
138 | #define SEQ_RESET_LUT_DATA 0xFF | ||
139 | |||
140 | /* Input source definitions */ | ||
141 | #define PARALLEL_RGB 0 | ||
142 | #define INT_TEST_PATTERN 1 | ||
143 | #define SPLASH_SCREEN 2 | ||
144 | #define CPU_INTF 3 | ||
145 | #define BT656 4 | ||
146 | |||
147 | /* Standard input resolution definitions */ | ||
148 | #define QWVGA_LANDSCAPE 3 /* (427h*240v) */ | ||
149 | #define WVGA_864_LANDSCAPE 21 /* (864h*480v) */ | ||
150 | #define WVGA_DMD_OPTICAL_TEST 35 /* (608h*684v) */ | ||
151 | |||
152 | /* Standard data format definitions */ | ||
153 | #define RGB565 0 | ||
154 | #define RGB666 1 | ||
155 | #define RGB888 2 | ||
156 | |||
157 | /* Test Pattern definitions */ | ||
158 | #define TPG_CHECKERBOARD 0 | ||
159 | #define TPG_BLACK 1 | ||
160 | #define TPG_WHITE 2 | ||
161 | #define TPG_RED 3 | ||
162 | #define TPG_BLUE 4 | ||
163 | #define TPG_GREEN 5 | ||
164 | #define TPG_VLINES_BLACK 6 | ||
165 | #define TPG_HLINES_BLACK 7 | ||
166 | #define TPG_VLINES_ALT 8 | ||
167 | #define TPG_HLINES_ALT 9 | ||
168 | #define TPG_DIAG_LINES 10 | ||
169 | #define TPG_GREYRAMP_VERT 11 | ||
170 | #define TPG_GREYRAMP_HORIZ 12 | ||
171 | #define TPG_ANSI_CHECKERBOARD 13 | ||
172 | |||
173 | /* sequence mode definitions */ | ||
174 | #define SEQ_FREE_RUN 0 | ||
175 | #define SEQ_LOCK 1 | ||
176 | |||
177 | /* curtain color definitions */ | ||
178 | #define CURTAIN_BLACK 0 | ||
179 | #define CURTAIN_RED 1 | ||
180 | #define CURTAIN_GREEN 2 | ||
181 | #define CURTAIN_BLUE 3 | ||
182 | #define CURTAIN_YELLOW 4 | ||
183 | #define CURTAIN_MAGENTA 5 | ||
184 | #define CURTAIN_CYAN 6 | ||
185 | #define CURTAIN_WHITE 7 | ||
186 | |||
187 | /* LUT definitions */ | ||
188 | #define CMT_LUT_NONE 0 | ||
189 | #define CMT_LUT_GREEN 1 | ||
190 | #define CMT_LUT_RED 2 | ||
191 | #define CMT_LUT_BLUE 3 | ||
192 | #define CMT_LUT_ALL 4 | ||
193 | #define SPLASH_LUT 5 | ||
194 | |||
195 | #define SEQ_LUT_NONE 0 | ||
196 | #define SEQ_DRC_LUT_0 1 | ||
197 | #define SEQ_DRC_LUT_1 2 | ||
198 | #define SEQ_DRC_LUT_2 3 | ||
199 | #define SEQ_DRC_LUT_3 4 | ||
200 | #define SEQ_SEQ_LUT 5 | ||
201 | #define SEQ_DRC_LUT_ALL 6 | ||
202 | #define WPC_PROGRAM_LUT 7 | ||
203 | |||
204 | #define BITSTREAM_START_ADDR 0x00000000 | ||
205 | #define BITSTREAM_SIZE 0x00040000 | ||
206 | |||
207 | #define WPC_FW_0_START_ADDR 0x00040000 | ||
208 | #define WPC_FW_0_SIZE 0x00000ce8 | ||
209 | |||
210 | #define SEQUENCE_0_START_ADDR 0x00044000 | ||
211 | #define SEQUENCE_0_SIZE 0x00001000 | ||
212 | |||
213 | #define SEQUENCE_1_START_ADDR 0x00045000 | ||
214 | #define SEQUENCE_1_SIZE 0x00000d10 | ||
215 | |||
216 | #define SEQUENCE_2_START_ADDR 0x00046000 | ||
217 | #define SEQUENCE_2_SIZE 0x00000d10 | ||
218 | |||
219 | #define SEQUENCE_3_START_ADDR 0x00047000 | ||
220 | #define SEQUENCE_3_SIZE 0x00000d10 | ||
221 | |||
222 | #define SEQUENCE_4_START_ADDR 0x00048000 | ||
223 | #define SEQUENCE_4_SIZE 0x00000d10 | ||
224 | |||
225 | #define SEQUENCE_5_START_ADDR 0x00049000 | ||
226 | #define SEQUENCE_5_SIZE 0x00000d10 | ||
227 | |||
228 | #define SEQUENCE_6_START_ADDR 0x0004a000 | ||
229 | #define SEQUENCE_6_SIZE 0x00000d10 | ||
230 | |||
231 | #define CMT_LUT_0_START_ADDR 0x0004b200 | ||
232 | #define CMT_LUT_0_SIZE 0x00000600 | ||
233 | |||
234 | #define CMT_LUT_1_START_ADDR 0x0004b800 | ||
235 | #define CMT_LUT_1_SIZE 0x00000600 | ||
236 | |||
237 | #define CMT_LUT_2_START_ADDR 0x0004be00 | ||
238 | #define CMT_LUT_2_SIZE 0x00000600 | ||
239 | |||
240 | #define CMT_LUT_3_START_ADDR 0x0004c400 | ||
241 | #define CMT_LUT_3_SIZE 0x00000600 | ||
242 | |||
243 | #define CMT_LUT_4_START_ADDR 0x0004ca00 | ||
244 | #define CMT_LUT_4_SIZE 0x00000600 | ||
245 | |||
246 | #define CMT_LUT_5_START_ADDR 0x0004d000 | ||
247 | #define CMT_LUT_5_SIZE 0x00000600 | ||
248 | |||
249 | #define CMT_LUT_6_START_ADDR 0x0004d600 | ||
250 | #define CMT_LUT_6_SIZE 0x00000600 | ||
251 | |||
252 | #define DRC_TABLE_0_START_ADDR 0x0004dc00 | ||
253 | #define DRC_TABLE_0_SIZE 0x00000100 | ||
254 | |||
255 | #define SPLASH_0_START_ADDR 0x0004dd00 | ||
256 | #define SPLASH_0_SIZE 0x00032280 | ||
257 | |||
258 | #define SEQUENCE_7_START_ADDR 0x00080000 | ||
259 | #define SEQUENCE_7_SIZE 0x00000d10 | ||
260 | |||
261 | #define SEQUENCE_8_START_ADDR 0x00081800 | ||
262 | #define SEQUENCE_8_SIZE 0x00000d10 | ||
263 | |||
264 | #define SEQUENCE_9_START_ADDR 0x00083000 | ||
265 | #define SEQUENCE_9_SIZE 0x00000d10 | ||
266 | |||
267 | #define CMT_LUT_7_START_ADDR 0x0008e000 | ||
268 | #define CMT_LUT_7_SIZE 0x00000600 | ||
269 | |||
270 | #define CMT_LUT_8_START_ADDR 0x0008e800 | ||
271 | #define CMT_LUT_8_SIZE 0x00000600 | ||
272 | |||
273 | #define CMT_LUT_9_START_ADDR 0x0008f000 | ||
274 | #define CMT_LUT_9_SIZE 0x00000600 | ||
275 | |||
276 | #define SPLASH_1_START_ADDR 0x0009a000 | ||
277 | #define SPLASH_1_SIZE 0x00032280 | ||
278 | |||
279 | #define SPLASH_2_START_ADDR 0x000cd000 | ||
280 | #define SPLASH_2_SIZE 0x00032280 | ||
281 | |||
282 | #define SPLASH_3_START_ADDR 0x00100000 | ||
283 | #define SPLASH_3_SIZE 0x00032280 | ||
284 | |||
285 | #define OPT_SPLASH_0_START_ADDR 0x00134000 | ||
286 | #define OPT_SPLASH_0_SIZE 0x000cb100 | ||
287 | |||
288 | #endif | ||
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c deleted file mode 100644 index 78f0a6779756..000000000000 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ /dev/null | |||
@@ -1,198 +0,0 @@ | |||
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/fb.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/gpio.h> | ||
27 | |||
28 | #include <video/omapdss.h> | ||
29 | #include <video/omap-panel-data.h> | ||
30 | |||
31 | static struct omap_video_timings sharp_ls_timings = { | ||
32 | .x_res = 480, | ||
33 | .y_res = 640, | ||
34 | |||
35 | .pixel_clock = 19200, | ||
36 | |||
37 | .hsw = 2, | ||
38 | .hfp = 1, | ||
39 | .hbp = 28, | ||
40 | |||
41 | .vsw = 1, | ||
42 | .vfp = 1, | ||
43 | .vbp = 1, | ||
44 | |||
45 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
46 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
47 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
48 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
49 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
50 | }; | ||
51 | |||
52 | static inline struct panel_sharp_ls037v7dw01_data | ||
53 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
54 | { | ||
55 | return (struct panel_sharp_ls037v7dw01_data *) dssdev->data; | ||
56 | } | ||
57 | |||
58 | static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) | ||
59 | { | ||
60 | struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); | ||
61 | int r; | ||
62 | |||
63 | if (!pd) | ||
64 | return -EINVAL; | ||
65 | |||
66 | dssdev->panel.timings = sharp_ls_timings; | ||
67 | |||
68 | if (gpio_is_valid(pd->mo_gpio)) { | ||
69 | r = devm_gpio_request_one(dssdev->dev, pd->mo_gpio, | ||
70 | GPIOF_OUT_INIT_LOW, "lcd MO"); | ||
71 | if (r) | ||
72 | return r; | ||
73 | } | ||
74 | |||
75 | if (gpio_is_valid(pd->lr_gpio)) { | ||
76 | r = devm_gpio_request_one(dssdev->dev, pd->lr_gpio, | ||
77 | GPIOF_OUT_INIT_HIGH, "lcd LR"); | ||
78 | if (r) | ||
79 | return r; | ||
80 | } | ||
81 | |||
82 | if (gpio_is_valid(pd->ud_gpio)) { | ||
83 | r = devm_gpio_request_one(dssdev->dev, pd->ud_gpio, | ||
84 | GPIOF_OUT_INIT_HIGH, "lcd UD"); | ||
85 | if (r) | ||
86 | return r; | ||
87 | } | ||
88 | |||
89 | if (gpio_is_valid(pd->resb_gpio)) { | ||
90 | r = devm_gpio_request_one(dssdev->dev, pd->resb_gpio, | ||
91 | GPIOF_OUT_INIT_LOW, "lcd RESB"); | ||
92 | if (r) | ||
93 | return r; | ||
94 | } | ||
95 | |||
96 | if (gpio_is_valid(pd->ini_gpio)) { | ||
97 | r = devm_gpio_request_one(dssdev->dev, pd->ini_gpio, | ||
98 | GPIOF_OUT_INIT_LOW, "lcd INI"); | ||
99 | if (r) | ||
100 | return r; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev) | ||
107 | { | ||
108 | } | ||
109 | |||
110 | static int sharp_ls_power_on(struct omap_dss_device *dssdev) | ||
111 | { | ||
112 | struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); | ||
113 | int r = 0; | ||
114 | |||
115 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
116 | return 0; | ||
117 | |||
118 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
119 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
120 | |||
121 | r = omapdss_dpi_display_enable(dssdev); | ||
122 | if (r) | ||
123 | goto err0; | ||
124 | |||
125 | /* wait couple of vsyncs until enabling the LCD */ | ||
126 | msleep(50); | ||
127 | |||
128 | if (gpio_is_valid(pd->resb_gpio)) | ||
129 | gpio_set_value_cansleep(pd->resb_gpio, 1); | ||
130 | |||
131 | if (gpio_is_valid(pd->ini_gpio)) | ||
132 | gpio_set_value_cansleep(pd->ini_gpio, 1); | ||
133 | |||
134 | return 0; | ||
135 | err0: | ||
136 | return r; | ||
137 | } | ||
138 | |||
139 | static void sharp_ls_power_off(struct omap_dss_device *dssdev) | ||
140 | { | ||
141 | struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); | ||
142 | |||
143 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
144 | return; | ||
145 | |||
146 | if (gpio_is_valid(pd->ini_gpio)) | ||
147 | gpio_set_value_cansleep(pd->ini_gpio, 0); | ||
148 | |||
149 | if (gpio_is_valid(pd->resb_gpio)) | ||
150 | gpio_set_value_cansleep(pd->resb_gpio, 0); | ||
151 | |||
152 | /* wait at least 5 vsyncs after disabling the LCD */ | ||
153 | |||
154 | msleep(100); | ||
155 | |||
156 | omapdss_dpi_display_disable(dssdev); | ||
157 | } | ||
158 | |||
159 | static int sharp_ls_panel_enable(struct omap_dss_device *dssdev) | ||
160 | { | ||
161 | int r; | ||
162 | r = sharp_ls_power_on(dssdev); | ||
163 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
164 | return r; | ||
165 | } | ||
166 | |||
167 | static void sharp_ls_panel_disable(struct omap_dss_device *dssdev) | ||
168 | { | ||
169 | sharp_ls_power_off(dssdev); | ||
170 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
171 | } | ||
172 | |||
173 | static struct omap_dss_driver sharp_ls_driver = { | ||
174 | .probe = sharp_ls_panel_probe, | ||
175 | .remove = __exit_p(sharp_ls_panel_remove), | ||
176 | |||
177 | .enable = sharp_ls_panel_enable, | ||
178 | .disable = sharp_ls_panel_disable, | ||
179 | |||
180 | .driver = { | ||
181 | .name = "sharp_ls_panel", | ||
182 | .owner = THIS_MODULE, | ||
183 | }, | ||
184 | }; | ||
185 | |||
186 | static int __init sharp_ls_panel_drv_init(void) | ||
187 | { | ||
188 | return omap_dss_register_driver(&sharp_ls_driver); | ||
189 | } | ||
190 | |||
191 | static void __exit sharp_ls_panel_drv_exit(void) | ||
192 | { | ||
193 | omap_dss_unregister_driver(&sharp_ls_driver); | ||
194 | } | ||
195 | |||
196 | module_init(sharp_ls_panel_drv_init); | ||
197 | module_exit(sharp_ls_panel_drv_exit); | ||
198 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c deleted file mode 100644 index 54a07da8587a..000000000000 --- a/drivers/video/omap2/displays/panel-taal.c +++ /dev/null | |||
@@ -1,1551 +0,0 @@ | |||
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/workqueue.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/mutex.h> | ||
34 | |||
35 | #include <video/omapdss.h> | ||
36 | #include <video/omap-panel-data.h> | ||
37 | #include <video/mipi_display.h> | ||
38 | |||
39 | /* DSI Virtual channel. Hardcoded for now. */ | ||
40 | #define TCH 0 | ||
41 | |||
42 | #define DCS_READ_NUM_ERRORS 0x05 | ||
43 | #define DCS_BRIGHTNESS 0x51 | ||
44 | #define DCS_CTRL_DISPLAY 0x53 | ||
45 | #define DCS_WRITE_CABC 0x55 | ||
46 | #define DCS_READ_CABC 0x56 | ||
47 | #define DCS_GET_ID1 0xda | ||
48 | #define DCS_GET_ID2 0xdb | ||
49 | #define DCS_GET_ID3 0xdc | ||
50 | |||
51 | static irqreturn_t taal_te_isr(int irq, void *data); | ||
52 | static void taal_te_timeout_work_callback(struct work_struct *work); | ||
53 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); | ||
54 | |||
55 | static int taal_panel_reset(struct omap_dss_device *dssdev); | ||
56 | |||
57 | struct taal_data { | ||
58 | struct mutex lock; | ||
59 | |||
60 | struct backlight_device *bldev; | ||
61 | |||
62 | unsigned long hw_guard_end; /* next value of jiffies when we can | ||
63 | * issue the next sleep in/out command | ||
64 | */ | ||
65 | unsigned long hw_guard_wait; /* max guard time in jiffies */ | ||
66 | |||
67 | struct omap_dss_device *dssdev; | ||
68 | |||
69 | /* panel HW configuration from DT or platform data */ | ||
70 | int reset_gpio; | ||
71 | int ext_te_gpio; | ||
72 | |||
73 | bool use_dsi_backlight; | ||
74 | |||
75 | struct omap_dsi_pin_config pin_config; | ||
76 | |||
77 | /* runtime variables */ | ||
78 | bool enabled; | ||
79 | |||
80 | bool te_enabled; | ||
81 | |||
82 | atomic_t do_update; | ||
83 | int channel; | ||
84 | |||
85 | struct delayed_work te_timeout_work; | ||
86 | |||
87 | bool cabc_broken; | ||
88 | unsigned cabc_mode; | ||
89 | |||
90 | bool intro_printed; | ||
91 | |||
92 | struct workqueue_struct *workqueue; | ||
93 | |||
94 | struct delayed_work esd_work; | ||
95 | unsigned esd_interval; | ||
96 | |||
97 | bool ulps_enabled; | ||
98 | unsigned ulps_timeout; | ||
99 | struct delayed_work ulps_work; | ||
100 | }; | ||
101 | |||
102 | static void taal_esd_work(struct work_struct *work); | ||
103 | static void taal_ulps_work(struct work_struct *work); | ||
104 | |||
105 | static void hw_guard_start(struct taal_data *td, int guard_msec) | ||
106 | { | ||
107 | td->hw_guard_wait = msecs_to_jiffies(guard_msec); | ||
108 | td->hw_guard_end = jiffies + td->hw_guard_wait; | ||
109 | } | ||
110 | |||
111 | static void hw_guard_wait(struct taal_data *td) | ||
112 | { | ||
113 | unsigned long wait = td->hw_guard_end - jiffies; | ||
114 | |||
115 | if ((long)wait > 0 && wait <= td->hw_guard_wait) { | ||
116 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
117 | schedule_timeout(wait); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data) | ||
122 | { | ||
123 | int r; | ||
124 | u8 buf[1]; | ||
125 | |||
126 | r = dsi_vc_dcs_read(td->dssdev, td->channel, dcs_cmd, buf, 1); | ||
127 | |||
128 | if (r < 0) | ||
129 | return r; | ||
130 | |||
131 | *data = buf[0]; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd) | ||
137 | { | ||
138 | return dsi_vc_dcs_write(td->dssdev, td->channel, &dcs_cmd, 1); | ||
139 | } | ||
140 | |||
141 | static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param) | ||
142 | { | ||
143 | u8 buf[2]; | ||
144 | buf[0] = dcs_cmd; | ||
145 | buf[1] = param; | ||
146 | return dsi_vc_dcs_write(td->dssdev, td->channel, buf, 2); | ||
147 | } | ||
148 | |||
149 | static int taal_sleep_in(struct taal_data *td) | ||
150 | |||
151 | { | ||
152 | u8 cmd; | ||
153 | int r; | ||
154 | |||
155 | hw_guard_wait(td); | ||
156 | |||
157 | cmd = MIPI_DCS_ENTER_SLEEP_MODE; | ||
158 | r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1); | ||
159 | if (r) | ||
160 | return r; | ||
161 | |||
162 | hw_guard_start(td, 120); | ||
163 | |||
164 | msleep(5); | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int taal_sleep_out(struct taal_data *td) | ||
170 | { | ||
171 | int r; | ||
172 | |||
173 | hw_guard_wait(td); | ||
174 | |||
175 | r = taal_dcs_write_0(td, MIPI_DCS_EXIT_SLEEP_MODE); | ||
176 | if (r) | ||
177 | return r; | ||
178 | |||
179 | hw_guard_start(td, 120); | ||
180 | |||
181 | msleep(5); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3) | ||
187 | { | ||
188 | int r; | ||
189 | |||
190 | r = taal_dcs_read_1(td, DCS_GET_ID1, id1); | ||
191 | if (r) | ||
192 | return r; | ||
193 | r = taal_dcs_read_1(td, DCS_GET_ID2, id2); | ||
194 | if (r) | ||
195 | return r; | ||
196 | r = taal_dcs_read_1(td, DCS_GET_ID3, id3); | ||
197 | if (r) | ||
198 | return r; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int taal_set_update_window(struct taal_data *td, | ||
204 | u16 x, u16 y, u16 w, u16 h) | ||
205 | { | ||
206 | int r; | ||
207 | u16 x1 = x; | ||
208 | u16 x2 = x + w - 1; | ||
209 | u16 y1 = y; | ||
210 | u16 y2 = y + h - 1; | ||
211 | |||
212 | u8 buf[5]; | ||
213 | buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS; | ||
214 | buf[1] = (x1 >> 8) & 0xff; | ||
215 | buf[2] = (x1 >> 0) & 0xff; | ||
216 | buf[3] = (x2 >> 8) & 0xff; | ||
217 | buf[4] = (x2 >> 0) & 0xff; | ||
218 | |||
219 | r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf)); | ||
220 | if (r) | ||
221 | return r; | ||
222 | |||
223 | buf[0] = MIPI_DCS_SET_PAGE_ADDRESS; | ||
224 | buf[1] = (y1 >> 8) & 0xff; | ||
225 | buf[2] = (y1 >> 0) & 0xff; | ||
226 | buf[3] = (y2 >> 8) & 0xff; | ||
227 | buf[4] = (y2 >> 0) & 0xff; | ||
228 | |||
229 | r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf)); | ||
230 | if (r) | ||
231 | return r; | ||
232 | |||
233 | dsi_vc_send_bta_sync(td->dssdev, td->channel); | ||
234 | |||
235 | return r; | ||
236 | } | ||
237 | |||
238 | static void taal_queue_esd_work(struct omap_dss_device *dssdev) | ||
239 | { | ||
240 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
241 | |||
242 | if (td->esd_interval > 0) | ||
243 | queue_delayed_work(td->workqueue, &td->esd_work, | ||
244 | msecs_to_jiffies(td->esd_interval)); | ||
245 | } | ||
246 | |||
247 | static void taal_cancel_esd_work(struct omap_dss_device *dssdev) | ||
248 | { | ||
249 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
250 | |||
251 | cancel_delayed_work(&td->esd_work); | ||
252 | } | ||
253 | |||
254 | static void taal_queue_ulps_work(struct omap_dss_device *dssdev) | ||
255 | { | ||
256 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
257 | |||
258 | if (td->ulps_timeout > 0) | ||
259 | queue_delayed_work(td->workqueue, &td->ulps_work, | ||
260 | msecs_to_jiffies(td->ulps_timeout)); | ||
261 | } | ||
262 | |||
263 | static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) | ||
264 | { | ||
265 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
266 | |||
267 | cancel_delayed_work(&td->ulps_work); | ||
268 | } | ||
269 | |||
270 | static int taal_enter_ulps(struct omap_dss_device *dssdev) | ||
271 | { | ||
272 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
273 | int r; | ||
274 | |||
275 | if (td->ulps_enabled) | ||
276 | return 0; | ||
277 | |||
278 | taal_cancel_ulps_work(dssdev); | ||
279 | |||
280 | r = _taal_enable_te(dssdev, false); | ||
281 | if (r) | ||
282 | goto err; | ||
283 | |||
284 | if (gpio_is_valid(td->ext_te_gpio)) | ||
285 | disable_irq(gpio_to_irq(td->ext_te_gpio)); | ||
286 | |||
287 | omapdss_dsi_display_disable(dssdev, false, true); | ||
288 | |||
289 | td->ulps_enabled = true; | ||
290 | |||
291 | return 0; | ||
292 | |||
293 | err: | ||
294 | dev_err(dssdev->dev, "enter ULPS failed"); | ||
295 | taal_panel_reset(dssdev); | ||
296 | |||
297 | td->ulps_enabled = false; | ||
298 | |||
299 | taal_queue_ulps_work(dssdev); | ||
300 | |||
301 | return r; | ||
302 | } | ||
303 | |||
304 | static int taal_exit_ulps(struct omap_dss_device *dssdev) | ||
305 | { | ||
306 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
307 | int r; | ||
308 | |||
309 | if (!td->ulps_enabled) | ||
310 | return 0; | ||
311 | |||
312 | r = omapdss_dsi_display_enable(dssdev); | ||
313 | if (r) { | ||
314 | dev_err(dssdev->dev, "failed to enable DSI\n"); | ||
315 | goto err1; | ||
316 | } | ||
317 | |||
318 | omapdss_dsi_vc_enable_hs(dssdev, td->channel, true); | ||
319 | |||
320 | r = _taal_enable_te(dssdev, true); | ||
321 | if (r) { | ||
322 | dev_err(dssdev->dev, "failed to re-enable TE"); | ||
323 | goto err2; | ||
324 | } | ||
325 | |||
326 | if (gpio_is_valid(td->ext_te_gpio)) | ||
327 | enable_irq(gpio_to_irq(td->ext_te_gpio)); | ||
328 | |||
329 | taal_queue_ulps_work(dssdev); | ||
330 | |||
331 | td->ulps_enabled = false; | ||
332 | |||
333 | return 0; | ||
334 | |||
335 | err2: | ||
336 | dev_err(dssdev->dev, "failed to exit ULPS"); | ||
337 | |||
338 | r = taal_panel_reset(dssdev); | ||
339 | if (!r) { | ||
340 | if (gpio_is_valid(td->ext_te_gpio)) | ||
341 | enable_irq(gpio_to_irq(td->ext_te_gpio)); | ||
342 | td->ulps_enabled = false; | ||
343 | } | ||
344 | err1: | ||
345 | taal_queue_ulps_work(dssdev); | ||
346 | |||
347 | return r; | ||
348 | } | ||
349 | |||
350 | static int taal_wake_up(struct omap_dss_device *dssdev) | ||
351 | { | ||
352 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
353 | |||
354 | if (td->ulps_enabled) | ||
355 | return taal_exit_ulps(dssdev); | ||
356 | |||
357 | taal_cancel_ulps_work(dssdev); | ||
358 | taal_queue_ulps_work(dssdev); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int taal_bl_update_status(struct backlight_device *dev) | ||
363 | { | ||
364 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | ||
365 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
366 | int r; | ||
367 | int level; | ||
368 | |||
369 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
370 | dev->props.power == FB_BLANK_UNBLANK) | ||
371 | level = dev->props.brightness; | ||
372 | else | ||
373 | level = 0; | ||
374 | |||
375 | dev_dbg(dssdev->dev, "update brightness to %d\n", level); | ||
376 | |||
377 | mutex_lock(&td->lock); | ||
378 | |||
379 | if (td->enabled) { | ||
380 | dsi_bus_lock(dssdev); | ||
381 | |||
382 | r = taal_wake_up(dssdev); | ||
383 | if (!r) | ||
384 | r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level); | ||
385 | |||
386 | dsi_bus_unlock(dssdev); | ||
387 | } else { | ||
388 | r = 0; | ||
389 | } | ||
390 | |||
391 | mutex_unlock(&td->lock); | ||
392 | |||
393 | return r; | ||
394 | } | ||
395 | |||
396 | static int taal_bl_get_intensity(struct backlight_device *dev) | ||
397 | { | ||
398 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
399 | dev->props.power == FB_BLANK_UNBLANK) | ||
400 | return dev->props.brightness; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static const struct backlight_ops taal_bl_ops = { | ||
406 | .get_brightness = taal_bl_get_intensity, | ||
407 | .update_status = taal_bl_update_status, | ||
408 | }; | ||
409 | |||
410 | static void taal_get_resolution(struct omap_dss_device *dssdev, | ||
411 | u16 *xres, u16 *yres) | ||
412 | { | ||
413 | *xres = dssdev->panel.timings.x_res; | ||
414 | *yres = dssdev->panel.timings.y_res; | ||
415 | } | ||
416 | |||
417 | static ssize_t taal_num_errors_show(struct device *dev, | ||
418 | struct device_attribute *attr, char *buf) | ||
419 | { | ||
420 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
421 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
422 | u8 errors = 0; | ||
423 | int r; | ||
424 | |||
425 | mutex_lock(&td->lock); | ||
426 | |||
427 | if (td->enabled) { | ||
428 | dsi_bus_lock(dssdev); | ||
429 | |||
430 | r = taal_wake_up(dssdev); | ||
431 | if (!r) | ||
432 | r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors); | ||
433 | |||
434 | dsi_bus_unlock(dssdev); | ||
435 | } else { | ||
436 | r = -ENODEV; | ||
437 | } | ||
438 | |||
439 | mutex_unlock(&td->lock); | ||
440 | |||
441 | if (r) | ||
442 | return r; | ||
443 | |||
444 | return snprintf(buf, PAGE_SIZE, "%d\n", errors); | ||
445 | } | ||
446 | |||
447 | static ssize_t taal_hw_revision_show(struct device *dev, | ||
448 | struct device_attribute *attr, char *buf) | ||
449 | { | ||
450 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
451 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
452 | u8 id1, id2, id3; | ||
453 | int r; | ||
454 | |||
455 | mutex_lock(&td->lock); | ||
456 | |||
457 | if (td->enabled) { | ||
458 | dsi_bus_lock(dssdev); | ||
459 | |||
460 | r = taal_wake_up(dssdev); | ||
461 | if (!r) | ||
462 | r = taal_get_id(td, &id1, &id2, &id3); | ||
463 | |||
464 | dsi_bus_unlock(dssdev); | ||
465 | } else { | ||
466 | r = -ENODEV; | ||
467 | } | ||
468 | |||
469 | mutex_unlock(&td->lock); | ||
470 | |||
471 | if (r) | ||
472 | return r; | ||
473 | |||
474 | return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3); | ||
475 | } | ||
476 | |||
477 | static const char *cabc_modes[] = { | ||
478 | "off", /* used also always when CABC is not supported */ | ||
479 | "ui", | ||
480 | "still-image", | ||
481 | "moving-image", | ||
482 | }; | ||
483 | |||
484 | static ssize_t show_cabc_mode(struct device *dev, | ||
485 | struct device_attribute *attr, | ||
486 | char *buf) | ||
487 | { | ||
488 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
489 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
490 | const char *mode_str; | ||
491 | int mode; | ||
492 | int len; | ||
493 | |||
494 | mode = td->cabc_mode; | ||
495 | |||
496 | mode_str = "unknown"; | ||
497 | if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) | ||
498 | mode_str = cabc_modes[mode]; | ||
499 | len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); | ||
500 | |||
501 | return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; | ||
502 | } | ||
503 | |||
504 | static ssize_t store_cabc_mode(struct device *dev, | ||
505 | struct device_attribute *attr, | ||
506 | const char *buf, size_t count) | ||
507 | { | ||
508 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
509 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
510 | int i; | ||
511 | int r; | ||
512 | |||
513 | for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { | ||
514 | if (sysfs_streq(cabc_modes[i], buf)) | ||
515 | break; | ||
516 | } | ||
517 | |||
518 | if (i == ARRAY_SIZE(cabc_modes)) | ||
519 | return -EINVAL; | ||
520 | |||
521 | mutex_lock(&td->lock); | ||
522 | |||
523 | if (td->enabled) { | ||
524 | dsi_bus_lock(dssdev); | ||
525 | |||
526 | if (!td->cabc_broken) { | ||
527 | r = taal_wake_up(dssdev); | ||
528 | if (r) | ||
529 | goto err; | ||
530 | |||
531 | r = taal_dcs_write_1(td, DCS_WRITE_CABC, i); | ||
532 | if (r) | ||
533 | goto err; | ||
534 | } | ||
535 | |||
536 | dsi_bus_unlock(dssdev); | ||
537 | } | ||
538 | |||
539 | td->cabc_mode = i; | ||
540 | |||
541 | mutex_unlock(&td->lock); | ||
542 | |||
543 | return count; | ||
544 | err: | ||
545 | dsi_bus_unlock(dssdev); | ||
546 | mutex_unlock(&td->lock); | ||
547 | return r; | ||
548 | } | ||
549 | |||
550 | static ssize_t show_cabc_available_modes(struct device *dev, | ||
551 | struct device_attribute *attr, | ||
552 | char *buf) | ||
553 | { | ||
554 | int len; | ||
555 | int i; | ||
556 | |||
557 | for (i = 0, len = 0; | ||
558 | len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) | ||
559 | len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", | ||
560 | i ? " " : "", cabc_modes[i], | ||
561 | i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); | ||
562 | |||
563 | return len < PAGE_SIZE ? len : PAGE_SIZE - 1; | ||
564 | } | ||
565 | |||
566 | static ssize_t taal_store_esd_interval(struct device *dev, | ||
567 | struct device_attribute *attr, | ||
568 | const char *buf, size_t count) | ||
569 | { | ||
570 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
571 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
572 | |||
573 | unsigned long t; | ||
574 | int r; | ||
575 | |||
576 | r = kstrtoul(buf, 10, &t); | ||
577 | if (r) | ||
578 | return r; | ||
579 | |||
580 | mutex_lock(&td->lock); | ||
581 | taal_cancel_esd_work(dssdev); | ||
582 | td->esd_interval = t; | ||
583 | if (td->enabled) | ||
584 | taal_queue_esd_work(dssdev); | ||
585 | mutex_unlock(&td->lock); | ||
586 | |||
587 | return count; | ||
588 | } | ||
589 | |||
590 | static ssize_t taal_show_esd_interval(struct device *dev, | ||
591 | struct device_attribute *attr, | ||
592 | char *buf) | ||
593 | { | ||
594 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
595 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
596 | unsigned t; | ||
597 | |||
598 | mutex_lock(&td->lock); | ||
599 | t = td->esd_interval; | ||
600 | mutex_unlock(&td->lock); | ||
601 | |||
602 | return snprintf(buf, PAGE_SIZE, "%u\n", t); | ||
603 | } | ||
604 | |||
605 | static ssize_t taal_store_ulps(struct device *dev, | ||
606 | struct device_attribute *attr, | ||
607 | const char *buf, size_t count) | ||
608 | { | ||
609 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
610 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
611 | unsigned long t; | ||
612 | int r; | ||
613 | |||
614 | r = kstrtoul(buf, 10, &t); | ||
615 | if (r) | ||
616 | return r; | ||
617 | |||
618 | mutex_lock(&td->lock); | ||
619 | |||
620 | if (td->enabled) { | ||
621 | dsi_bus_lock(dssdev); | ||
622 | |||
623 | if (t) | ||
624 | r = taal_enter_ulps(dssdev); | ||
625 | else | ||
626 | r = taal_wake_up(dssdev); | ||
627 | |||
628 | dsi_bus_unlock(dssdev); | ||
629 | } | ||
630 | |||
631 | mutex_unlock(&td->lock); | ||
632 | |||
633 | if (r) | ||
634 | return r; | ||
635 | |||
636 | return count; | ||
637 | } | ||
638 | |||
639 | static ssize_t taal_show_ulps(struct device *dev, | ||
640 | struct device_attribute *attr, | ||
641 | char *buf) | ||
642 | { | ||
643 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
644 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
645 | unsigned t; | ||
646 | |||
647 | mutex_lock(&td->lock); | ||
648 | t = td->ulps_enabled; | ||
649 | mutex_unlock(&td->lock); | ||
650 | |||
651 | return snprintf(buf, PAGE_SIZE, "%u\n", t); | ||
652 | } | ||
653 | |||
654 | static ssize_t taal_store_ulps_timeout(struct device *dev, | ||
655 | struct device_attribute *attr, | ||
656 | const char *buf, size_t count) | ||
657 | { | ||
658 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
659 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
660 | unsigned long t; | ||
661 | int r; | ||
662 | |||
663 | r = kstrtoul(buf, 10, &t); | ||
664 | if (r) | ||
665 | return r; | ||
666 | |||
667 | mutex_lock(&td->lock); | ||
668 | td->ulps_timeout = t; | ||
669 | |||
670 | if (td->enabled) { | ||
671 | /* taal_wake_up will restart the timer */ | ||
672 | dsi_bus_lock(dssdev); | ||
673 | r = taal_wake_up(dssdev); | ||
674 | dsi_bus_unlock(dssdev); | ||
675 | } | ||
676 | |||
677 | mutex_unlock(&td->lock); | ||
678 | |||
679 | if (r) | ||
680 | return r; | ||
681 | |||
682 | return count; | ||
683 | } | ||
684 | |||
685 | static ssize_t taal_show_ulps_timeout(struct device *dev, | ||
686 | struct device_attribute *attr, | ||
687 | char *buf) | ||
688 | { | ||
689 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
690 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
691 | unsigned t; | ||
692 | |||
693 | mutex_lock(&td->lock); | ||
694 | t = td->ulps_timeout; | ||
695 | mutex_unlock(&td->lock); | ||
696 | |||
697 | return snprintf(buf, PAGE_SIZE, "%u\n", t); | ||
698 | } | ||
699 | |||
700 | static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL); | ||
701 | static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL); | ||
702 | static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, | ||
703 | show_cabc_mode, store_cabc_mode); | ||
704 | static DEVICE_ATTR(cabc_available_modes, S_IRUGO, | ||
705 | show_cabc_available_modes, NULL); | ||
706 | static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR, | ||
707 | taal_show_esd_interval, taal_store_esd_interval); | ||
708 | static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR, | ||
709 | taal_show_ulps, taal_store_ulps); | ||
710 | static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR, | ||
711 | taal_show_ulps_timeout, taal_store_ulps_timeout); | ||
712 | |||
713 | static struct attribute *taal_attrs[] = { | ||
714 | &dev_attr_num_dsi_errors.attr, | ||
715 | &dev_attr_hw_revision.attr, | ||
716 | &dev_attr_cabc_mode.attr, | ||
717 | &dev_attr_cabc_available_modes.attr, | ||
718 | &dev_attr_esd_interval.attr, | ||
719 | &dev_attr_ulps.attr, | ||
720 | &dev_attr_ulps_timeout.attr, | ||
721 | NULL, | ||
722 | }; | ||
723 | |||
724 | static struct attribute_group taal_attr_group = { | ||
725 | .attrs = taal_attrs, | ||
726 | }; | ||
727 | |||
728 | static void taal_hw_reset(struct omap_dss_device *dssdev) | ||
729 | { | ||
730 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
731 | |||
732 | if (!gpio_is_valid(td->reset_gpio)) | ||
733 | return; | ||
734 | |||
735 | gpio_set_value(td->reset_gpio, 1); | ||
736 | udelay(10); | ||
737 | /* reset the panel */ | ||
738 | gpio_set_value(td->reset_gpio, 0); | ||
739 | /* assert reset */ | ||
740 | udelay(10); | ||
741 | gpio_set_value(td->reset_gpio, 1); | ||
742 | /* wait after releasing reset */ | ||
743 | msleep(5); | ||
744 | } | ||
745 | |||
746 | static void taal_probe_pdata(struct taal_data *td, | ||
747 | const struct nokia_dsi_panel_data *pdata) | ||
748 | { | ||
749 | td->reset_gpio = pdata->reset_gpio; | ||
750 | |||
751 | if (pdata->use_ext_te) | ||
752 | td->ext_te_gpio = pdata->ext_te_gpio; | ||
753 | else | ||
754 | td->ext_te_gpio = -1; | ||
755 | |||
756 | td->esd_interval = pdata->esd_interval; | ||
757 | td->ulps_timeout = pdata->ulps_timeout; | ||
758 | |||
759 | td->use_dsi_backlight = pdata->use_dsi_backlight; | ||
760 | |||
761 | td->pin_config = pdata->pin_config; | ||
762 | } | ||
763 | |||
764 | static int taal_probe(struct omap_dss_device *dssdev) | ||
765 | { | ||
766 | struct backlight_properties props; | ||
767 | struct taal_data *td; | ||
768 | struct backlight_device *bldev = NULL; | ||
769 | int r; | ||
770 | |||
771 | dev_dbg(dssdev->dev, "probe\n"); | ||
772 | |||
773 | td = devm_kzalloc(dssdev->dev, sizeof(*td), GFP_KERNEL); | ||
774 | if (!td) | ||
775 | return -ENOMEM; | ||
776 | |||
777 | dev_set_drvdata(dssdev->dev, td); | ||
778 | td->dssdev = dssdev; | ||
779 | |||
780 | if (dssdev->data) { | ||
781 | const struct nokia_dsi_panel_data *pdata = dssdev->data; | ||
782 | |||
783 | taal_probe_pdata(td, pdata); | ||
784 | } else { | ||
785 | return -ENODEV; | ||
786 | } | ||
787 | |||
788 | dssdev->panel.timings.x_res = 864; | ||
789 | dssdev->panel.timings.y_res = 480; | ||
790 | dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000); | ||
791 | dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; | ||
792 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | ||
793 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; | ||
794 | |||
795 | mutex_init(&td->lock); | ||
796 | |||
797 | atomic_set(&td->do_update, 0); | ||
798 | |||
799 | if (gpio_is_valid(td->reset_gpio)) { | ||
800 | r = devm_gpio_request_one(dssdev->dev, td->reset_gpio, | ||
801 | GPIOF_OUT_INIT_LOW, "taal rst"); | ||
802 | if (r) { | ||
803 | dev_err(dssdev->dev, "failed to request reset gpio\n"); | ||
804 | return r; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | if (gpio_is_valid(td->ext_te_gpio)) { | ||
809 | r = devm_gpio_request_one(dssdev->dev, td->ext_te_gpio, | ||
810 | GPIOF_IN, "taal irq"); | ||
811 | if (r) { | ||
812 | dev_err(dssdev->dev, "GPIO request failed\n"); | ||
813 | return r; | ||
814 | } | ||
815 | |||
816 | r = devm_request_irq(dssdev->dev, gpio_to_irq(td->ext_te_gpio), | ||
817 | taal_te_isr, | ||
818 | IRQF_TRIGGER_RISING, | ||
819 | "taal vsync", dssdev); | ||
820 | |||
821 | if (r) { | ||
822 | dev_err(dssdev->dev, "IRQ request failed\n"); | ||
823 | return r; | ||
824 | } | ||
825 | |||
826 | INIT_DEFERRABLE_WORK(&td->te_timeout_work, | ||
827 | taal_te_timeout_work_callback); | ||
828 | |||
829 | dev_dbg(dssdev->dev, "Using GPIO TE\n"); | ||
830 | } | ||
831 | |||
832 | td->workqueue = create_singlethread_workqueue("taal_esd"); | ||
833 | if (td->workqueue == NULL) { | ||
834 | dev_err(dssdev->dev, "can't create ESD workqueue\n"); | ||
835 | return -ENOMEM; | ||
836 | } | ||
837 | INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); | ||
838 | INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); | ||
839 | |||
840 | taal_hw_reset(dssdev); | ||
841 | |||
842 | if (td->use_dsi_backlight) { | ||
843 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
844 | props.max_brightness = 255; | ||
845 | |||
846 | props.type = BACKLIGHT_RAW; | ||
847 | bldev = backlight_device_register(dev_name(dssdev->dev), | ||
848 | dssdev->dev, dssdev, &taal_bl_ops, &props); | ||
849 | if (IS_ERR(bldev)) { | ||
850 | r = PTR_ERR(bldev); | ||
851 | goto err_bl; | ||
852 | } | ||
853 | |||
854 | td->bldev = bldev; | ||
855 | |||
856 | bldev->props.fb_blank = FB_BLANK_UNBLANK; | ||
857 | bldev->props.power = FB_BLANK_UNBLANK; | ||
858 | bldev->props.brightness = 255; | ||
859 | |||
860 | taal_bl_update_status(bldev); | ||
861 | } | ||
862 | |||
863 | r = omap_dsi_request_vc(dssdev, &td->channel); | ||
864 | if (r) { | ||
865 | dev_err(dssdev->dev, "failed to get virtual channel\n"); | ||
866 | goto err_req_vc; | ||
867 | } | ||
868 | |||
869 | r = omap_dsi_set_vc_id(dssdev, td->channel, TCH); | ||
870 | if (r) { | ||
871 | dev_err(dssdev->dev, "failed to set VC_ID\n"); | ||
872 | goto err_vc_id; | ||
873 | } | ||
874 | |||
875 | r = sysfs_create_group(&dssdev->dev->kobj, &taal_attr_group); | ||
876 | if (r) { | ||
877 | dev_err(dssdev->dev, "failed to create sysfs files\n"); | ||
878 | goto err_vc_id; | ||
879 | } | ||
880 | |||
881 | return 0; | ||
882 | |||
883 | err_vc_id: | ||
884 | omap_dsi_release_vc(dssdev, td->channel); | ||
885 | err_req_vc: | ||
886 | if (bldev != NULL) | ||
887 | backlight_device_unregister(bldev); | ||
888 | err_bl: | ||
889 | destroy_workqueue(td->workqueue); | ||
890 | return r; | ||
891 | } | ||
892 | |||
893 | static void __exit taal_remove(struct omap_dss_device *dssdev) | ||
894 | { | ||
895 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
896 | struct backlight_device *bldev; | ||
897 | |||
898 | dev_dbg(dssdev->dev, "remove\n"); | ||
899 | |||
900 | sysfs_remove_group(&dssdev->dev->kobj, &taal_attr_group); | ||
901 | omap_dsi_release_vc(dssdev, td->channel); | ||
902 | |||
903 | bldev = td->bldev; | ||
904 | if (bldev != NULL) { | ||
905 | bldev->props.power = FB_BLANK_POWERDOWN; | ||
906 | taal_bl_update_status(bldev); | ||
907 | backlight_device_unregister(bldev); | ||
908 | } | ||
909 | |||
910 | taal_cancel_ulps_work(dssdev); | ||
911 | taal_cancel_esd_work(dssdev); | ||
912 | destroy_workqueue(td->workqueue); | ||
913 | |||
914 | /* reset, to be sure that the panel is in a valid state */ | ||
915 | taal_hw_reset(dssdev); | ||
916 | } | ||
917 | |||
918 | static int taal_power_on(struct omap_dss_device *dssdev) | ||
919 | { | ||
920 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
921 | u8 id1, id2, id3; | ||
922 | int r; | ||
923 | struct omap_dss_dsi_config dsi_config = { | ||
924 | .mode = OMAP_DSS_DSI_CMD_MODE, | ||
925 | .pixel_format = OMAP_DSS_DSI_FMT_RGB888, | ||
926 | .timings = &dssdev->panel.timings, | ||
927 | .hs_clk_min = 150000000, | ||
928 | .hs_clk_max = 300000000, | ||
929 | .lp_clk_min = 7000000, | ||
930 | .lp_clk_max = 10000000, | ||
931 | }; | ||
932 | |||
933 | r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); | ||
934 | if (r) { | ||
935 | dev_err(dssdev->dev, "failed to configure DSI pins\n"); | ||
936 | goto err0; | ||
937 | }; | ||
938 | |||
939 | r = omapdss_dsi_set_config(dssdev, &dsi_config); | ||
940 | if (r) { | ||
941 | dev_err(dssdev->dev, "failed to configure DSI\n"); | ||
942 | goto err0; | ||
943 | } | ||
944 | |||
945 | r = omapdss_dsi_display_enable(dssdev); | ||
946 | if (r) { | ||
947 | dev_err(dssdev->dev, "failed to enable DSI\n"); | ||
948 | goto err0; | ||
949 | } | ||
950 | |||
951 | taal_hw_reset(dssdev); | ||
952 | |||
953 | omapdss_dsi_vc_enable_hs(dssdev, td->channel, false); | ||
954 | |||
955 | r = taal_sleep_out(td); | ||
956 | if (r) | ||
957 | goto err; | ||
958 | |||
959 | r = taal_get_id(td, &id1, &id2, &id3); | ||
960 | if (r) | ||
961 | goto err; | ||
962 | |||
963 | /* on early Taal revisions CABC is broken */ | ||
964 | if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) | ||
965 | td->cabc_broken = true; | ||
966 | |||
967 | r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff); | ||
968 | if (r) | ||
969 | goto err; | ||
970 | |||
971 | r = taal_dcs_write_1(td, DCS_CTRL_DISPLAY, | ||
972 | (1<<2) | (1<<5)); /* BL | BCTRL */ | ||
973 | if (r) | ||
974 | goto err; | ||
975 | |||
976 | r = taal_dcs_write_1(td, MIPI_DCS_SET_PIXEL_FORMAT, | ||
977 | MIPI_DCS_PIXEL_FMT_24BIT); | ||
978 | if (r) | ||
979 | goto err; | ||
980 | |||
981 | if (!td->cabc_broken) { | ||
982 | r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode); | ||
983 | if (r) | ||
984 | goto err; | ||
985 | } | ||
986 | |||
987 | r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_ON); | ||
988 | if (r) | ||
989 | goto err; | ||
990 | |||
991 | r = _taal_enable_te(dssdev, td->te_enabled); | ||
992 | if (r) | ||
993 | goto err; | ||
994 | |||
995 | r = dsi_enable_video_output(dssdev, td->channel); | ||
996 | if (r) | ||
997 | goto err; | ||
998 | |||
999 | td->enabled = 1; | ||
1000 | |||
1001 | if (!td->intro_printed) { | ||
1002 | dev_info(dssdev->dev, "panel revision %02x.%02x.%02x\n", | ||
1003 | id1, id2, id3); | ||
1004 | if (td->cabc_broken) | ||
1005 | dev_info(dssdev->dev, | ||
1006 | "old Taal version, CABC disabled\n"); | ||
1007 | td->intro_printed = true; | ||
1008 | } | ||
1009 | |||
1010 | omapdss_dsi_vc_enable_hs(dssdev, td->channel, true); | ||
1011 | |||
1012 | return 0; | ||
1013 | err: | ||
1014 | dev_err(dssdev->dev, "error while enabling panel, issuing HW reset\n"); | ||
1015 | |||
1016 | taal_hw_reset(dssdev); | ||
1017 | |||
1018 | omapdss_dsi_display_disable(dssdev, true, false); | ||
1019 | err0: | ||
1020 | return r; | ||
1021 | } | ||
1022 | |||
1023 | static void taal_power_off(struct omap_dss_device *dssdev) | ||
1024 | { | ||
1025 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1026 | int r; | ||
1027 | |||
1028 | dsi_disable_video_output(dssdev, td->channel); | ||
1029 | |||
1030 | r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); | ||
1031 | if (!r) | ||
1032 | r = taal_sleep_in(td); | ||
1033 | |||
1034 | if (r) { | ||
1035 | dev_err(dssdev->dev, | ||
1036 | "error disabling panel, issuing HW reset\n"); | ||
1037 | taal_hw_reset(dssdev); | ||
1038 | } | ||
1039 | |||
1040 | omapdss_dsi_display_disable(dssdev, true, false); | ||
1041 | |||
1042 | td->enabled = 0; | ||
1043 | } | ||
1044 | |||
1045 | static int taal_panel_reset(struct omap_dss_device *dssdev) | ||
1046 | { | ||
1047 | dev_err(dssdev->dev, "performing LCD reset\n"); | ||
1048 | |||
1049 | taal_power_off(dssdev); | ||
1050 | taal_hw_reset(dssdev); | ||
1051 | return taal_power_on(dssdev); | ||
1052 | } | ||
1053 | |||
1054 | static int taal_enable(struct omap_dss_device *dssdev) | ||
1055 | { | ||
1056 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1057 | int r; | ||
1058 | |||
1059 | dev_dbg(dssdev->dev, "enable\n"); | ||
1060 | |||
1061 | mutex_lock(&td->lock); | ||
1062 | |||
1063 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
1064 | r = -EINVAL; | ||
1065 | goto err; | ||
1066 | } | ||
1067 | |||
1068 | dsi_bus_lock(dssdev); | ||
1069 | |||
1070 | r = taal_power_on(dssdev); | ||
1071 | |||
1072 | dsi_bus_unlock(dssdev); | ||
1073 | |||
1074 | if (r) | ||
1075 | goto err; | ||
1076 | |||
1077 | taal_queue_esd_work(dssdev); | ||
1078 | |||
1079 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
1080 | |||
1081 | mutex_unlock(&td->lock); | ||
1082 | |||
1083 | return 0; | ||
1084 | err: | ||
1085 | dev_dbg(dssdev->dev, "enable failed\n"); | ||
1086 | mutex_unlock(&td->lock); | ||
1087 | return r; | ||
1088 | } | ||
1089 | |||
1090 | static void taal_disable(struct omap_dss_device *dssdev) | ||
1091 | { | ||
1092 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1093 | |||
1094 | dev_dbg(dssdev->dev, "disable\n"); | ||
1095 | |||
1096 | mutex_lock(&td->lock); | ||
1097 | |||
1098 | taal_cancel_ulps_work(dssdev); | ||
1099 | taal_cancel_esd_work(dssdev); | ||
1100 | |||
1101 | dsi_bus_lock(dssdev); | ||
1102 | |||
1103 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
1104 | int r; | ||
1105 | |||
1106 | r = taal_wake_up(dssdev); | ||
1107 | if (!r) | ||
1108 | taal_power_off(dssdev); | ||
1109 | } | ||
1110 | |||
1111 | dsi_bus_unlock(dssdev); | ||
1112 | |||
1113 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
1114 | |||
1115 | mutex_unlock(&td->lock); | ||
1116 | } | ||
1117 | |||
1118 | static void taal_framedone_cb(int err, void *data) | ||
1119 | { | ||
1120 | struct omap_dss_device *dssdev = data; | ||
1121 | dev_dbg(dssdev->dev, "framedone, err %d\n", err); | ||
1122 | dsi_bus_unlock(dssdev); | ||
1123 | } | ||
1124 | |||
1125 | static irqreturn_t taal_te_isr(int irq, void *data) | ||
1126 | { | ||
1127 | struct omap_dss_device *dssdev = data; | ||
1128 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1129 | int old; | ||
1130 | int r; | ||
1131 | |||
1132 | old = atomic_cmpxchg(&td->do_update, 1, 0); | ||
1133 | |||
1134 | if (old) { | ||
1135 | cancel_delayed_work(&td->te_timeout_work); | ||
1136 | |||
1137 | r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, | ||
1138 | dssdev); | ||
1139 | if (r) | ||
1140 | goto err; | ||
1141 | } | ||
1142 | |||
1143 | return IRQ_HANDLED; | ||
1144 | err: | ||
1145 | dev_err(dssdev->dev, "start update failed\n"); | ||
1146 | dsi_bus_unlock(dssdev); | ||
1147 | return IRQ_HANDLED; | ||
1148 | } | ||
1149 | |||
1150 | static void taal_te_timeout_work_callback(struct work_struct *work) | ||
1151 | { | ||
1152 | struct taal_data *td = container_of(work, struct taal_data, | ||
1153 | te_timeout_work.work); | ||
1154 | struct omap_dss_device *dssdev = td->dssdev; | ||
1155 | |||
1156 | dev_err(dssdev->dev, "TE not received for 250ms!\n"); | ||
1157 | |||
1158 | atomic_set(&td->do_update, 0); | ||
1159 | dsi_bus_unlock(dssdev); | ||
1160 | } | ||
1161 | |||
1162 | static int taal_update(struct omap_dss_device *dssdev, | ||
1163 | u16 x, u16 y, u16 w, u16 h) | ||
1164 | { | ||
1165 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1166 | int r; | ||
1167 | |||
1168 | dev_dbg(dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | ||
1169 | |||
1170 | mutex_lock(&td->lock); | ||
1171 | dsi_bus_lock(dssdev); | ||
1172 | |||
1173 | r = taal_wake_up(dssdev); | ||
1174 | if (r) | ||
1175 | goto err; | ||
1176 | |||
1177 | if (!td->enabled) { | ||
1178 | r = 0; | ||
1179 | goto err; | ||
1180 | } | ||
1181 | |||
1182 | /* XXX no need to send this every frame, but dsi break if not done */ | ||
1183 | r = taal_set_update_window(td, 0, 0, | ||
1184 | dssdev->panel.timings.x_res, | ||
1185 | dssdev->panel.timings.y_res); | ||
1186 | if (r) | ||
1187 | goto err; | ||
1188 | |||
1189 | if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { | ||
1190 | schedule_delayed_work(&td->te_timeout_work, | ||
1191 | msecs_to_jiffies(250)); | ||
1192 | atomic_set(&td->do_update, 1); | ||
1193 | } else { | ||
1194 | r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, | ||
1195 | dssdev); | ||
1196 | if (r) | ||
1197 | goto err; | ||
1198 | } | ||
1199 | |||
1200 | /* note: no bus_unlock here. unlock is in framedone_cb */ | ||
1201 | mutex_unlock(&td->lock); | ||
1202 | return 0; | ||
1203 | err: | ||
1204 | dsi_bus_unlock(dssdev); | ||
1205 | mutex_unlock(&td->lock); | ||
1206 | return r; | ||
1207 | } | ||
1208 | |||
1209 | static int taal_sync(struct omap_dss_device *dssdev) | ||
1210 | { | ||
1211 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1212 | |||
1213 | dev_dbg(dssdev->dev, "sync\n"); | ||
1214 | |||
1215 | mutex_lock(&td->lock); | ||
1216 | dsi_bus_lock(dssdev); | ||
1217 | dsi_bus_unlock(dssdev); | ||
1218 | mutex_unlock(&td->lock); | ||
1219 | |||
1220 | dev_dbg(dssdev->dev, "sync done\n"); | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | ||
1226 | { | ||
1227 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1228 | int r; | ||
1229 | |||
1230 | if (enable) | ||
1231 | r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); | ||
1232 | else | ||
1233 | r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF); | ||
1234 | |||
1235 | if (!gpio_is_valid(td->ext_te_gpio)) | ||
1236 | omapdss_dsi_enable_te(dssdev, enable); | ||
1237 | |||
1238 | /* possible panel bug */ | ||
1239 | msleep(100); | ||
1240 | |||
1241 | return r; | ||
1242 | } | ||
1243 | |||
1244 | static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) | ||
1245 | { | ||
1246 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1247 | int r; | ||
1248 | |||
1249 | mutex_lock(&td->lock); | ||
1250 | |||
1251 | if (td->te_enabled == enable) | ||
1252 | goto end; | ||
1253 | |||
1254 | dsi_bus_lock(dssdev); | ||
1255 | |||
1256 | if (td->enabled) { | ||
1257 | r = taal_wake_up(dssdev); | ||
1258 | if (r) | ||
1259 | goto err; | ||
1260 | |||
1261 | r = _taal_enable_te(dssdev, enable); | ||
1262 | if (r) | ||
1263 | goto err; | ||
1264 | } | ||
1265 | |||
1266 | td->te_enabled = enable; | ||
1267 | |||
1268 | dsi_bus_unlock(dssdev); | ||
1269 | end: | ||
1270 | mutex_unlock(&td->lock); | ||
1271 | |||
1272 | return 0; | ||
1273 | err: | ||
1274 | dsi_bus_unlock(dssdev); | ||
1275 | mutex_unlock(&td->lock); | ||
1276 | |||
1277 | return r; | ||
1278 | } | ||
1279 | |||
1280 | static int taal_get_te(struct omap_dss_device *dssdev) | ||
1281 | { | ||
1282 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1283 | int r; | ||
1284 | |||
1285 | mutex_lock(&td->lock); | ||
1286 | r = td->te_enabled; | ||
1287 | mutex_unlock(&td->lock); | ||
1288 | |||
1289 | return r; | ||
1290 | } | ||
1291 | |||
1292 | static int taal_run_test(struct omap_dss_device *dssdev, int test_num) | ||
1293 | { | ||
1294 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1295 | u8 id1, id2, id3; | ||
1296 | int r; | ||
1297 | |||
1298 | mutex_lock(&td->lock); | ||
1299 | |||
1300 | if (!td->enabled) { | ||
1301 | r = -ENODEV; | ||
1302 | goto err1; | ||
1303 | } | ||
1304 | |||
1305 | dsi_bus_lock(dssdev); | ||
1306 | |||
1307 | r = taal_wake_up(dssdev); | ||
1308 | if (r) | ||
1309 | goto err2; | ||
1310 | |||
1311 | r = taal_dcs_read_1(td, DCS_GET_ID1, &id1); | ||
1312 | if (r) | ||
1313 | goto err2; | ||
1314 | r = taal_dcs_read_1(td, DCS_GET_ID2, &id2); | ||
1315 | if (r) | ||
1316 | goto err2; | ||
1317 | r = taal_dcs_read_1(td, DCS_GET_ID3, &id3); | ||
1318 | if (r) | ||
1319 | goto err2; | ||
1320 | |||
1321 | dsi_bus_unlock(dssdev); | ||
1322 | mutex_unlock(&td->lock); | ||
1323 | return 0; | ||
1324 | err2: | ||
1325 | dsi_bus_unlock(dssdev); | ||
1326 | err1: | ||
1327 | mutex_unlock(&td->lock); | ||
1328 | return r; | ||
1329 | } | ||
1330 | |||
1331 | static int taal_memory_read(struct omap_dss_device *dssdev, | ||
1332 | void *buf, size_t size, | ||
1333 | u16 x, u16 y, u16 w, u16 h) | ||
1334 | { | ||
1335 | int r; | ||
1336 | int first = 1; | ||
1337 | int plen; | ||
1338 | unsigned buf_used = 0; | ||
1339 | struct taal_data *td = dev_get_drvdata(dssdev->dev); | ||
1340 | |||
1341 | if (size < w * h * 3) | ||
1342 | return -ENOMEM; | ||
1343 | |||
1344 | mutex_lock(&td->lock); | ||
1345 | |||
1346 | if (!td->enabled) { | ||
1347 | r = -ENODEV; | ||
1348 | goto err1; | ||
1349 | } | ||
1350 | |||
1351 | size = min(w * h * 3, | ||
1352 | dssdev->panel.timings.x_res * | ||
1353 | dssdev->panel.timings.y_res * 3); | ||
1354 | |||
1355 | dsi_bus_lock(dssdev); | ||
1356 | |||
1357 | r = taal_wake_up(dssdev); | ||
1358 | if (r) | ||
1359 | goto err2; | ||
1360 | |||
1361 | /* plen 1 or 2 goes into short packet. until checksum error is fixed, | ||
1362 | * use short packets. plen 32 works, but bigger packets seem to cause | ||
1363 | * an error. */ | ||
1364 | if (size % 2) | ||
1365 | plen = 1; | ||
1366 | else | ||
1367 | plen = 2; | ||
1368 | |||
1369 | taal_set_update_window(td, x, y, w, h); | ||
1370 | |||
1371 | r = dsi_vc_set_max_rx_packet_size(dssdev, td->channel, plen); | ||
1372 | if (r) | ||
1373 | goto err2; | ||
1374 | |||
1375 | while (buf_used < size) { | ||
1376 | u8 dcs_cmd = first ? 0x2e : 0x3e; | ||
1377 | first = 0; | ||
1378 | |||
1379 | r = dsi_vc_dcs_read(dssdev, td->channel, dcs_cmd, | ||
1380 | buf + buf_used, size - buf_used); | ||
1381 | |||
1382 | if (r < 0) { | ||
1383 | dev_err(dssdev->dev, "read error\n"); | ||
1384 | goto err3; | ||
1385 | } | ||
1386 | |||
1387 | buf_used += r; | ||
1388 | |||
1389 | if (r < plen) { | ||
1390 | dev_err(dssdev->dev, "short read\n"); | ||
1391 | break; | ||
1392 | } | ||
1393 | |||
1394 | if (signal_pending(current)) { | ||
1395 | dev_err(dssdev->dev, "signal pending, " | ||
1396 | "aborting memory read\n"); | ||
1397 | r = -ERESTARTSYS; | ||
1398 | goto err3; | ||
1399 | } | ||
1400 | } | ||
1401 | |||
1402 | r = buf_used; | ||
1403 | |||
1404 | err3: | ||
1405 | dsi_vc_set_max_rx_packet_size(dssdev, td->channel, 1); | ||
1406 | err2: | ||
1407 | dsi_bus_unlock(dssdev); | ||
1408 | err1: | ||
1409 | mutex_unlock(&td->lock); | ||
1410 | return r; | ||
1411 | } | ||
1412 | |||
1413 | static void taal_ulps_work(struct work_struct *work) | ||
1414 | { | ||
1415 | struct taal_data *td = container_of(work, struct taal_data, | ||
1416 | ulps_work.work); | ||
1417 | struct omap_dss_device *dssdev = td->dssdev; | ||
1418 | |||
1419 | mutex_lock(&td->lock); | ||
1420 | |||
1421 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !td->enabled) { | ||
1422 | mutex_unlock(&td->lock); | ||
1423 | return; | ||
1424 | } | ||
1425 | |||
1426 | dsi_bus_lock(dssdev); | ||
1427 | |||
1428 | taal_enter_ulps(dssdev); | ||
1429 | |||
1430 | dsi_bus_unlock(dssdev); | ||
1431 | mutex_unlock(&td->lock); | ||
1432 | } | ||
1433 | |||
1434 | static void taal_esd_work(struct work_struct *work) | ||
1435 | { | ||
1436 | struct taal_data *td = container_of(work, struct taal_data, | ||
1437 | esd_work.work); | ||
1438 | struct omap_dss_device *dssdev = td->dssdev; | ||
1439 | u8 state1, state2; | ||
1440 | int r; | ||
1441 | |||
1442 | mutex_lock(&td->lock); | ||
1443 | |||
1444 | if (!td->enabled) { | ||
1445 | mutex_unlock(&td->lock); | ||
1446 | return; | ||
1447 | } | ||
1448 | |||
1449 | dsi_bus_lock(dssdev); | ||
1450 | |||
1451 | r = taal_wake_up(dssdev); | ||
1452 | if (r) { | ||
1453 | dev_err(dssdev->dev, "failed to exit ULPS\n"); | ||
1454 | goto err; | ||
1455 | } | ||
1456 | |||
1457 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1); | ||
1458 | if (r) { | ||
1459 | dev_err(dssdev->dev, "failed to read Taal status\n"); | ||
1460 | goto err; | ||
1461 | } | ||
1462 | |||
1463 | /* Run self diagnostics */ | ||
1464 | r = taal_sleep_out(td); | ||
1465 | if (r) { | ||
1466 | dev_err(dssdev->dev, "failed to run Taal self-diagnostics\n"); | ||
1467 | goto err; | ||
1468 | } | ||
1469 | |||
1470 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2); | ||
1471 | if (r) { | ||
1472 | dev_err(dssdev->dev, "failed to read Taal status\n"); | ||
1473 | goto err; | ||
1474 | } | ||
1475 | |||
1476 | /* Each sleep out command will trigger a self diagnostic and flip | ||
1477 | * Bit6 if the test passes. | ||
1478 | */ | ||
1479 | if (!((state1 ^ state2) & (1 << 6))) { | ||
1480 | dev_err(dssdev->dev, "LCD self diagnostics failed\n"); | ||
1481 | goto err; | ||
1482 | } | ||
1483 | /* Self-diagnostics result is also shown on TE GPIO line. We need | ||
1484 | * to re-enable TE after self diagnostics */ | ||
1485 | if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { | ||
1486 | r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); | ||
1487 | if (r) | ||
1488 | goto err; | ||
1489 | } | ||
1490 | |||
1491 | dsi_bus_unlock(dssdev); | ||
1492 | |||
1493 | taal_queue_esd_work(dssdev); | ||
1494 | |||
1495 | mutex_unlock(&td->lock); | ||
1496 | return; | ||
1497 | err: | ||
1498 | dev_err(dssdev->dev, "performing LCD reset\n"); | ||
1499 | |||
1500 | taal_panel_reset(dssdev); | ||
1501 | |||
1502 | dsi_bus_unlock(dssdev); | ||
1503 | |||
1504 | taal_queue_esd_work(dssdev); | ||
1505 | |||
1506 | mutex_unlock(&td->lock); | ||
1507 | } | ||
1508 | |||
1509 | static struct omap_dss_driver taal_driver = { | ||
1510 | .probe = taal_probe, | ||
1511 | .remove = __exit_p(taal_remove), | ||
1512 | |||
1513 | .enable = taal_enable, | ||
1514 | .disable = taal_disable, | ||
1515 | |||
1516 | .update = taal_update, | ||
1517 | .sync = taal_sync, | ||
1518 | |||
1519 | .get_resolution = taal_get_resolution, | ||
1520 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
1521 | |||
1522 | .enable_te = taal_enable_te, | ||
1523 | .get_te = taal_get_te, | ||
1524 | |||
1525 | .run_test = taal_run_test, | ||
1526 | .memory_read = taal_memory_read, | ||
1527 | |||
1528 | .driver = { | ||
1529 | .name = "taal", | ||
1530 | .owner = THIS_MODULE, | ||
1531 | }, | ||
1532 | }; | ||
1533 | |||
1534 | static int __init taal_init(void) | ||
1535 | { | ||
1536 | omap_dss_register_driver(&taal_driver); | ||
1537 | |||
1538 | return 0; | ||
1539 | } | ||
1540 | |||
1541 | static void __exit taal_exit(void) | ||
1542 | { | ||
1543 | omap_dss_unregister_driver(&taal_driver); | ||
1544 | } | ||
1545 | |||
1546 | module_init(taal_init); | ||
1547 | module_exit(taal_exit); | ||
1548 | |||
1549 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); | ||
1550 | MODULE_DESCRIPTION("Taal Driver"); | ||
1551 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c deleted file mode 100644 index 1fdfb158a2a9..000000000000 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ /dev/null | |||
@@ -1,353 +0,0 @@ | |||
1 | /* | ||
2 | * TFP410 DPI-to-DVI chip | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Inc | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * 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/slab.h> | ||
22 | #include <video/omapdss.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <drm/drm_edid.h> | ||
26 | |||
27 | #include <video/omap-panel-data.h> | ||
28 | |||
29 | static const struct omap_video_timings tfp410_default_timings = { | ||
30 | .x_res = 640, | ||
31 | .y_res = 480, | ||
32 | |||
33 | .pixel_clock = 23500, | ||
34 | |||
35 | .hfp = 48, | ||
36 | .hsw = 32, | ||
37 | .hbp = 80, | ||
38 | |||
39 | .vfp = 3, | ||
40 | .vsw = 4, | ||
41 | .vbp = 7, | ||
42 | |||
43 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
44 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
45 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
46 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
47 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
48 | }; | ||
49 | |||
50 | struct panel_drv_data { | ||
51 | struct omap_dss_device *dssdev; | ||
52 | |||
53 | struct mutex lock; | ||
54 | |||
55 | int pd_gpio; | ||
56 | |||
57 | struct i2c_adapter *i2c_adapter; | ||
58 | }; | ||
59 | |||
60 | static int tfp410_power_on(struct omap_dss_device *dssdev) | ||
61 | { | ||
62 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
63 | int r; | ||
64 | |||
65 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
66 | return 0; | ||
67 | |||
68 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
69 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
70 | |||
71 | r = omapdss_dpi_display_enable(dssdev); | ||
72 | if (r) | ||
73 | goto err0; | ||
74 | |||
75 | if (gpio_is_valid(ddata->pd_gpio)) | ||
76 | gpio_set_value_cansleep(ddata->pd_gpio, 1); | ||
77 | |||
78 | return 0; | ||
79 | err0: | ||
80 | return r; | ||
81 | } | ||
82 | |||
83 | static void tfp410_power_off(struct omap_dss_device *dssdev) | ||
84 | { | ||
85 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
86 | |||
87 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
88 | return; | ||
89 | |||
90 | if (gpio_is_valid(ddata->pd_gpio)) | ||
91 | gpio_set_value_cansleep(ddata->pd_gpio, 0); | ||
92 | |||
93 | omapdss_dpi_display_disable(dssdev); | ||
94 | } | ||
95 | |||
96 | static int tfp410_probe(struct omap_dss_device *dssdev) | ||
97 | { | ||
98 | struct panel_drv_data *ddata; | ||
99 | int r; | ||
100 | int i2c_bus_num; | ||
101 | |||
102 | ddata = devm_kzalloc(dssdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
103 | if (!ddata) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | dssdev->panel.timings = tfp410_default_timings; | ||
107 | |||
108 | ddata->dssdev = dssdev; | ||
109 | mutex_init(&ddata->lock); | ||
110 | |||
111 | if (dssdev->data) { | ||
112 | struct tfp410_platform_data *pdata = dssdev->data; | ||
113 | |||
114 | ddata->pd_gpio = pdata->power_down_gpio; | ||
115 | i2c_bus_num = pdata->i2c_bus_num; | ||
116 | } else { | ||
117 | ddata->pd_gpio = -1; | ||
118 | i2c_bus_num = -1; | ||
119 | } | ||
120 | |||
121 | if (gpio_is_valid(ddata->pd_gpio)) { | ||
122 | r = devm_gpio_request_one(dssdev->dev, ddata->pd_gpio, | ||
123 | GPIOF_OUT_INIT_LOW, "tfp410 pd"); | ||
124 | if (r) { | ||
125 | dev_err(dssdev->dev, "Failed to request PD GPIO %d\n", | ||
126 | ddata->pd_gpio); | ||
127 | return r; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (i2c_bus_num != -1) { | ||
132 | struct i2c_adapter *adapter; | ||
133 | |||
134 | adapter = i2c_get_adapter(i2c_bus_num); | ||
135 | if (!adapter) { | ||
136 | dev_err(dssdev->dev, "Failed to get I2C adapter, bus %d\n", | ||
137 | i2c_bus_num); | ||
138 | return -EPROBE_DEFER; | ||
139 | } | ||
140 | |||
141 | ddata->i2c_adapter = adapter; | ||
142 | } | ||
143 | |||
144 | dev_set_drvdata(dssdev->dev, ddata); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) | ||
150 | { | ||
151 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
152 | |||
153 | mutex_lock(&ddata->lock); | ||
154 | |||
155 | if (ddata->i2c_adapter) | ||
156 | i2c_put_adapter(ddata->i2c_adapter); | ||
157 | |||
158 | dev_set_drvdata(dssdev->dev, NULL); | ||
159 | |||
160 | mutex_unlock(&ddata->lock); | ||
161 | } | ||
162 | |||
163 | static int tfp410_enable(struct omap_dss_device *dssdev) | ||
164 | { | ||
165 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
166 | int r; | ||
167 | |||
168 | mutex_lock(&ddata->lock); | ||
169 | |||
170 | r = tfp410_power_on(dssdev); | ||
171 | if (r == 0) | ||
172 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
173 | |||
174 | mutex_unlock(&ddata->lock); | ||
175 | |||
176 | return r; | ||
177 | } | ||
178 | |||
179 | static void tfp410_disable(struct omap_dss_device *dssdev) | ||
180 | { | ||
181 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
182 | |||
183 | mutex_lock(&ddata->lock); | ||
184 | |||
185 | tfp410_power_off(dssdev); | ||
186 | |||
187 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
188 | |||
189 | mutex_unlock(&ddata->lock); | ||
190 | } | ||
191 | |||
192 | static void tfp410_set_timings(struct omap_dss_device *dssdev, | ||
193 | struct omap_video_timings *timings) | ||
194 | { | ||
195 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
196 | |||
197 | mutex_lock(&ddata->lock); | ||
198 | omapdss_dpi_set_timings(dssdev, timings); | ||
199 | dssdev->panel.timings = *timings; | ||
200 | mutex_unlock(&ddata->lock); | ||
201 | } | ||
202 | |||
203 | static void tfp410_get_timings(struct omap_dss_device *dssdev, | ||
204 | struct omap_video_timings *timings) | ||
205 | { | ||
206 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
207 | |||
208 | mutex_lock(&ddata->lock); | ||
209 | *timings = dssdev->panel.timings; | ||
210 | mutex_unlock(&ddata->lock); | ||
211 | } | ||
212 | |||
213 | static int tfp410_check_timings(struct omap_dss_device *dssdev, | ||
214 | struct omap_video_timings *timings) | ||
215 | { | ||
216 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
217 | int r; | ||
218 | |||
219 | mutex_lock(&ddata->lock); | ||
220 | r = dpi_check_timings(dssdev, timings); | ||
221 | mutex_unlock(&ddata->lock); | ||
222 | |||
223 | return r; | ||
224 | } | ||
225 | |||
226 | |||
227 | static int tfp410_ddc_read(struct i2c_adapter *adapter, | ||
228 | unsigned char *buf, u16 count, u8 offset) | ||
229 | { | ||
230 | int r, retries; | ||
231 | |||
232 | for (retries = 3; retries > 0; retries--) { | ||
233 | struct i2c_msg msgs[] = { | ||
234 | { | ||
235 | .addr = DDC_ADDR, | ||
236 | .flags = 0, | ||
237 | .len = 1, | ||
238 | .buf = &offset, | ||
239 | }, { | ||
240 | .addr = DDC_ADDR, | ||
241 | .flags = I2C_M_RD, | ||
242 | .len = count, | ||
243 | .buf = buf, | ||
244 | } | ||
245 | }; | ||
246 | |||
247 | r = i2c_transfer(adapter, msgs, 2); | ||
248 | if (r == 2) | ||
249 | return 0; | ||
250 | |||
251 | if (r != -EAGAIN) | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | return r < 0 ? r : -EIO; | ||
256 | } | ||
257 | |||
258 | static int tfp410_read_edid(struct omap_dss_device *dssdev, | ||
259 | u8 *edid, int len) | ||
260 | { | ||
261 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
262 | int r, l, bytes_read; | ||
263 | |||
264 | mutex_lock(&ddata->lock); | ||
265 | |||
266 | if (!ddata->i2c_adapter) { | ||
267 | r = -ENODEV; | ||
268 | goto err; | ||
269 | } | ||
270 | |||
271 | l = min(EDID_LENGTH, len); | ||
272 | r = tfp410_ddc_read(ddata->i2c_adapter, edid, l, 0); | ||
273 | if (r) | ||
274 | goto err; | ||
275 | |||
276 | bytes_read = l; | ||
277 | |||
278 | /* if there are extensions, read second block */ | ||
279 | if (len > EDID_LENGTH && edid[0x7e] > 0) { | ||
280 | l = min(EDID_LENGTH, len - EDID_LENGTH); | ||
281 | |||
282 | r = tfp410_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH, | ||
283 | l, EDID_LENGTH); | ||
284 | if (r) | ||
285 | goto err; | ||
286 | |||
287 | bytes_read += l; | ||
288 | } | ||
289 | |||
290 | mutex_unlock(&ddata->lock); | ||
291 | |||
292 | return bytes_read; | ||
293 | |||
294 | err: | ||
295 | mutex_unlock(&ddata->lock); | ||
296 | return r; | ||
297 | } | ||
298 | |||
299 | static bool tfp410_detect(struct omap_dss_device *dssdev) | ||
300 | { | ||
301 | struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev); | ||
302 | unsigned char out; | ||
303 | int r; | ||
304 | |||
305 | mutex_lock(&ddata->lock); | ||
306 | |||
307 | if (!ddata->i2c_adapter) | ||
308 | goto out; | ||
309 | |||
310 | r = tfp410_ddc_read(ddata->i2c_adapter, &out, 1, 0); | ||
311 | |||
312 | mutex_unlock(&ddata->lock); | ||
313 | |||
314 | return r == 0; | ||
315 | |||
316 | out: | ||
317 | mutex_unlock(&ddata->lock); | ||
318 | return true; | ||
319 | } | ||
320 | |||
321 | static struct omap_dss_driver tfp410_driver = { | ||
322 | .probe = tfp410_probe, | ||
323 | .remove = __exit_p(tfp410_remove), | ||
324 | |||
325 | .enable = tfp410_enable, | ||
326 | .disable = tfp410_disable, | ||
327 | |||
328 | .set_timings = tfp410_set_timings, | ||
329 | .get_timings = tfp410_get_timings, | ||
330 | .check_timings = tfp410_check_timings, | ||
331 | |||
332 | .read_edid = tfp410_read_edid, | ||
333 | .detect = tfp410_detect, | ||
334 | |||
335 | .driver = { | ||
336 | .name = "tfp410", | ||
337 | .owner = THIS_MODULE, | ||
338 | }, | ||
339 | }; | ||
340 | |||
341 | static int __init tfp410_init(void) | ||
342 | { | ||
343 | return omap_dss_register_driver(&tfp410_driver); | ||
344 | } | ||
345 | |||
346 | static void __exit tfp410_exit(void) | ||
347 | { | ||
348 | omap_dss_unregister_driver(&tfp410_driver); | ||
349 | } | ||
350 | |||
351 | module_init(tfp410_init); | ||
352 | module_exit(tfp410_exit); | ||
353 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c deleted file mode 100644 index 7729b6fa6f97..000000000000 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ /dev/null | |||
@@ -1,596 +0,0 @@ | |||
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 <video/omapdss.h> | ||
21 | #include <video/omap-panel-data.h> | ||
22 | |||
23 | #define TPO_R02_MODE(x) ((x) & 7) | ||
24 | #define TPO_R02_MODE_800x480 7 | ||
25 | #define TPO_R02_NCLK_RISING BIT(3) | ||
26 | #define TPO_R02_HSYNC_HIGH BIT(4) | ||
27 | #define TPO_R02_VSYNC_HIGH BIT(5) | ||
28 | |||
29 | #define TPO_R03_NSTANDBY BIT(0) | ||
30 | #define TPO_R03_EN_CP_CLK BIT(1) | ||
31 | #define TPO_R03_EN_VGL_PUMP BIT(2) | ||
32 | #define TPO_R03_EN_PWM BIT(3) | ||
33 | #define TPO_R03_DRIVING_CAP_100 BIT(4) | ||
34 | #define TPO_R03_EN_PRE_CHARGE BIT(6) | ||
35 | #define TPO_R03_SOFTWARE_CTL BIT(7) | ||
36 | |||
37 | #define TPO_R04_NFLIP_H BIT(0) | ||
38 | #define TPO_R04_NFLIP_V BIT(1) | ||
39 | #define TPO_R04_CP_CLK_FREQ_1H BIT(2) | ||
40 | #define TPO_R04_VGL_FREQ_1H BIT(4) | ||
41 | |||
42 | #define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \ | ||
43 | TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \ | ||
44 | TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ | ||
45 | TPO_R03_SOFTWARE_CTL) | ||
46 | |||
47 | #define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \ | ||
48 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) | ||
49 | |||
50 | static const u16 tpo_td043_def_gamma[12] = { | ||
51 | 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 | ||
52 | }; | ||
53 | |||
54 | struct tpo_td043_device { | ||
55 | struct spi_device *spi; | ||
56 | struct regulator *vcc_reg; | ||
57 | int nreset_gpio; | ||
58 | u16 gamma[12]; | ||
59 | u32 mode; | ||
60 | u32 hmirror:1; | ||
61 | u32 vmirror:1; | ||
62 | u32 powered_on:1; | ||
63 | u32 spi_suspended:1; | ||
64 | u32 power_on_resume:1; | ||
65 | }; | ||
66 | |||
67 | /* used to pass spi_device from SPI to DSS portion of the driver */ | ||
68 | static struct tpo_td043_device *g_tpo_td043; | ||
69 | |||
70 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) | ||
71 | { | ||
72 | struct spi_message m; | ||
73 | struct spi_transfer xfer; | ||
74 | u16 w; | ||
75 | int r; | ||
76 | |||
77 | spi_message_init(&m); | ||
78 | |||
79 | memset(&xfer, 0, sizeof(xfer)); | ||
80 | |||
81 | w = ((u16)addr << 10) | (1 << 8) | data; | ||
82 | xfer.tx_buf = &w; | ||
83 | xfer.bits_per_word = 16; | ||
84 | xfer.len = 2; | ||
85 | spi_message_add_tail(&xfer, &m); | ||
86 | |||
87 | r = spi_sync(spi, &m); | ||
88 | if (r < 0) | ||
89 | dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r); | ||
90 | return r; | ||
91 | } | ||
92 | |||
93 | static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12]) | ||
94 | { | ||
95 | u8 i, val; | ||
96 | |||
97 | /* gamma bits [9:8] */ | ||
98 | for (val = i = 0; i < 4; i++) | ||
99 | val |= (gamma[i] & 0x300) >> ((i + 1) * 2); | ||
100 | tpo_td043_write(spi, 0x11, val); | ||
101 | |||
102 | for (val = i = 0; i < 4; i++) | ||
103 | val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2); | ||
104 | tpo_td043_write(spi, 0x12, val); | ||
105 | |||
106 | for (val = i = 0; i < 4; i++) | ||
107 | val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2); | ||
108 | tpo_td043_write(spi, 0x13, val); | ||
109 | |||
110 | /* gamma bits [7:0] */ | ||
111 | for (val = i = 0; i < 12; i++) | ||
112 | tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff); | ||
113 | } | ||
114 | |||
115 | static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v) | ||
116 | { | ||
117 | u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \ | ||
118 | TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H; | ||
119 | if (h) | ||
120 | reg4 &= ~TPO_R04_NFLIP_H; | ||
121 | if (v) | ||
122 | reg4 &= ~TPO_R04_NFLIP_V; | ||
123 | |||
124 | return tpo_td043_write(spi, 4, reg4); | ||
125 | } | ||
126 | |||
127 | static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable) | ||
128 | { | ||
129 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); | ||
130 | |||
131 | tpo_td043->hmirror = enable; | ||
132 | return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, | ||
133 | tpo_td043->vmirror); | ||
134 | } | ||
135 | |||
136 | static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev) | ||
137 | { | ||
138 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); | ||
139 | |||
140 | return tpo_td043->hmirror; | ||
141 | } | ||
142 | |||
143 | static ssize_t tpo_td043_vmirror_show(struct device *dev, | ||
144 | struct device_attribute *attr, char *buf) | ||
145 | { | ||
146 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
147 | |||
148 | return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror); | ||
149 | } | ||
150 | |||
151 | static ssize_t tpo_td043_vmirror_store(struct device *dev, | ||
152 | struct device_attribute *attr, const char *buf, size_t count) | ||
153 | { | ||
154 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
155 | int val; | ||
156 | int ret; | ||
157 | |||
158 | ret = kstrtoint(buf, 0, &val); | ||
159 | if (ret < 0) | ||
160 | return ret; | ||
161 | |||
162 | val = !!val; | ||
163 | |||
164 | ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val); | ||
165 | if (ret < 0) | ||
166 | return ret; | ||
167 | |||
168 | tpo_td043->vmirror = val; | ||
169 | |||
170 | return count; | ||
171 | } | ||
172 | |||
173 | static ssize_t tpo_td043_mode_show(struct device *dev, | ||
174 | struct device_attribute *attr, char *buf) | ||
175 | { | ||
176 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
177 | |||
178 | return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode); | ||
179 | } | ||
180 | |||
181 | static ssize_t tpo_td043_mode_store(struct device *dev, | ||
182 | struct device_attribute *attr, const char *buf, size_t count) | ||
183 | { | ||
184 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
185 | long val; | ||
186 | int ret; | ||
187 | |||
188 | ret = kstrtol(buf, 0, &val); | ||
189 | if (ret != 0 || val & ~7) | ||
190 | return -EINVAL; | ||
191 | |||
192 | tpo_td043->mode = val; | ||
193 | |||
194 | val |= TPO_R02_NCLK_RISING; | ||
195 | tpo_td043_write(tpo_td043->spi, 2, val); | ||
196 | |||
197 | return count; | ||
198 | } | ||
199 | |||
200 | static ssize_t tpo_td043_gamma_show(struct device *dev, | ||
201 | struct device_attribute *attr, char *buf) | ||
202 | { | ||
203 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
204 | ssize_t len = 0; | ||
205 | int ret; | ||
206 | int i; | ||
207 | |||
208 | for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) { | ||
209 | ret = snprintf(buf + len, PAGE_SIZE - len, "%u ", | ||
210 | tpo_td043->gamma[i]); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | len += ret; | ||
214 | } | ||
215 | buf[len - 1] = '\n'; | ||
216 | |||
217 | return len; | ||
218 | } | ||
219 | |||
220 | static ssize_t tpo_td043_gamma_store(struct device *dev, | ||
221 | struct device_attribute *attr, const char *buf, size_t count) | ||
222 | { | ||
223 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
224 | unsigned int g[12]; | ||
225 | int ret; | ||
226 | int i; | ||
227 | |||
228 | ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u", | ||
229 | &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], | ||
230 | &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]); | ||
231 | |||
232 | if (ret != 12) | ||
233 | return -EINVAL; | ||
234 | |||
235 | for (i = 0; i < 12; i++) | ||
236 | tpo_td043->gamma[i] = g[i]; | ||
237 | |||
238 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); | ||
239 | |||
240 | return count; | ||
241 | } | ||
242 | |||
243 | static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR, | ||
244 | tpo_td043_vmirror_show, tpo_td043_vmirror_store); | ||
245 | static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, | ||
246 | tpo_td043_mode_show, tpo_td043_mode_store); | ||
247 | static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR, | ||
248 | tpo_td043_gamma_show, tpo_td043_gamma_store); | ||
249 | |||
250 | static struct attribute *tpo_td043_attrs[] = { | ||
251 | &dev_attr_vmirror.attr, | ||
252 | &dev_attr_mode.attr, | ||
253 | &dev_attr_gamma.attr, | ||
254 | NULL, | ||
255 | }; | ||
256 | |||
257 | static struct attribute_group tpo_td043_attr_group = { | ||
258 | .attrs = tpo_td043_attrs, | ||
259 | }; | ||
260 | |||
261 | static const struct omap_video_timings tpo_td043_timings = { | ||
262 | .x_res = 800, | ||
263 | .y_res = 480, | ||
264 | |||
265 | .pixel_clock = 36000, | ||
266 | |||
267 | .hsw = 1, | ||
268 | .hfp = 68, | ||
269 | .hbp = 214, | ||
270 | |||
271 | .vsw = 1, | ||
272 | .vfp = 39, | ||
273 | .vbp = 34, | ||
274 | |||
275 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
276 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
277 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
278 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
279 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
280 | }; | ||
281 | |||
282 | static inline struct panel_tpo_td043_data | ||
283 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
284 | { | ||
285 | return (struct panel_tpo_td043_data *) dssdev->data; | ||
286 | } | ||
287 | |||
288 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | ||
289 | { | ||
290 | int r; | ||
291 | |||
292 | if (tpo_td043->powered_on) | ||
293 | return 0; | ||
294 | |||
295 | r = regulator_enable(tpo_td043->vcc_reg); | ||
296 | if (r != 0) | ||
297 | return r; | ||
298 | |||
299 | /* wait for panel to stabilize */ | ||
300 | msleep(160); | ||
301 | |||
302 | if (gpio_is_valid(tpo_td043->nreset_gpio)) | ||
303 | gpio_set_value(tpo_td043->nreset_gpio, 1); | ||
304 | |||
305 | tpo_td043_write(tpo_td043->spi, 2, | ||
306 | TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING); | ||
307 | tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL); | ||
308 | tpo_td043_write(tpo_td043->spi, 0x20, 0xf0); | ||
309 | tpo_td043_write(tpo_td043->spi, 0x21, 0xf0); | ||
310 | tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, | ||
311 | tpo_td043->vmirror); | ||
312 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); | ||
313 | |||
314 | tpo_td043->powered_on = 1; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | ||
319 | { | ||
320 | if (!tpo_td043->powered_on) | ||
321 | return; | ||
322 | |||
323 | tpo_td043_write(tpo_td043->spi, 3, | ||
324 | TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); | ||
325 | |||
326 | if (gpio_is_valid(tpo_td043->nreset_gpio)) | ||
327 | gpio_set_value(tpo_td043->nreset_gpio, 0); | ||
328 | |||
329 | /* wait for at least 2 vsyncs before cutting off power */ | ||
330 | msleep(50); | ||
331 | |||
332 | tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY); | ||
333 | |||
334 | regulator_disable(tpo_td043->vcc_reg); | ||
335 | |||
336 | tpo_td043->powered_on = 0; | ||
337 | } | ||
338 | |||
339 | static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) | ||
340 | { | ||
341 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); | ||
342 | int r; | ||
343 | |||
344 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
345 | return 0; | ||
346 | |||
347 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
348 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
349 | |||
350 | r = omapdss_dpi_display_enable(dssdev); | ||
351 | if (r) | ||
352 | goto err0; | ||
353 | |||
354 | /* | ||
355 | * If we are resuming from system suspend, SPI clocks might not be | ||
356 | * enabled yet, so we'll program the LCD from SPI PM resume callback. | ||
357 | */ | ||
358 | if (!tpo_td043->spi_suspended) { | ||
359 | r = tpo_td043_power_on(tpo_td043); | ||
360 | if (r) | ||
361 | goto err1; | ||
362 | } | ||
363 | |||
364 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
365 | |||
366 | return 0; | ||
367 | err1: | ||
368 | omapdss_dpi_display_disable(dssdev); | ||
369 | err0: | ||
370 | return r; | ||
371 | } | ||
372 | |||
373 | static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | ||
374 | { | ||
375 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); | ||
376 | |||
377 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
378 | return; | ||
379 | |||
380 | omapdss_dpi_display_disable(dssdev); | ||
381 | |||
382 | if (!tpo_td043->spi_suspended) | ||
383 | tpo_td043_power_off(tpo_td043); | ||
384 | } | ||
385 | |||
386 | static int tpo_td043_enable(struct omap_dss_device *dssdev) | ||
387 | { | ||
388 | dev_dbg(dssdev->dev, "enable\n"); | ||
389 | |||
390 | return tpo_td043_enable_dss(dssdev); | ||
391 | } | ||
392 | |||
393 | static void tpo_td043_disable(struct omap_dss_device *dssdev) | ||
394 | { | ||
395 | dev_dbg(dssdev->dev, "disable\n"); | ||
396 | |||
397 | tpo_td043_disable_dss(dssdev); | ||
398 | |||
399 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
400 | } | ||
401 | |||
402 | static int tpo_td043_probe(struct omap_dss_device *dssdev) | ||
403 | { | ||
404 | struct tpo_td043_device *tpo_td043 = g_tpo_td043; | ||
405 | struct panel_tpo_td043_data *pdata = get_panel_data(dssdev); | ||
406 | int ret = 0; | ||
407 | |||
408 | dev_dbg(dssdev->dev, "probe\n"); | ||
409 | |||
410 | if (tpo_td043 == NULL) { | ||
411 | dev_err(dssdev->dev, "missing tpo_td043_device\n"); | ||
412 | return -ENODEV; | ||
413 | } | ||
414 | |||
415 | if (!pdata) | ||
416 | return -EINVAL; | ||
417 | |||
418 | tpo_td043->nreset_gpio = pdata->nreset_gpio; | ||
419 | |||
420 | dssdev->panel.timings = tpo_td043_timings; | ||
421 | dssdev->ctrl.pixel_size = 24; | ||
422 | |||
423 | tpo_td043->mode = TPO_R02_MODE_800x480; | ||
424 | memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma)); | ||
425 | |||
426 | tpo_td043->vcc_reg = regulator_get(dssdev->dev, "vcc"); | ||
427 | if (IS_ERR(tpo_td043->vcc_reg)) { | ||
428 | dev_err(dssdev->dev, "failed to get LCD VCC regulator\n"); | ||
429 | ret = PTR_ERR(tpo_td043->vcc_reg); | ||
430 | goto fail_regulator; | ||
431 | } | ||
432 | |||
433 | if (gpio_is_valid(tpo_td043->nreset_gpio)) { | ||
434 | ret = devm_gpio_request_one(dssdev->dev, | ||
435 | tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW, | ||
436 | "lcd reset"); | ||
437 | if (ret < 0) { | ||
438 | dev_err(dssdev->dev, "couldn't request reset GPIO\n"); | ||
439 | goto fail_gpio_req; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | ret = sysfs_create_group(&dssdev->dev->kobj, &tpo_td043_attr_group); | ||
444 | if (ret) | ||
445 | dev_warn(dssdev->dev, "failed to create sysfs files\n"); | ||
446 | |||
447 | dev_set_drvdata(dssdev->dev, tpo_td043); | ||
448 | |||
449 | return 0; | ||
450 | |||
451 | fail_gpio_req: | ||
452 | regulator_put(tpo_td043->vcc_reg); | ||
453 | fail_regulator: | ||
454 | kfree(tpo_td043); | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | static void tpo_td043_remove(struct omap_dss_device *dssdev) | ||
459 | { | ||
460 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dssdev->dev); | ||
461 | |||
462 | dev_dbg(dssdev->dev, "remove\n"); | ||
463 | |||
464 | sysfs_remove_group(&dssdev->dev->kobj, &tpo_td043_attr_group); | ||
465 | regulator_put(tpo_td043->vcc_reg); | ||
466 | } | ||
467 | |||
468 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, | ||
469 | struct omap_video_timings *timings) | ||
470 | { | ||
471 | omapdss_dpi_set_timings(dssdev, timings); | ||
472 | |||
473 | dssdev->panel.timings = *timings; | ||
474 | } | ||
475 | |||
476 | static int tpo_td043_check_timings(struct omap_dss_device *dssdev, | ||
477 | struct omap_video_timings *timings) | ||
478 | { | ||
479 | return dpi_check_timings(dssdev, timings); | ||
480 | } | ||
481 | |||
482 | static struct omap_dss_driver tpo_td043_driver = { | ||
483 | .probe = tpo_td043_probe, | ||
484 | .remove = tpo_td043_remove, | ||
485 | |||
486 | .enable = tpo_td043_enable, | ||
487 | .disable = tpo_td043_disable, | ||
488 | .set_mirror = tpo_td043_set_hmirror, | ||
489 | .get_mirror = tpo_td043_get_hmirror, | ||
490 | |||
491 | .set_timings = tpo_td043_set_timings, | ||
492 | .check_timings = tpo_td043_check_timings, | ||
493 | |||
494 | .driver = { | ||
495 | .name = "tpo_td043mtea1_panel", | ||
496 | .owner = THIS_MODULE, | ||
497 | }, | ||
498 | }; | ||
499 | |||
500 | static int tpo_td043_spi_probe(struct spi_device *spi) | ||
501 | { | ||
502 | struct omap_dss_device *dssdev = spi->dev.platform_data; | ||
503 | struct tpo_td043_device *tpo_td043; | ||
504 | int ret; | ||
505 | |||
506 | if (dssdev == NULL) { | ||
507 | dev_err(&spi->dev, "missing dssdev\n"); | ||
508 | return -ENODEV; | ||
509 | } | ||
510 | |||
511 | if (g_tpo_td043 != NULL) | ||
512 | return -EBUSY; | ||
513 | |||
514 | spi->bits_per_word = 16; | ||
515 | spi->mode = SPI_MODE_0; | ||
516 | |||
517 | ret = spi_setup(spi); | ||
518 | if (ret < 0) { | ||
519 | dev_err(&spi->dev, "spi_setup failed: %d\n", ret); | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL); | ||
524 | if (tpo_td043 == NULL) | ||
525 | return -ENOMEM; | ||
526 | |||
527 | tpo_td043->spi = spi; | ||
528 | dev_set_drvdata(&spi->dev, tpo_td043); | ||
529 | g_tpo_td043 = tpo_td043; | ||
530 | |||
531 | omap_dss_register_driver(&tpo_td043_driver); | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int tpo_td043_spi_remove(struct spi_device *spi) | ||
537 | { | ||
538 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); | ||
539 | |||
540 | omap_dss_unregister_driver(&tpo_td043_driver); | ||
541 | kfree(tpo_td043); | ||
542 | g_tpo_td043 = NULL; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | #ifdef CONFIG_PM_SLEEP | ||
548 | static int tpo_td043_spi_suspend(struct device *dev) | ||
549 | { | ||
550 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
551 | |||
552 | dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", tpo_td043); | ||
553 | |||
554 | tpo_td043->power_on_resume = tpo_td043->powered_on; | ||
555 | tpo_td043_power_off(tpo_td043); | ||
556 | tpo_td043->spi_suspended = 1; | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int tpo_td043_spi_resume(struct device *dev) | ||
562 | { | ||
563 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
564 | int ret; | ||
565 | |||
566 | dev_dbg(dev, "tpo_td043_spi_resume\n"); | ||
567 | |||
568 | if (tpo_td043->power_on_resume) { | ||
569 | ret = tpo_td043_power_on(tpo_td043); | ||
570 | if (ret) | ||
571 | return ret; | ||
572 | } | ||
573 | tpo_td043->spi_suspended = 0; | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | #endif | ||
578 | |||
579 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, | ||
580 | tpo_td043_spi_suspend, tpo_td043_spi_resume); | ||
581 | |||
582 | static struct spi_driver tpo_td043_spi_driver = { | ||
583 | .driver = { | ||
584 | .name = "tpo_td043mtea1_panel_spi", | ||
585 | .owner = THIS_MODULE, | ||
586 | .pm = &tpo_td043_spi_pm, | ||
587 | }, | ||
588 | .probe = tpo_td043_spi_probe, | ||
589 | .remove = tpo_td043_spi_remove, | ||
590 | }; | ||
591 | |||
592 | module_spi_driver(tpo_td043_spi_driver); | ||
593 | |||
594 | MODULE_AUTHOR("GraÅžvydas Ignotas <notasas@gmail.com>"); | ||
595 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); | ||
596 | MODULE_LICENSE("GPL"); | ||