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/gpio.h>
17 #include <linux/slab.h>
18 #include <linux/init.h>
19 #include <linux/types.h>
20 #include <linux/interrupt.h>
21 #include <linux/device.h>
22 #include <linux/backlight.h>
23 #include <linux/lcd.h>
24 #include <linux/dma-mapping.h>
25 #include <linux/platform_device.h>
26 #include <linux/spi/spi.h>
28 #include <asm/blackfin.h>
31 #include <asm/portmux.h>
32 #include <asm/gptimers.h>
34 #include <asm/bfin-lq035q1.h>
36 #if defined(BF533_FAMILY) || defined(BF538_FAMILY)
37 #define TIMER_HSYNC_id TIMER1_id
38 #define TIMER_HSYNCbit TIMER1bit
39 #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
40 #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
41 #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
43 #define TIMER_VSYNC_id TIMER2_id
44 #define TIMER_VSYNCbit TIMER2bit
45 #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2
46 #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2
47 #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2
49 #define TIMER_HSYNC_id TIMER0_id
50 #define TIMER_HSYNCbit TIMER0bit
51 #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0
52 #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0
53 #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0
55 #define TIMER_VSYNC_id TIMER1_id
56 #define TIMER_VSYNCbit TIMER1bit
57 #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
58 #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
59 #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
62 #define LCD_X_RES 320 /* Horizontal Resolution */
63 #define LCD_Y_RES 240 /* Vertical Resolution */
64 #define DMA_BUS_SIZE 16
65 #define U_LINE 4 /* Blanking Lines */
68 /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
69 * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
73 #define BFIN_LCD_NBR_PALETTE_ENTRIES 256
75 #define PPI_TX_MODE 0x2
76 #define PPI_XFER_TYPE_11 0xC
77 #define PPI_PORT_CFG_01 0x10
78 #define PPI_POLS_1 0x8000
80 #define LQ035_INDEX 0x74
81 #define LQ035_DATA 0x76
83 #define LQ035_DRIVER_OUTPUT_CTL 0x1
84 #define LQ035_SHUT_CTL 0x11
86 #define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV)
87 #define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK)
89 #define LQ035_SHUT (1 << 0) /* Shutdown */
90 #define LQ035_ON (0 << 0) /* Shutdown */
92 struct bfin_lq035q1fb_info
{
95 struct spi_driver spidrv
;
96 struct bfin_lq035q1fb_disp_info
*disp_info
;
97 unsigned char *fb_buffer
; /* RGB Buffer */
98 dma_addr_t dma_handle
;
101 spinlock_t lock
; /* lock */
115 module_param(nocursor
, int, 0644);
116 MODULE_PARM_DESC(nocursor
, "cursor enable/disable");
122 static int lq035q1_control(struct spi_device
*spi
, unsigned char reg
, unsigned short value
)
125 u8 regs
[3] = { LQ035_INDEX
, 0, 0 };
126 u8 dat
[3] = { LQ035_DATA
, 0, 0 };
133 dat
[2] = value
& 0xFF;
135 ret
= spi_write(spi
, regs
, ARRAY_SIZE(regs
));
136 ret
|= spi_write(spi
, dat
, ARRAY_SIZE(dat
));
140 static int lq035q1_spidev_probe(struct spi_device
*spi
)
143 struct spi_control
*ctl
;
144 struct bfin_lq035q1fb_info
*info
= container_of(spi
->dev
.driver
,
145 struct bfin_lq035q1fb_info
,
148 ctl
= kzalloc(sizeof(*ctl
), GFP_KERNEL
);
153 ctl
->mode
= (info
->disp_info
->mode
&
154 LQ035_DRIVER_OUTPUT_MASK
) | LQ035_DRIVER_OUTPUT_DEFAULT
;
156 ret
= lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_ON
);
157 ret
|= lq035q1_control(spi
, LQ035_DRIVER_OUTPUT_CTL
, ctl
->mode
);
163 spi_set_drvdata(spi
, ctl
);
168 static int lq035q1_spidev_remove(struct spi_device
*spi
)
170 return lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_SHUT
);
173 #ifdef CONFIG_PM_SLEEP
174 static int lq035q1_spidev_suspend(struct device
*dev
)
176 struct spi_device
*spi
= to_spi_device(dev
);
178 return lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_SHUT
);
181 static int lq035q1_spidev_resume(struct device
*dev
)
183 struct spi_device
*spi
= to_spi_device(dev
);
184 struct spi_control
*ctl
= spi_get_drvdata(spi
);
187 ret
= lq035q1_control(spi
, LQ035_DRIVER_OUTPUT_CTL
, ctl
->mode
);
191 return lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_ON
);
194 static SIMPLE_DEV_PM_OPS(lq035q1_spidev_pm_ops
, lq035q1_spidev_suspend
,
195 lq035q1_spidev_resume
);
196 #define LQ035Q1_SPIDEV_PM_OPS (&lq035q1_spidev_pm_ops)
199 #define LQ035Q1_SPIDEV_PM_OPS NULL
202 /* Power down all displays on reboot, poweroff or halt */
203 static void lq035q1_spidev_shutdown(struct spi_device
*spi
)
205 lq035q1_control(spi
, LQ035_SHUT_CTL
, LQ035_SHUT
);
208 static int lq035q1_backlight(struct bfin_lq035q1fb_info
*info
, unsigned arg
)
210 if (info
->disp_info
->use_bl
)
211 gpio_set_value(info
->disp_info
->gpio_bl
, arg
);
216 static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info
*fbi
)
218 unsigned long clocks_per_pix
, cpld_pipeline_delay_cor
;
221 * Interface 16/18-bit TFT over an 8-bit wide PPI using a small
222 * Programmable Logic Device (CPLD)
223 * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
226 switch (fbi
->disp_info
->ppi_mode
) {
227 case USE_RGB565_16_BIT_PPI
:
230 cpld_pipeline_delay_cor
= 0;
232 case USE_RGB565_8_BIT_PPI
:
235 cpld_pipeline_delay_cor
= 3;
237 case USE_RGB888_8_BIT_PPI
:
240 cpld_pipeline_delay_cor
= 5;
247 * HS and VS timing parameters (all in number of PPI clk ticks)
250 fbi
->h_actpix
= (LCD_X_RES
* clocks_per_pix
); /* active horizontal pixel */
251 fbi
->h_period
= (336 * clocks_per_pix
); /* HS period */
252 fbi
->h_pulse
= (2 * clocks_per_pix
); /* HS pulse width */
253 fbi
->h_start
= (7 * clocks_per_pix
+ cpld_pipeline_delay_cor
); /* first valid pixel */
255 fbi
->v_lines
= (LCD_Y_RES
+ U_LINE
); /* total vertical lines */
256 fbi
->v_pulse
= (2 * clocks_per_pix
); /* VS pulse width (1-5 H_PERIODs) */
257 fbi
->v_period
= (fbi
->h_period
* fbi
->v_lines
); /* VS period */
262 static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info
*fbi
)
266 if (fbi
->disp_info
->ppi_mode
== USE_RGB565_16_BIT_PPI
)
269 ppi_pmode
= (DLEN_8
| PACK_EN
);
271 bfin_write_PPI_DELAY(fbi
->h_start
);
272 bfin_write_PPI_COUNT(fbi
->h_actpix
- 1);
273 bfin_write_PPI_FRAME(fbi
->v_lines
);
275 bfin_write_PPI_CONTROL(PPI_TX_MODE
| /* output mode , PORT_DIR */
276 PPI_XFER_TYPE_11
| /* sync mode XFR_TYPE */
277 PPI_PORT_CFG_01
| /* two frame sync PORT_CFG */
278 ppi_pmode
| /* 8/16 bit data length / PACK_EN? */
279 PPI_POLS_1
); /* faling edge syncs POLS */
282 static inline void bfin_lq035q1_disable_ppi(void)
284 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN
);
287 static inline void bfin_lq035q1_enable_ppi(void)
289 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN
);
292 static void bfin_lq035q1_start_timers(void)
294 enable_gptimers(TIMER_VSYNCbit
| TIMER_HSYNCbit
);
297 static void bfin_lq035q1_stop_timers(void)
299 disable_gptimers(TIMER_HSYNCbit
| TIMER_VSYNCbit
);
301 set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN
| TIMER_VSYNC_STATUS_TRUN
|
302 TIMER_HSYNC_STATUS_TIMIL
| TIMER_VSYNC_STATUS_TIMIL
|
303 TIMER_HSYNC_STATUS_TOVF
| TIMER_VSYNC_STATUS_TOVF
);
307 static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info
*fbi
)
310 bfin_lq035q1_stop_timers();
312 set_gptimer_period(TIMER_HSYNC_id
, fbi
->h_period
);
313 set_gptimer_pwidth(TIMER_HSYNC_id
, fbi
->h_pulse
);
314 set_gptimer_config(TIMER_HSYNC_id
, TIMER_MODE_PWM
| TIMER_PERIOD_CNT
|
315 TIMER_TIN_SEL
| TIMER_CLK_SEL
|
318 set_gptimer_period(TIMER_VSYNC_id
, fbi
->v_period
);
319 set_gptimer_pwidth(TIMER_VSYNC_id
, fbi
->v_pulse
);
320 set_gptimer_config(TIMER_VSYNC_id
, TIMER_MODE_PWM
| TIMER_PERIOD_CNT
|
321 TIMER_TIN_SEL
| TIMER_CLK_SEL
|
326 static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info
*fbi
)
330 set_dma_config(CH_PPI
,
331 set_bfin_dma_config(DIR_READ
, DMA_FLOW_AUTO
,
332 INTR_DISABLE
, DIMENSION_2D
,
334 DMA_NOSYNC_KEEP_DMA_BUF
));
335 set_dma_x_count(CH_PPI
, (LCD_X_RES
* fbi
->lcd_bpp
) / DMA_BUS_SIZE
);
336 set_dma_x_modify(CH_PPI
, DMA_BUS_SIZE
/ 8);
337 set_dma_y_count(CH_PPI
, fbi
->v_lines
);
339 set_dma_y_modify(CH_PPI
, DMA_BUS_SIZE
/ 8);
340 set_dma_start_addr(CH_PPI
, (unsigned long)fbi
->fb_buffer
);
344 static const u16 ppi0_req_16
[] = {P_PPI0_CLK
, P_PPI0_FS1
, P_PPI0_FS2
,
345 P_PPI0_D0
, P_PPI0_D1
, P_PPI0_D2
,
346 P_PPI0_D3
, P_PPI0_D4
, P_PPI0_D5
,
347 P_PPI0_D6
, P_PPI0_D7
, P_PPI0_D8
,
348 P_PPI0_D9
, P_PPI0_D10
, P_PPI0_D11
,
349 P_PPI0_D12
, P_PPI0_D13
, P_PPI0_D14
,
352 static const u16 ppi0_req_8
[] = {P_PPI0_CLK
, P_PPI0_FS1
, P_PPI0_FS2
,
353 P_PPI0_D0
, P_PPI0_D1
, P_PPI0_D2
,
354 P_PPI0_D3
, P_PPI0_D4
, P_PPI0_D5
,
355 P_PPI0_D6
, P_PPI0_D7
, 0};
357 static inline void bfin_lq035q1_free_ports(unsigned ppi16
)
360 peripheral_free_list(ppi0_req_16
);
362 peripheral_free_list(ppi0_req_8
);
364 if (ANOMALY_05000400
)
365 gpio_free(P_IDENT(P_PPI0_FS3
));
368 static int bfin_lq035q1_request_ports(struct platform_device
*pdev
,
372 /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
375 if (ANOMALY_05000400
) {
376 int ret
= gpio_request_one(P_IDENT(P_PPI0_FS3
),
377 GPIOF_OUT_INIT_LOW
, "PPI_FS3");
383 ret
= peripheral_request_list(ppi0_req_16
, DRIVER_NAME
);
385 ret
= peripheral_request_list(ppi0_req_8
, DRIVER_NAME
);
388 dev_err(&pdev
->dev
, "requesting peripherals failed\n");
395 static int bfin_lq035q1_fb_open(struct fb_info
*info
, int user
)
397 struct bfin_lq035q1fb_info
*fbi
= info
->par
;
399 spin_lock(&fbi
->lock
);
400 fbi
->lq035_open_cnt
++;
402 if (fbi
->lq035_open_cnt
<= 1) {
404 bfin_lq035q1_disable_ppi();
407 bfin_lq035q1_config_dma(fbi
);
408 bfin_lq035q1_config_ppi(fbi
);
409 bfin_lq035q1_init_timers(fbi
);
413 bfin_lq035q1_enable_ppi();
414 bfin_lq035q1_start_timers();
415 lq035q1_backlight(fbi
, 1);
418 spin_unlock(&fbi
->lock
);
423 static int bfin_lq035q1_fb_release(struct fb_info
*info
, int user
)
425 struct bfin_lq035q1fb_info
*fbi
= info
->par
;
427 spin_lock(&fbi
->lock
);
429 fbi
->lq035_open_cnt
--;
431 if (fbi
->lq035_open_cnt
<= 0) {
432 lq035q1_backlight(fbi
, 0);
433 bfin_lq035q1_disable_ppi();
436 bfin_lq035q1_stop_timers();
439 spin_unlock(&fbi
->lock
);
444 static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo
*var
,
445 struct fb_info
*info
)
447 struct bfin_lq035q1fb_info
*fbi
= info
->par
;
449 if (var
->bits_per_pixel
== fbi
->lcd_bpp
) {
450 var
->red
.offset
= info
->var
.red
.offset
;
451 var
->green
.offset
= info
->var
.green
.offset
;
452 var
->blue
.offset
= info
->var
.blue
.offset
;
453 var
->red
.length
= info
->var
.red
.length
;
454 var
->green
.length
= info
->var
.green
.length
;
455 var
->blue
.length
= info
->var
.blue
.length
;
456 var
->transp
.offset
= 0;
457 var
->transp
.length
= 0;
458 var
->transp
.msb_right
= 0;
459 var
->red
.msb_right
= 0;
460 var
->green
.msb_right
= 0;
461 var
->blue
.msb_right
= 0;
463 pr_debug("%s: depth not supported: %u BPP\n", __func__
,
464 var
->bits_per_pixel
);
468 if (info
->var
.xres
!= var
->xres
|| info
->var
.yres
!= var
->yres
||
469 info
->var
.xres_virtual
!= var
->xres_virtual
||
470 info
->var
.yres_virtual
!= var
->yres_virtual
) {
471 pr_debug("%s: Resolution not supported: X%u x Y%u \n",
472 __func__
, var
->xres
, var
->yres
);
480 if ((info
->fix
.line_length
* var
->yres_virtual
) > info
->fix
.smem_len
) {
481 pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
482 __func__
, var
->yres_virtual
);
490 int bfin_lq035q1_fb_cursor(struct fb_info
*info
, struct fb_cursor
*cursor
)
495 return -EINVAL
; /* just to force soft_cursor() call */
498 static int bfin_lq035q1_fb_setcolreg(u_int regno
, u_int red
, u_int green
,
499 u_int blue
, u_int transp
,
500 struct fb_info
*info
)
502 if (regno
>= BFIN_LCD_NBR_PALETTE_ENTRIES
)
505 if (info
->var
.grayscale
) {
506 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
507 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
510 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
513 /* Place color in the pseudopalette */
517 red
>>= (16 - info
->var
.red
.length
);
518 green
>>= (16 - info
->var
.green
.length
);
519 blue
>>= (16 - info
->var
.blue
.length
);
521 value
= (red
<< info
->var
.red
.offset
) |
522 (green
<< info
->var
.green
.offset
) |
523 (blue
<< info
->var
.blue
.offset
);
526 ((u32
*) (info
->pseudo_palette
))[regno
] = value
;
533 static struct fb_ops bfin_lq035q1_fb_ops
= {
534 .owner
= THIS_MODULE
,
535 .fb_open
= bfin_lq035q1_fb_open
,
536 .fb_release
= bfin_lq035q1_fb_release
,
537 .fb_check_var
= bfin_lq035q1_fb_check_var
,
538 .fb_fillrect
= cfb_fillrect
,
539 .fb_copyarea
= cfb_copyarea
,
540 .fb_imageblit
= cfb_imageblit
,
541 .fb_cursor
= bfin_lq035q1_fb_cursor
,
542 .fb_setcolreg
= bfin_lq035q1_fb_setcolreg
,
545 static irqreturn_t
bfin_lq035q1_irq_error(int irq
, void *dev_id
)
547 /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/
549 u16 status
= bfin_read_PPI_STATUS();
550 bfin_write_PPI_STATUS(-1);
553 bfin_lq035q1_disable_ppi();
558 bfin_lq035q1_enable_ppi();
559 bfin_write_PPI_STATUS(-1);
565 static int bfin_lq035q1_probe(struct platform_device
*pdev
)
567 struct bfin_lq035q1fb_info
*info
;
568 struct fb_info
*fbinfo
;
569 u32 active_video_mem_offset
;
572 ret
= request_dma(CH_PPI
, DRIVER_NAME
"_CH_PPI");
574 dev_err(&pdev
->dev
, "PPI DMA unavailable\n");
578 fbinfo
= framebuffer_alloc(sizeof(*info
), &pdev
->dev
);
586 info
->dev
= &pdev
->dev
;
587 spin_lock_init(&info
->lock
);
589 info
->disp_info
= pdev
->dev
.platform_data
;
591 platform_set_drvdata(pdev
, fbinfo
);
593 ret
= bfin_lq035q1_calc_timing(info
);
595 dev_err(&pdev
->dev
, "Failed PPI Mode\n");
599 strcpy(fbinfo
->fix
.id
, DRIVER_NAME
);
601 fbinfo
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
602 fbinfo
->fix
.type_aux
= 0;
603 fbinfo
->fix
.xpanstep
= 0;
604 fbinfo
->fix
.ypanstep
= 0;
605 fbinfo
->fix
.ywrapstep
= 0;
606 fbinfo
->fix
.accel
= FB_ACCEL_NONE
;
607 fbinfo
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
609 fbinfo
->var
.nonstd
= 0;
610 fbinfo
->var
.activate
= FB_ACTIVATE_NOW
;
611 fbinfo
->var
.height
= -1;
612 fbinfo
->var
.width
= -1;
613 fbinfo
->var
.accel_flags
= 0;
614 fbinfo
->var
.vmode
= FB_VMODE_NONINTERLACED
;
616 fbinfo
->var
.xres
= LCD_X_RES
;
617 fbinfo
->var
.xres_virtual
= LCD_X_RES
;
618 fbinfo
->var
.yres
= LCD_Y_RES
;
619 fbinfo
->var
.yres_virtual
= LCD_Y_RES
;
620 fbinfo
->var
.bits_per_pixel
= info
->lcd_bpp
;
622 if (info
->disp_info
->mode
& LQ035_BGR
) {
623 if (info
->lcd_bpp
== 24) {
624 fbinfo
->var
.red
.offset
= 0;
625 fbinfo
->var
.green
.offset
= 8;
626 fbinfo
->var
.blue
.offset
= 16;
628 fbinfo
->var
.red
.offset
= 0;
629 fbinfo
->var
.green
.offset
= 5;
630 fbinfo
->var
.blue
.offset
= 11;
633 if (info
->lcd_bpp
== 24) {
634 fbinfo
->var
.red
.offset
= 16;
635 fbinfo
->var
.green
.offset
= 8;
636 fbinfo
->var
.blue
.offset
= 0;
638 fbinfo
->var
.red
.offset
= 11;
639 fbinfo
->var
.green
.offset
= 5;
640 fbinfo
->var
.blue
.offset
= 0;
644 fbinfo
->var
.transp
.offset
= 0;
646 if (info
->lcd_bpp
== 24) {
647 fbinfo
->var
.red
.length
= 8;
648 fbinfo
->var
.green
.length
= 8;
649 fbinfo
->var
.blue
.length
= 8;
651 fbinfo
->var
.red
.length
= 5;
652 fbinfo
->var
.green
.length
= 6;
653 fbinfo
->var
.blue
.length
= 5;
656 fbinfo
->var
.transp
.length
= 0;
658 active_video_mem_offset
= ((U_LINE
/ 2) * LCD_X_RES
* (info
->lcd_bpp
/ 8));
660 fbinfo
->fix
.smem_len
= LCD_X_RES
* LCD_Y_RES
* info
->lcd_bpp
/ 8
661 + active_video_mem_offset
;
663 fbinfo
->fix
.line_length
= fbinfo
->var
.xres_virtual
*
664 fbinfo
->var
.bits_per_pixel
/ 8;
667 fbinfo
->fbops
= &bfin_lq035q1_fb_ops
;
668 fbinfo
->flags
= FBINFO_FLAG_DEFAULT
;
671 dma_alloc_coherent(NULL
, fbinfo
->fix
.smem_len
, &info
->dma_handle
,
674 if (NULL
== info
->fb_buffer
) {
675 dev_err(&pdev
->dev
, "couldn't allocate dma buffer\n");
680 fbinfo
->screen_base
= (void *)info
->fb_buffer
+ active_video_mem_offset
;
681 fbinfo
->fix
.smem_start
= (int)info
->fb_buffer
+ active_video_mem_offset
;
683 fbinfo
->fbops
= &bfin_lq035q1_fb_ops
;
685 fbinfo
->pseudo_palette
= &info
->pseudo_pal
;
687 ret
= fb_alloc_cmap(&fbinfo
->cmap
, BFIN_LCD_NBR_PALETTE_ENTRIES
, 0);
689 dev_err(&pdev
->dev
, "failed to allocate colormap (%d entries)\n",
690 BFIN_LCD_NBR_PALETTE_ENTRIES
);
694 ret
= bfin_lq035q1_request_ports(pdev
,
695 info
->disp_info
->ppi_mode
== USE_RGB565_16_BIT_PPI
);
697 dev_err(&pdev
->dev
, "couldn't request gpio port\n");
701 info
->irq
= platform_get_irq(pdev
, 0);
707 ret
= request_irq(info
->irq
, bfin_lq035q1_irq_error
, 0,
708 DRIVER_NAME
" PPI ERROR", info
);
710 dev_err(&pdev
->dev
, "unable to request PPI ERROR IRQ\n");
714 info
->spidrv
.driver
.name
= DRIVER_NAME
"-spi";
715 info
->spidrv
.probe
= lq035q1_spidev_probe
;
716 info
->spidrv
.remove
= lq035q1_spidev_remove
;
717 info
->spidrv
.shutdown
= lq035q1_spidev_shutdown
;
718 info
->spidrv
.driver
.pm
= LQ035Q1_SPIDEV_PM_OPS
;
720 ret
= spi_register_driver(&info
->spidrv
);
722 dev_err(&pdev
->dev
, "couldn't register SPI Interface\n");
726 if (info
->disp_info
->use_bl
) {
727 ret
= gpio_request_one(info
->disp_info
->gpio_bl
,
728 GPIOF_OUT_INIT_LOW
, "LQ035 Backlight");
731 dev_err(&pdev
->dev
, "failed to request GPIO %d\n",
732 info
->disp_info
->gpio_bl
);
737 ret
= register_framebuffer(fbinfo
);
739 dev_err(&pdev
->dev
, "unable to register framebuffer\n");
743 dev_info(&pdev
->dev
, "%dx%d %d-bit RGB FrameBuffer initialized\n",
744 LCD_X_RES
, LCD_Y_RES
, info
->lcd_bpp
);
749 if (info
->disp_info
->use_bl
)
750 gpio_free(info
->disp_info
->gpio_bl
);
752 spi_unregister_driver(&info
->spidrv
);
754 free_irq(info
->irq
, info
);
756 bfin_lq035q1_free_ports(info
->disp_info
->ppi_mode
==
757 USE_RGB565_16_BIT_PPI
);
759 fb_dealloc_cmap(&fbinfo
->cmap
);
761 dma_free_coherent(NULL
, fbinfo
->fix
.smem_len
, info
->fb_buffer
,
764 framebuffer_release(fbinfo
);
772 static int bfin_lq035q1_remove(struct platform_device
*pdev
)
774 struct fb_info
*fbinfo
= platform_get_drvdata(pdev
);
775 struct bfin_lq035q1fb_info
*info
= fbinfo
->par
;
777 if (info
->disp_info
->use_bl
)
778 gpio_free(info
->disp_info
->gpio_bl
);
780 spi_unregister_driver(&info
->spidrv
);
782 unregister_framebuffer(fbinfo
);
785 free_irq(info
->irq
, info
);
787 if (info
->fb_buffer
!= NULL
)
788 dma_free_coherent(NULL
, fbinfo
->fix
.smem_len
, info
->fb_buffer
,
791 fb_dealloc_cmap(&fbinfo
->cmap
);
793 bfin_lq035q1_free_ports(info
->disp_info
->ppi_mode
==
794 USE_RGB565_16_BIT_PPI
);
796 framebuffer_release(fbinfo
);
798 dev_info(&pdev
->dev
, "unregistered LCD driver\n");
804 static int bfin_lq035q1_suspend(struct device
*dev
)
806 struct fb_info
*fbinfo
= dev_get_drvdata(dev
);
807 struct bfin_lq035q1fb_info
*info
= fbinfo
->par
;
809 if (info
->lq035_open_cnt
) {
810 lq035q1_backlight(info
, 0);
811 bfin_lq035q1_disable_ppi();
814 bfin_lq035q1_stop_timers();
815 bfin_write_PPI_STATUS(-1);
821 static int bfin_lq035q1_resume(struct device
*dev
)
823 struct fb_info
*fbinfo
= dev_get_drvdata(dev
);
824 struct bfin_lq035q1fb_info
*info
= fbinfo
->par
;
826 if (info
->lq035_open_cnt
) {
827 bfin_lq035q1_disable_ppi();
830 bfin_lq035q1_config_dma(info
);
831 bfin_lq035q1_config_ppi(info
);
832 bfin_lq035q1_init_timers(info
);
836 bfin_lq035q1_enable_ppi();
837 bfin_lq035q1_start_timers();
838 lq035q1_backlight(info
, 1);
844 static struct dev_pm_ops bfin_lq035q1_dev_pm_ops
= {
845 .suspend
= bfin_lq035q1_suspend
,
846 .resume
= bfin_lq035q1_resume
,
850 static struct platform_driver bfin_lq035q1_driver
= {
851 .probe
= bfin_lq035q1_probe
,
852 .remove
= bfin_lq035q1_remove
,
856 .pm
= &bfin_lq035q1_dev_pm_ops
,
861 module_platform_driver(bfin_lq035q1_driver
);
863 MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
864 MODULE_LICENSE("GPL");