1 #include <linux/module.h>
2 #include <linux/delay.h>
4 #include <asm/arch/hardware.h>
5 #include <asm/arch/gpio.h>
6 #include <asm/arch/board.h>
7 #include <asm/arch/omapfb.h>
8 #include <asm/arch/lcd_lph8923.h>
10 #include <linux/spi/spi.h>
11 #include <asm/arch/mcspi.h>
13 #include "../../cbus/tahvo.h"
15 /* #define OMAPFB_DBG 1 */
19 #define LPH8923_MODULE_NAME "lcd_lph8923"
21 #define LPH8923_VER_BUGGY 1
22 #define LPH8923_VER_NON_BUGGY 3
29 unsigned int saved_bklight_level;
30 unsigned long hw_guard_end; /* next value of jiffies
32 next sleep in/out command */
33 unsigned long hw_guard_wait; /* max guard time in jiffies */
34 struct omapfb_device *fbdev;
35 struct spi_device *spi;
38 #define LPH8923_CMD_READ_DISP_ID 0x04
39 #define LPH8923_CMD_READ_RED 0x06
40 #define LPH8923_CMD_READ_GREEN 0x07
41 #define LPH8923_CMD_READ_BLUE 0x08
42 #define LPH8923_CMD_READ_DISP_STATUS 0x09
43 #define LPH8923_CMD_SLEEP_IN 0x10
44 #define LPH8923_CMD_SLEEP_OUT 0x11
45 #define LPH8923_CMD_DISP_OFF 0x28
46 #define LPH8923_CMD_DISP_ON 0x29
48 static struct lcd_panel lph8923_panel;
50 #define LPH8923_SPEED_HZ 12000000
52 static int lph8923_spi_probe(struct spi_device *spi)
56 spi->dev.power.power_state = PMSG_ON;
57 spi->mode = SPI_MODE_0;
58 spi->bits_per_word = 9;
61 DBGPRINT(1, "spi %p\n", spi);
64 omapfb_register_panel(&lph8923_panel);
69 static int lph8923_spi_remove(struct spi_device *spi)
78 static struct spi_driver lph8923_spi_driver = {
80 .name = LPH8923_MODULE_NAME,
84 .probe = lph8923_spi_probe,
85 .remove = __devexit_p(lph8923_spi_remove),
88 static int lph8923_drv_init(void)
90 spi_register_driver(&lph8923_spi_driver);
94 module_init(lph8923_drv_init);
96 static void lph8923_drv_cleanup(void)
98 spi_unregister_driver(&lph8923_spi_driver);
100 module_exit(lph8923_drv_cleanup);
102 static void set_spi_data_width(int width)
104 if (lph8923.spi->bits_per_word != width) {
105 lph8923.spi->bits_per_word = width;
106 spi_setup(lph8923.spi);
110 static void lph8923_read(int cmd, u8 *buf, int len)
112 struct spi_message m;
113 struct spi_transfer t;
116 BUG_ON(lph8923.spi == NULL);
118 spi_message_init(&m);
123 set_spi_data_width(10);
125 set_spi_data_width(9);
128 t.cs_change = len ? 1 : 0;
133 spi_message_add_tail(&t, &m);
140 spi_message_init(&m);
148 set_spi_data_width(8);
150 spi_message_add_tail(&t, &m);
155 static void lph8923_write(int cmd, const u8 *buf, int len)
157 struct spi_message m;
158 struct spi_transfer t;
162 BUG_ON(lph8923.spi == NULL);
164 spi_message_init(&m);
166 set_spi_data_width(9);
174 spi_message_add_tail(&t, &m);
181 for (i = 0; i < len; i++) {
182 spi_message_init(&m);
184 spi_message_add_tail(&t, &m);
185 w = buf[i] | (1 << 8);
190 static inline void lph8923_cmd(int cmd)
192 lph8923_write(cmd, NULL, 0);
199 } __attribute__ ((packed));;
201 static const struct cmd_data init_cmds_buggy_lph8923[] = {
203 { 0xb1, 2, "\x0b\x1c" },
204 { 0xb2, 4, "\x00\x00\x00\x00" },
205 { 0xb3, 4, "\x00\x00\x00\x00" },
207 { 0xb5, 4, "\x37\x07\x37\x07" },
208 { 0xb6, 2, "\x64\x24" },
210 { 0xb8, 3, "\x10\x11\x20" },
211 { 0xb9, 2, "\x31\x02" },
212 { 0xba, 3, "\x04\xa3\x9d" },
213 { 0xbb, 4, "\x15\xb2\x8c\x00" },
214 { 0xc2, 3, "\x02\x00\x00" },
217 static const struct cmd_data init_cmds_non_buggy_lph8923[] = {
218 { 0xc2, 3, "\x02\x00\x00" },
221 static inline void lph8923_set_16bit_mode(void)
223 lph8923_write(0x3a, "\x50", 1);
226 static void lph8923_send_init_string(void)
229 const struct cmd_data *cd;
231 switch (lph8923.version) {
232 case LPH8923_VER_BUGGY:
233 c = sizeof(init_cmds_buggy_lph8923)/sizeof(init_cmds_buggy_lph8923[0]);
234 cd = init_cmds_buggy_lph8923;
236 case LPH8923_VER_NON_BUGGY:
238 c = sizeof(init_cmds_non_buggy_lph8923)/sizeof(init_cmds_non_buggy_lph8923[0]);
239 cd = init_cmds_non_buggy_lph8923;
243 lph8923_write(cd->cmd, cd->data, cd->len);
246 lph8923_set_16bit_mode();
249 static void hw_guard_start(int guard_msec)
251 lph8923.hw_guard_wait = msecs_to_jiffies(guard_msec);
252 lph8923.hw_guard_end = jiffies + lph8923.hw_guard_wait;
255 static void hw_guard_wait(void)
257 unsigned long wait = lph8923.hw_guard_end - jiffies;
259 if ((long)wait > 0 && wait <= lph8923.hw_guard_wait) {
260 set_current_state(TASK_UNINTERRUPTIBLE);
261 schedule_timeout(wait);
265 static void lph8923_set_sleep_mode(int on)
267 int cmd, sleep_time = 5;
270 cmd = LPH8923_CMD_SLEEP_IN;
272 cmd = LPH8923_CMD_SLEEP_OUT;
276 /* When we enable the panel, it seems we _have_ to sleep
277 * 120 ms before sending the init string */
283 static void lph8923_set_display_state(int enabled)
285 int cmd = enabled ? LPH8923_CMD_DISP_ON : LPH8923_CMD_DISP_OFF;
290 static void lph8923_detect(void)
292 lph8923_read(LPH8923_CMD_READ_DISP_ID, lph8923.display_id, 3);
293 printk(KERN_INFO "Moscow display id: %02x%02x%02x\n",
294 lph8923.display_id[0], lph8923.display_id[1],
295 lph8923.display_id[2]);
297 if (lph8923.display_id[0] == 0x45) {
298 lph8923.version = LPH8923_VER_NON_BUGGY;
299 printk(KERN_INFO "Non-buggy Moscow detected\n");
302 lph8923.version = LPH8923_VER_BUGGY;
303 printk(KERN_INFO "Buggy Moscow detected\n");
307 static int lph8923_enabled(void)
312 lph8923_read(LPH8923_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
313 disp_status = __be32_to_cpu(disp_status);
314 enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
315 DBGPRINT(1, ": panel %senabled by bootloader (status 0x%04x)\n",
316 enabled ? "" : "not ", disp_status);
320 static int lph8923_panel_init(struct omapfb_device *fbdev)
322 lph8923.fbdev = fbdev;
326 if (lph8923.version == LPH8923_VER_NON_BUGGY)
327 lph8923.enabled = lph8923_enabled();
329 /* We can't be sure, but assume the bootloader
330 * enabled it already */
336 static void lph8923_panel_cleanup(void)
340 static int lph8923_panel_set_bklight_level(unsigned int level)
342 if (level > tahvo_get_max_backlight_level())
344 if (!lph8923.enabled) {
345 lph8923.saved_bklight_level = level;
348 tahvo_set_backlight_level(level);
353 static unsigned int lph8923_panel_get_bklight_level(void)
355 return tahvo_get_backlight_level();
358 static unsigned int lph8923_panel_get_bklight_max(void)
360 return tahvo_get_max_backlight_level();
363 static int lph8923_panel_enable(void)
368 lph8923_set_sleep_mode(0);
370 lph8923_send_init_string();
371 lph8923_set_display_state(1);
372 lph8923_panel_set_bklight_level(lph8923.saved_bklight_level);
377 static void lph8923_panel_disable(void)
379 if (!lph8923.enabled)
381 lph8923.saved_bklight_level = lph8923_panel_get_bklight_level();
382 lph8923_panel_set_bklight_level(0);
383 lph8923_set_display_state(0);
384 lph8923_set_sleep_mode(1);
388 static unsigned long lph8923_panel_get_caps(void)
390 return OMAPFB_CAPS_SET_BACKLIGHT;
393 static u16 read_first_pixel(void)
398 lph8923_read(LPH8923_CMD_READ_RED, &b, 1);
399 pixel = (b >> 1) << 11;
400 lph8923_read(LPH8923_CMD_READ_GREEN, &b, 1);
402 lph8923_read(LPH8923_CMD_READ_BLUE, &b, 1);
408 static int lph8923_panel_test(int test_num)
410 static const u16 test_values[4] = {
411 0x0000, 0xffff, 0xaaaa, 0x5555,
415 if (test_num != LCD_LPH8923_TEST_RGB_LINES)
416 return LCD_LPH8923_TEST_INVALID;
418 for (i = 0; i < ARRAY_SIZE(test_values); i++) {
422 omapfb_write_first_pixel(lph8923.fbdev, test_values[i]);
423 tmo = jiffies + msecs_to_jiffies(100);
424 delay = msecs_to_jiffies(25);
428 set_current_state(TASK_UNINTERRUPTIBLE);
429 schedule_timeout(delay);
430 pixel = read_first_pixel();
431 if (pixel == test_values[i])
433 if (time_after(jiffies, tmo)) {
434 printk(KERN_ERR "Moscow RGB I/F test failed: "
435 "expecting %04x, got %04x\n",
436 test_values[i], pixel);
437 return LCD_LPH8923_TEST_FAILED;
439 delay = msecs_to_jiffies(10);
446 static struct lcd_panel lph8923_panel = {
448 .config = OMAP_LCDC_PANEL_TFT,
454 .pixel_clock = 21940,
462 .init = lph8923_panel_init,
463 .cleanup = lph8923_panel_cleanup,
464 .enable = lph8923_panel_enable,
465 .disable = lph8923_panel_disable,
466 .get_caps = lph8923_panel_get_caps,
467 .set_bklight_level= lph8923_panel_set_bklight_level,
468 .get_bklight_level= lph8923_panel_get_bklight_level,
469 .get_bklight_max= lph8923_panel_get_bklight_max,
470 .run_test = lph8923_panel_test,