blob: 9565958ebaa95086230dfdefc0de22fdd8ca6b91 [file] [log] [blame]
Tomi Valkeinen562a0602011-04-21 19:53:59 +03001/* #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/backlight.h>
9#include <linux/fb.h>
10
11#include <video/omapdss.h>
12#include <video/omap-panel-n8x0.h>
13
14#define BLIZZARD_REV_CODE 0x00
15#define BLIZZARD_CONFIG 0x02
16#define BLIZZARD_PLL_DIV 0x04
17#define BLIZZARD_PLL_LOCK_RANGE 0x06
18#define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08
19#define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a
20#define BLIZZARD_PLL_MODE 0x0c
21#define BLIZZARD_CLK_SRC 0x0e
22#define BLIZZARD_MEM_BANK0_ACTIVATE 0x10
23#define BLIZZARD_MEM_BANK0_STATUS 0x14
24#define BLIZZARD_PANEL_CONFIGURATION 0x28
25#define BLIZZARD_HDISP 0x2a
26#define BLIZZARD_HNDP 0x2c
27#define BLIZZARD_VDISP0 0x2e
28#define BLIZZARD_VDISP1 0x30
29#define BLIZZARD_VNDP 0x32
30#define BLIZZARD_HSW 0x34
31#define BLIZZARD_VSW 0x38
32#define BLIZZARD_DISPLAY_MODE 0x68
33#define BLIZZARD_INPUT_WIN_X_START_0 0x6c
34#define BLIZZARD_DATA_SOURCE_SELECT 0x8e
35#define BLIZZARD_DISP_MEM_DATA_PORT 0x90
36#define BLIZZARD_DISP_MEM_READ_ADDR0 0x92
37#define BLIZZARD_POWER_SAVE 0xE6
38#define BLIZZARD_NDISP_CTRL_STATUS 0xE8
39
40/* Data source select */
41/* For S1D13745 */
42#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00
43#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01
44#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04
45#define BLIZZARD_SRC_DISABLE_OVERLAY 0x05
46/* For S1D13744 */
47#define BLIZZARD_SRC_WRITE_LCD 0x00
48#define BLIZZARD_SRC_BLT_LCD 0x06
49
50#define BLIZZARD_COLOR_RGB565 0x01
51#define BLIZZARD_COLOR_YUV420 0x09
52
53#define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */
54#define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */
55
56#define MIPID_CMD_READ_DISP_ID 0x04
57#define MIPID_CMD_READ_RED 0x06
58#define MIPID_CMD_READ_GREEN 0x07
59#define MIPID_CMD_READ_BLUE 0x08
60#define MIPID_CMD_READ_DISP_STATUS 0x09
61#define MIPID_CMD_RDDSDR 0x0F
62#define MIPID_CMD_SLEEP_IN 0x10
63#define MIPID_CMD_SLEEP_OUT 0x11
64#define MIPID_CMD_DISP_OFF 0x28
65#define MIPID_CMD_DISP_ON 0x29
66
67static struct panel_drv_data {
68 struct mutex lock;
69
70 struct omap_dss_device *dssdev;
71 struct spi_device *spidev;
72 struct backlight_device *bldev;
73
74 int blizzard_ver;
75} s_drv_data;
76
77
78static inline
79struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev)
80{
81 return dssdev->data;
82}
83
84static inline
85struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev)
86{
87 return &s_drv_data;
88}
89
90
91static inline void blizzard_cmd(u8 cmd)
92{
93 omap_rfbi_write_command(&cmd, 1);
94}
95
96static inline void blizzard_write(u8 cmd, const u8 *buf, int len)
97{
98 omap_rfbi_write_command(&cmd, 1);
99 omap_rfbi_write_data(buf, len);
100}
101
102static inline void blizzard_read(u8 cmd, u8 *buf, int len)
103{
104 omap_rfbi_write_command(&cmd, 1);
105 omap_rfbi_read_data(buf, len);
106}
107
108static u8 blizzard_read_reg(u8 cmd)
109{
110 u8 data;
111 blizzard_read(cmd, &data, 1);
112 return data;
113}
114
115static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
116 int x, int y, int w, int h)
117{
118 struct panel_drv_data *ddata = get_drv_data(dssdev);
119 u8 tmp[18];
120 int x_end, y_end;
121
122 x_end = x + w - 1;
123 y_end = y + h - 1;
124
125 tmp[0] = x;
126 tmp[1] = x >> 8;
127 tmp[2] = y;
128 tmp[3] = y >> 8;
129 tmp[4] = x_end;
130 tmp[5] = x_end >> 8;
131 tmp[6] = y_end;
132 tmp[7] = y_end >> 8;
133
134 /* scaling? */
135 tmp[8] = x;
136 tmp[9] = x >> 8;
137 tmp[10] = y;
138 tmp[11] = y >> 8;
139 tmp[12] = x_end;
140 tmp[13] = x_end >> 8;
141 tmp[14] = y_end;
142 tmp[15] = y_end >> 8;
143
144 tmp[16] = BLIZZARD_COLOR_RGB565;
145
146 if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745)
147 tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
148 else
149 tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ?
150 BLIZZARD_SRC_WRITE_LCD :
151 BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
152
Archit Tanejab02875b2012-08-13 15:26:49 +0530153 omapdss_rfbi_set_pixel_size(dssdev, 16);
154
155 omap_rfbi_configure(dssdev, 8);
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300156
157 blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
158
Archit Tanejab02875b2012-08-13 15:26:49 +0530159 omapdss_rfbi_set_pixel_size(dssdev, 16);
160
161 omap_rfbi_configure(dssdev, 16);
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300162}
163
164static 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
219static inline void mipid_cmd(struct spi_device *spi, int cmd)
220{
221 mipid_transfer(spi, cmd, NULL, 0, NULL, 0);
222}
223
224static 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
230static 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
236static 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
255static 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
261static void send_display_on(struct spi_device *spi)
262{
263 mipid_cmd(spi, MIPID_CMD_DISP_ON);
264}
265
266static void send_display_off(struct spi_device *spi)
267{
268 mipid_cmd(spi, MIPID_CMD_DISP_OFF);
269}
270
271static void send_sleep_out(struct spi_device *spi)
272{
273 mipid_cmd(spi, MIPID_CMD_SLEEP_OUT);
274 msleep(120);
275}
276
277static void send_sleep_in(struct spi_device *spi)
278{
279 mipid_cmd(spi, MIPID_CMD_SLEEP_IN);
280 msleep(50);
281}
282
283static 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 if (bdata->platform_enable) {
299 r = bdata->platform_enable(dssdev);
300 if (r)
301 goto err_plat_en;
302 }
303
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530304 omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res,
305 dssdev->panel.timings.y_res);
Archit Tanejab02875b2012-08-13 15:26:49 +0530306 omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size);
Archit Taneja6ff9dd52012-08-13 15:12:10 +0530307
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300308 r = omapdss_rfbi_display_enable(dssdev);
309 if (r)
310 goto err_rfbi_en;
311
312 rev = blizzard_read_reg(BLIZZARD_REV_CODE);
313 conf = blizzard_read_reg(BLIZZARD_CONFIG);
314
315 switch (rev & 0xfc) {
316 case 0x9c:
317 ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744;
318 dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d "
319 "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
320 break;
321 case 0xa4:
322 ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745;
323 dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d "
324 "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
325 break;
326 default:
327 dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev);
328 r = -ENODEV;
329 goto err_inv_chip;
330 }
331
332 /* panel */
333
334 gpio_direction_output(bdata->panel_reset, 1);
335
336 mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3);
337 dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n",
338 display_id[0], display_id[1], display_id[2]);
339
340 switch (display_id[0]) {
341 case 0x45:
342 panel_name = "lph8923";
343 break;
344 case 0x83:
345 panel_name = "ls041y3";
346 break;
347 default:
348 dev_err(&dssdev->dev, "invalid display ID 0x%x\n",
349 display_id[0]);
350 r = -ENODEV;
351 goto err_inv_panel;
352 }
353
354 dev_info(&dssdev->dev, "%s rev %02x LCD detected\n",
355 panel_name, display_id[1]);
356
357 send_sleep_out(spi);
358 send_init_string(spi);
359 set_data_lines(spi, 24);
360 send_display_on(spi);
361
362 return 0;
363
364err_inv_panel:
365 /*
366 * HACK: we should turn off the panel here, but there is some problem
367 * with the initialization sequence, and we fail to init the panel if we
368 * have turned it off
369 */
370 /* gpio_direction_output(bdata->panel_reset, 0); */
371err_inv_chip:
372 omapdss_rfbi_display_disable(dssdev);
373err_rfbi_en:
374 if (bdata->platform_disable)
375 bdata->platform_disable(dssdev);
376err_plat_en:
377 gpio_direction_output(bdata->ctrl_pwrdown, 0);
378 return r;
379}
380
381static void n8x0_panel_power_off(struct omap_dss_device *dssdev)
382{
383 struct panel_n8x0_data *bdata = get_board_data(dssdev);
384 struct panel_drv_data *ddata = get_drv_data(dssdev);
385 struct spi_device *spi = ddata->spidev;
386
387 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
388 return;
389
390 send_display_off(spi);
391 send_sleep_in(spi);
392
393 if (bdata->platform_disable)
394 bdata->platform_disable(dssdev);
395
396 /*
397 * HACK: we should turn off the panel here, but there is some problem
398 * with the initialization sequence, and we fail to init the panel if we
399 * have turned it off
400 */
401 /* gpio_direction_output(bdata->panel_reset, 0); */
402 gpio_direction_output(bdata->ctrl_pwrdown, 0);
403 omapdss_rfbi_display_disable(dssdev);
404}
405
406static const struct rfbi_timings n8x0_panel_timings = {
407 .cs_on_time = 0,
408
409 .we_on_time = 9000,
410 .we_off_time = 18000,
411 .we_cycle_time = 36000,
412
413 .re_on_time = 9000,
414 .re_off_time = 27000,
415 .re_cycle_time = 36000,
416
417 .access_time = 27000,
418 .cs_off_time = 36000,
419
420 .cs_pulse_width = 0,
421};
422
423static int n8x0_bl_update_status(struct backlight_device *dev)
424{
425 struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
426 struct panel_n8x0_data *bdata = get_board_data(dssdev);
427 struct panel_drv_data *ddata = get_drv_data(dssdev);
428 int r;
429 int level;
430
431 mutex_lock(&ddata->lock);
432
433 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
434 dev->props.power == FB_BLANK_UNBLANK)
435 level = dev->props.brightness;
436 else
437 level = 0;
438
439 dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
440
441 if (!bdata->set_backlight)
442 r = -EINVAL;
443 else
444 r = bdata->set_backlight(dssdev, level);
445
446 mutex_unlock(&ddata->lock);
447
448 return r;
449}
450
451static int n8x0_bl_get_intensity(struct backlight_device *dev)
452{
453 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
454 dev->props.power == FB_BLANK_UNBLANK)
455 return dev->props.brightness;
456
457 return 0;
458}
459
460static const struct backlight_ops n8x0_bl_ops = {
461 .get_brightness = n8x0_bl_get_intensity,
462 .update_status = n8x0_bl_update_status,
463};
464
465static int n8x0_panel_probe(struct omap_dss_device *dssdev)
466{
467 struct panel_n8x0_data *bdata = get_board_data(dssdev);
468 struct panel_drv_data *ddata;
469 struct backlight_device *bldev;
470 struct backlight_properties props;
471 int r;
472
473 dev_dbg(&dssdev->dev, "probe\n");
474
475 if (!bdata)
476 return -EINVAL;
477
478 s_drv_data.dssdev = dssdev;
479
480 ddata = &s_drv_data;
481
482 mutex_init(&ddata->lock);
483
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300484 dssdev->panel.timings.x_res = 800;
485 dssdev->panel.timings.y_res = 480;
486 dssdev->ctrl.pixel_size = 16;
487 dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
488
489 memset(&props, 0, sizeof(props));
490 props.max_brightness = 127;
491 props.type = BACKLIGHT_PLATFORM;
492 bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
493 dssdev, &n8x0_bl_ops, &props);
494 if (IS_ERR(bldev)) {
495 r = PTR_ERR(bldev);
496 dev_err(&dssdev->dev, "register backlight failed\n");
497 return r;
498 }
499
500 ddata->bldev = bldev;
501
502 bldev->props.fb_blank = FB_BLANK_UNBLANK;
503 bldev->props.power = FB_BLANK_UNBLANK;
504 bldev->props.brightness = 127;
505
506 n8x0_bl_update_status(bldev);
507
508 return 0;
509}
510
511static void n8x0_panel_remove(struct omap_dss_device *dssdev)
512{
513 struct panel_drv_data *ddata = get_drv_data(dssdev);
514 struct backlight_device *bldev;
515
516 dev_dbg(&dssdev->dev, "remove\n");
517
518 bldev = ddata->bldev;
519 bldev->props.power = FB_BLANK_POWERDOWN;
520 n8x0_bl_update_status(bldev);
521 backlight_device_unregister(bldev);
522
523 dev_set_drvdata(&dssdev->dev, NULL);
524}
525
526static int n8x0_panel_enable(struct omap_dss_device *dssdev)
527{
528 struct panel_drv_data *ddata = get_drv_data(dssdev);
529 int r;
530
531 dev_dbg(&dssdev->dev, "enable\n");
532
533 mutex_lock(&ddata->lock);
534
535 rfbi_bus_lock();
536
537 r = n8x0_panel_power_on(dssdev);
538
539 rfbi_bus_unlock();
540
541 if (r) {
542 mutex_unlock(&ddata->lock);
543 return r;
544 }
545
546 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
547
548 mutex_unlock(&ddata->lock);
549
550 return 0;
551}
552
553static void n8x0_panel_disable(struct omap_dss_device *dssdev)
554{
555 struct panel_drv_data *ddata = get_drv_data(dssdev);
556
557 dev_dbg(&dssdev->dev, "disable\n");
558
559 mutex_lock(&ddata->lock);
560
561 rfbi_bus_lock();
562
563 n8x0_panel_power_off(dssdev);
564
565 rfbi_bus_unlock();
566
567 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
568
569 mutex_unlock(&ddata->lock);
570}
571
572static int n8x0_panel_suspend(struct omap_dss_device *dssdev)
573{
574 struct panel_drv_data *ddata = get_drv_data(dssdev);
575
576 dev_dbg(&dssdev->dev, "suspend\n");
577
578 mutex_lock(&ddata->lock);
579
580 rfbi_bus_lock();
581
582 n8x0_panel_power_off(dssdev);
583
584 rfbi_bus_unlock();
585
586 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
587
588 mutex_unlock(&ddata->lock);
589
590 return 0;
591}
592
593static int n8x0_panel_resume(struct omap_dss_device *dssdev)
594{
595 struct panel_drv_data *ddata = get_drv_data(dssdev);
596 int r;
597
598 dev_dbg(&dssdev->dev, "resume\n");
599
600 mutex_lock(&ddata->lock);
601
602 rfbi_bus_lock();
603
604 r = n8x0_panel_power_on(dssdev);
605
606 rfbi_bus_unlock();
607
608 if (r) {
609 mutex_unlock(&ddata->lock);
610 return r;
611 }
612
613 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
614
615 mutex_unlock(&ddata->lock);
616
617 return 0;
618}
619
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300620static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
621 u16 *xres, u16 *yres)
622{
623 *xres = dssdev->panel.timings.x_res;
624 *yres = dssdev->panel.timings.y_res;
625}
626
627static void update_done(void *data)
628{
629 rfbi_bus_unlock();
630}
631
632static int n8x0_panel_update(struct omap_dss_device *dssdev,
633 u16 x, u16 y, u16 w, u16 h)
634{
635 struct panel_drv_data *ddata = get_drv_data(dssdev);
Archit Taneja43eab862012-08-13 12:24:53 +0530636 u16 dw, dh;
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300637
638 dev_dbg(&dssdev->dev, "update\n");
639
Archit Taneja43eab862012-08-13 12:24:53 +0530640 dw = dssdev->panel.timings.x_res;
641 dh = dssdev->panel.timings.y_res;
642
643 if (x != 0 || y != 0 || w != dw || h != dh) {
644 dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n",
645 x, y, w, h);
646 return -EINVAL;
647 }
648
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300649 mutex_lock(&ddata->lock);
650 rfbi_bus_lock();
651
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300652 blizzard_ctrl_setup_update(dssdev, x, y, w, h);
653
Archit Taneja43eab862012-08-13 12:24:53 +0530654 omap_rfbi_update(dssdev, update_done, NULL);
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300655
656 mutex_unlock(&ddata->lock);
657
658 return 0;
659}
660
661static int n8x0_panel_sync(struct omap_dss_device *dssdev)
662{
663 struct panel_drv_data *ddata = get_drv_data(dssdev);
664
665 dev_dbg(&dssdev->dev, "sync\n");
666
667 mutex_lock(&ddata->lock);
668 rfbi_bus_lock();
669 rfbi_bus_unlock();
670 mutex_unlock(&ddata->lock);
671
672 return 0;
673}
674
675static struct omap_dss_driver n8x0_panel_driver = {
676 .probe = n8x0_panel_probe,
677 .remove = n8x0_panel_remove,
678
679 .enable = n8x0_panel_enable,
680 .disable = n8x0_panel_disable,
681 .suspend = n8x0_panel_suspend,
682 .resume = n8x0_panel_resume,
683
684 .update = n8x0_panel_update,
685 .sync = n8x0_panel_sync,
686
687 .get_resolution = n8x0_panel_get_resolution,
688 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
689
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300690 .driver = {
691 .name = "n8x0_panel",
692 .owner = THIS_MODULE,
693 },
694};
695
696/* PANEL */
697
698static int mipid_spi_probe(struct spi_device *spi)
699{
700 dev_dbg(&spi->dev, "mipid_spi_probe\n");
701
702 spi->mode = SPI_MODE_0;
703
704 s_drv_data.spidev = spi;
705
706 return 0;
707}
708
709static int mipid_spi_remove(struct spi_device *spi)
710{
711 dev_dbg(&spi->dev, "mipid_spi_remove\n");
712 return 0;
713}
714
715static struct spi_driver mipid_spi_driver = {
716 .driver = {
717 .name = "lcd_mipid",
Tomi Valkeinen562a0602011-04-21 19:53:59 +0300718 .owner = THIS_MODULE,
719 },
720 .probe = mipid_spi_probe,
721 .remove = __devexit_p(mipid_spi_remove),
722};
723
724static int __init n8x0_panel_drv_init(void)
725{
726 int r;
727
728 r = spi_register_driver(&mipid_spi_driver);
729 if (r) {
730 pr_err("n8x0_panel: spi driver registration failed\n");
731 return r;
732 }
733
734 r = omap_dss_register_driver(&n8x0_panel_driver);
735 if (r) {
736 pr_err("n8x0_panel: dss driver registration failed\n");
737 spi_unregister_driver(&mipid_spi_driver);
738 return r;
739 }
740
741 return 0;
742}
743
744static void __exit n8x0_panel_drv_exit(void)
745{
746 spi_unregister_driver(&mipid_spi_driver);
747
748 omap_dss_unregister_driver(&n8x0_panel_driver);
749}
750
751module_init(n8x0_panel_drv_init);
752module_exit(n8x0_panel_drv_exit);
753MODULE_LICENSE("GPL");