2 * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02
4 * Copyright 2008-2009 Analog Devices Inc.
5 * Licensed under the GPL-2 or later.
8 #define DRIVER_NAME "bfin-lq035q1"
9 #define pr_fmt(fmt) DRIVER_NAME ": " fmt
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.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 #include <linux/dma-mapping.h>
27 #include <asm/blackfin.h>
30 #include <asm/portmux.h>
31 #include <asm/gptimers.h>
33 #include <asm/bfin-lq035q1.h>
35 #if defined(BF533_FAMILY) || defined(BF538_FAMILY)
36 #define TIMER_HSYNC_id TIMER1_id
37 #define TIMER_HSYNCbit TIMER1bit
38 #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
39 #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
40 #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
42 #define TIMER_VSYNC_id TIMER2_id
43 #define TIMER_VSYNCbit TIMER2bit
44 #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2
45 #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2
46 #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2
48 #define TIMER_HSYNC_id TIMER0_id
49 #define TIMER_HSYNCbit TIMER0bit
50 #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0
51 #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0
52 #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0
54 #define TIMER_VSYNC_id TIMER1_id
55 #define TIMER_VSYNCbit TIMER1bit
56 #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
57 #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
58 #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
61 #define LCD_X_RES 320 /* Horizontal Resolution */
62 #define LCD_Y_RES 240 /* Vertical Resolution */
63 #define DMA_BUS_SIZE 16
65 #define USE_RGB565_16_BIT_PPI
67 #ifdef USE_RGB565_16_BIT_PPI
68 #define LCD_BPP 16 /* Bit Per Pixel */
69 #define CLOCKS_PER_PIX 1
70 #define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */
73 /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
74 * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
77 #ifdef USE_RGB565_8_BIT_PPI
78 #define LCD_BPP 16 /* Bit Per Pixel */
79 #define CLOCKS_PER_PIX 2
80 #define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */
83 #ifdef USE_RGB888_8_BIT_PPI
84 #define LCD_BPP 24 /* Bit Per Pixel */
85 #define CLOCKS_PER_PIX 3
86 #define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */
90 * HS and VS timing parameters (all in number of PPI clk ticks)
93 #define U_LINE 4 /* Blanking Lines */
95 #define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */
96 #define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */
97 #define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */
98 #define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */
100 #define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */
101 #define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */
102 #define V_PERIOD (H_PERIOD * V_LINES) /* VS period */
104 #define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
106 #define BFIN_LCD_NBR_PALETTE_ENTRIES 256
108 #define PPI_TX_MODE 0x2
109 #define PPI_XFER_TYPE_11 0xC
110 #define PPI_PORT_CFG_01 0x10
111 #define PPI_POLS_1 0x8000
113 #if (CLOCKS_PER_PIX > 1)
114 #define PPI_PMODE (DLEN_8 | PACK_EN)
116 #define PPI_PMODE (DLEN_16)
119 #define LQ035_INDEX 0x74
120 #define LQ035_DATA 0x76
122 #define LQ035_DRIVER_OUTPUT_CTL 0x1
123 #define LQ035_SHUT_CTL 0x11
125 #define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV)
126 #define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK)
128 #define LQ035_SHUT (1 << 0) /* Shutdown */
129 #define LQ035_ON (0 << 0) /* Shutdown */
131 struct bfin_lq035q1fb_info
{
134 struct spi_driver spidrv
;
135 struct bfin_lq035q1fb_disp_info
*disp_info
;
136 unsigned char *fb_buffer
; /* RGB Buffer */
137 dma_addr_t dma_handle
;
140 spinlock_t lock
; /* lock */
145 module_param(nocursor
, int, 0644);
146 MODULE_PARM_DESC(nocursor
, "cursor enable/disable");
152 static int lq035q1_control(struct spi_device
*spi
, unsigned char reg
, unsigned short value
)
155 u8 regs
[3] = { LQ035_INDEX
, 0, 0 };
156 u8 dat
[3] = { LQ035_DATA
, 0, 0 };
163 dat
[2] = value
& 0xFF;
165 ret
= spi_write(spi
, regs
, ARRAY_SIZE(regs
));
166 ret
|= spi_write(spi
, dat
, ARRAY_SIZE(dat
));
170 static int __devinit
lq035q1_spidev_probe(struct spi_device
*spi
)
173 struct spi_control
*ctl
;
174 struct bfin_lq035q1fb_info
*info
= container_of(spi
->dev
.driver
,
175 struct bfin_lq035q1fb_info
,
178 ctl
= kzalloc(sizeof(*ctl
), GFP_KERNEL
);
183 ctl
->mode
= (info
->disp_info
->mode
&
184 LQ035_DRIVER_OUTPUT_MASK
) | LQ035_DRIVER_OUTPUT_DEFAULT
;
186 ret
= lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_ON
);
187 ret
|= lq035q1_control(spi
, LQ035_DRIVER_OUTPUT_CTL
, ctl
->mode
);
191 spi_set_drvdata(spi
, ctl
);
196 static int lq035q1_spidev_remove(struct spi_device
*spi
)
198 return lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_SHUT
);
202 static int lq035q1_spidev_suspend(struct spi_device
*spi
, pm_message_t state
)
204 return lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_SHUT
);
207 static int lq035q1_spidev_resume(struct spi_device
*spi
)
210 struct spi_control
*ctl
= spi_get_drvdata(spi
);
212 ret
= lq035q1_control(spi
, LQ035_DRIVER_OUTPUT_CTL
, ctl
->mode
);
216 return lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_ON
);
219 # define lq035q1_spidev_suspend NULL
220 # define lq035q1_spidev_resume NULL
223 /* Power down all displays on reboot, poweroff or halt */
224 static void lq035q1_spidev_shutdown(struct spi_device
*spi
)
226 lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_SHUT
);
229 static int lq035q1_backlight(struct bfin_lq035q1fb_info
*info
, unsigned arg
)
231 if (info
->disp_info
->use_bl
)
232 gpio_set_value(info
->disp_info
->gpio_bl
, arg
);
237 static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info
*fbi
)
239 bfin_write_PPI_DELAY(H_START
);
240 bfin_write_PPI_COUNT(H_ACTPIX
- 1);
241 bfin_write_PPI_FRAME(V_LINES
);
243 bfin_write_PPI_CONTROL(PPI_TX_MODE
| /* output mode , PORT_DIR */
244 PPI_XFER_TYPE_11
| /* sync mode XFR_TYPE */
245 PPI_PORT_CFG_01
| /* two frame sync PORT_CFG */
246 PPI_PMODE
| /* 8/16 bit data length / PACK_EN? */
247 PPI_POLS_1
); /* faling edge syncs POLS */
250 static inline void bfin_lq035q1_disable_ppi(void)
252 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN
);
255 static inline void bfin_lq035q1_enable_ppi(void)
257 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN
);
260 static void bfin_lq035q1_start_timers(void)
262 enable_gptimers(TIMER_VSYNCbit
| TIMER_HSYNCbit
);
265 static void bfin_lq035q1_stop_timers(void)
267 disable_gptimers(TIMER_HSYNCbit
| TIMER_VSYNCbit
);
269 set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN
| TIMER_VSYNC_STATUS_TRUN
|
270 TIMER_HSYNC_STATUS_TIMIL
| TIMER_VSYNC_STATUS_TIMIL
|
271 TIMER_HSYNC_STATUS_TOVF
| TIMER_VSYNC_STATUS_TOVF
);
275 static void bfin_lq035q1_init_timers(void)
278 bfin_lq035q1_stop_timers();
280 set_gptimer_period(TIMER_HSYNC_id
, H_PERIOD
);
281 set_gptimer_pwidth(TIMER_HSYNC_id
, H_PULSE
);
282 set_gptimer_config(TIMER_HSYNC_id
, TIMER_MODE_PWM
| TIMER_PERIOD_CNT
|
283 TIMER_TIN_SEL
| TIMER_CLK_SEL
|
286 set_gptimer_period(TIMER_VSYNC_id
, V_PERIOD
);
287 set_gptimer_pwidth(TIMER_VSYNC_id
, V_PULSE
);
288 set_gptimer_config(TIMER_VSYNC_id
, TIMER_MODE_PWM
| TIMER_PERIOD_CNT
|
289 TIMER_TIN_SEL
| TIMER_CLK_SEL
|
294 static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info
*fbi
)
297 set_dma_config(CH_PPI
,
298 set_bfin_dma_config(DIR_READ
, DMA_FLOW_AUTO
,
299 INTR_DISABLE
, DIMENSION_2D
,
301 DMA_NOSYNC_KEEP_DMA_BUF
));
302 set_dma_x_count(CH_PPI
, (LCD_X_RES
* LCD_BPP
) / DMA_BUS_SIZE
);
303 set_dma_x_modify(CH_PPI
, DMA_BUS_SIZE
/ 8);
304 set_dma_y_count(CH_PPI
, V_LINES
);
306 set_dma_y_modify(CH_PPI
, DMA_BUS_SIZE
/ 8);
307 set_dma_start_addr(CH_PPI
, (unsigned long)fbi
->fb_buffer
);
311 #if (CLOCKS_PER_PIX == 1)
312 static const u16 ppi0_req_16
[] = {P_PPI0_CLK
, P_PPI0_FS1
, P_PPI0_FS2
,
313 P_PPI0_D0
, P_PPI0_D1
, P_PPI0_D2
,
314 P_PPI0_D3
, P_PPI0_D4
, P_PPI0_D5
,
315 P_PPI0_D6
, P_PPI0_D7
, P_PPI0_D8
,
316 P_PPI0_D9
, P_PPI0_D10
, P_PPI0_D11
,
317 P_PPI0_D12
, P_PPI0_D13
, P_PPI0_D14
,
320 static const u16 ppi0_req_16
[] = {P_PPI0_CLK
, P_PPI0_FS1
, P_PPI0_FS2
,
321 P_PPI0_D0
, P_PPI0_D1
, P_PPI0_D2
,
322 P_PPI0_D3
, P_PPI0_D4
, P_PPI0_D5
,
323 P_PPI0_D6
, P_PPI0_D7
, 0};
326 static inline void bfin_lq035q1_free_ports(void)
328 peripheral_free_list(ppi0_req_16
);
329 if (ANOMALY_05000400
)
330 gpio_free(P_IDENT(P_PPI0_FS3
));
333 static int __devinit
bfin_lq035q1_request_ports(struct platform_device
*pdev
)
335 /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
338 if (ANOMALY_05000400
) {
339 int ret
= gpio_request(P_IDENT(P_PPI0_FS3
), "PPI_FS3");
342 gpio_direction_output(P_IDENT(P_PPI0_FS3
), 0);
345 if (peripheral_request_list(ppi0_req_16
, DRIVER_NAME
)) {
346 dev_err(&pdev
->dev
, "requesting peripherals failed\n");
353 static int bfin_lq035q1_fb_open(struct fb_info
*info
, int user
)
355 struct bfin_lq035q1fb_info
*fbi
= info
->par
;
357 spin_lock(&fbi
->lock
);
358 fbi
->lq035_open_cnt
++;
360 if (fbi
->lq035_open_cnt
<= 1) {
362 bfin_lq035q1_disable_ppi();
365 bfin_lq035q1_config_dma(fbi
);
366 bfin_lq035q1_config_ppi(fbi
);
367 bfin_lq035q1_init_timers();
371 bfin_lq035q1_enable_ppi();
372 bfin_lq035q1_start_timers();
373 lq035q1_backlight(fbi
, 1);
376 spin_unlock(&fbi
->lock
);
381 static int bfin_lq035q1_fb_release(struct fb_info
*info
, int user
)
383 struct bfin_lq035q1fb_info
*fbi
= info
->par
;
385 spin_lock(&fbi
->lock
);
387 fbi
->lq035_open_cnt
--;
389 if (fbi
->lq035_open_cnt
<= 0) {
390 lq035q1_backlight(fbi
, 0);
391 bfin_lq035q1_disable_ppi();
394 bfin_lq035q1_stop_timers();
397 spin_unlock(&fbi
->lock
);
402 static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo
*var
,
403 struct fb_info
*info
)
405 switch (var
->bits_per_pixel
) {
407 case 24:/* TRUECOLOUR, 16m */
409 case 16:/* DIRECTCOLOUR, 64k */
411 var
->red
.offset
= info
->var
.red
.offset
;
412 var
->green
.offset
= info
->var
.green
.offset
;
413 var
->blue
.offset
= info
->var
.blue
.offset
;
414 var
->red
.length
= info
->var
.red
.length
;
415 var
->green
.length
= info
->var
.green
.length
;
416 var
->blue
.length
= info
->var
.blue
.length
;
417 var
->transp
.offset
= 0;
418 var
->transp
.length
= 0;
419 var
->transp
.msb_right
= 0;
420 var
->red
.msb_right
= 0;
421 var
->green
.msb_right
= 0;
422 var
->blue
.msb_right
= 0;
425 pr_debug("%s: depth not supported: %u BPP\n", __func__
,
426 var
->bits_per_pixel
);
430 if (info
->var
.xres
!= var
->xres
|| info
->var
.yres
!= var
->yres
||
431 info
->var
.xres_virtual
!= var
->xres_virtual
||
432 info
->var
.yres_virtual
!= var
->yres_virtual
) {
433 pr_debug("%s: Resolution not supported: X%u x Y%u \n",
434 __func__
, var
->xres
, var
->yres
);
442 if ((info
->fix
.line_length
* var
->yres_virtual
) > info
->fix
.smem_len
) {
443 pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
444 __func__
, var
->yres_virtual
);
452 int bfin_lq035q1_fb_cursor(struct fb_info
*info
, struct fb_cursor
*cursor
)
457 return -EINVAL
; /* just to force soft_cursor() call */
460 static int bfin_lq035q1_fb_setcolreg(u_int regno
, u_int red
, u_int green
,
461 u_int blue
, u_int transp
,
462 struct fb_info
*info
)
464 if (regno
>= BFIN_LCD_NBR_PALETTE_ENTRIES
)
467 if (info
->var
.grayscale
) {
468 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
469 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
472 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
475 /* Place color in the pseudopalette */
479 red
>>= (16 - info
->var
.red
.length
);
480 green
>>= (16 - info
->var
.green
.length
);
481 blue
>>= (16 - info
->var
.blue
.length
);
483 value
= (red
<< info
->var
.red
.offset
) |
484 (green
<< info
->var
.green
.offset
) |
485 (blue
<< info
->var
.blue
.offset
);
488 ((u32
*) (info
->pseudo_palette
))[regno
] = value
;
495 static struct fb_ops bfin_lq035q1_fb_ops
= {
496 .owner
= THIS_MODULE
,
497 .fb_open
= bfin_lq035q1_fb_open
,
498 .fb_release
= bfin_lq035q1_fb_release
,
499 .fb_check_var
= bfin_lq035q1_fb_check_var
,
500 .fb_fillrect
= cfb_fillrect
,
501 .fb_copyarea
= cfb_copyarea
,
502 .fb_imageblit
= cfb_imageblit
,
503 .fb_cursor
= bfin_lq035q1_fb_cursor
,
504 .fb_setcolreg
= bfin_lq035q1_fb_setcolreg
,
507 static irqreturn_t
bfin_lq035q1_irq_error(int irq
, void *dev_id
)
509 /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/
511 u16 status
= bfin_read_PPI_STATUS();
512 bfin_write_PPI_STATUS(-1);
515 bfin_lq035q1_disable_ppi();
520 bfin_lq035q1_enable_ppi();
521 bfin_write_PPI_STATUS(-1);
527 static int __devinit
bfin_lq035q1_probe(struct platform_device
*pdev
)
529 struct bfin_lq035q1fb_info
*info
;
530 struct fb_info
*fbinfo
;
533 ret
= request_dma(CH_PPI
, DRIVER_NAME
"_CH_PPI");
535 dev_err(&pdev
->dev
, "PPI DMA unavailable\n");
539 fbinfo
= framebuffer_alloc(sizeof(*info
), &pdev
->dev
);
547 info
->dev
= &pdev
->dev
;
549 info
->disp_info
= pdev
->dev
.platform_data
;
551 platform_set_drvdata(pdev
, fbinfo
);
553 strcpy(fbinfo
->fix
.id
, DRIVER_NAME
);
555 fbinfo
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
556 fbinfo
->fix
.type_aux
= 0;
557 fbinfo
->fix
.xpanstep
= 0;
558 fbinfo
->fix
.ypanstep
= 0;
559 fbinfo
->fix
.ywrapstep
= 0;
560 fbinfo
->fix
.accel
= FB_ACCEL_NONE
;
561 fbinfo
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
563 fbinfo
->var
.nonstd
= 0;
564 fbinfo
->var
.activate
= FB_ACTIVATE_NOW
;
565 fbinfo
->var
.height
= -1;
566 fbinfo
->var
.width
= -1;
567 fbinfo
->var
.accel_flags
= 0;
568 fbinfo
->var
.vmode
= FB_VMODE_NONINTERLACED
;
570 fbinfo
->var
.xres
= LCD_X_RES
;
571 fbinfo
->var
.xres_virtual
= LCD_X_RES
;
572 fbinfo
->var
.yres
= LCD_Y_RES
;
573 fbinfo
->var
.yres_virtual
= LCD_Y_RES
;
574 fbinfo
->var
.bits_per_pixel
= LCD_BPP
;
576 if (info
->disp_info
->mode
& LQ035_BGR
) {
578 fbinfo
->var
.red
.offset
= 0;
579 fbinfo
->var
.green
.offset
= 8;
580 fbinfo
->var
.blue
.offset
= 16;
582 fbinfo
->var
.red
.offset
= 0;
583 fbinfo
->var
.green
.offset
= 5;
584 fbinfo
->var
.blue
.offset
= 11;
588 fbinfo
->var
.red
.offset
= 16;
589 fbinfo
->var
.green
.offset
= 8;
590 fbinfo
->var
.blue
.offset
= 0;
592 fbinfo
->var
.red
.offset
= 11;
593 fbinfo
->var
.green
.offset
= 5;
594 fbinfo
->var
.blue
.offset
= 0;
598 fbinfo
->var
.transp
.offset
= 0;
601 fbinfo
->var
.red
.length
= 8;
602 fbinfo
->var
.green
.length
= 8;
603 fbinfo
->var
.blue
.length
= 8;
605 fbinfo
->var
.red
.length
= 5;
606 fbinfo
->var
.green
.length
= 6;
607 fbinfo
->var
.blue
.length
= 5;
610 fbinfo
->var
.transp
.length
= 0;
612 fbinfo
->fix
.smem_len
= LCD_X_RES
* LCD_Y_RES
* LCD_BPP
/ 8
613 + ACTIVE_VIDEO_MEM_OFFSET
;
615 fbinfo
->fix
.line_length
= fbinfo
->var
.xres_virtual
*
616 fbinfo
->var
.bits_per_pixel
/ 8;
619 fbinfo
->fbops
= &bfin_lq035q1_fb_ops
;
620 fbinfo
->flags
= FBINFO_FLAG_DEFAULT
;
623 dma_alloc_coherent(NULL
, fbinfo
->fix
.smem_len
, &info
->dma_handle
,
626 if (NULL
== info
->fb_buffer
) {
627 dev_err(&pdev
->dev
, "couldn't allocate dma buffer\n");
632 fbinfo
->screen_base
= (void *)info
->fb_buffer
+ ACTIVE_VIDEO_MEM_OFFSET
;
633 fbinfo
->fix
.smem_start
= (int)info
->fb_buffer
+ ACTIVE_VIDEO_MEM_OFFSET
;
635 fbinfo
->fbops
= &bfin_lq035q1_fb_ops
;
637 fbinfo
->pseudo_palette
= &info
->pseudo_pal
;
639 ret
= fb_alloc_cmap(&fbinfo
->cmap
, BFIN_LCD_NBR_PALETTE_ENTRIES
, 0);
641 dev_err(&pdev
->dev
, "failed to allocate colormap (%d entries)\n",
642 BFIN_LCD_NBR_PALETTE_ENTRIES
);
646 ret
= bfin_lq035q1_request_ports(pdev
);
648 dev_err(&pdev
->dev
, "couldn't request gpio port\n");
652 info
->irq
= platform_get_irq(pdev
, 0);
658 ret
= request_irq(info
->irq
, bfin_lq035q1_irq_error
, IRQF_DISABLED
,
659 DRIVER_NAME
" PPI ERROR", info
);
661 dev_err(&pdev
->dev
, "unable to request PPI ERROR IRQ\n");
665 info
->spidrv
.driver
.name
= DRIVER_NAME
"-spi";
666 info
->spidrv
.probe
= lq035q1_spidev_probe
;
667 info
->spidrv
.remove
= __devexit_p(lq035q1_spidev_remove
);
668 info
->spidrv
.shutdown
= lq035q1_spidev_shutdown
;
669 info
->spidrv
.suspend
= lq035q1_spidev_suspend
;
670 info
->spidrv
.resume
= lq035q1_spidev_resume
;
672 ret
= spi_register_driver(&info
->spidrv
);
674 dev_err(&pdev
->dev
, "couldn't register SPI Interface\n");
678 if (info
->disp_info
->use_bl
) {
679 ret
= gpio_request(info
->disp_info
->gpio_bl
, "LQ035 Backlight");
682 dev_err(&pdev
->dev
, "failed to request GPIO %d\n",
683 info
->disp_info
->gpio_bl
);
686 gpio_direction_output(info
->disp_info
->gpio_bl
, 0);
689 ret
= register_framebuffer(fbinfo
);
691 dev_err(&pdev
->dev
, "unable to register framebuffer\n");
695 dev_info(&pdev
->dev
, "%dx%d %d-bit RGB FrameBuffer initialized\n",
696 LCD_X_RES
, LCD_Y_RES
, LCD_BPP
);
701 if (info
->disp_info
->use_bl
)
702 gpio_free(info
->disp_info
->gpio_bl
);
704 spi_unregister_driver(&info
->spidrv
);
706 free_irq(info
->irq
, info
);
708 bfin_lq035q1_free_ports();
710 fb_dealloc_cmap(&fbinfo
->cmap
);
712 dma_free_coherent(NULL
, fbinfo
->fix
.smem_len
, info
->fb_buffer
,
715 framebuffer_release(fbinfo
);
719 platform_set_drvdata(pdev
, NULL
);
724 static int __devexit
bfin_lq035q1_remove(struct platform_device
*pdev
)
726 struct fb_info
*fbinfo
= platform_get_drvdata(pdev
);
727 struct bfin_lq035q1fb_info
*info
= fbinfo
->par
;
729 if (info
->disp_info
->use_bl
)
730 gpio_free(info
->disp_info
->gpio_bl
);
732 spi_unregister_driver(&info
->spidrv
);
734 unregister_framebuffer(fbinfo
);
737 free_irq(info
->irq
, info
);
739 if (info
->fb_buffer
!= NULL
)
740 dma_free_coherent(NULL
, fbinfo
->fix
.smem_len
, info
->fb_buffer
,
743 fb_dealloc_cmap(&fbinfo
->cmap
);
745 bfin_lq035q1_free_ports();
747 platform_set_drvdata(pdev
, NULL
);
748 framebuffer_release(fbinfo
);
750 dev_info(&pdev
->dev
, "unregistered LCD driver\n");
756 static int bfin_lq035q1_suspend(struct device
*dev
)
758 struct fb_info
*fbinfo
= dev_get_drvdata(dev
);
759 struct bfin_lq035q1fb_info
*info
= fbinfo
->par
;
761 if (info
->lq035_open_cnt
) {
762 lq035q1_backlight(info
, 0);
763 bfin_lq035q1_disable_ppi();
766 bfin_lq035q1_stop_timers();
767 bfin_write_PPI_STATUS(-1);
773 static int bfin_lq035q1_resume(struct device
*dev
)
775 struct fb_info
*fbinfo
= dev_get_drvdata(dev
);
776 struct bfin_lq035q1fb_info
*info
= fbinfo
->par
;
778 if (info
->lq035_open_cnt
) {
779 bfin_lq035q1_disable_ppi();
782 bfin_lq035q1_config_dma(info
);
783 bfin_lq035q1_config_ppi(info
);
784 bfin_lq035q1_init_timers();
788 bfin_lq035q1_enable_ppi();
789 bfin_lq035q1_start_timers();
790 lq035q1_backlight(info
, 1);
796 static struct dev_pm_ops bfin_lq035q1_dev_pm_ops
= {
797 .suspend
= bfin_lq035q1_suspend
,
798 .resume
= bfin_lq035q1_resume
,
802 static struct platform_driver bfin_lq035q1_driver
= {
803 .probe
= bfin_lq035q1_probe
,
804 .remove
= __devexit_p(bfin_lq035q1_remove
),
808 .pm
= &bfin_lq035q1_dev_pm_ops
,
813 static int __init
bfin_lq035q1_driver_init(void)
815 return platform_driver_register(&bfin_lq035q1_driver
);
817 module_init(bfin_lq035q1_driver_init
);
819 static void __exit
bfin_lq035q1_driver_cleanup(void)
821 platform_driver_unregister(&bfin_lq035q1_driver
);
823 module_exit(bfin_lq035q1_driver_cleanup
);
825 MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
826 MODULE_LICENSE("GPL");