Merge branches 'sh/intc-extension', 'sh/dmaengine', 'sh/serial-dma' and 'sh/clkfwk'
[linux-2.6-block.git] / drivers / video / bfin-lq035q1-fb.c
1 /*
2  * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02
3  *
4  * Copyright 2008-2009 Analog Devices Inc.
5  * Licensed under the GPL-2 or later.
6  */
7
8 #define DRIVER_NAME "bfin-lq035q1"
9 #define pr_fmt(fmt) DRIVER_NAME ": " fmt
10
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/fb.h>
16 #include <linux/init.h>
17 #include <linux/types.h>
18 #include <linux/interrupt.h>
19 #include <linux/device.h>
20 #include <linux/backlight.h>
21 #include <linux/lcd.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/platform_device.h>
24 #include <linux/spi/spi.h>
25
26 #include <asm/blackfin.h>
27 #include <asm/irq.h>
28 #include <asm/dma.h>
29 #include <asm/portmux.h>
30 #include <asm/gptimers.h>
31
32 #include <asm/bfin-lq035q1.h>
33
34 #if defined(BF533_FAMILY) || defined(BF538_FAMILY)
35 #define TIMER_HSYNC_id                  TIMER1_id
36 #define TIMER_HSYNCbit                  TIMER1bit
37 #define TIMER_HSYNC_STATUS_TRUN         TIMER_STATUS_TRUN1
38 #define TIMER_HSYNC_STATUS_TIMIL        TIMER_STATUS_TIMIL1
39 #define TIMER_HSYNC_STATUS_TOVF         TIMER_STATUS_TOVF1
40
41 #define TIMER_VSYNC_id                  TIMER2_id
42 #define TIMER_VSYNCbit                  TIMER2bit
43 #define TIMER_VSYNC_STATUS_TRUN         TIMER_STATUS_TRUN2
44 #define TIMER_VSYNC_STATUS_TIMIL        TIMER_STATUS_TIMIL2
45 #define TIMER_VSYNC_STATUS_TOVF         TIMER_STATUS_TOVF2
46 #else
47 #define TIMER_HSYNC_id                  TIMER0_id
48 #define TIMER_HSYNCbit                  TIMER0bit
49 #define TIMER_HSYNC_STATUS_TRUN         TIMER_STATUS_TRUN0
50 #define TIMER_HSYNC_STATUS_TIMIL        TIMER_STATUS_TIMIL0
51 #define TIMER_HSYNC_STATUS_TOVF         TIMER_STATUS_TOVF0
52
53 #define TIMER_VSYNC_id                  TIMER1_id
54 #define TIMER_VSYNCbit                  TIMER1bit
55 #define TIMER_VSYNC_STATUS_TRUN         TIMER_STATUS_TRUN1
56 #define TIMER_VSYNC_STATUS_TIMIL        TIMER_STATUS_TIMIL1
57 #define TIMER_VSYNC_STATUS_TOVF         TIMER_STATUS_TOVF1
58 #endif
59
60 #define LCD_X_RES               320     /* Horizontal Resolution */
61 #define LCD_Y_RES               240     /* Vertical Resolution */
62 #define DMA_BUS_SIZE            16
63
64 #define USE_RGB565_16_BIT_PPI
65
66 #ifdef USE_RGB565_16_BIT_PPI
67 #define LCD_BPP         16      /* Bit Per Pixel */
68 #define CLOCKS_PER_PIX  1
69 #define CPLD_PIPELINE_DELAY_COR 0       /* NO CPLB */
70 #endif
71
72 /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
73  * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
74  */
75
76 #ifdef USE_RGB565_8_BIT_PPI
77 #define LCD_BPP         16      /* Bit Per Pixel */
78 #define CLOCKS_PER_PIX  2
79 #define CPLD_PIPELINE_DELAY_COR 3       /* RGB565 */
80 #endif
81
82 #ifdef USE_RGB888_8_BIT_PPI
83 #define LCD_BPP         24      /* Bit Per Pixel */
84 #define CLOCKS_PER_PIX  3
85 #define CPLD_PIPELINE_DELAY_COR 5       /* RGB888 */
86 #endif
87
88         /*
89          * HS and VS timing parameters (all in number of PPI clk ticks)
90          */
91
92 #define U_LINE          4                               /* Blanking Lines */
93
94 #define H_ACTPIX        (LCD_X_RES * CLOCKS_PER_PIX)    /* active horizontal pixel */
95 #define H_PERIOD        (336 * CLOCKS_PER_PIX)          /* HS period */
96 #define H_PULSE         (2 * CLOCKS_PER_PIX)                            /* HS pulse width */
97 #define H_START         (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR)  /* first valid pixel */
98
99 #define V_LINES         (LCD_Y_RES + U_LINE)            /* total vertical lines */
100 #define V_PULSE         (2 * CLOCKS_PER_PIX)            /* VS pulse width (1-5 H_PERIODs) */
101 #define V_PERIOD        (H_PERIOD * V_LINES)            /* VS period */
102
103 #define ACTIVE_VIDEO_MEM_OFFSET         ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
104
105 #define BFIN_LCD_NBR_PALETTE_ENTRIES    256
106
107 #define PPI_TX_MODE                     0x2
108 #define PPI_XFER_TYPE_11                0xC
109 #define PPI_PORT_CFG_01                 0x10
110 #define PPI_POLS_1                      0x8000
111
112 #if (CLOCKS_PER_PIX > 1)
113 #define PPI_PMODE (DLEN_8 | PACK_EN)
114 #else
115 #define PPI_PMODE (DLEN_16)
116 #endif
117
118 #define LQ035_INDEX                     0x74
119 #define LQ035_DATA                      0x76
120
121 #define LQ035_DRIVER_OUTPUT_CTL         0x1
122 #define LQ035_SHUT_CTL                  0x11
123
124 #define LQ035_DRIVER_OUTPUT_MASK        (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV)
125 #define LQ035_DRIVER_OUTPUT_DEFAULT     (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK)
126
127 #define LQ035_SHUT                      (1 << 0)        /* Shutdown */
128 #define LQ035_ON                        (0 << 0)        /* Shutdown */
129
130 struct bfin_lq035q1fb_info {
131         struct fb_info *fb;
132         struct device *dev;
133         struct spi_driver spidrv;
134         struct bfin_lq035q1fb_disp_info *disp_info;
135         unsigned char *fb_buffer;       /* RGB Buffer */
136         dma_addr_t dma_handle;
137         int lq035_open_cnt;
138         int irq;
139         spinlock_t lock;        /* lock */
140         u32 pseudo_pal[16];
141 };
142
143 static int nocursor;
144 module_param(nocursor, int, 0644);
145 MODULE_PARM_DESC(nocursor, "cursor enable/disable");
146
147 struct spi_control {
148         unsigned short mode;
149 };
150
151 static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value)
152 {
153         int ret;
154         u8 regs[3] = { LQ035_INDEX, 0, 0 };
155         u8 dat[3] = { LQ035_DATA, 0, 0 };
156
157         if (!spi)
158                 return -ENODEV;
159
160         regs[2] = reg;
161         dat[1] = value >> 8;
162         dat[2] = value & 0xFF;
163
164         ret = spi_write(spi, regs, ARRAY_SIZE(regs));
165         ret |= spi_write(spi, dat, ARRAY_SIZE(dat));
166         return ret;
167 }
168
169 static int __devinit lq035q1_spidev_probe(struct spi_device *spi)
170 {
171         int ret;
172         struct spi_control *ctl;
173         struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver,
174                                                 struct bfin_lq035q1fb_info,
175                                                 spidrv.driver);
176
177         ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
178
179         if (!ctl)
180                 return -ENOMEM;
181
182         ctl->mode = (info->disp_info->mode &
183                 LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT;
184
185         ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
186         ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
187         if (ret)
188                 return ret;
189
190         spi_set_drvdata(spi, ctl);
191
192         return 0;
193 }
194
195 static int lq035q1_spidev_remove(struct spi_device *spi)
196 {
197         return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
198 }
199
200 #ifdef CONFIG_PM
201 static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state)
202 {
203         return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
204 }
205
206 static int lq035q1_spidev_resume(struct spi_device *spi)
207 {
208         int ret;
209         struct spi_control *ctl = spi_get_drvdata(spi);
210
211         ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
212         if (ret)
213                 return ret;
214
215         return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
216 }
217 #else
218 # define lq035q1_spidev_suspend NULL
219 # define lq035q1_spidev_resume  NULL
220 #endif
221
222 /* Power down all displays on reboot, poweroff or halt */
223 static void lq035q1_spidev_shutdown(struct spi_device *spi)
224 {
225         lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
226 }
227
228 static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg)
229 {
230         if (info->disp_info->use_bl)
231                 gpio_set_value(info->disp_info->gpio_bl, arg);
232
233         return 0;
234 }
235
236 static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi)
237 {
238         bfin_write_PPI_DELAY(H_START);
239         bfin_write_PPI_COUNT(H_ACTPIX - 1);
240         bfin_write_PPI_FRAME(V_LINES);
241
242         bfin_write_PPI_CONTROL(PPI_TX_MODE |       /* output mode , PORT_DIR */
243                                 PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */
244                                 PPI_PORT_CFG_01 |  /* two frame sync PORT_CFG */
245                                 PPI_PMODE |        /* 8/16 bit data length / PACK_EN? */
246                                 PPI_POLS_1);       /* faling edge syncs POLS */
247 }
248
249 static inline void bfin_lq035q1_disable_ppi(void)
250 {
251         bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN);
252 }
253
254 static inline void bfin_lq035q1_enable_ppi(void)
255 {
256         bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
257 }
258
259 static void bfin_lq035q1_start_timers(void)
260 {
261         enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit);
262 }
263
264 static void bfin_lq035q1_stop_timers(void)
265 {
266         disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit);
267
268         set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN |
269                                 TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL |
270                                  TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF);
271
272 }
273
274 static void bfin_lq035q1_init_timers(void)
275 {
276
277         bfin_lq035q1_stop_timers();
278
279         set_gptimer_period(TIMER_HSYNC_id, H_PERIOD);
280         set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE);
281         set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
282                                       TIMER_TIN_SEL | TIMER_CLK_SEL|
283                                       TIMER_EMU_RUN);
284
285         set_gptimer_period(TIMER_VSYNC_id, V_PERIOD);
286         set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE);
287         set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
288                                       TIMER_TIN_SEL | TIMER_CLK_SEL |
289                                       TIMER_EMU_RUN);
290
291 }
292
293 static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi)
294 {
295
296         set_dma_config(CH_PPI,
297                        set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
298                                            INTR_DISABLE, DIMENSION_2D,
299                                            DATA_SIZE_16,
300                                            DMA_NOSYNC_KEEP_DMA_BUF));
301         set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
302         set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8);
303         set_dma_y_count(CH_PPI, V_LINES);
304
305         set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8);
306         set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer);
307
308 }
309
310 #if (CLOCKS_PER_PIX == 1)
311 static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
312                             P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
313                             P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
314                             P_PPI0_D6, P_PPI0_D7, P_PPI0_D8,
315                             P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
316                             P_PPI0_D12, P_PPI0_D13, P_PPI0_D14,
317                             P_PPI0_D15, 0};
318 #else
319 static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
320                             P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
321                             P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
322                             P_PPI0_D6, P_PPI0_D7, 0};
323 #endif
324
325 static inline void bfin_lq035q1_free_ports(void)
326 {
327         peripheral_free_list(ppi0_req_16);
328         if (ANOMALY_05000400)
329                 gpio_free(P_IDENT(P_PPI0_FS3));
330 }
331
332 static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
333 {
334         /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
335          * Drive PPI_FS3 Low
336          */
337         if (ANOMALY_05000400) {
338                 int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3");
339                 if (ret)
340                         return ret;
341                 gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
342         }
343
344         if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) {
345                 dev_err(&pdev->dev, "requesting peripherals failed\n");
346                 return -EFAULT;
347         }
348
349         return 0;
350 }
351
352 static int bfin_lq035q1_fb_open(struct fb_info *info, int user)
353 {
354         struct bfin_lq035q1fb_info *fbi = info->par;
355
356         spin_lock(&fbi->lock);
357         fbi->lq035_open_cnt++;
358
359         if (fbi->lq035_open_cnt <= 1) {
360
361                 bfin_lq035q1_disable_ppi();
362                 SSYNC();
363
364                 bfin_lq035q1_config_dma(fbi);
365                 bfin_lq035q1_config_ppi(fbi);
366                 bfin_lq035q1_init_timers();
367
368                 /* start dma */
369                 enable_dma(CH_PPI);
370                 bfin_lq035q1_enable_ppi();
371                 bfin_lq035q1_start_timers();
372                 lq035q1_backlight(fbi, 1);
373         }
374
375         spin_unlock(&fbi->lock);
376
377         return 0;
378 }
379
380 static int bfin_lq035q1_fb_release(struct fb_info *info, int user)
381 {
382         struct bfin_lq035q1fb_info *fbi = info->par;
383
384         spin_lock(&fbi->lock);
385
386         fbi->lq035_open_cnt--;
387
388         if (fbi->lq035_open_cnt <= 0) {
389                 lq035q1_backlight(fbi, 0);
390                 bfin_lq035q1_disable_ppi();
391                 SSYNC();
392                 disable_dma(CH_PPI);
393                 bfin_lq035q1_stop_timers();
394         }
395
396         spin_unlock(&fbi->lock);
397
398         return 0;
399 }
400
401 static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
402                                      struct fb_info *info)
403 {
404         switch (var->bits_per_pixel) {
405 #if (LCD_BPP == 24)
406         case 24:/* TRUECOLOUR, 16m */
407 #else
408         case 16:/* DIRECTCOLOUR, 64k */
409 #endif
410                 var->red.offset = info->var.red.offset;
411                 var->green.offset = info->var.green.offset;
412                 var->blue.offset = info->var.blue.offset;
413                 var->red.length = info->var.red.length;
414                 var->green.length = info->var.green.length;
415                 var->blue.length = info->var.blue.length;
416                 var->transp.offset = 0;
417                 var->transp.length = 0;
418                 var->transp.msb_right = 0;
419                 var->red.msb_right = 0;
420                 var->green.msb_right = 0;
421                 var->blue.msb_right = 0;
422                 break;
423         default:
424                 pr_debug("%s: depth not supported: %u BPP\n", __func__,
425                          var->bits_per_pixel);
426                 return -EINVAL;
427         }
428
429         if (info->var.xres != var->xres || info->var.yres != var->yres ||
430             info->var.xres_virtual != var->xres_virtual ||
431             info->var.yres_virtual != var->yres_virtual) {
432                 pr_debug("%s: Resolution not supported: X%u x Y%u \n",
433                          __func__, var->xres, var->yres);
434                 return -EINVAL;
435         }
436
437         /*
438          *  Memory limit
439          */
440
441         if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
442                 pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
443                          __func__, var->yres_virtual);
444                 return -ENOMEM;
445         }
446
447
448         return 0;
449 }
450
451 int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
452 {
453         if (nocursor)
454                 return 0;
455         else
456                 return -EINVAL; /* just to force soft_cursor() call */
457 }
458
459 static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green,
460                                    u_int blue, u_int transp,
461                                    struct fb_info *info)
462 {
463         if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES)
464                 return -EINVAL;
465
466         if (info->var.grayscale) {
467                 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
468                 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
469         }
470
471         if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
472
473                 u32 value;
474                 /* Place color in the pseudopalette */
475                 if (regno > 16)
476                         return -EINVAL;
477
478                 red >>= (16 - info->var.red.length);
479                 green >>= (16 - info->var.green.length);
480                 blue >>= (16 - info->var.blue.length);
481
482                 value = (red << info->var.red.offset) |
483                     (green << info->var.green.offset) |
484                     (blue << info->var.blue.offset);
485                 value &= 0xFFFFFF;
486
487                 ((u32 *) (info->pseudo_palette))[regno] = value;
488
489         }
490
491         return 0;
492 }
493
494 static struct fb_ops bfin_lq035q1_fb_ops = {
495         .owner = THIS_MODULE,
496         .fb_open = bfin_lq035q1_fb_open,
497         .fb_release = bfin_lq035q1_fb_release,
498         .fb_check_var = bfin_lq035q1_fb_check_var,
499         .fb_fillrect = cfb_fillrect,
500         .fb_copyarea = cfb_copyarea,
501         .fb_imageblit = cfb_imageblit,
502         .fb_cursor = bfin_lq035q1_fb_cursor,
503         .fb_setcolreg = bfin_lq035q1_fb_setcolreg,
504 };
505
506 static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id)
507 {
508         /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/
509
510         u16 status = bfin_read_PPI_STATUS();
511         bfin_write_PPI_STATUS(-1);
512
513         if (status) {
514                 bfin_lq035q1_disable_ppi();
515                 disable_dma(CH_PPI);
516
517                 /* start dma */
518                 enable_dma(CH_PPI);
519                 bfin_lq035q1_enable_ppi();
520                 bfin_write_PPI_STATUS(-1);
521         }
522
523         return IRQ_HANDLED;
524 }
525
526 static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
527 {
528         struct bfin_lq035q1fb_info *info;
529         struct fb_info *fbinfo;
530         int ret;
531
532         ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI");
533         if (ret < 0) {
534                 dev_err(&pdev->dev, "PPI DMA unavailable\n");
535                 goto out1;
536         }
537
538         fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev);
539         if (!fbinfo) {
540                 ret = -ENOMEM;
541                 goto out2;
542         }
543
544         info = fbinfo->par;
545         info->fb = fbinfo;
546         info->dev = &pdev->dev;
547
548         info->disp_info = pdev->dev.platform_data;
549
550         platform_set_drvdata(pdev, fbinfo);
551
552         strcpy(fbinfo->fix.id, DRIVER_NAME);
553
554         fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
555         fbinfo->fix.type_aux = 0;
556         fbinfo->fix.xpanstep = 0;
557         fbinfo->fix.ypanstep = 0;
558         fbinfo->fix.ywrapstep = 0;
559         fbinfo->fix.accel = FB_ACCEL_NONE;
560         fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
561
562         fbinfo->var.nonstd = 0;
563         fbinfo->var.activate = FB_ACTIVATE_NOW;
564         fbinfo->var.height = -1;
565         fbinfo->var.width = -1;
566         fbinfo->var.accel_flags = 0;
567         fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
568
569         fbinfo->var.xres = LCD_X_RES;
570         fbinfo->var.xres_virtual = LCD_X_RES;
571         fbinfo->var.yres = LCD_Y_RES;
572         fbinfo->var.yres_virtual = LCD_Y_RES;
573         fbinfo->var.bits_per_pixel = LCD_BPP;
574
575         if (info->disp_info->mode & LQ035_BGR) {
576 #if (LCD_BPP == 24)
577                 fbinfo->var.red.offset = 0;
578                 fbinfo->var.green.offset = 8;
579                 fbinfo->var.blue.offset = 16;
580 #else
581                 fbinfo->var.red.offset = 0;
582                 fbinfo->var.green.offset = 5;
583                 fbinfo->var.blue.offset = 11;
584 #endif
585         } else {
586 #if (LCD_BPP == 24)
587                 fbinfo->var.red.offset = 16;
588                 fbinfo->var.green.offset = 8;
589                 fbinfo->var.blue.offset = 0;
590 #else
591                 fbinfo->var.red.offset = 11;
592                 fbinfo->var.green.offset = 5;
593                 fbinfo->var.blue.offset = 0;
594 #endif
595         }
596
597         fbinfo->var.transp.offset = 0;
598
599 #if (LCD_BPP == 24)
600         fbinfo->var.red.length = 8;
601         fbinfo->var.green.length = 8;
602         fbinfo->var.blue.length = 8;
603 #else
604         fbinfo->var.red.length = 5;
605         fbinfo->var.green.length = 6;
606         fbinfo->var.blue.length = 5;
607 #endif
608
609         fbinfo->var.transp.length = 0;
610
611         fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8
612                                 + ACTIVE_VIDEO_MEM_OFFSET;
613
614         fbinfo->fix.line_length = fbinfo->var.xres_virtual *
615             fbinfo->var.bits_per_pixel / 8;
616
617
618         fbinfo->fbops = &bfin_lq035q1_fb_ops;
619         fbinfo->flags = FBINFO_FLAG_DEFAULT;
620
621         info->fb_buffer =
622             dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
623                                GFP_KERNEL);
624
625         if (NULL == info->fb_buffer) {
626                 dev_err(&pdev->dev, "couldn't allocate dma buffer\n");
627                 ret = -ENOMEM;
628                 goto out3;
629         }
630
631         fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
632         fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
633
634         fbinfo->fbops = &bfin_lq035q1_fb_ops;
635
636         fbinfo->pseudo_palette = &info->pseudo_pal;
637
638         ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0);
639         if (ret < 0) {
640                 dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n",
641                        BFIN_LCD_NBR_PALETTE_ENTRIES);
642                 goto out4;
643         }
644
645         ret = bfin_lq035q1_request_ports(pdev);
646         if (ret) {
647                 dev_err(&pdev->dev, "couldn't request gpio port\n");
648                 goto out6;
649         }
650
651         info->irq = platform_get_irq(pdev, 0);
652         if (info->irq < 0) {
653                 ret = -EINVAL;
654                 goto out7;
655         }
656
657         ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED,
658                         DRIVER_NAME" PPI ERROR", info);
659         if (ret < 0) {
660                 dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n");
661                 goto out7;
662         }
663
664         info->spidrv.driver.name = DRIVER_NAME"-spi";
665         info->spidrv.probe    = lq035q1_spidev_probe;
666         info->spidrv.remove   = __devexit_p(lq035q1_spidev_remove);
667         info->spidrv.shutdown = lq035q1_spidev_shutdown;
668         info->spidrv.suspend  = lq035q1_spidev_suspend;
669         info->spidrv.resume   = lq035q1_spidev_resume;
670
671         ret = spi_register_driver(&info->spidrv);
672         if (ret < 0) {
673                 dev_err(&pdev->dev, "couldn't register SPI Interface\n");
674                 goto out8;
675         }
676
677         if (info->disp_info->use_bl) {
678                 ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight");
679
680                 if (ret) {
681                         dev_err(&pdev->dev, "failed to request GPIO %d\n",
682                                 info->disp_info->gpio_bl);
683                         goto out9;
684                 }
685                 gpio_direction_output(info->disp_info->gpio_bl, 0);
686         }
687
688         ret = register_framebuffer(fbinfo);
689         if (ret < 0) {
690                 dev_err(&pdev->dev, "unable to register framebuffer\n");
691                 goto out10;
692         }
693
694         dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n",
695                 LCD_X_RES, LCD_Y_RES, LCD_BPP);
696
697         return 0;
698
699  out10:
700         if (info->disp_info->use_bl)
701                 gpio_free(info->disp_info->gpio_bl);
702  out9:
703         spi_unregister_driver(&info->spidrv);
704  out8:
705         free_irq(info->irq, info);
706  out7:
707         bfin_lq035q1_free_ports();
708  out6:
709         fb_dealloc_cmap(&fbinfo->cmap);
710  out4:
711         dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
712                           info->dma_handle);
713  out3:
714         framebuffer_release(fbinfo);
715  out2:
716         free_dma(CH_PPI);
717  out1:
718         platform_set_drvdata(pdev, NULL);
719
720         return ret;
721 }
722
723 static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
724 {
725         struct fb_info *fbinfo = platform_get_drvdata(pdev);
726         struct bfin_lq035q1fb_info *info = fbinfo->par;
727
728         if (info->disp_info->use_bl)
729                 gpio_free(info->disp_info->gpio_bl);
730
731         spi_unregister_driver(&info->spidrv);
732
733         unregister_framebuffer(fbinfo);
734
735         free_dma(CH_PPI);
736         free_irq(info->irq, info);
737
738         if (info->fb_buffer != NULL)
739                 dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
740                                   info->dma_handle);
741
742         fb_dealloc_cmap(&fbinfo->cmap);
743
744         bfin_lq035q1_free_ports();
745
746         platform_set_drvdata(pdev, NULL);
747         framebuffer_release(fbinfo);
748
749         dev_info(&pdev->dev, "unregistered LCD driver\n");
750
751         return 0;
752 }
753
754 #ifdef CONFIG_PM
755 static int bfin_lq035q1_suspend(struct device *dev)
756 {
757         struct fb_info *fbinfo = dev_get_drvdata(dev);
758         struct bfin_lq035q1fb_info *info = fbinfo->par;
759
760         if (info->lq035_open_cnt) {
761                 lq035q1_backlight(info, 0);
762                 bfin_lq035q1_disable_ppi();
763                 SSYNC();
764                 disable_dma(CH_PPI);
765                 bfin_lq035q1_stop_timers();
766                 bfin_write_PPI_STATUS(-1);
767         }
768
769         return 0;
770 }
771
772 static int bfin_lq035q1_resume(struct device *dev)
773 {
774         struct fb_info *fbinfo = dev_get_drvdata(dev);
775         struct bfin_lq035q1fb_info *info = fbinfo->par;
776
777         if (info->lq035_open_cnt) {
778                 bfin_lq035q1_disable_ppi();
779                 SSYNC();
780
781                 bfin_lq035q1_config_dma(info);
782                 bfin_lq035q1_config_ppi(info);
783                 bfin_lq035q1_init_timers();
784
785                 /* start dma */
786                 enable_dma(CH_PPI);
787                 bfin_lq035q1_enable_ppi();
788                 bfin_lq035q1_start_timers();
789                 lq035q1_backlight(info, 1);
790         }
791
792         return 0;
793 }
794
795 static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = {
796         .suspend = bfin_lq035q1_suspend,
797         .resume  = bfin_lq035q1_resume,
798 };
799 #endif
800
801 static struct platform_driver bfin_lq035q1_driver = {
802         .probe   = bfin_lq035q1_probe,
803         .remove  = __devexit_p(bfin_lq035q1_remove),
804         .driver = {
805                 .name = DRIVER_NAME,
806 #ifdef CONFIG_PM
807                 .pm   = &bfin_lq035q1_dev_pm_ops,
808 #endif
809         },
810 };
811
812 static int __init bfin_lq035q1_driver_init(void)
813 {
814         return platform_driver_register(&bfin_lq035q1_driver);
815 }
816 module_init(bfin_lq035q1_driver_init);
817
818 static void __exit bfin_lq035q1_driver_cleanup(void)
819 {
820         platform_driver_unregister(&bfin_lq035q1_driver);
821 }
822 module_exit(bfin_lq035q1_driver_cleanup);
823
824 MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
825 MODULE_LICENSE("GPL");