linux/drivers/video/bfin-lq035q1-fb.c
<<
>>
Prefs
   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/slab.h>
  17#include <linux/init.h>
  18#include <linux/types.h>
  19#include <linux/interrupt.h>
  20#include <linux/device.h>
  21#include <linux/backlight.h>
  22#include <linux/lcd.h>
  23#include <linux/dma-mapping.h>
  24#include <linux/platform_device.h>
  25#include <linux/spi/spi.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");
 827
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.