linux/drivers/video/bf54x-lq043fb.c
<<
>>
Prefs
   1/*
   2 * File:         drivers/video/bf54x-lq043.c
   3 * Based on:
   4 * Author:       Michael Hennerich <hennerich@blackfin.uclinux.org>
   5 *
   6 * Created:
   7 * Description:  ADSP-BF54x Framebufer driver
   8 *
   9 *
  10 * Modified:
  11 *               Copyright 2007-2008 Analog Devices Inc.
  12 *
  13 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  14 *
  15 * This program is free software; you can redistribute it and/or modify
  16 * it under the terms of the GNU General Public License as published by
  17 * the Free Software Foundation; either version 2 of the License, or
  18 * (at your option) any later version.
  19 *
  20 * This program is distributed in the hope that it will be useful,
  21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23 * GNU General Public License for more details.
  24 *
  25 * You should have received a copy of the GNU General Public License
  26 * along with this program; if not, see the file COPYING, or write
  27 * to the Free Software Foundation, Inc.,
  28 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  29 */
  30
  31#include <linux/module.h>
  32#include <linux/kernel.h>
  33#include <linux/errno.h>
  34#include <linux/string.h>
  35#include <linux/mm.h>
  36#include <linux/tty.h>
  37#include <linux/slab.h>
  38#include <linux/delay.h>
  39#include <linux/fb.h>
  40#include <linux/ioport.h>
  41#include <linux/init.h>
  42#include <linux/types.h>
  43#include <linux/interrupt.h>
  44#include <linux/sched.h>
  45#include <linux/timer.h>
  46#include <linux/device.h>
  47#include <linux/backlight.h>
  48#include <linux/lcd.h>
  49#include <linux/spinlock.h>
  50#include <linux/dma-mapping.h>
  51#include <linux/platform_device.h>
  52
  53#include <asm/blackfin.h>
  54#include <asm/irq.h>
  55#include <asm/dpmc.h>
  56#include <asm/dma-mapping.h>
  57#include <asm/dma.h>
  58#include <asm/gpio.h>
  59#include <asm/portmux.h>
  60
  61#include <mach/bf54x-lq043.h>
  62
  63#define NO_BL_SUPPORT
  64
  65#define DRIVER_NAME "bf54x-lq043"
  66static char driver_name[] = DRIVER_NAME;
  67
  68#define BFIN_LCD_NBR_PALETTE_ENTRIES    256
  69
  70#define EPPI0_18 {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, \
  71 P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, \
  72 P_PPI0_D11, P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, P_PPI0_D16, P_PPI0_D17, 0}
  73
  74#define EPPI0_24 {P_PPI0_D18, P_PPI0_D19, P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23, 0}
  75
  76struct bfin_bf54xfb_info {
  77        struct fb_info *fb;
  78        struct device *dev;
  79
  80        struct bfin_bf54xfb_mach_info *mach_info;
  81
  82        unsigned char *fb_buffer;       /* RGB Buffer */
  83
  84        dma_addr_t dma_handle;
  85        int lq043_mmap;
  86        int lq043_open_cnt;
  87        int irq;
  88        spinlock_t lock;        /* lock */
  89};
  90
  91static int nocursor;
  92module_param(nocursor, int, 0644);
  93MODULE_PARM_DESC(nocursor, "cursor enable/disable");
  94
  95static int outp_rgb666;
  96module_param(outp_rgb666, int, 0);
  97MODULE_PARM_DESC(outp_rgb666, "Output 18-bit RGB666");
  98
  99#define LCD_X_RES               480     /*Horizontal Resolution */
 100#define LCD_Y_RES               272     /* Vertical Resolution */
 101
 102#define LCD_BPP                 24      /* Bit Per Pixel */
 103#define DMA_BUS_SIZE            32
 104
 105/*      -- Horizontal synchronizing --
 106 *
 107 * Timing characteristics taken from the SHARP LQ043T1DG01 datasheet
 108 * (LCY-W-06602A Page 9 of 22)
 109 *
 110 * Clock Frequency      1/Tc Min 7.83 Typ 9.00 Max 9.26 MHz
 111 *
 112 * Period               TH - 525 - Clock
 113 * Pulse width          THp - 41 - Clock
 114 * Horizontal period    THd - 480 - Clock
 115 * Back porch           THb - 2 - Clock
 116 * Front porch          THf - 2 - Clock
 117 *
 118 * -- Vertical synchronizing --
 119 * Period               TV - 286 - Line
 120 * Pulse width          TVp - 10 - Line
 121 * Vertical period      TVd - 272 - Line
 122 * Back porch           TVb - 2 - Line
 123 * Front porch          TVf - 2 - Line
 124 */
 125
 126#define LCD_CLK                 (8*1000*1000)   /* 8MHz */
 127
 128/* # active data to transfer after Horizontal Delay clock */
 129#define EPPI_HCOUNT             LCD_X_RES
 130
 131/* # active lines to transfer after Vertical Delay clock */
 132#define EPPI_VCOUNT             LCD_Y_RES
 133
 134/* Samples per Line = 480 (active data) + 45 (padding) */
 135#define EPPI_LINE               525
 136
 137/* Lines per Frame = 272 (active data) + 14 (padding) */
 138#define EPPI_FRAME              286
 139
 140/* FS1 (Hsync) Width (Typical)*/
 141#define EPPI_FS1W_HBL           41
 142
 143/* FS1 (Hsync) Period (Typical) */
 144#define EPPI_FS1P_AVPL          EPPI_LINE
 145
 146/* Horizontal Delay clock after assertion of Hsync (Typical) */
 147#define EPPI_HDELAY             43
 148
 149/* FS2 (Vsync) Width    = FS1 (Hsync) Period * 10 */
 150#define EPPI_FS2W_LVB           (EPPI_LINE * 10)
 151
 152 /* FS2 (Vsync) Period   = FS1 (Hsync) Period * Lines per Frame */
 153#define EPPI_FS2P_LAVF          (EPPI_LINE * EPPI_FRAME)
 154
 155/* Vertical Delay after assertion of Vsync (2 Lines) */
 156#define EPPI_VDELAY             12
 157
 158#define EPPI_CLIP               0xFF00FF00
 159
 160/* EPPI Control register configuration value for RGB out
 161 * - EPPI as Output
 162 * GP 2 frame sync mode,
 163 * Internal Clock generation disabled, Internal FS generation enabled,
 164 * Receives samples on EPPI_CLK raising edge, Transmits samples on EPPI_CLK falling edge,
 165 * FS1 & FS2 are active high,
 166 * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out)
 167 * DMA Unpacking disabled when RGB Formating is enabled, otherwise DMA unpacking enabled
 168 * Swapping Enabled,
 169 * One (DMA) Channel Mode,
 170 * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output
 171 * Regular watermark - when FIFO is 100% full,
 172 * Urgent watermark - when FIFO is 75% full
 173 */
 174
 175#define EPPI_CONTROL            (0x20136E2E | SWAPEN)
 176
 177static inline u16 get_eppi_clkdiv(u32 target_ppi_clk)
 178{
 179        u32 sclk = get_sclk();
 180
 181        /* EPPI_CLK = (SCLK) / (2 * (EPPI_CLKDIV[15:0] + 1)) */
 182
 183        return (((sclk / target_ppi_clk) / 2) - 1);
 184}
 185
 186static void config_ppi(struct bfin_bf54xfb_info *fbi)
 187{
 188
 189        u16 eppi_clkdiv = get_eppi_clkdiv(LCD_CLK);
 190
 191        bfin_write_EPPI0_FS1W_HBL(EPPI_FS1W_HBL);
 192        bfin_write_EPPI0_FS1P_AVPL(EPPI_FS1P_AVPL);
 193        bfin_write_EPPI0_FS2W_LVB(EPPI_FS2W_LVB);
 194        bfin_write_EPPI0_FS2P_LAVF(EPPI_FS2P_LAVF);
 195        bfin_write_EPPI0_CLIP(EPPI_CLIP);
 196
 197        bfin_write_EPPI0_FRAME(EPPI_FRAME);
 198        bfin_write_EPPI0_LINE(EPPI_LINE);
 199
 200        bfin_write_EPPI0_HCOUNT(EPPI_HCOUNT);
 201        bfin_write_EPPI0_HDELAY(EPPI_HDELAY);
 202        bfin_write_EPPI0_VCOUNT(EPPI_VCOUNT);
 203        bfin_write_EPPI0_VDELAY(EPPI_VDELAY);
 204
 205        bfin_write_EPPI0_CLKDIV(eppi_clkdiv);
 206
 207/*
 208 * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out)
 209 * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output
 210 */
 211        if (outp_rgb666)
 212                bfin_write_EPPI0_CONTROL((EPPI_CONTROL & ~DLENGTH) | DLEN_18 |
 213                                         RGB_FMT_EN);
 214        else
 215                bfin_write_EPPI0_CONTROL(((EPPI_CONTROL & ~DLENGTH) | DLEN_24) &
 216                                         ~RGB_FMT_EN);
 217
 218
 219}
 220
 221static int config_dma(struct bfin_bf54xfb_info *fbi)
 222{
 223
 224        set_dma_config(CH_EPPI0,
 225                       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
 226                                           INTR_DISABLE, DIMENSION_2D,
 227                                           DATA_SIZE_32,
 228                                           DMA_NOSYNC_KEEP_DMA_BUF));
 229        set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
 230        set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
 231        set_dma_y_count(CH_EPPI0, LCD_Y_RES);
 232        set_dma_y_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
 233        set_dma_start_addr(CH_EPPI0, (unsigned long)fbi->fb_buffer);
 234
 235        return 0;
 236}
 237
 238static int request_ports(struct bfin_bf54xfb_info *fbi)
 239{
 240
 241        u16 eppi_req_18[] = EPPI0_18;
 242        u16 disp = fbi->mach_info->disp;
 243
 244        if (gpio_request(disp, DRIVER_NAME)) {
 245                printk(KERN_ERR "Requesting GPIO %d faild\n", disp);
 246                return -EFAULT;
 247        }
 248
 249        if (peripheral_request_list(eppi_req_18, DRIVER_NAME)) {
 250                printk(KERN_ERR "Requesting Peripherals faild\n");
 251                gpio_free(disp);
 252                return -EFAULT;
 253        }
 254
 255        if (!outp_rgb666) {
 256
 257                u16 eppi_req_24[] = EPPI0_24;
 258
 259                if (peripheral_request_list(eppi_req_24, DRIVER_NAME)) {
 260                        printk(KERN_ERR "Requesting Peripherals faild\n");
 261                        peripheral_free_list(eppi_req_18);
 262                        gpio_free(disp);
 263                        return -EFAULT;
 264                }
 265        }
 266
 267        gpio_direction_output(disp, 1);
 268
 269        return 0;
 270}
 271
 272static void free_ports(struct bfin_bf54xfb_info *fbi)
 273{
 274
 275        u16 eppi_req_18[] = EPPI0_18;
 276
 277        gpio_free(fbi->mach_info->disp);
 278
 279        peripheral_free_list(eppi_req_18);
 280
 281        if (!outp_rgb666) {
 282                u16 eppi_req_24[] = EPPI0_24;
 283                peripheral_free_list(eppi_req_24);
 284        }
 285}
 286
 287static int bfin_bf54x_fb_open(struct fb_info *info, int user)
 288{
 289        struct bfin_bf54xfb_info *fbi = info->par;
 290
 291        spin_lock(&fbi->lock);
 292        fbi->lq043_open_cnt++;
 293
 294        if (fbi->lq043_open_cnt <= 1) {
 295
 296                bfin_write_EPPI0_CONTROL(0);
 297                SSYNC();
 298
 299                config_dma(fbi);
 300                config_ppi(fbi);
 301
 302                /* start dma */
 303                enable_dma(CH_EPPI0);
 304                bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN);
 305        }
 306
 307        spin_unlock(&fbi->lock);
 308
 309        return 0;
 310}
 311
 312static int bfin_bf54x_fb_release(struct fb_info *info, int user)
 313{
 314        struct bfin_bf54xfb_info *fbi = info->par;
 315
 316        spin_lock(&fbi->lock);
 317
 318        fbi->lq043_open_cnt--;
 319        fbi->lq043_mmap = 0;
 320
 321        if (fbi->lq043_open_cnt <= 0) {
 322
 323                bfin_write_EPPI0_CONTROL(0);
 324                SSYNC();
 325                disable_dma(CH_EPPI0);
 326        }
 327
 328        spin_unlock(&fbi->lock);
 329
 330        return 0;
 331}
 332
 333static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
 334                                   struct fb_info *info)
 335{
 336
 337        switch (var->bits_per_pixel) {
 338        case 24:/* TRUECOLOUR, 16m */
 339                var->red.offset = 16;
 340                var->green.offset = 8;
 341                var->blue.offset = 0;
 342                var->red.length = var->green.length = var->blue.length = 8;
 343                var->transp.offset = 0;
 344                var->transp.length = 0;
 345                var->transp.msb_right = 0;
 346                var->red.msb_right = 0;
 347                var->green.msb_right = 0;
 348                var->blue.msb_right = 0;
 349                break;
 350        default:
 351                pr_debug("%s: depth not supported: %u BPP\n", __func__,
 352                         var->bits_per_pixel);
 353                return -EINVAL;
 354        }
 355
 356        if (info->var.xres != var->xres || info->var.yres != var->yres ||
 357            info->var.xres_virtual != var->xres_virtual ||
 358            info->var.yres_virtual != var->yres_virtual) {
 359                pr_debug("%s: Resolution not supported: X%u x Y%u \n",
 360                         __func__, var->xres, var->yres);
 361                return -EINVAL;
 362        }
 363
 364        /*
 365         *  Memory limit
 366         */
 367
 368        if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
 369                pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
 370                         __func__, var->yres_virtual);
 371                return -ENOMEM;
 372        }
 373
 374        return 0;
 375}
 376
 377static int bfin_bf54x_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 378{
 379
 380        struct bfin_bf54xfb_info *fbi = info->par;
 381
 382        if (fbi->lq043_mmap)
 383                return -1;
 384
 385        spin_lock(&fbi->lock);
 386        fbi->lq043_mmap = 1;
 387        spin_unlock(&fbi->lock);
 388
 389        vma->vm_start = (unsigned long)(fbi->fb_buffer);
 390
 391        vma->vm_end = vma->vm_start + info->fix.smem_len;
 392        /* For those who don't understand how mmap works, go read
 393         *   Documentation/nommu-mmap.txt.
 394         * For those that do, you will know that the VM_MAYSHARE flag
 395         * must be set in the vma->vm_flags structure on noMMU
 396         *   Other flags can be set, and are documented in
 397         *   include/linux/mm.h
 398         */
 399        vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
 400
 401        return 0;
 402}
 403
 404int bfin_bf54x_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 405{
 406        if (nocursor)
 407                return 0;
 408        else
 409                return -EINVAL; /* just to force soft_cursor() call */
 410}
 411
 412static int bfin_bf54x_fb_setcolreg(u_int regno, u_int red, u_int green,
 413                                   u_int blue, u_int transp,
 414                                   struct fb_info *info)
 415{
 416        if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES)
 417                return -EINVAL;
 418
 419        if (info->var.grayscale) {
 420                /* grayscale = 0.30*R + 0.59*G + 0.11*B */
 421                red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
 422        }
 423
 424        if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
 425
 426                u32 value;
 427                /* Place color in the pseudopalette */
 428                if (regno > 16)
 429                        return -EINVAL;
 430
 431                red >>= (16 - info->var.red.length);
 432                green >>= (16 - info->var.green.length);
 433                blue >>= (16 - info->var.blue.length);
 434
 435                value = (red << info->var.red.offset) |
 436                    (green << info->var.green.offset) |
 437                    (blue << info->var.blue.offset);
 438                value &= 0xFFFFFF;
 439
 440                ((u32 *) (info->pseudo_palette))[regno] = value;
 441
 442        }
 443
 444        return 0;
 445}
 446
 447static struct fb_ops bfin_bf54x_fb_ops = {
 448        .owner = THIS_MODULE,
 449        .fb_open = bfin_bf54x_fb_open,
 450        .fb_release = bfin_bf54x_fb_release,
 451        .fb_check_var = bfin_bf54x_fb_check_var,
 452        .fb_fillrect = cfb_fillrect,
 453        .fb_copyarea = cfb_copyarea,
 454        .fb_imageblit = cfb_imageblit,
 455        .fb_mmap = bfin_bf54x_fb_mmap,
 456        .fb_cursor = bfin_bf54x_fb_cursor,
 457        .fb_setcolreg = bfin_bf54x_fb_setcolreg,
 458};
 459
 460#ifndef NO_BL_SUPPORT
 461static int bl_get_brightness(struct backlight_device *bd)
 462{
 463        return 0;
 464}
 465
 466static struct backlight_ops bfin_lq043fb_bl_ops = {
 467        .get_brightness = bl_get_brightness,
 468};
 469
 470static struct backlight_device *bl_dev;
 471
 472static int bfin_lcd_get_power(struct lcd_device *dev)
 473{
 474        return 0;
 475}
 476
 477static int bfin_lcd_set_power(struct lcd_device *dev, int power)
 478{
 479        return 0;
 480}
 481
 482static int bfin_lcd_get_contrast(struct lcd_device *dev)
 483{
 484        return 0;
 485}
 486
 487static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast)
 488{
 489
 490        return 0;
 491}
 492
 493static int bfin_lcd_check_fb(struct lcd_device *dev, struct fb_info *fi)
 494{
 495        if (!fi || (fi == &bfin_bf54x_fb))
 496                return 1;
 497        return 0;
 498}
 499
 500static struct lcd_ops bfin_lcd_ops = {
 501        .get_power = bfin_lcd_get_power,
 502        .set_power = bfin_lcd_set_power,
 503        .get_contrast = bfin_lcd_get_contrast,
 504        .set_contrast = bfin_lcd_set_contrast,
 505        .check_fb = bfin_lcd_check_fb,
 506};
 507
 508static struct lcd_device *lcd_dev;
 509#endif
 510
 511static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
 512{
 513        /*struct bfin_bf54xfb_info *info = dev_id;*/
 514
 515        u16 status = bfin_read_EPPI0_STATUS();
 516
 517        bfin_write_EPPI0_STATUS(0xFFFF);
 518
 519        if (status) {
 520                bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN);
 521                disable_dma(CH_EPPI0);
 522
 523                /* start dma */
 524                enable_dma(CH_EPPI0);
 525                bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN);
 526                bfin_write_EPPI0_STATUS(0xFFFF);
 527        }
 528
 529        return IRQ_HANDLED;
 530}
 531
 532static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 533{
 534        struct bfin_bf54xfb_info *info;
 535        struct fb_info *fbinfo;
 536        int ret;
 537
 538        printk(KERN_INFO DRIVER_NAME ": FrameBuffer initializing...\n");
 539
 540        if (request_dma(CH_EPPI0, "CH_EPPI0") < 0) {
 541                printk(KERN_ERR DRIVER_NAME
 542                       ": couldn't request CH_EPPI0 DMA\n");
 543                ret = -EFAULT;
 544                goto out1;
 545        }
 546
 547        fbinfo =
 548            framebuffer_alloc(sizeof(struct bfin_bf54xfb_info), &pdev->dev);
 549        if (!fbinfo) {
 550                ret = -ENOMEM;
 551                goto out2;
 552        }
 553
 554        info = fbinfo->par;
 555        info->fb = fbinfo;
 556        info->dev = &pdev->dev;
 557
 558        platform_set_drvdata(pdev, fbinfo);
 559
 560        strcpy(fbinfo->fix.id, driver_name);
 561
 562        info->mach_info = pdev->dev.platform_data;
 563
 564        if (info->mach_info == NULL) {
 565                dev_err(&pdev->dev,
 566                        "no platform data for lcd, cannot attach\n");
 567                ret = -EINVAL;
 568                goto out3;
 569        }
 570
 571        fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
 572        fbinfo->fix.type_aux = 0;
 573        fbinfo->fix.xpanstep = 0;
 574        fbinfo->fix.ypanstep = 0;
 575        fbinfo->fix.ywrapstep = 0;
 576        fbinfo->fix.accel = FB_ACCEL_NONE;
 577        fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
 578
 579        fbinfo->var.nonstd = 0;
 580        fbinfo->var.activate = FB_ACTIVATE_NOW;
 581        fbinfo->var.height = info->mach_info->height;
 582        fbinfo->var.width = info->mach_info->width;
 583        fbinfo->var.accel_flags = 0;
 584        fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
 585
 586        fbinfo->fbops = &bfin_bf54x_fb_ops;
 587        fbinfo->flags = FBINFO_FLAG_DEFAULT;
 588
 589        fbinfo->var.xres = info->mach_info->xres.defval;
 590        fbinfo->var.xres_virtual = info->mach_info->xres.defval;
 591        fbinfo->var.yres = info->mach_info->yres.defval;
 592        fbinfo->var.yres_virtual = info->mach_info->yres.defval;
 593        fbinfo->var.bits_per_pixel = info->mach_info->bpp.defval;
 594
 595        fbinfo->var.upper_margin = 0;
 596        fbinfo->var.lower_margin = 0;
 597        fbinfo->var.vsync_len = 0;
 598
 599        fbinfo->var.left_margin = 0;
 600        fbinfo->var.right_margin = 0;
 601        fbinfo->var.hsync_len = 0;
 602
 603        fbinfo->var.red.offset = 16;
 604        fbinfo->var.green.offset = 8;
 605        fbinfo->var.blue.offset = 0;
 606        fbinfo->var.transp.offset = 0;
 607        fbinfo->var.red.length = 8;
 608        fbinfo->var.green.length = 8;
 609        fbinfo->var.blue.length = 8;
 610        fbinfo->var.transp.length = 0;
 611        fbinfo->fix.smem_len = info->mach_info->xres.max *
 612            info->mach_info->yres.max * info->mach_info->bpp.max / 8;
 613
 614        fbinfo->fix.line_length = fbinfo->var.xres_virtual *
 615            fbinfo->var.bits_per_pixel / 8;
 616
 617        info->fb_buffer =
 618            dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
 619                               GFP_KERNEL);
 620
 621        if (NULL == info->fb_buffer) {
 622                printk(KERN_ERR DRIVER_NAME
 623                       ": couldn't allocate dma buffer.\n");
 624                ret = -ENOMEM;
 625                goto out3;
 626        }
 627
 628        fbinfo->screen_base = (void *)info->fb_buffer;
 629        fbinfo->fix.smem_start = (int)info->fb_buffer;
 630
 631        fbinfo->fbops = &bfin_bf54x_fb_ops;
 632
 633        fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
 634        if (!fbinfo->pseudo_palette) {
 635                printk(KERN_ERR DRIVER_NAME
 636                       "Fail to allocate pseudo_palette\n");
 637
 638                ret = -ENOMEM;
 639                goto out4;
 640        }
 641
 642        if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0)
 643            < 0) {
 644                printk(KERN_ERR DRIVER_NAME
 645                       "Fail to allocate colormap (%d entries)\n",
 646                       BFIN_LCD_NBR_PALETTE_ENTRIES);
 647                ret = -EFAULT;
 648                goto out5;
 649        }
 650
 651        if (request_ports(info)) {
 652                printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n");
 653                ret = -EFAULT;
 654                goto out6;
 655        }
 656
 657        info->irq = platform_get_irq(pdev, 0);
 658        if (info->irq < 0) {
 659                ret = -EINVAL;
 660                goto out7;
 661        }
 662
 663        if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED,
 664                        "PPI ERROR", info) < 0) {
 665                printk(KERN_ERR DRIVER_NAME
 666                       ": unable to request PPI ERROR IRQ\n");
 667                ret = -EFAULT;
 668                goto out7;
 669        }
 670
 671        if (register_framebuffer(fbinfo) < 0) {
 672                printk(KERN_ERR DRIVER_NAME
 673                       ": unable to register framebuffer.\n");
 674                ret = -EINVAL;
 675                goto out8;
 676        }
 677#ifndef NO_BL_SUPPORT
 678        bl_dev =
 679            backlight_device_register("bf54x-bl", NULL, NULL,
 680                                      &bfin_lq043fb_bl_ops);
 681        bl_dev->props.max_brightness = 255;
 682
 683        lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops);
 684        lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n");
 685#endif
 686
 687        return 0;
 688
 689out8:
 690        free_irq(info->irq, info);
 691out7:
 692        free_ports(info);
 693out6:
 694        fb_dealloc_cmap(&fbinfo->cmap);
 695out5:
 696        kfree(fbinfo->pseudo_palette);
 697out4:
 698        dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
 699                          info->dma_handle);
 700out3:
 701        framebuffer_release(fbinfo);
 702out2:
 703        free_dma(CH_EPPI0);
 704out1:
 705        platform_set_drvdata(pdev, NULL);
 706
 707        return ret;
 708}
 709
 710static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
 711{
 712
 713        struct fb_info *fbinfo = platform_get_drvdata(pdev);
 714        struct bfin_bf54xfb_info *info = fbinfo->par;
 715
 716        free_dma(CH_EPPI0);
 717        free_irq(info->irq, info);
 718
 719        if (info->fb_buffer != NULL)
 720                dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
 721                                  info->dma_handle);
 722
 723        kfree(fbinfo->pseudo_palette);
 724        fb_dealloc_cmap(&fbinfo->cmap);
 725
 726#ifndef NO_BL_SUPPORT
 727        lcd_device_unregister(lcd_dev);
 728        backlight_device_unregister(bl_dev);
 729#endif
 730
 731        unregister_framebuffer(fbinfo);
 732
 733        free_ports(info);
 734
 735        printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n");
 736
 737        return 0;
 738}
 739
 740#ifdef CONFIG_PM
 741static int bfin_bf54x_suspend(struct platform_device *pdev, pm_message_t state)
 742{
 743        struct fb_info *fbinfo = platform_get_drvdata(pdev);
 744
 745        bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN);
 746        disable_dma(CH_EPPI0);
 747        bfin_write_EPPI0_STATUS(0xFFFF);
 748
 749        return 0;
 750}
 751
 752static int bfin_bf54x_resume(struct platform_device *pdev)
 753{
 754        struct fb_info *fbinfo = platform_get_drvdata(pdev);
 755        struct bfin_bf54xfb_info *info = fbinfo->par;
 756
 757        if (info->lq043_open_cnt) {
 758
 759                bfin_write_EPPI0_CONTROL(0);
 760                SSYNC();
 761
 762                config_dma(info);
 763                config_ppi(info);
 764
 765                /* start dma */
 766                enable_dma(CH_EPPI0);
 767                bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN);
 768        }
 769
 770        return 0;
 771}
 772#else
 773#define bfin_bf54x_suspend      NULL
 774#define bfin_bf54x_resume       NULL
 775#endif
 776
 777static struct platform_driver bfin_bf54x_driver = {
 778        .probe = bfin_bf54x_probe,
 779        .remove = __devexit_p(bfin_bf54x_remove),
 780        .suspend = bfin_bf54x_suspend,
 781        .resume = bfin_bf54x_resume,
 782        .driver = {
 783                   .name = DRIVER_NAME,
 784                   .owner = THIS_MODULE,
 785                   },
 786};
 787
 788static int __init bfin_bf54x_driver_init(void)
 789{
 790        return platform_driver_register(&bfin_bf54x_driver);
 791}
 792
 793static void __exit bfin_bf54x_driver_cleanup(void)
 794{
 795        platform_driver_unregister(&bfin_bf54x_driver);
 796}
 797
 798MODULE_DESCRIPTION("Blackfin BF54x TFT LCD Driver");
 799MODULE_LICENSE("GPL");
 800
 801module_init(bfin_bf54x_driver_init);
 802module_exit(bfin_bf54x_driver_cleanup);
 803