Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.33 826 lines 20 kB view raw
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#include <linux/dma-mapping.h> 26 27#include <asm/blackfin.h> 28#include <asm/irq.h> 29#include <asm/dma.h> 30#include <asm/portmux.h> 31#include <asm/gptimers.h> 32 33#include <asm/bfin-lq035q1.h> 34 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 41 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 47#else 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 53 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 59#endif 60 61#define LCD_X_RES 320 /* Horizontal Resolution */ 62#define LCD_Y_RES 240 /* Vertical Resolution */ 63#define DMA_BUS_SIZE 16 64 65#define USE_RGB565_16_BIT_PPI 66 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 */ 71#endif 72 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 75 */ 76 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 */ 81#endif 82 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 */ 87#endif 88 89 /* 90 * HS and VS timing parameters (all in number of PPI clk ticks) 91 */ 92 93#define U_LINE 4 /* Blanking Lines */ 94 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 */ 99 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 */ 103 104#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) 105 106#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 107 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 112 113#if (CLOCKS_PER_PIX > 1) 114#define PPI_PMODE (DLEN_8 | PACK_EN) 115#else 116#define PPI_PMODE (DLEN_16) 117#endif 118 119#define LQ035_INDEX 0x74 120#define LQ035_DATA 0x76 121 122#define LQ035_DRIVER_OUTPUT_CTL 0x1 123#define LQ035_SHUT_CTL 0x11 124 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) 127 128#define LQ035_SHUT (1 << 0) /* Shutdown */ 129#define LQ035_ON (0 << 0) /* Shutdown */ 130 131struct bfin_lq035q1fb_info { 132 struct fb_info *fb; 133 struct device *dev; 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; 138 int lq035_open_cnt; 139 int irq; 140 spinlock_t lock; /* lock */ 141 u32 pseudo_pal[16]; 142}; 143 144static int nocursor; 145module_param(nocursor, int, 0644); 146MODULE_PARM_DESC(nocursor, "cursor enable/disable"); 147 148struct spi_control { 149 unsigned short mode; 150}; 151 152static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value) 153{ 154 int ret; 155 u8 regs[3] = { LQ035_INDEX, 0, 0 }; 156 u8 dat[3] = { LQ035_DATA, 0, 0 }; 157 158 if (!spi) 159 return -ENODEV; 160 161 regs[2] = reg; 162 dat[1] = value >> 8; 163 dat[2] = value & 0xFF; 164 165 ret = spi_write(spi, regs, ARRAY_SIZE(regs)); 166 ret |= spi_write(spi, dat, ARRAY_SIZE(dat)); 167 return ret; 168} 169 170static int __devinit lq035q1_spidev_probe(struct spi_device *spi) 171{ 172 int ret; 173 struct spi_control *ctl; 174 struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver, 175 struct bfin_lq035q1fb_info, 176 spidrv.driver); 177 178 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 179 180 if (!ctl) 181 return -ENOMEM; 182 183 ctl->mode = (info->disp_info->mode & 184 LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; 185 186 ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); 187 ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); 188 if (ret) 189 return ret; 190 191 spi_set_drvdata(spi, ctl); 192 193 return 0; 194} 195 196static int lq035q1_spidev_remove(struct spi_device *spi) 197{ 198 return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); 199} 200 201#ifdef CONFIG_PM 202static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) 203{ 204 return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); 205} 206 207static int lq035q1_spidev_resume(struct spi_device *spi) 208{ 209 int ret; 210 struct spi_control *ctl = spi_get_drvdata(spi); 211 212 ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); 213 if (ret) 214 return ret; 215 216 return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); 217} 218#else 219# define lq035q1_spidev_suspend NULL 220# define lq035q1_spidev_resume NULL 221#endif 222 223/* Power down all displays on reboot, poweroff or halt */ 224static void lq035q1_spidev_shutdown(struct spi_device *spi) 225{ 226 lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); 227} 228 229static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) 230{ 231 if (info->disp_info->use_bl) 232 gpio_set_value(info->disp_info->gpio_bl, arg); 233 234 return 0; 235} 236 237static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) 238{ 239 bfin_write_PPI_DELAY(H_START); 240 bfin_write_PPI_COUNT(H_ACTPIX - 1); 241 bfin_write_PPI_FRAME(V_LINES); 242 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 */ 248} 249 250static inline void bfin_lq035q1_disable_ppi(void) 251{ 252 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); 253} 254 255static inline void bfin_lq035q1_enable_ppi(void) 256{ 257 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); 258} 259 260static void bfin_lq035q1_start_timers(void) 261{ 262 enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); 263} 264 265static void bfin_lq035q1_stop_timers(void) 266{ 267 disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); 268 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); 272 273} 274 275static void bfin_lq035q1_init_timers(void) 276{ 277 278 bfin_lq035q1_stop_timers(); 279 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| 284 TIMER_EMU_RUN); 285 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 | 290 TIMER_EMU_RUN); 291 292} 293 294static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) 295{ 296 297 set_dma_config(CH_PPI, 298 set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, 299 INTR_DISABLE, DIMENSION_2D, 300 DATA_SIZE_16, 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); 305 306 set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); 307 set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); 308 309} 310 311#if (CLOCKS_PER_PIX == 1) 312static 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, 318 P_PPI0_D15, 0}; 319#else 320static 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}; 324#endif 325 326static inline void bfin_lq035q1_free_ports(void) 327{ 328 peripheral_free_list(ppi0_req_16); 329 if (ANOMALY_05000400) 330 gpio_free(P_IDENT(P_PPI0_FS3)); 331} 332 333static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) 334{ 335 /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: 336 * Drive PPI_FS3 Low 337 */ 338 if (ANOMALY_05000400) { 339 int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); 340 if (ret) 341 return ret; 342 gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); 343 } 344 345 if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { 346 dev_err(&pdev->dev, "requesting peripherals failed\n"); 347 return -EFAULT; 348 } 349 350 return 0; 351} 352 353static int bfin_lq035q1_fb_open(struct fb_info *info, int user) 354{ 355 struct bfin_lq035q1fb_info *fbi = info->par; 356 357 spin_lock(&fbi->lock); 358 fbi->lq035_open_cnt++; 359 360 if (fbi->lq035_open_cnt <= 1) { 361 362 bfin_lq035q1_disable_ppi(); 363 SSYNC(); 364 365 bfin_lq035q1_config_dma(fbi); 366 bfin_lq035q1_config_ppi(fbi); 367 bfin_lq035q1_init_timers(); 368 369 /* start dma */ 370 enable_dma(CH_PPI); 371 bfin_lq035q1_enable_ppi(); 372 bfin_lq035q1_start_timers(); 373 lq035q1_backlight(fbi, 1); 374 } 375 376 spin_unlock(&fbi->lock); 377 378 return 0; 379} 380 381static int bfin_lq035q1_fb_release(struct fb_info *info, int user) 382{ 383 struct bfin_lq035q1fb_info *fbi = info->par; 384 385 spin_lock(&fbi->lock); 386 387 fbi->lq035_open_cnt--; 388 389 if (fbi->lq035_open_cnt <= 0) { 390 lq035q1_backlight(fbi, 0); 391 bfin_lq035q1_disable_ppi(); 392 SSYNC(); 393 disable_dma(CH_PPI); 394 bfin_lq035q1_stop_timers(); 395 } 396 397 spin_unlock(&fbi->lock); 398 399 return 0; 400} 401 402static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, 403 struct fb_info *info) 404{ 405 switch (var->bits_per_pixel) { 406#if (LCD_BPP == 24) 407 case 24:/* TRUECOLOUR, 16m */ 408#else 409 case 16:/* DIRECTCOLOUR, 64k */ 410#endif 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; 423 break; 424 default: 425 pr_debug("%s: depth not supported: %u BPP\n", __func__, 426 var->bits_per_pixel); 427 return -EINVAL; 428 } 429 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); 435 return -EINVAL; 436 } 437 438 /* 439 * Memory limit 440 */ 441 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); 445 return -ENOMEM; 446 } 447 448 449 return 0; 450} 451 452int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) 453{ 454 if (nocursor) 455 return 0; 456 else 457 return -EINVAL; /* just to force soft_cursor() call */ 458} 459 460static 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) 463{ 464 if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) 465 return -EINVAL; 466 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; 470 } 471 472 if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 473 474 u32 value; 475 /* Place color in the pseudopalette */ 476 if (regno > 16) 477 return -EINVAL; 478 479 red >>= (16 - info->var.red.length); 480 green >>= (16 - info->var.green.length); 481 blue >>= (16 - info->var.blue.length); 482 483 value = (red << info->var.red.offset) | 484 (green << info->var.green.offset) | 485 (blue << info->var.blue.offset); 486 value &= 0xFFFFFF; 487 488 ((u32 *) (info->pseudo_palette))[regno] = value; 489 490 } 491 492 return 0; 493} 494 495static 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, 505}; 506 507static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) 508{ 509 /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ 510 511 u16 status = bfin_read_PPI_STATUS(); 512 bfin_write_PPI_STATUS(-1); 513 514 if (status) { 515 bfin_lq035q1_disable_ppi(); 516 disable_dma(CH_PPI); 517 518 /* start dma */ 519 enable_dma(CH_PPI); 520 bfin_lq035q1_enable_ppi(); 521 bfin_write_PPI_STATUS(-1); 522 } 523 524 return IRQ_HANDLED; 525} 526 527static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) 528{ 529 struct bfin_lq035q1fb_info *info; 530 struct fb_info *fbinfo; 531 int ret; 532 533 ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); 534 if (ret < 0) { 535 dev_err(&pdev->dev, "PPI DMA unavailable\n"); 536 goto out1; 537 } 538 539 fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev); 540 if (!fbinfo) { 541 ret = -ENOMEM; 542 goto out2; 543 } 544 545 info = fbinfo->par; 546 info->fb = fbinfo; 547 info->dev = &pdev->dev; 548 549 info->disp_info = pdev->dev.platform_data; 550 551 platform_set_drvdata(pdev, fbinfo); 552 553 strcpy(fbinfo->fix.id, DRIVER_NAME); 554 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; 562 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; 569 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; 575 576 if (info->disp_info->mode & LQ035_BGR) { 577#if (LCD_BPP == 24) 578 fbinfo->var.red.offset = 0; 579 fbinfo->var.green.offset = 8; 580 fbinfo->var.blue.offset = 16; 581#else 582 fbinfo->var.red.offset = 0; 583 fbinfo->var.green.offset = 5; 584 fbinfo->var.blue.offset = 11; 585#endif 586 } else { 587#if (LCD_BPP == 24) 588 fbinfo->var.red.offset = 16; 589 fbinfo->var.green.offset = 8; 590 fbinfo->var.blue.offset = 0; 591#else 592 fbinfo->var.red.offset = 11; 593 fbinfo->var.green.offset = 5; 594 fbinfo->var.blue.offset = 0; 595#endif 596 } 597 598 fbinfo->var.transp.offset = 0; 599 600#if (LCD_BPP == 24) 601 fbinfo->var.red.length = 8; 602 fbinfo->var.green.length = 8; 603 fbinfo->var.blue.length = 8; 604#else 605 fbinfo->var.red.length = 5; 606 fbinfo->var.green.length = 6; 607 fbinfo->var.blue.length = 5; 608#endif 609 610 fbinfo->var.transp.length = 0; 611 612 fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 613 + ACTIVE_VIDEO_MEM_OFFSET; 614 615 fbinfo->fix.line_length = fbinfo->var.xres_virtual * 616 fbinfo->var.bits_per_pixel / 8; 617 618 619 fbinfo->fbops = &bfin_lq035q1_fb_ops; 620 fbinfo->flags = FBINFO_FLAG_DEFAULT; 621 622 info->fb_buffer = 623 dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, 624 GFP_KERNEL); 625 626 if (NULL == info->fb_buffer) { 627 dev_err(&pdev->dev, "couldn't allocate dma buffer\n"); 628 ret = -ENOMEM; 629 goto out3; 630 } 631 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; 634 635 fbinfo->fbops = &bfin_lq035q1_fb_ops; 636 637 fbinfo->pseudo_palette = &info->pseudo_pal; 638 639 ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); 640 if (ret < 0) { 641 dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n", 642 BFIN_LCD_NBR_PALETTE_ENTRIES); 643 goto out4; 644 } 645 646 ret = bfin_lq035q1_request_ports(pdev); 647 if (ret) { 648 dev_err(&pdev->dev, "couldn't request gpio port\n"); 649 goto out6; 650 } 651 652 info->irq = platform_get_irq(pdev, 0); 653 if (info->irq < 0) { 654 ret = -EINVAL; 655 goto out7; 656 } 657 658 ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, 659 DRIVER_NAME" PPI ERROR", info); 660 if (ret < 0) { 661 dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n"); 662 goto out7; 663 } 664 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; 671 672 ret = spi_register_driver(&info->spidrv); 673 if (ret < 0) { 674 dev_err(&pdev->dev, "couldn't register SPI Interface\n"); 675 goto out8; 676 } 677 678 if (info->disp_info->use_bl) { 679 ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); 680 681 if (ret) { 682 dev_err(&pdev->dev, "failed to request GPIO %d\n", 683 info->disp_info->gpio_bl); 684 goto out9; 685 } 686 gpio_direction_output(info->disp_info->gpio_bl, 0); 687 } 688 689 ret = register_framebuffer(fbinfo); 690 if (ret < 0) { 691 dev_err(&pdev->dev, "unable to register framebuffer\n"); 692 goto out10; 693 } 694 695 dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", 696 LCD_X_RES, LCD_Y_RES, LCD_BPP); 697 698 return 0; 699 700 out10: 701 if (info->disp_info->use_bl) 702 gpio_free(info->disp_info->gpio_bl); 703 out9: 704 spi_unregister_driver(&info->spidrv); 705 out8: 706 free_irq(info->irq, info); 707 out7: 708 bfin_lq035q1_free_ports(); 709 out6: 710 fb_dealloc_cmap(&fbinfo->cmap); 711 out4: 712 dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, 713 info->dma_handle); 714 out3: 715 framebuffer_release(fbinfo); 716 out2: 717 free_dma(CH_PPI); 718 out1: 719 platform_set_drvdata(pdev, NULL); 720 721 return ret; 722} 723 724static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) 725{ 726 struct fb_info *fbinfo = platform_get_drvdata(pdev); 727 struct bfin_lq035q1fb_info *info = fbinfo->par; 728 729 if (info->disp_info->use_bl) 730 gpio_free(info->disp_info->gpio_bl); 731 732 spi_unregister_driver(&info->spidrv); 733 734 unregister_framebuffer(fbinfo); 735 736 free_dma(CH_PPI); 737 free_irq(info->irq, info); 738 739 if (info->fb_buffer != NULL) 740 dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, 741 info->dma_handle); 742 743 fb_dealloc_cmap(&fbinfo->cmap); 744 745 bfin_lq035q1_free_ports(); 746 747 platform_set_drvdata(pdev, NULL); 748 framebuffer_release(fbinfo); 749 750 dev_info(&pdev->dev, "unregistered LCD driver\n"); 751 752 return 0; 753} 754 755#ifdef CONFIG_PM 756static int bfin_lq035q1_suspend(struct device *dev) 757{ 758 struct fb_info *fbinfo = dev_get_drvdata(dev); 759 struct bfin_lq035q1fb_info *info = fbinfo->par; 760 761 if (info->lq035_open_cnt) { 762 lq035q1_backlight(info, 0); 763 bfin_lq035q1_disable_ppi(); 764 SSYNC(); 765 disable_dma(CH_PPI); 766 bfin_lq035q1_stop_timers(); 767 bfin_write_PPI_STATUS(-1); 768 } 769 770 return 0; 771} 772 773static int bfin_lq035q1_resume(struct device *dev) 774{ 775 struct fb_info *fbinfo = dev_get_drvdata(dev); 776 struct bfin_lq035q1fb_info *info = fbinfo->par; 777 778 if (info->lq035_open_cnt) { 779 bfin_lq035q1_disable_ppi(); 780 SSYNC(); 781 782 bfin_lq035q1_config_dma(info); 783 bfin_lq035q1_config_ppi(info); 784 bfin_lq035q1_init_timers(); 785 786 /* start dma */ 787 enable_dma(CH_PPI); 788 bfin_lq035q1_enable_ppi(); 789 bfin_lq035q1_start_timers(); 790 lq035q1_backlight(info, 1); 791 } 792 793 return 0; 794} 795 796static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = { 797 .suspend = bfin_lq035q1_suspend, 798 .resume = bfin_lq035q1_resume, 799}; 800#endif 801 802static struct platform_driver bfin_lq035q1_driver = { 803 .probe = bfin_lq035q1_probe, 804 .remove = __devexit_p(bfin_lq035q1_remove), 805 .driver = { 806 .name = DRIVER_NAME, 807#ifdef CONFIG_PM 808 .pm = &bfin_lq035q1_dev_pm_ops, 809#endif 810 }, 811}; 812 813static int __init bfin_lq035q1_driver_init(void) 814{ 815 return platform_driver_register(&bfin_lq035q1_driver); 816} 817module_init(bfin_lq035q1_driver_init); 818 819static void __exit bfin_lq035q1_driver_cleanup(void) 820{ 821 platform_driver_unregister(&bfin_lq035q1_driver); 822} 823module_exit(bfin_lq035q1_driver_cleanup); 824 825MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); 826MODULE_LICENSE("GPL");