linux/drivers/video/ep93xx-fb.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/ep93xx-fb.c
   3 *
   4 * Framebuffer support for the EP93xx series.
   5 *
   6 * Copyright (C) 2007 Bluewater Systems Ltd
   7 * Author: Ryan Mallon <ryan@bluewatersys.com>
   8 *
   9 * Copyright (c) 2009 H Hartley Sweeten <hsweeten@visionengravers.com>
  10 *
  11 * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
  12 * drivers.
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License version 2 as
  16 * published by the Free Software Foundation.
  17 *
  18 */
  19
  20#include <linux/platform_device.h>
  21#include <linux/dma-mapping.h>
  22#include <linux/slab.h>
  23#include <linux/clk.h>
  24#include <linux/fb.h>
  25
  26#include <mach/fb.h>
  27
  28/* Vertical Frame Timing Registers */
  29#define EP93XXFB_VLINES_TOTAL                   0x0000  /* SW locked */
  30#define EP93XXFB_VSYNC                          0x0004  /* SW locked */
  31#define EP93XXFB_VACTIVE                        0x0008  /* SW locked */
  32#define EP93XXFB_VBLANK                         0x0228  /* SW locked */
  33#define EP93XXFB_VCLK                           0x000c  /* SW locked */
  34
  35/* Horizontal Frame Timing Registers */
  36#define EP93XXFB_HCLKS_TOTAL                    0x0010  /* SW locked */
  37#define EP93XXFB_HSYNC                          0x0014  /* SW locked */
  38#define EP93XXFB_HACTIVE                        0x0018  /* SW locked */
  39#define EP93XXFB_HBLANK                         0x022c  /* SW locked */
  40#define EP93XXFB_HCLK                           0x001c  /* SW locked */
  41
  42/* Frame Buffer Memory Configuration Registers */
  43#define EP93XXFB_SCREEN_PAGE                    0x0028
  44#define EP93XXFB_SCREEN_HPAGE                   0x002c
  45#define EP93XXFB_SCREEN_LINES                   0x0030
  46#define EP93XXFB_LINE_LENGTH                    0x0034
  47#define EP93XXFB_VLINE_STEP                     0x0038
  48#define EP93XXFB_LINE_CARRY                     0x003c  /* SW locked */
  49#define EP93XXFB_EOL_OFFSET                     0x0230
  50
  51/* Other Video Registers */
  52#define EP93XXFB_BRIGHTNESS                     0x0020
  53#define EP93XXFB_ATTRIBS                        0x0024  /* SW locked */
  54#define EP93XXFB_SWLOCK                         0x007c  /* SW locked */
  55#define EP93XXFB_AC_RATE                        0x0214
  56#define EP93XXFB_FIFO_LEVEL                     0x0234
  57#define EP93XXFB_PIXELMODE                      0x0054
  58#define EP93XXFB_PIXELMODE_32BPP                (0x7 << 0)
  59#define EP93XXFB_PIXELMODE_24BPP                (0x6 << 0)
  60#define EP93XXFB_PIXELMODE_16BPP                (0x4 << 0)
  61#define EP93XXFB_PIXELMODE_8BPP                 (0x2 << 0)
  62#define EP93XXFB_PIXELMODE_SHIFT_1P_24B         (0x0 << 3)
  63#define EP93XXFB_PIXELMODE_SHIFT_1P_18B         (0x1 << 3)
  64#define EP93XXFB_PIXELMODE_COLOR_LUT            (0x0 << 10)
  65#define EP93XXFB_PIXELMODE_COLOR_888            (0x4 << 10)
  66#define EP93XXFB_PIXELMODE_COLOR_555            (0x5 << 10)
  67#define EP93XXFB_PARL_IF_OUT                    0x0058
  68#define EP93XXFB_PARL_IF_IN                     0x005c
  69
  70/* Blink Control Registers */
  71#define EP93XXFB_BLINK_RATE                     0x0040
  72#define EP93XXFB_BLINK_MASK                     0x0044
  73#define EP93XXFB_BLINK_PATTRN                   0x0048
  74#define EP93XXFB_PATTRN_MASK                    0x004c
  75#define EP93XXFB_BKGRND_OFFSET                  0x0050
  76
  77/* Hardware Cursor Registers */
  78#define EP93XXFB_CURSOR_ADR_START               0x0060
  79#define EP93XXFB_CURSOR_ADR_RESET               0x0064
  80#define EP93XXFB_CURSOR_SIZE                    0x0068
  81#define EP93XXFB_CURSOR_COLOR1                  0x006c
  82#define EP93XXFB_CURSOR_COLOR2                  0x0070
  83#define EP93XXFB_CURSOR_BLINK_COLOR1            0x021c
  84#define EP93XXFB_CURSOR_BLINK_COLOR2            0x0220
  85#define EP93XXFB_CURSOR_XY_LOC                  0x0074
  86#define EP93XXFB_CURSOR_DSCAN_HY_LOC            0x0078
  87#define EP93XXFB_CURSOR_BLINK_RATE_CTRL         0x0224
  88
  89/* LUT Registers */
  90#define EP93XXFB_GRY_SCL_LUTR                   0x0080
  91#define EP93XXFB_GRY_SCL_LUTG                   0x0280
  92#define EP93XXFB_GRY_SCL_LUTB                   0x0300
  93#define EP93XXFB_LUT_SW_CONTROL                 0x0218
  94#define EP93XXFB_LUT_SW_CONTROL_SWTCH           (1 << 0)
  95#define EP93XXFB_LUT_SW_CONTROL_SSTAT           (1 << 1)
  96#define EP93XXFB_COLOR_LUT                      0x0400
  97
  98/* Video Signature Registers */
  99#define EP93XXFB_VID_SIG_RSLT_VAL               0x0200
 100#define EP93XXFB_VID_SIG_CTRL                   0x0204
 101#define EP93XXFB_VSIG                           0x0208
 102#define EP93XXFB_HSIG                           0x020c
 103#define EP93XXFB_SIG_CLR_STR                    0x0210
 104
 105/* Minimum / Maximum resolutions supported */
 106#define EP93XXFB_MIN_XRES                       64
 107#define EP93XXFB_MIN_YRES                       64
 108#define EP93XXFB_MAX_XRES                       1024
 109#define EP93XXFB_MAX_YRES                       768
 110
 111struct ep93xx_fbi {
 112        struct ep93xxfb_mach_info       *mach_info;
 113        struct clk                      *clk;
 114        struct resource                 *res;
 115        void __iomem                    *mmio_base;
 116        unsigned int                    pseudo_palette[256];
 117};
 118
 119static int check_screenpage_bug = 1;
 120module_param(check_screenpage_bug, int, 0644);
 121MODULE_PARM_DESC(check_screenpage_bug,
 122                 "Check for bit 27 screen page bug. Default = 1");
 123
 124static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi,
 125                                          unsigned int off)
 126{
 127        return __raw_readl(fbi->mmio_base + off);
 128}
 129
 130static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi,
 131                                   unsigned int val, unsigned int off)
 132{
 133        __raw_writel(val, fbi->mmio_base + off);
 134}
 135
 136/*
 137 * Write to one of the locked raster registers.
 138 */
 139static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi,
 140                                       unsigned int val, unsigned int reg)
 141{
 142        /*
 143         * We don't need a lock or delay here since the raster register
 144         * block will remain unlocked until the next access.
 145         */
 146        ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK);
 147        ep93xxfb_writel(fbi, val, reg);
 148}
 149
 150static void ep93xxfb_set_video_attribs(struct fb_info *info)
 151{
 152        struct ep93xx_fbi *fbi = info->par;
 153        unsigned int attribs;
 154
 155        attribs = EP93XXFB_ENABLE;
 156        attribs |= fbi->mach_info->flags;
 157        ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS);
 158}
 159
 160static int ep93xxfb_set_pixelmode(struct fb_info *info)
 161{
 162        struct ep93xx_fbi *fbi = info->par;
 163        unsigned int val;
 164
 165        info->var.transp.offset = 0;
 166        info->var.transp.length = 0;
 167
 168        switch (info->var.bits_per_pixel) {
 169        case 8:
 170                val = EP93XXFB_PIXELMODE_8BPP | EP93XXFB_PIXELMODE_COLOR_LUT |
 171                        EP93XXFB_PIXELMODE_SHIFT_1P_18B;
 172
 173                info->var.red.offset    = 0;
 174                info->var.red.length    = 8;
 175                info->var.green.offset  = 0;
 176                info->var.green.length  = 8;
 177                info->var.blue.offset   = 0;
 178                info->var.blue.length   = 8;
 179                info->fix.visual        = FB_VISUAL_PSEUDOCOLOR;
 180                break;
 181
 182        case 16:
 183                val = EP93XXFB_PIXELMODE_16BPP | EP93XXFB_PIXELMODE_COLOR_555 |
 184                        EP93XXFB_PIXELMODE_SHIFT_1P_18B;
 185
 186                info->var.red.offset    = 11;
 187                info->var.red.length    = 5;
 188                info->var.green.offset  = 5;
 189                info->var.green.length  = 6;
 190                info->var.blue.offset   = 0;
 191                info->var.blue.length   = 5;
 192                info->fix.visual        = FB_VISUAL_TRUECOLOR;
 193                break;
 194
 195        case 24:
 196                val = EP93XXFB_PIXELMODE_24BPP | EP93XXFB_PIXELMODE_COLOR_888 |
 197                        EP93XXFB_PIXELMODE_SHIFT_1P_24B;
 198
 199                info->var.red.offset    = 16;
 200                info->var.red.length    = 8;
 201                info->var.green.offset  = 8;
 202                info->var.green.length  = 8;
 203                info->var.blue.offset   = 0;
 204                info->var.blue.length   = 8;
 205                info->fix.visual        = FB_VISUAL_TRUECOLOR;
 206                break;
 207
 208        case 32:
 209                val = EP93XXFB_PIXELMODE_32BPP | EP93XXFB_PIXELMODE_COLOR_888 |
 210                        EP93XXFB_PIXELMODE_SHIFT_1P_24B;
 211
 212                info->var.red.offset    = 16;
 213                info->var.red.length    = 8;
 214                info->var.green.offset  = 8;
 215                info->var.green.length  = 8;
 216                info->var.blue.offset   = 0;
 217                info->var.blue.length   = 8;
 218                info->fix.visual        = FB_VISUAL_TRUECOLOR;
 219                break;
 220
 221        default:
 222                return -EINVAL;
 223        }
 224
 225        ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE);
 226        return 0;
 227}
 228
 229static void ep93xxfb_set_timing(struct fb_info *info)
 230{
 231        struct ep93xx_fbi *fbi = info->par;
 232        unsigned int vlines_total, hclks_total, start, stop;
 233
 234        vlines_total = info->var.yres + info->var.upper_margin +
 235                info->var.lower_margin + info->var.vsync_len - 1;
 236
 237        hclks_total = info->var.xres + info->var.left_margin +
 238                info->var.right_margin + info->var.hsync_len - 1;
 239
 240        ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL);
 241        ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL);
 242
 243        start = vlines_total;
 244        stop = vlines_total - info->var.vsync_len;
 245        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC);
 246
 247        start = vlines_total - info->var.vsync_len - info->var.upper_margin;
 248        stop = info->var.lower_margin - 1;
 249        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK);
 250        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE);
 251
 252        start = vlines_total;
 253        stop = vlines_total + 1;
 254        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK);
 255
 256        start = hclks_total;
 257        stop = hclks_total - info->var.hsync_len;
 258        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC);
 259
 260        start = hclks_total - info->var.hsync_len - info->var.left_margin;
 261        stop = info->var.right_margin - 1;
 262        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK);
 263        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE);
 264
 265        start = hclks_total;
 266        stop = hclks_total;
 267        ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK);
 268
 269        ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY);
 270}
 271
 272static int ep93xxfb_set_par(struct fb_info *info)
 273{
 274        struct ep93xx_fbi *fbi = info->par;
 275
 276        clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock));
 277
 278        ep93xxfb_set_timing(info);
 279
 280        info->fix.line_length = info->var.xres_virtual *
 281                info->var.bits_per_pixel / 8;
 282
 283        ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE);
 284        ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES);
 285        ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel)
 286                              / 32) - 1, EP93XXFB_LINE_LENGTH);
 287        ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP);
 288        ep93xxfb_set_video_attribs(info);
 289        return 0;
 290}
 291
 292static int ep93xxfb_check_var(struct fb_var_screeninfo *var,
 293                              struct fb_info *info)
 294{
 295        int err;
 296
 297        err = ep93xxfb_set_pixelmode(info);
 298        if (err)
 299                return err;
 300
 301        var->xres = max_t(unsigned int, var->xres, EP93XXFB_MIN_XRES);
 302        var->xres = min_t(unsigned int, var->xres, EP93XXFB_MAX_XRES);
 303        var->xres_virtual = max(var->xres_virtual, var->xres);
 304
 305        var->yres = max_t(unsigned int, var->yres, EP93XXFB_MIN_YRES);
 306        var->yres = min_t(unsigned int, var->yres, EP93XXFB_MAX_YRES);
 307        var->yres_virtual = max(var->yres_virtual, var->yres);
 308
 309        return 0;
 310}
 311
 312static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 313{
 314        unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
 315
 316        if (offset < info->fix.smem_len) {
 317                return dma_mmap_writecombine(info->dev, vma, info->screen_base,
 318                                             info->fix.smem_start,
 319                                             info->fix.smem_len);
 320        }
 321
 322        return -EINVAL;
 323}
 324
 325static int ep93xxfb_blank(int blank_mode, struct fb_info *info)
 326{
 327        struct ep93xx_fbi *fbi = info->par;
 328        unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS);
 329
 330        if (blank_mode) {
 331                if (fbi->mach_info->blank)
 332                        fbi->mach_info->blank(blank_mode, info);
 333                ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE,
 334                                    EP93XXFB_ATTRIBS);
 335                clk_disable(fbi->clk);
 336        } else {
 337                clk_enable(fbi->clk);
 338                ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE,
 339                                    EP93XXFB_ATTRIBS);
 340                if (fbi->mach_info->blank)
 341                        fbi->mach_info->blank(blank_mode, info);
 342        }
 343
 344        return 0;
 345}
 346
 347static inline int ep93xxfb_convert_color(int val, int width)
 348{
 349        return ((val << width) + 0x7fff - val) >> 16;
 350}
 351
 352static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
 353                              unsigned int green, unsigned int blue,
 354                              unsigned int transp, struct fb_info *info)
 355{
 356        struct ep93xx_fbi *fbi = info->par;
 357        unsigned int *pal = info->pseudo_palette;
 358        unsigned int ctrl, i, rgb, lut_current, lut_stat;
 359
 360        switch (info->fix.visual) {
 361        case FB_VISUAL_PSEUDOCOLOR:
 362                if (regno > 255)
 363                        return 1;
 364                rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
 365                        ((blue & 0xff00) >> 8);
 366
 367                pal[regno] = rgb;
 368                ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
 369                ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
 370                lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
 371                lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
 372
 373                if (lut_stat == lut_current) {
 374                        for (i = 0; i < 256; i++) {
 375                                ep93xxfb_writel(fbi, pal[i],
 376                                        EP93XXFB_COLOR_LUT + (i << 2));
 377                        }
 378
 379                        ep93xxfb_writel(fbi,
 380                                        ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
 381                                        EP93XXFB_LUT_SW_CONTROL);
 382                }
 383                break;
 384
 385        case FB_VISUAL_TRUECOLOR:
 386                if (regno > 16)
 387                        return 1;
 388
 389                red = ep93xxfb_convert_color(red, info->var.red.length);
 390                green = ep93xxfb_convert_color(green, info->var.green.length);
 391                blue = ep93xxfb_convert_color(blue, info->var.blue.length);
 392                transp = ep93xxfb_convert_color(transp,
 393                                                info->var.transp.length);
 394
 395                pal[regno] = (red << info->var.red.offset) |
 396                        (green << info->var.green.offset) |
 397                        (blue << info->var.blue.offset) |
 398                        (transp << info->var.transp.offset);
 399                break;
 400
 401        default:
 402                return 1;
 403        }
 404
 405        return 0;
 406}
 407
 408static struct fb_ops ep93xxfb_ops = {
 409        .owner          = THIS_MODULE,
 410        .fb_check_var   = ep93xxfb_check_var,
 411        .fb_set_par     = ep93xxfb_set_par,
 412        .fb_blank       = ep93xxfb_blank,
 413        .fb_fillrect    = cfb_fillrect,
 414        .fb_copyarea    = cfb_copyarea,
 415        .fb_imageblit   = cfb_imageblit,
 416        .fb_setcolreg   = ep93xxfb_setcolreg,
 417        .fb_mmap        = ep93xxfb_mmap,
 418};
 419
 420static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
 421{
 422        int i, fb_size = 0;
 423
 424        if (mach_info->num_modes == EP93XXFB_USE_MODEDB) {
 425                fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES *
 426                        mach_info->bpp / 8;
 427        } else {
 428                for (i = 0; i < mach_info->num_modes; i++) {
 429                        const struct fb_videomode *mode;
 430                        int size;
 431
 432                        mode = &mach_info->modes[i];
 433                        size = mode->xres * mode->yres * mach_info->bpp / 8;
 434                        if (size > fb_size)
 435                                fb_size = size;
 436                }
 437        }
 438
 439        return fb_size;
 440}
 441
 442static int __init ep93xxfb_alloc_videomem(struct fb_info *info)
 443{
 444        struct ep93xx_fbi *fbi = info->par;
 445        char __iomem *virt_addr;
 446        dma_addr_t phys_addr;
 447        unsigned int fb_size;
 448
 449        fb_size = ep93xxfb_calc_fbsize(fbi->mach_info);
 450        virt_addr = dma_alloc_writecombine(info->dev, fb_size,
 451                                           &phys_addr, GFP_KERNEL);
 452        if (!virt_addr)
 453                return -ENOMEM;
 454
 455        /*
 456         * There is a bug in the ep93xx framebuffer which causes problems
 457         * if bit 27 of the physical address is set.
 458         * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
 459         * There does not seem to be any offical errata for this, but I
 460         * have confirmed the problem exists on my hardware (ep9315) at
 461         * least.
 462         */
 463        if (check_screenpage_bug && phys_addr & (1 << 27)) {
 464                dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
 465                        "has bit 27 set: cannot init framebuffer\n",
 466                        phys_addr);
 467
 468                dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
 469                return -ENOMEM;
 470        }
 471
 472        info->fix.smem_start = phys_addr;
 473        info->fix.smem_len = fb_size;
 474        info->screen_base = virt_addr;
 475
 476        return 0;
 477}
 478
 479static void ep93xxfb_dealloc_videomem(struct fb_info *info)
 480{
 481        if (info->screen_base)
 482                dma_free_coherent(info->dev, info->fix.smem_len,
 483                                  info->screen_base, info->fix.smem_start);
 484}
 485
 486static int __init ep93xxfb_probe(struct platform_device *pdev)
 487{
 488        struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
 489        struct fb_info *info;
 490        struct ep93xx_fbi *fbi;
 491        struct resource *res;
 492        char *video_mode;
 493        int err;
 494
 495        if (!mach_info)
 496                return -EINVAL;
 497
 498        info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
 499        if (!info)
 500                return -ENOMEM;
 501
 502        info->dev = &pdev->dev;
 503        platform_set_drvdata(pdev, info);
 504        fbi = info->par;
 505        fbi->mach_info = mach_info;
 506
 507        err = fb_alloc_cmap(&info->cmap, 256, 0);
 508        if (err)
 509                goto failed;
 510
 511        err = ep93xxfb_alloc_videomem(info);
 512        if (err)
 513                goto failed;
 514
 515        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 516        if (!res) {
 517                err = -ENXIO;
 518                goto failed;
 519        }
 520
 521        res = request_mem_region(res->start, resource_size(res), pdev->name);
 522        if (!res) {
 523                err = -EBUSY;
 524                goto failed;
 525        }
 526
 527        fbi->res = res;
 528        fbi->mmio_base = ioremap(res->start, resource_size(res));
 529        if (!fbi->mmio_base) {
 530                err = -ENXIO;
 531                goto failed;
 532        }
 533
 534        strcpy(info->fix.id, pdev->name);
 535        info->fbops             = &ep93xxfb_ops;
 536        info->fix.type          = FB_TYPE_PACKED_PIXELS;
 537        info->fix.accel         = FB_ACCEL_NONE;
 538        info->var.activate      = FB_ACTIVATE_NOW;
 539        info->var.vmode         = FB_VMODE_NONINTERLACED;
 540        info->flags             = FBINFO_DEFAULT;
 541        info->node              = -1;
 542        info->state             = FBINFO_STATE_RUNNING;
 543        info->pseudo_palette    = &fbi->pseudo_palette;
 544
 545        fb_get_options("ep93xx-fb", &video_mode);
 546        err = fb_find_mode(&info->var, info, video_mode,
 547                           fbi->mach_info->modes, fbi->mach_info->num_modes,
 548                           fbi->mach_info->default_mode, fbi->mach_info->bpp);
 549        if (err == 0) {
 550                dev_err(info->dev, "No suitable video mode found\n");
 551                err = -EINVAL;
 552                goto failed;
 553        }
 554
 555        if (mach_info->setup) {
 556                err = mach_info->setup(pdev);
 557                if (err)
 558                        return err;
 559        }
 560
 561        err = ep93xxfb_check_var(&info->var, info);
 562        if (err)
 563                goto failed;
 564
 565        fbi->clk = clk_get(info->dev, NULL);
 566        if (IS_ERR(fbi->clk)) {
 567                err = PTR_ERR(fbi->clk);
 568                fbi->clk = NULL;
 569                goto failed;
 570        }
 571
 572        ep93xxfb_set_par(info);
 573        clk_enable(fbi->clk);
 574
 575        err = register_framebuffer(info);
 576        if (err)
 577                goto failed;
 578
 579        dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
 580                 info->var.xres, info->var.yres, info->var.bits_per_pixel);
 581        return 0;
 582
 583failed:
 584        if (fbi->clk)
 585                clk_put(fbi->clk);
 586        if (fbi->mmio_base)
 587                iounmap(fbi->mmio_base);
 588        if (fbi->res)
 589                release_mem_region(fbi->res->start, resource_size(fbi->res));
 590        ep93xxfb_dealloc_videomem(info);
 591        if (&info->cmap)
 592                fb_dealloc_cmap(&info->cmap);
 593        if (fbi->mach_info->teardown)
 594                fbi->mach_info->teardown(pdev);
 595        kfree(info);
 596        platform_set_drvdata(pdev, NULL);
 597
 598        return err;
 599}
 600
 601static int ep93xxfb_remove(struct platform_device *pdev)
 602{
 603        struct fb_info *info = platform_get_drvdata(pdev);
 604        struct ep93xx_fbi *fbi = info->par;
 605
 606        unregister_framebuffer(info);
 607        clk_disable(fbi->clk);
 608        clk_put(fbi->clk);
 609        iounmap(fbi->mmio_base);
 610        release_mem_region(fbi->res->start, resource_size(fbi->res));
 611        ep93xxfb_dealloc_videomem(info);
 612        fb_dealloc_cmap(&info->cmap);
 613
 614        if (fbi->mach_info->teardown)
 615                fbi->mach_info->teardown(pdev);
 616
 617        kfree(info);
 618        platform_set_drvdata(pdev, NULL);
 619
 620        return 0;
 621}
 622
 623static struct platform_driver ep93xxfb_driver = {
 624        .probe          = ep93xxfb_probe,
 625        .remove         = ep93xxfb_remove,
 626        .driver = {
 627                .name   = "ep93xx-fb",
 628                .owner  = THIS_MODULE,
 629        },
 630};
 631
 632static int __devinit ep93xxfb_init(void)
 633{
 634        return platform_driver_register(&ep93xxfb_driver);
 635}
 636
 637static void __exit ep93xxfb_exit(void)
 638{
 639        platform_driver_unregister(&ep93xxfb_driver);
 640}
 641
 642module_init(ep93xxfb_init);
 643module_exit(ep93xxfb_exit);
 644
 645MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
 646MODULE_ALIAS("platform:ep93xx-fb");
 647MODULE_AUTHOR("Ryan Mallon <ryan&bluewatersys.com>, "
 648              "H Hartley Sweeten <hsweeten@visionengravers.com");
 649MODULE_LICENSE("GPL");
 650
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.