This source file includes following definitions.
- mipid_transfer
- mipid_cmd
- mipid_write
- mipid_read
- set_data_lines
- send_init_string
- hw_guard_start
- hw_guard_wait
- set_sleep_mode
- set_display_state
- mipid_set_bklight_level
- mipid_get_bklight_level
- mipid_get_bklight_max
- mipid_get_caps
- read_first_pixel
- mipid_run_test
- ls041y3_esd_recover
- ls041y3_esd_check_mode1
- ls041y3_esd_check_mode2
- ls041y3_esd_check
- mipid_esd_start_check
- mipid_esd_stop_check
- mipid_esd_work
- mipid_enable
- mipid_disable
- panel_enabled
- mipid_init
- mipid_cleanup
- mipid_detect
- mipid_spi_probe
- mipid_spi_remove
1
2
3
4
5
6
7
8 #include <linux/device.h>
9 #include <linux/delay.h>
10 #include <linux/slab.h>
11 #include <linux/workqueue.h>
12 #include <linux/spi/spi.h>
13 #include <linux/module.h>
14
15 #include <linux/platform_data/lcd-mipid.h>
16
17 #include "omapfb.h"
18
19 #define MIPID_MODULE_NAME "lcd_mipid"
20
21 #define MIPID_CMD_READ_DISP_ID 0x04
22 #define MIPID_CMD_READ_RED 0x06
23 #define MIPID_CMD_READ_GREEN 0x07
24 #define MIPID_CMD_READ_BLUE 0x08
25 #define MIPID_CMD_READ_DISP_STATUS 0x09
26 #define MIPID_CMD_RDDSDR 0x0F
27 #define MIPID_CMD_SLEEP_IN 0x10
28 #define MIPID_CMD_SLEEP_OUT 0x11
29 #define MIPID_CMD_DISP_OFF 0x28
30 #define MIPID_CMD_DISP_ON 0x29
31
32 #define MIPID_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
33
34 #define to_mipid_device(p) container_of(p, struct mipid_device, \
35 panel)
36 struct mipid_device {
37 int enabled;
38 int revision;
39 unsigned int saved_bklight_level;
40 unsigned long hw_guard_end;
41
42
43 unsigned long hw_guard_wait;
44
45 struct omapfb_device *fbdev;
46 struct spi_device *spi;
47 struct mutex mutex;
48 struct lcd_panel panel;
49
50 struct delayed_work esd_work;
51 void (*esd_check)(struct mipid_device *m);
52 };
53
54 static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf,
55 int wlen, u8 *rbuf, int rlen)
56 {
57 struct spi_message m;
58 struct spi_transfer *x, xfer[4];
59 u16 w;
60 int r;
61
62 BUG_ON(md->spi == NULL);
63
64 spi_message_init(&m);
65
66 memset(xfer, 0, sizeof(xfer));
67 x = &xfer[0];
68
69 cmd &= 0xff;
70 x->tx_buf = &cmd;
71 x->bits_per_word = 9;
72 x->len = 2;
73 spi_message_add_tail(x, &m);
74
75 if (wlen) {
76 x++;
77 x->tx_buf = wbuf;
78 x->len = wlen;
79 x->bits_per_word = 9;
80 spi_message_add_tail(x, &m);
81 }
82
83 if (rlen) {
84 x++;
85 x->rx_buf = &w;
86 x->len = 1;
87 spi_message_add_tail(x, &m);
88
89 if (rlen > 1) {
90
91
92
93 x->bits_per_word = 9;
94 x->len = 2;
95
96 x++;
97 x->rx_buf = &rbuf[1];
98 x->len = rlen - 1;
99 spi_message_add_tail(x, &m);
100 }
101 }
102
103 r = spi_sync(md->spi, &m);
104 if (r < 0)
105 dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
106
107 if (rlen)
108 rbuf[0] = w & 0xff;
109 }
110
111 static inline void mipid_cmd(struct mipid_device *md, int cmd)
112 {
113 mipid_transfer(md, cmd, NULL, 0, NULL, 0);
114 }
115
116 static inline void mipid_write(struct mipid_device *md,
117 int reg, const u8 *buf, int len)
118 {
119 mipid_transfer(md, reg, buf, len, NULL, 0);
120 }
121
122 static inline void mipid_read(struct mipid_device *md,
123 int reg, u8 *buf, int len)
124 {
125 mipid_transfer(md, reg, NULL, 0, buf, len);
126 }
127
128 static void set_data_lines(struct mipid_device *md, int data_lines)
129 {
130 u16 par;
131
132 switch (data_lines) {
133 case 16:
134 par = 0x150;
135 break;
136 case 18:
137 par = 0x160;
138 break;
139 case 24:
140 par = 0x170;
141 break;
142 }
143 mipid_write(md, 0x3a, (u8 *)&par, 2);
144 }
145
146 static void send_init_string(struct mipid_device *md)
147 {
148 u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
149
150 mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));
151 set_data_lines(md, md->panel.data_lines);
152 }
153
154 static void hw_guard_start(struct mipid_device *md, int guard_msec)
155 {
156 md->hw_guard_wait = msecs_to_jiffies(guard_msec);
157 md->hw_guard_end = jiffies + md->hw_guard_wait;
158 }
159
160 static void hw_guard_wait(struct mipid_device *md)
161 {
162 unsigned long wait = md->hw_guard_end - jiffies;
163
164 if ((long)wait > 0 && time_before_eq(wait, md->hw_guard_wait)) {
165 set_current_state(TASK_UNINTERRUPTIBLE);
166 schedule_timeout(wait);
167 }
168 }
169
170 static void set_sleep_mode(struct mipid_device *md, int on)
171 {
172 int cmd, sleep_time = 50;
173
174 if (on)
175 cmd = MIPID_CMD_SLEEP_IN;
176 else
177 cmd = MIPID_CMD_SLEEP_OUT;
178 hw_guard_wait(md);
179 mipid_cmd(md, cmd);
180 hw_guard_start(md, 120);
181
182
183
184
185
186
187 if (!on)
188 sleep_time = 120;
189 msleep(sleep_time);
190 }
191
192 static void set_display_state(struct mipid_device *md, int enabled)
193 {
194 int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
195
196 mipid_cmd(md, cmd);
197 }
198
199 static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level)
200 {
201 struct mipid_device *md = to_mipid_device(panel);
202 struct mipid_platform_data *pd = md->spi->dev.platform_data;
203
204 if (pd->get_bklight_max == NULL || pd->set_bklight_level == NULL)
205 return -ENODEV;
206 if (level > pd->get_bklight_max(pd))
207 return -EINVAL;
208 if (!md->enabled) {
209 md->saved_bklight_level = level;
210 return 0;
211 }
212 pd->set_bklight_level(pd, level);
213
214 return 0;
215 }
216
217 static unsigned int mipid_get_bklight_level(struct lcd_panel *panel)
218 {
219 struct mipid_device *md = to_mipid_device(panel);
220 struct mipid_platform_data *pd = md->spi->dev.platform_data;
221
222 if (pd->get_bklight_level == NULL)
223 return -ENODEV;
224 return pd->get_bklight_level(pd);
225 }
226
227 static unsigned int mipid_get_bklight_max(struct lcd_panel *panel)
228 {
229 struct mipid_device *md = to_mipid_device(panel);
230 struct mipid_platform_data *pd = md->spi->dev.platform_data;
231
232 if (pd->get_bklight_max == NULL)
233 return -ENODEV;
234
235 return pd->get_bklight_max(pd);
236 }
237
238 static unsigned long mipid_get_caps(struct lcd_panel *panel)
239 {
240 return OMAPFB_CAPS_SET_BACKLIGHT;
241 }
242
243 static u16 read_first_pixel(struct mipid_device *md)
244 {
245 u16 pixel;
246 u8 red, green, blue;
247
248 mutex_lock(&md->mutex);
249 mipid_read(md, MIPID_CMD_READ_RED, &red, 1);
250 mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1);
251 mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1);
252 mutex_unlock(&md->mutex);
253
254 switch (md->panel.data_lines) {
255 case 16:
256 pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1);
257 break;
258 case 24:
259
260 pixel = ((red >> 3) << 11) | ((green >> 2) << 5) |
261 (blue >> 3);
262 break;
263 default:
264 pixel = 0;
265 BUG();
266 }
267
268 return pixel;
269 }
270
271 static int mipid_run_test(struct lcd_panel *panel, int test_num)
272 {
273 struct mipid_device *md = to_mipid_device(panel);
274 static const u16 test_values[4] = {
275 0x0000, 0xffff, 0xaaaa, 0x5555,
276 };
277 int i;
278
279 if (test_num != MIPID_TEST_RGB_LINES)
280 return MIPID_TEST_INVALID;
281
282 for (i = 0; i < ARRAY_SIZE(test_values); i++) {
283 int delay;
284 unsigned long tmo;
285
286 omapfb_write_first_pixel(md->fbdev, test_values[i]);
287 tmo = jiffies + msecs_to_jiffies(100);
288 delay = 25;
289 while (1) {
290 u16 pixel;
291
292 msleep(delay);
293 pixel = read_first_pixel(md);
294 if (pixel == test_values[i])
295 break;
296 if (time_after(jiffies, tmo)) {
297 dev_err(&md->spi->dev,
298 "MIPI LCD RGB I/F test failed: "
299 "expecting %04x, got %04x\n",
300 test_values[i], pixel);
301 return MIPID_TEST_FAILED;
302 }
303 delay = 10;
304 }
305 }
306
307 return 0;
308 }
309
310 static void ls041y3_esd_recover(struct mipid_device *md)
311 {
312 dev_err(&md->spi->dev, "performing LCD ESD recovery\n");
313 set_sleep_mode(md, 1);
314 set_sleep_mode(md, 0);
315 }
316
317 static void ls041y3_esd_check_mode1(struct mipid_device *md)
318 {
319 u8 state1, state2;
320
321 mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1);
322 set_sleep_mode(md, 0);
323 mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1);
324 dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n",
325 state1, state2);
326
327
328
329 if (!((state1 ^ state2) & (1 << 6)))
330 ls041y3_esd_recover(md);
331 }
332
333 static void ls041y3_esd_check_mode2(struct mipid_device *md)
334 {
335 int i;
336 u8 rbuf[2];
337 static const struct {
338 int cmd;
339 int wlen;
340 u16 wbuf[3];
341 } *rd, rd_ctrl[7] = {
342 { 0xb0, 4, { 0x0101, 0x01fe, } },
343 { 0xb1, 4, { 0x01de, 0x0121, } },
344 { 0xc2, 4, { 0x0100, 0x0100, } },
345 { 0xbd, 2, { 0x0100, } },
346 { 0xc2, 4, { 0x01fc, 0x0103, } },
347 { 0xb4, 0, },
348 { 0x00, 0, },
349 };
350
351 rd = rd_ctrl;
352 for (i = 0; i < 3; i++, rd++)
353 mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
354
355 udelay(10);
356 mipid_read(md, rd->cmd, rbuf, 2);
357 rd++;
358
359 for (i = 0; i < 3; i++, rd++) {
360 udelay(10);
361 mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
362 }
363
364 dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]);
365 if (rbuf[1] == 0x00)
366 ls041y3_esd_recover(md);
367 }
368
369 static void ls041y3_esd_check(struct mipid_device *md)
370 {
371 ls041y3_esd_check_mode1(md);
372 if (md->revision >= 0x88)
373 ls041y3_esd_check_mode2(md);
374 }
375
376 static void mipid_esd_start_check(struct mipid_device *md)
377 {
378 if (md->esd_check != NULL)
379 schedule_delayed_work(&md->esd_work,
380 MIPID_ESD_CHECK_PERIOD);
381 }
382
383 static void mipid_esd_stop_check(struct mipid_device *md)
384 {
385 if (md->esd_check != NULL)
386 cancel_delayed_work_sync(&md->esd_work);
387 }
388
389 static void mipid_esd_work(struct work_struct *work)
390 {
391 struct mipid_device *md = container_of(work, struct mipid_device,
392 esd_work.work);
393
394 mutex_lock(&md->mutex);
395 md->esd_check(md);
396 mutex_unlock(&md->mutex);
397 mipid_esd_start_check(md);
398 }
399
400 static int mipid_enable(struct lcd_panel *panel)
401 {
402 struct mipid_device *md = to_mipid_device(panel);
403
404 mutex_lock(&md->mutex);
405
406 if (md->enabled) {
407 mutex_unlock(&md->mutex);
408 return 0;
409 }
410 set_sleep_mode(md, 0);
411 md->enabled = 1;
412 send_init_string(md);
413 set_display_state(md, 1);
414 mipid_set_bklight_level(panel, md->saved_bklight_level);
415 mipid_esd_start_check(md);
416
417 mutex_unlock(&md->mutex);
418 return 0;
419 }
420
421 static void mipid_disable(struct lcd_panel *panel)
422 {
423 struct mipid_device *md = to_mipid_device(panel);
424
425
426
427
428
429 mipid_esd_stop_check(md);
430 mutex_lock(&md->mutex);
431
432 if (!md->enabled) {
433 mutex_unlock(&md->mutex);
434 return;
435 }
436 md->saved_bklight_level = mipid_get_bklight_level(panel);
437 mipid_set_bklight_level(panel, 0);
438 set_display_state(md, 0);
439 set_sleep_mode(md, 1);
440 md->enabled = 0;
441
442 mutex_unlock(&md->mutex);
443 }
444
445 static int panel_enabled(struct mipid_device *md)
446 {
447 u32 disp_status;
448 int enabled;
449
450 mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
451 disp_status = __be32_to_cpu(disp_status);
452 enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
453 dev_dbg(&md->spi->dev,
454 "LCD panel %senabled by bootloader (status 0x%04x)\n",
455 enabled ? "" : "not ", disp_status);
456 return enabled;
457 }
458
459 static int mipid_init(struct lcd_panel *panel,
460 struct omapfb_device *fbdev)
461 {
462 struct mipid_device *md = to_mipid_device(panel);
463
464 md->fbdev = fbdev;
465 INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work);
466 mutex_init(&md->mutex);
467
468 md->enabled = panel_enabled(md);
469
470 if (md->enabled)
471 mipid_esd_start_check(md);
472 else
473 md->saved_bklight_level = mipid_get_bklight_level(panel);
474
475 return 0;
476 }
477
478 static void mipid_cleanup(struct lcd_panel *panel)
479 {
480 struct mipid_device *md = to_mipid_device(panel);
481
482 if (md->enabled)
483 mipid_esd_stop_check(md);
484 }
485
486 static const struct lcd_panel mipid_panel = {
487 .config = OMAP_LCDC_PANEL_TFT,
488
489 .bpp = 16,
490 .x_res = 800,
491 .y_res = 480,
492 .pixel_clock = 21940,
493 .hsw = 50,
494 .hfp = 20,
495 .hbp = 15,
496 .vsw = 2,
497 .vfp = 1,
498 .vbp = 3,
499
500 .init = mipid_init,
501 .cleanup = mipid_cleanup,
502 .enable = mipid_enable,
503 .disable = mipid_disable,
504 .get_caps = mipid_get_caps,
505 .set_bklight_level = mipid_set_bklight_level,
506 .get_bklight_level = mipid_get_bklight_level,
507 .get_bklight_max = mipid_get_bklight_max,
508 .run_test = mipid_run_test,
509 };
510
511 static int mipid_detect(struct mipid_device *md)
512 {
513 struct mipid_platform_data *pdata;
514 u8 display_id[3];
515
516 pdata = md->spi->dev.platform_data;
517 if (pdata == NULL) {
518 dev_err(&md->spi->dev, "missing platform data\n");
519 return -ENOENT;
520 }
521
522 mipid_read(md, MIPID_CMD_READ_DISP_ID, display_id, 3);
523 dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
524 display_id[0], display_id[1], display_id[2]);
525
526 switch (display_id[0]) {
527 case 0x45:
528 md->panel.name = "lph8923";
529 break;
530 case 0x83:
531 md->panel.name = "ls041y3";
532 md->esd_check = ls041y3_esd_check;
533 break;
534 default:
535 md->panel.name = "unknown";
536 dev_err(&md->spi->dev, "invalid display ID\n");
537 return -ENODEV;
538 }
539
540 md->revision = display_id[1];
541 md->panel.data_lines = pdata->data_lines;
542 pr_info("omapfb: %s rev %02x LCD detected, %d data lines\n",
543 md->panel.name, md->revision, md->panel.data_lines);
544
545 return 0;
546 }
547
548 static int mipid_spi_probe(struct spi_device *spi)
549 {
550 struct mipid_device *md;
551 int r;
552
553 md = kzalloc(sizeof(*md), GFP_KERNEL);
554 if (md == NULL) {
555 dev_err(&spi->dev, "out of memory\n");
556 return -ENOMEM;
557 }
558
559 spi->mode = SPI_MODE_0;
560 md->spi = spi;
561 dev_set_drvdata(&spi->dev, md);
562 md->panel = mipid_panel;
563
564 r = mipid_detect(md);
565 if (r < 0)
566 return r;
567
568 omapfb_register_panel(&md->panel);
569
570 return 0;
571 }
572
573 static int mipid_spi_remove(struct spi_device *spi)
574 {
575 struct mipid_device *md = dev_get_drvdata(&spi->dev);
576
577 mipid_disable(&md->panel);
578 kfree(md);
579
580 return 0;
581 }
582
583 static struct spi_driver mipid_spi_driver = {
584 .driver = {
585 .name = MIPID_MODULE_NAME,
586 },
587 .probe = mipid_spi_probe,
588 .remove = mipid_spi_remove,
589 };
590
591 module_spi_driver(mipid_spi_driver);
592
593 MODULE_DESCRIPTION("MIPI display driver");
594 MODULE_LICENSE("GPL");