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 v3.0-rc1 775 lines 21 kB view raw
1/* 2 * BRIEF MODULE DESCRIPTION 3 * Au1100 LCD Driver. 4 * 5 * Rewritten for 2.6 by Embedded Alley Solutions 6 * <source@embeddedalley.com>, based on submissions by 7 * Karl Lessard <klessard@sunrisetelecom.com> 8 * <c.pellegrin@exadron.com> 9 * 10 * PM support added by Rodolfo Giometti <giometti@linux.it> 11 * Cursor enable/disable by Rodolfo Giometti <giometti@linux.it> 12 * 13 * Copyright 2002 MontaVista Software 14 * Author: MontaVista Software, Inc. 15 * ppopov@mvista.com or source@mvista.com 16 * 17 * Copyright 2002 Alchemy Semiconductor 18 * Author: Alchemy Semiconductor 19 * 20 * Based on: 21 * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device 22 * Created 28 Dec 1997 by Geert Uytterhoeven 23 * 24 * This program is free software; you can redistribute it and/or modify it 25 * under the terms of the GNU General Public License as published by the 26 * Free Software Foundation; either version 2 of the License, or (at your 27 * option) any later version. 28 * 29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 30 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 31 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 32 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 36 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * You should have received a copy of the GNU General Public License along 41 * with this program; if not, write to the Free Software Foundation, Inc., 42 * 675 Mass Ave, Cambridge, MA 02139, USA. 43 */ 44#include <linux/module.h> 45#include <linux/kernel.h> 46#include <linux/errno.h> 47#include <linux/string.h> 48#include <linux/mm.h> 49#include <linux/fb.h> 50#include <linux/init.h> 51#include <linux/interrupt.h> 52#include <linux/ctype.h> 53#include <linux/dma-mapping.h> 54#include <linux/platform_device.h> 55#include <linux/slab.h> 56 57#include <asm/mach-au1x00/au1000.h> 58 59#define DEBUG 0 60 61#include "au1100fb.h" 62 63/* 64 * Sanity check. If this is a new Au1100 based board, search for 65 * the PB1100 ifdefs to make sure you modify the code accordingly. 66 */ 67#if defined(CONFIG_MIPS_PB1100) 68 #include <asm/mach-pb1x00/pb1100.h> 69#elif defined(CONFIG_MIPS_DB1100) 70 #include <asm/mach-db1x00/db1x00.h> 71#else 72 #error "Unknown Au1100 board, Au1100 FB driver not supported" 73#endif 74 75#define DRIVER_NAME "au1100fb" 76#define DRIVER_DESC "LCD controller driver for AU1100 processors" 77 78#define to_au1100fb_device(_info) \ 79 (_info ? container_of(_info, struct au1100fb_device, info) : NULL); 80 81/* Bitfields format supported by the controller. Note that the order of formats 82 * SHOULD be the same as in the LCD_CONTROL_SBPPF field, so we can retrieve the 83 * right pixel format by doing rgb_bitfields[LCD_CONTROL_SBPPF_XXX >> LCD_CONTROL_SBPPF] 84 */ 85struct fb_bitfield rgb_bitfields[][4] = 86{ 87 /* Red, Green, Blue, Transp */ 88 { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, 89 { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, 90 { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } }, 91 { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } }, 92 { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } }, 93 94 /* The last is used to describe 12bpp format */ 95 { { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } }, 96}; 97 98static struct fb_fix_screeninfo au1100fb_fix __devinitdata = { 99 .id = "AU1100 FB", 100 .xpanstep = 1, 101 .ypanstep = 1, 102 .type = FB_TYPE_PACKED_PIXELS, 103 .accel = FB_ACCEL_NONE, 104}; 105 106static struct fb_var_screeninfo au1100fb_var __devinitdata = { 107 .activate = FB_ACTIVATE_NOW, 108 .height = -1, 109 .width = -1, 110 .vmode = FB_VMODE_NONINTERLACED, 111}; 112 113static struct au1100fb_drv_info drv_info; 114 115static int nocursor = 0; 116module_param(nocursor, int, 0644); 117MODULE_PARM_DESC(nocursor, "cursor enable/disable"); 118 119/* fb_blank 120 * Blank the screen. Depending on the mode, the screen will be 121 * activated with the backlight color, or desactivated 122 */ 123static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi) 124{ 125 struct au1100fb_device *fbdev = to_au1100fb_device(fbi); 126 127 print_dbg("fb_blank %d %p", blank_mode, fbi); 128 129 switch (blank_mode) { 130 131 case VESA_NO_BLANKING: 132 /* Turn on panel */ 133 fbdev->regs->lcd_control |= LCD_CONTROL_GO; 134#ifdef CONFIG_MIPS_PB1100 135 if (drv_info.panel_idx == 1) { 136 au_writew(au_readw(PB1100_G_CONTROL) 137 | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD), 138 PB1100_G_CONTROL); 139 } 140#endif 141 au_sync(); 142 break; 143 144 case VESA_VSYNC_SUSPEND: 145 case VESA_HSYNC_SUSPEND: 146 case VESA_POWERDOWN: 147 /* Turn off panel */ 148 fbdev->regs->lcd_control &= ~LCD_CONTROL_GO; 149#ifdef CONFIG_MIPS_PB1100 150 if (drv_info.panel_idx == 1) { 151 au_writew(au_readw(PB1100_G_CONTROL) 152 & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD), 153 PB1100_G_CONTROL); 154 } 155#endif 156 au_sync(); 157 break; 158 default: 159 break; 160 161 } 162 return 0; 163} 164 165/* 166 * Set hardware with var settings. This will enable the controller with a specific 167 * mode, normally validated with the fb_check_var method 168 */ 169int au1100fb_setmode(struct au1100fb_device *fbdev) 170{ 171 struct fb_info *info = &fbdev->info; 172 u32 words; 173 int index; 174 175 if (!fbdev) 176 return -EINVAL; 177 178 /* Update var-dependent FB info */ 179 if (panel_is_active(fbdev->panel) || panel_is_color(fbdev->panel)) { 180 if (info->var.bits_per_pixel <= 8) { 181 /* palettized */ 182 info->var.red.offset = 0; 183 info->var.red.length = info->var.bits_per_pixel; 184 info->var.red.msb_right = 0; 185 186 info->var.green.offset = 0; 187 info->var.green.length = info->var.bits_per_pixel; 188 info->var.green.msb_right = 0; 189 190 info->var.blue.offset = 0; 191 info->var.blue.length = info->var.bits_per_pixel; 192 info->var.blue.msb_right = 0; 193 194 info->var.transp.offset = 0; 195 info->var.transp.length = 0; 196 info->var.transp.msb_right = 0; 197 198 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 199 info->fix.line_length = info->var.xres_virtual / 200 (8/info->var.bits_per_pixel); 201 } else { 202 /* non-palettized */ 203 index = (fbdev->panel->control_base & LCD_CONTROL_SBPPF_MASK) >> LCD_CONTROL_SBPPF_BIT; 204 info->var.red = rgb_bitfields[index][0]; 205 info->var.green = rgb_bitfields[index][1]; 206 info->var.blue = rgb_bitfields[index][2]; 207 info->var.transp = rgb_bitfields[index][3]; 208 209 info->fix.visual = FB_VISUAL_TRUECOLOR; 210 info->fix.line_length = info->var.xres_virtual << 1; /* depth=16 */ 211 } 212 } else { 213 /* mono */ 214 info->fix.visual = FB_VISUAL_MONO10; 215 info->fix.line_length = info->var.xres_virtual / 8; 216 } 217 218 info->screen_size = info->fix.line_length * info->var.yres_virtual; 219 info->var.rotate = ((fbdev->panel->control_base&LCD_CONTROL_SM_MASK) \ 220 >> LCD_CONTROL_SM_BIT) * 90; 221 222 /* Determine BPP mode and format */ 223 fbdev->regs->lcd_control = fbdev->panel->control_base; 224 fbdev->regs->lcd_horztiming = fbdev->panel->horztiming; 225 fbdev->regs->lcd_verttiming = fbdev->panel->verttiming; 226 fbdev->regs->lcd_clkcontrol = fbdev->panel->clkcontrol_base; 227 fbdev->regs->lcd_intenable = 0; 228 fbdev->regs->lcd_intstatus = 0; 229 fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(fbdev->fb_phys); 230 231 if (panel_is_dual(fbdev->panel)) { 232 /* Second panel display seconf half of screen if possible, 233 * otherwise display the same as the first panel */ 234 if (info->var.yres_virtual >= (info->var.yres << 1)) { 235 fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys + 236 (info->fix.line_length * 237 (info->var.yres_virtual >> 1))); 238 } else { 239 fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys); 240 } 241 } 242 243 words = info->fix.line_length / sizeof(u32); 244 if (!info->var.rotate || (info->var.rotate == 180)) { 245 words *= info->var.yres_virtual; 246 if (info->var.rotate /* 180 */) { 247 words -= (words % 8); /* should be divisable by 8 */ 248 } 249 } 250 fbdev->regs->lcd_words = LCD_WRD_WRDS_N(words); 251 252 fbdev->regs->lcd_pwmdiv = 0; 253 fbdev->regs->lcd_pwmhi = 0; 254 255 /* Resume controller */ 256 fbdev->regs->lcd_control |= LCD_CONTROL_GO; 257 mdelay(10); 258 au1100fb_fb_blank(VESA_NO_BLANKING, info); 259 260 return 0; 261} 262 263/* fb_setcolreg 264 * Set color in LCD palette. 265 */ 266int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi) 267{ 268 struct au1100fb_device *fbdev; 269 u32 *palette; 270 u32 value; 271 272 fbdev = to_au1100fb_device(fbi); 273 palette = fbdev->regs->lcd_pallettebase; 274 275 if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1)) 276 return -EINVAL; 277 278 if (fbi->var.grayscale) { 279 /* Convert color to grayscale */ 280 red = green = blue = 281 (19595 * red + 38470 * green + 7471 * blue) >> 16; 282 } 283 284 if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { 285 /* Place color in the pseudopalette */ 286 if (regno > 16) 287 return -EINVAL; 288 289 palette = (u32*)fbi->pseudo_palette; 290 291 red >>= (16 - fbi->var.red.length); 292 green >>= (16 - fbi->var.green.length); 293 blue >>= (16 - fbi->var.blue.length); 294 295 value = (red << fbi->var.red.offset) | 296 (green << fbi->var.green.offset)| 297 (blue << fbi->var.blue.offset); 298 value &= 0xFFFF; 299 300 } else if (panel_is_active(fbdev->panel)) { 301 /* COLOR TFT PALLETTIZED (use RGB 565) */ 302 value = (red & 0xF800)|((green >> 5) & 0x07E0)|((blue >> 11) & 0x001F); 303 value &= 0xFFFF; 304 305 } else if (panel_is_color(fbdev->panel)) { 306 /* COLOR STN MODE */ 307 value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) | 308 ((green >> 8) & 0x00F0) | 309 (((panel_swap_rgb(fbdev->panel) ? red : blue) >> 4) & 0x0F00); 310 value &= 0xFFF; 311 } else { 312 /* MONOCHROME MODE */ 313 value = (green >> 12) & 0x000F; 314 value &= 0xF; 315 } 316 317 palette[regno] = value; 318 319 return 0; 320} 321 322/* fb_pan_display 323 * Pan display in x and/or y as specified 324 */ 325int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) 326{ 327 struct au1100fb_device *fbdev; 328 int dy; 329 330 fbdev = to_au1100fb_device(fbi); 331 332 print_dbg("fb_pan_display %p %p", var, fbi); 333 334 if (!var || !fbdev) { 335 return -EINVAL; 336 } 337 338 if (var->xoffset - fbi->var.xoffset) { 339 /* No support for X panning for now! */ 340 return -EINVAL; 341 } 342 343 print_dbg("fb_pan_display 2 %p %p", var, fbi); 344 dy = var->yoffset - fbi->var.yoffset; 345 if (dy) { 346 347 u32 dmaaddr; 348 349 print_dbg("Panning screen of %d lines", dy); 350 351 dmaaddr = fbdev->regs->lcd_dmaaddr0; 352 dmaaddr += (fbi->fix.line_length * dy); 353 354 /* TODO: Wait for current frame to finished */ 355 fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr); 356 357 if (panel_is_dual(fbdev->panel)) { 358 dmaaddr = fbdev->regs->lcd_dmaaddr1; 359 dmaaddr += (fbi->fix.line_length * dy); 360 fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr); 361 } 362 } 363 print_dbg("fb_pan_display 3 %p %p", var, fbi); 364 365 return 0; 366} 367 368/* fb_rotate 369 * Rotate the display of this angle. This doesn't seems to be used by the core, 370 * but as our hardware supports it, so why not implementing it... 371 */ 372void au1100fb_fb_rotate(struct fb_info *fbi, int angle) 373{ 374 struct au1100fb_device *fbdev = to_au1100fb_device(fbi); 375 376 print_dbg("fb_rotate %p %d", fbi, angle); 377 378 if (fbdev && (angle > 0) && !(angle % 90)) { 379 380 fbdev->regs->lcd_control &= ~LCD_CONTROL_GO; 381 382 fbdev->regs->lcd_control &= ~(LCD_CONTROL_SM_MASK); 383 fbdev->regs->lcd_control |= ((angle/90) << LCD_CONTROL_SM_BIT); 384 385 fbdev->regs->lcd_control |= LCD_CONTROL_GO; 386 } 387} 388 389/* fb_mmap 390 * Map video memory in user space. We don't use the generic fb_mmap method mainly 391 * to allow the use of the TLB streaming flag (CCA=6) 392 */ 393int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) 394{ 395 struct au1100fb_device *fbdev; 396 unsigned int len; 397 unsigned long start=0, off; 398 399 fbdev = to_au1100fb_device(fbi); 400 401 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { 402 return -EINVAL; 403 } 404 405 start = fbdev->fb_phys & PAGE_MASK; 406 len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); 407 408 off = vma->vm_pgoff << PAGE_SHIFT; 409 410 if ((vma->vm_end - vma->vm_start + off) > len) { 411 return -EINVAL; 412 } 413 414 off += start; 415 vma->vm_pgoff = off >> PAGE_SHIFT; 416 417 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 418 pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6 419 420 vma->vm_flags |= VM_IO; 421 422 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, 423 vma->vm_end - vma->vm_start, 424 vma->vm_page_prot)) { 425 return -EAGAIN; 426 } 427 428 return 0; 429} 430 431/* fb_cursor 432 * Used to disable cursor drawing... 433 */ 434int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) 435{ 436 if (nocursor) 437 return 0; 438 else 439 return -EINVAL; /* just to force soft_cursor() call */ 440} 441 442static struct fb_ops au1100fb_ops = 443{ 444 .owner = THIS_MODULE, 445 .fb_setcolreg = au1100fb_fb_setcolreg, 446 .fb_blank = au1100fb_fb_blank, 447 .fb_pan_display = au1100fb_fb_pan_display, 448 .fb_fillrect = cfb_fillrect, 449 .fb_copyarea = cfb_copyarea, 450 .fb_imageblit = cfb_imageblit, 451 .fb_rotate = au1100fb_fb_rotate, 452 .fb_mmap = au1100fb_fb_mmap, 453 .fb_cursor = au1100fb_fb_cursor, 454}; 455 456 457/*-------------------------------------------------------------------------*/ 458 459/* AU1100 LCD controller device driver */ 460 461static int __devinit au1100fb_drv_probe(struct platform_device *dev) 462{ 463 struct au1100fb_device *fbdev = NULL; 464 struct resource *regs_res; 465 unsigned long page; 466 u32 sys_clksrc; 467 468 if (!dev) 469 return -EINVAL; 470 471 /* Allocate new device private */ 472 if (!(fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) { 473 print_err("fail to allocate device private record"); 474 return -ENOMEM; 475 } 476 477 fbdev->panel = &known_lcd_panels[drv_info.panel_idx]; 478 479 platform_set_drvdata(dev, (void *)fbdev); 480 481 /* Allocate region for our registers and map them */ 482 if (!(regs_res = platform_get_resource(to_platform_device(dev), 483 IORESOURCE_MEM, 0))) { 484 print_err("fail to retrieve registers resource"); 485 return -EFAULT; 486 } 487 488 au1100fb_fix.mmio_start = regs_res->start; 489 au1100fb_fix.mmio_len = regs_res->end - regs_res->start + 1; 490 491 if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len, 492 DRIVER_NAME)) { 493 print_err("fail to lock memory region at 0x%08lx", 494 au1100fb_fix.mmio_start); 495 return -EBUSY; 496 } 497 498 fbdev->regs = (struct au1100fb_regs*)KSEG1ADDR(au1100fb_fix.mmio_start); 499 500 print_dbg("Register memory map at %p", fbdev->regs); 501 print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len); 502 503 504 505 /* Allocate the framebuffer to the maximum screen size * nbr of video buffers */ 506 fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres * 507 (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS; 508 509 fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len), 510 &fbdev->fb_phys, GFP_KERNEL); 511 if (!fbdev->fb_mem) { 512 print_err("fail to allocate frambuffer (size: %dK))", 513 fbdev->fb_len / 1024); 514 return -ENOMEM; 515 } 516 517 au1100fb_fix.smem_start = fbdev->fb_phys; 518 au1100fb_fix.smem_len = fbdev->fb_len; 519 520 /* 521 * Set page reserved so that mmap will work. This is necessary 522 * since we'll be remapping normal memory. 523 */ 524 for (page = (unsigned long)fbdev->fb_mem; 525 page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len); 526 page += PAGE_SIZE) { 527#if CONFIG_DMA_NONCOHERENT 528 SetPageReserved(virt_to_page(CAC_ADDR(page))); 529#else 530 SetPageReserved(virt_to_page(page)); 531#endif 532 } 533 534 print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); 535 print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); 536 537 /* Setup LCD clock to AUX (48 MHz) */ 538 sys_clksrc = au_readl(SYS_CLKSRC) & ~(SYS_CS_ML_MASK | SYS_CS_DL | SYS_CS_CL); 539 au_writel((sys_clksrc | (1 << SYS_CS_ML_BIT)), SYS_CLKSRC); 540 541 /* load the panel info into the var struct */ 542 au1100fb_var.bits_per_pixel = fbdev->panel->bpp; 543 au1100fb_var.xres = fbdev->panel->xres; 544 au1100fb_var.xres_virtual = au1100fb_var.xres; 545 au1100fb_var.yres = fbdev->panel->yres; 546 au1100fb_var.yres_virtual = au1100fb_var.yres; 547 548 fbdev->info.screen_base = fbdev->fb_mem; 549 fbdev->info.fbops = &au1100fb_ops; 550 fbdev->info.fix = au1100fb_fix; 551 552 if (!(fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL))) { 553 return -ENOMEM; 554 } 555 556 if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { 557 print_err("Fail to allocate colormap (%d entries)", 558 AU1100_LCD_NBR_PALETTE_ENTRIES); 559 kfree(fbdev->info.pseudo_palette); 560 return -EFAULT; 561 } 562 563 fbdev->info.var = au1100fb_var; 564 565 /* Set h/w registers */ 566 au1100fb_setmode(fbdev); 567 568 /* Register new framebuffer */ 569 if (register_framebuffer(&fbdev->info) < 0) { 570 print_err("cannot register new framebuffer"); 571 goto failed; 572 } 573 574 return 0; 575 576failed: 577 if (fbdev->regs) { 578 release_mem_region(fbdev->regs_phys, fbdev->regs_len); 579 } 580 if (fbdev->fb_mem) { 581 dma_free_noncoherent(dev, fbdev->fb_len, fbdev->fb_mem, fbdev->fb_phys); 582 } 583 if (fbdev->info.cmap.len != 0) { 584 fb_dealloc_cmap(&fbdev->info.cmap); 585 } 586 kfree(fbdev); 587 platform_set_drvdata(dev, NULL); 588 589 return 0; 590} 591 592int au1100fb_drv_remove(struct platform_device *dev) 593{ 594 struct au1100fb_device *fbdev = NULL; 595 596 if (!dev) 597 return -ENODEV; 598 599 fbdev = (struct au1100fb_device *) platform_get_drvdata(dev); 600 601#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) 602 au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info); 603#endif 604 fbdev->regs->lcd_control &= ~LCD_CONTROL_GO; 605 606 /* Clean up all probe data */ 607 unregister_framebuffer(&fbdev->info); 608 609 release_mem_region(fbdev->regs_phys, fbdev->regs_len); 610 611 dma_free_coherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); 612 613 fb_dealloc_cmap(&fbdev->info.cmap); 614 kfree(fbdev->info.pseudo_palette); 615 kfree((void*)fbdev); 616 617 return 0; 618} 619 620#ifdef CONFIG_PM 621static u32 sys_clksrc; 622static struct au1100fb_regs fbregs; 623 624int au1100fb_drv_suspend(struct platform_device *dev, pm_message_t state) 625{ 626 struct au1100fb_device *fbdev = platform_get_drvdata(dev); 627 628 if (!fbdev) 629 return 0; 630 631 /* Save the clock source state */ 632 sys_clksrc = au_readl(SYS_CLKSRC); 633 634 /* Blank the LCD */ 635 au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info); 636 637 /* Stop LCD clocking */ 638 au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC); 639 640 memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs)); 641 642 return 0; 643} 644 645int au1100fb_drv_resume(struct platform_device *dev) 646{ 647 struct au1100fb_device *fbdev = platform_get_drvdata(dev); 648 649 if (!fbdev) 650 return 0; 651 652 memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs)); 653 654 /* Restart LCD clocking */ 655 au_writel(sys_clksrc, SYS_CLKSRC); 656 657 /* Unblank the LCD */ 658 au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info); 659 660 return 0; 661} 662#else 663#define au1100fb_drv_suspend NULL 664#define au1100fb_drv_resume NULL 665#endif 666 667static struct platform_driver au1100fb_driver = { 668 .driver = { 669 .name = "au1100-lcd", 670 .owner = THIS_MODULE, 671 }, 672 .probe = au1100fb_drv_probe, 673 .remove = au1100fb_drv_remove, 674 .suspend = au1100fb_drv_suspend, 675 .resume = au1100fb_drv_resume, 676}; 677 678/*-------------------------------------------------------------------------*/ 679 680/* Kernel driver */ 681 682int au1100fb_setup(char *options) 683{ 684 char* this_opt; 685 int num_panels = ARRAY_SIZE(known_lcd_panels); 686 char* mode = NULL; 687 int panel_idx = 0; 688 689 if (num_panels <= 0) { 690 print_err("No LCD panels supported by driver!"); 691 return -EFAULT; 692 } 693 694 if (options) { 695 while ((this_opt = strsep(&options,",")) != NULL) { 696 /* Panel option */ 697 if (!strncmp(this_opt, "panel:", 6)) { 698 int i; 699 this_opt += 6; 700 for (i = 0; i < num_panels; i++) { 701 if (!strncmp(this_opt, 702 known_lcd_panels[i].name, 703 strlen(this_opt))) { 704 panel_idx = i; 705 break; 706 } 707 } 708 if (i >= num_panels) { 709 print_warn("Panel %s not supported!", this_opt); 710 } 711 } 712 if (!strncmp(this_opt, "nocursor", 8)) { 713 this_opt += 8; 714 nocursor = 1; 715 print_info("Cursor disabled"); 716 } 717 /* Mode option (only option that start with digit) */ 718 else if (isdigit(this_opt[0])) { 719 mode = kstrdup(this_opt, GFP_KERNEL); 720 if (!mode) { 721 print_err("memory allocation failed"); 722 return -ENOMEM; 723 } 724 } 725 /* Unsupported option */ 726 else { 727 print_warn("Unsupported option \"%s\"", this_opt); 728 } 729 } 730 } 731 732 drv_info.panel_idx = panel_idx; 733 drv_info.opt_mode = mode; 734 735 print_info("Panel=%s Mode=%s", 736 known_lcd_panels[drv_info.panel_idx].name, 737 drv_info.opt_mode ? drv_info.opt_mode : "default"); 738 739 return 0; 740} 741 742int __init au1100fb_init(void) 743{ 744 char* options; 745 int ret; 746 747 print_info("" DRIVER_DESC ""); 748 749 memset(&drv_info, 0, sizeof(drv_info)); 750 751 if (fb_get_options(DRIVER_NAME, &options)) 752 return -ENODEV; 753 754 /* Setup driver with options */ 755 ret = au1100fb_setup(options); 756 if (ret < 0) { 757 print_err("Fail to setup driver"); 758 return ret; 759 } 760 761 return platform_driver_register(&au1100fb_driver); 762} 763 764void __exit au1100fb_cleanup(void) 765{ 766 platform_driver_unregister(&au1100fb_driver); 767 768 kfree(drv_info.opt_mode); 769} 770 771module_init(au1100fb_init); 772module_exit(au1100fb_cleanup); 773 774MODULE_DESCRIPTION(DRIVER_DESC); 775MODULE_LICENSE("GPL");