linux/drivers/video/metronomefb.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/metronomefb.c -- FB driver for Metronome controller
   3 *
   4 * Copyright (C) 2008, Jaya Kumar
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License. See the file COPYING in the main directory of this archive for
   8 * more details.
   9 *
  10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
  11 *
  12 * This work was made possible by help and equipment support from E-Ink
  13 * Corporation. http://support.eink.com/community
  14 *
  15 * This driver is written to be used with the Metronome display controller.
  16 * It is intended to be architecture independent. A board specific driver
  17 * must be used to perform all the physical IO interactions. An example
  18 * is provided as am200epd.c
  19 *
  20 */
  21#include <linux/module.h>
  22#include <linux/kernel.h>
  23#include <linux/errno.h>
  24#include <linux/string.h>
  25#include <linux/mm.h>
  26#include <linux/slab.h>
  27#include <linux/vmalloc.h>
  28#include <linux/delay.h>
  29#include <linux/interrupt.h>
  30#include <linux/fb.h>
  31#include <linux/init.h>
  32#include <linux/platform_device.h>
  33#include <linux/list.h>
  34#include <linux/firmware.h>
  35#include <linux/dma-mapping.h>
  36#include <linux/uaccess.h>
  37#include <linux/irq.h>
  38
  39#include <video/metronomefb.h>
  40
  41#include <asm/unaligned.h>
  42
  43/* Display specific information */
  44#define DPY_W 832
  45#define DPY_H 622
  46
  47static int user_wfm_size;
  48
  49/* frame differs from image. frame includes non-visible pixels */
  50struct epd_frame {
  51        int fw; /* frame width */
  52        int fh; /* frame height */
  53        u16 config[4];
  54        int wfm_size;
  55};
  56
  57static struct epd_frame epd_frame_table[] = {
  58        {
  59                .fw = 832,
  60                .fh = 622,
  61                .config = {
  62                        15 /* sdlew */
  63                        | 2 << 8 /* sdosz */
  64                        | 0 << 11 /* sdor */
  65                        | 0 << 12 /* sdces */
  66                        | 0 << 15, /* sdcer */
  67                        42 /* gdspl */
  68                        | 1 << 8 /* gdr1 */
  69                        | 1 << 9 /* sdshr */
  70                        | 0 << 15, /* gdspp */
  71                        18 /* gdspw */
  72                        | 0 << 15, /* dispc */
  73                        599 /* vdlc */
  74                        | 0 << 11 /* dsi */
  75                        | 0 << 12, /* dsic */
  76                },
  77                .wfm_size = 47001,
  78        },
  79        {
  80                .fw = 1088,
  81                .fh = 791,
  82                .config = {
  83                        0x0104,
  84                        0x031f,
  85                        0x0088,
  86                        0x02ff,
  87                },
  88                .wfm_size = 46770,
  89        },
  90        {
  91                .fw = 1200,
  92                .fh = 842,
  93                .config = {
  94                        0x0101,
  95                        0x030e,
  96                        0x0012,
  97                        0x0280,
  98                },
  99                .wfm_size = 46770,
 100        },
 101};
 102
 103static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
 104        .id =           "metronomefb",
 105        .type =         FB_TYPE_PACKED_PIXELS,
 106        .visual =       FB_VISUAL_STATIC_PSEUDOCOLOR,
 107        .xpanstep =     0,
 108        .ypanstep =     0,
 109        .ywrapstep =    0,
 110        .line_length =  DPY_W,
 111        .accel =        FB_ACCEL_NONE,
 112};
 113
 114static struct fb_var_screeninfo metronomefb_var __devinitdata = {
 115        .xres           = DPY_W,
 116        .yres           = DPY_H,
 117        .xres_virtual   = DPY_W,
 118        .yres_virtual   = DPY_H,
 119        .bits_per_pixel = 8,
 120        .grayscale      = 1,
 121        .nonstd         = 1,
 122        .red =          { 4, 3, 0 },
 123        .green =        { 0, 0, 0 },
 124        .blue =         { 0, 0, 0 },
 125        .transp =       { 0, 0, 0 },
 126};
 127
 128/* the waveform structure that is coming from userspace firmware */
 129struct waveform_hdr {
 130        u8 stuff[32];
 131
 132        u8 wmta[3];
 133        u8 fvsn;
 134
 135        u8 luts;
 136        u8 mc;
 137        u8 trc;
 138        u8 stuff3;
 139
 140        u8 endb;
 141        u8 swtb;
 142        u8 stuff2a[2];
 143
 144        u8 stuff2b[3];
 145        u8 wfm_cs;
 146} __attribute__ ((packed));
 147
 148/* main metronomefb functions */
 149static u8 calc_cksum(int start, int end, u8 *mem)
 150{
 151        u8 tmp = 0;
 152        int i;
 153
 154        for (i = start; i < end; i++)
 155                tmp += mem[i];
 156
 157        return tmp;
 158}
 159
 160static u16 calc_img_cksum(u16 *start, int length)
 161{
 162        u16 tmp = 0;
 163
 164        while (length--)
 165                tmp += *start++;
 166
 167        return tmp;
 168}
 169
 170/* here we decode the incoming waveform file and populate metromem */
 171static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
 172                                struct metronomefb_par *par)
 173{
 174        int tta;
 175        int wmta;
 176        int trn = 0;
 177        int i;
 178        unsigned char v;
 179        u8 cksum;
 180        int cksum_idx;
 181        int wfm_idx, owfm_idx;
 182        int mem_idx = 0;
 183        struct waveform_hdr *wfm_hdr;
 184        u8 *metromem = par->metromem_wfm;
 185        struct device *dev = par->info->dev;
 186
 187        if (user_wfm_size)
 188                epd_frame_table[par->dt].wfm_size = user_wfm_size;
 189
 190        if (size != epd_frame_table[par->dt].wfm_size) {
 191                dev_err(dev, "Error: unexpected size %Zd != %d\n", size,
 192                                        epd_frame_table[par->dt].wfm_size);
 193                return -EINVAL;
 194        }
 195
 196        wfm_hdr = (struct waveform_hdr *) mem;
 197
 198        if (wfm_hdr->fvsn != 1) {
 199                dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn);
 200                return -EINVAL;
 201        }
 202        if (wfm_hdr->luts != 0) {
 203                dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts);
 204                return -EINVAL;
 205        }
 206        cksum = calc_cksum(32, 47, mem);
 207        if (cksum != wfm_hdr->wfm_cs) {
 208                dev_err(dev, "Error: bad cksum %x != %x\n", cksum,
 209                                        wfm_hdr->wfm_cs);
 210                return -EINVAL;
 211        }
 212        wfm_hdr->mc += 1;
 213        wfm_hdr->trc += 1;
 214        for (i = 0; i < 5; i++) {
 215                if (*(wfm_hdr->stuff2a + i) != 0) {
 216                        dev_err(dev, "Error: unexpected value in padding\n");
 217                        return -EINVAL;
 218                }
 219        }
 220
 221        /* calculating trn. trn is something used to index into
 222        the waveform. presumably selecting the right one for the
 223        desired temperature. it works out the offset of the first
 224        v that exceeds the specified temperature */
 225        if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size)
 226                return -EINVAL;
 227
 228        for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
 229                if (mem[i] > t) {
 230                        trn = i - sizeof(*wfm_hdr) - 1;
 231                        break;
 232                }
 233        }
 234
 235        /* check temperature range table checksum */
 236        cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
 237        if (cksum_idx > size)
 238                return -EINVAL;
 239        cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
 240        if (cksum != mem[cksum_idx]) {
 241                dev_err(dev, "Error: bad temperature range table cksum"
 242                                " %x != %x\n", cksum, mem[cksum_idx]);
 243                return -EINVAL;
 244        }
 245
 246        /* check waveform mode table address checksum */
 247        wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
 248        cksum_idx = wmta + m*4 + 3;
 249        if (cksum_idx > size)
 250                return -EINVAL;
 251        cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
 252        if (cksum != mem[cksum_idx]) {
 253                dev_err(dev, "Error: bad mode table address cksum"
 254                                " %x != %x\n", cksum, mem[cksum_idx]);
 255                return -EINVAL;
 256        }
 257
 258        /* check waveform temperature table address checksum */
 259        tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
 260        cksum_idx = tta + trn*4 + 3;
 261        if (cksum_idx > size)
 262                return -EINVAL;
 263        cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
 264        if (cksum != mem[cksum_idx]) {
 265                dev_err(dev, "Error: bad temperature table address cksum"
 266                        " %x != %x\n", cksum, mem[cksum_idx]);
 267                return -EINVAL;
 268        }
 269
 270        /* here we do the real work of putting the waveform into the
 271        metromem buffer. this does runlength decoding of the waveform */
 272        wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
 273        owfm_idx = wfm_idx;
 274        if (wfm_idx > size)
 275                return -EINVAL;
 276        while (wfm_idx < size) {
 277                unsigned char rl;
 278                v = mem[wfm_idx++];
 279                if (v == wfm_hdr->swtb) {
 280                        while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
 281                                wfm_idx < size)
 282                                metromem[mem_idx++] = v;
 283
 284                        continue;
 285                }
 286
 287                if (v == wfm_hdr->endb)
 288                        break;
 289
 290                rl = mem[wfm_idx++];
 291                for (i = 0; i <= rl; i++)
 292                        metromem[mem_idx++] = v;
 293        }
 294
 295        cksum_idx = wfm_idx;
 296        if (cksum_idx > size)
 297                return -EINVAL;
 298        cksum = calc_cksum(owfm_idx, cksum_idx, mem);
 299        if (cksum != mem[cksum_idx]) {
 300                dev_err(dev, "Error: bad waveform data cksum"
 301                                " %x != %x\n", cksum, mem[cksum_idx]);
 302                return -EINVAL;
 303        }
 304        par->frame_count = (mem_idx/64);
 305
 306        return 0;
 307}
 308
 309static int metronome_display_cmd(struct metronomefb_par *par)
 310{
 311        int i;
 312        u16 cs;
 313        u16 opcode;
 314        static u8 borderval;
 315
 316        /* setup display command
 317        we can't immediately set the opcode since the controller
 318        will try parse the command before we've set it all up
 319        so we just set cs here and set the opcode at the end */
 320
 321        if (par->metromem_cmd->opcode == 0xCC40)
 322                opcode = cs = 0xCC41;
 323        else
 324                opcode = cs = 0xCC40;
 325
 326        /* set the args ( 2 bytes ) for display */
 327        i = 0;
 328        par->metromem_cmd->args[i] =    1 << 3 /* border update */
 329                                        | ((borderval++ % 4) & 0x0F) << 4
 330                                        | (par->frame_count - 1) << 8;
 331        cs += par->metromem_cmd->args[i++];
 332
 333        /* the rest are 0 */
 334        memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
 335
 336        par->metromem_cmd->csum = cs;
 337        par->metromem_cmd->opcode = opcode; /* display cmd */
 338
 339        return par->board->met_wait_event_intr(par);
 340}
 341
 342static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
 343{
 344        int i;
 345        u16 cs;
 346
 347        /* setup power up command */
 348        par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
 349        cs = par->metromem_cmd->opcode;
 350
 351        /* set pwr1,2,3 to 1024 */
 352        for (i = 0; i < 3; i++) {
 353                par->metromem_cmd->args[i] = 1024;
 354                cs += par->metromem_cmd->args[i];
 355        }
 356
 357        /* the rest are 0 */
 358        memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
 359
 360        par->metromem_cmd->csum = cs;
 361
 362        msleep(1);
 363        par->board->set_rst(par, 1);
 364
 365        msleep(1);
 366        par->board->set_stdby(par, 1);
 367
 368        return par->board->met_wait_event(par);
 369}
 370
 371static int __devinit metronome_config_cmd(struct metronomefb_par *par)
 372{
 373        /* setup config command
 374        we can't immediately set the opcode since the controller
 375        will try parse the command before we've set it all up */
 376
 377        memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config,
 378                sizeof(epd_frame_table[par->dt].config));
 379        /* the rest are 0 */
 380        memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2);
 381
 382        par->metromem_cmd->csum = 0xCC10;
 383        par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4);
 384        par->metromem_cmd->opcode = 0xCC10; /* config cmd */
 385
 386        return par->board->met_wait_event(par);
 387}
 388
 389static int __devinit metronome_init_cmd(struct metronomefb_par *par)
 390{
 391        int i;
 392        u16 cs;
 393
 394        /* setup init command
 395        we can't immediately set the opcode since the controller
 396        will try parse the command before we've set it all up
 397        so we just set cs here and set the opcode at the end */
 398
 399        cs = 0xCC20;
 400
 401        /* set the args ( 2 bytes ) for init */
 402        i = 0;
 403        par->metromem_cmd->args[i] = 0;
 404        cs += par->metromem_cmd->args[i++];
 405
 406        /* the rest are 0 */
 407        memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
 408
 409        par->metromem_cmd->csum = cs;
 410        par->metromem_cmd->opcode = 0xCC20; /* init cmd */
 411
 412        return par->board->met_wait_event(par);
 413}
 414
 415static int __devinit metronome_init_regs(struct metronomefb_par *par)
 416{
 417        int res;
 418
 419        res = par->board->setup_io(par);
 420        if (res)
 421                return res;
 422
 423        res = metronome_powerup_cmd(par);
 424        if (res)
 425                return res;
 426
 427        res = metronome_config_cmd(par);
 428        if (res)
 429                return res;
 430
 431        res = metronome_init_cmd(par);
 432
 433        return res;
 434}
 435
 436static void metronomefb_dpy_update(struct metronomefb_par *par)
 437{
 438        int fbsize;
 439        u16 cksum;
 440        unsigned char *buf = (unsigned char __force *)par->info->screen_base;
 441
 442        fbsize = par->info->fix.smem_len;
 443        /* copy from vm to metromem */
 444        memcpy(par->metromem_img, buf, fbsize);
 445
 446        cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2);
 447        *((u16 *)(par->metromem_img) + fbsize/2) = cksum;
 448        metronome_display_cmd(par);
 449}
 450
 451static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
 452{
 453        int i;
 454        u16 csum = 0;
 455        u16 *buf = (u16 __force *)(par->info->screen_base + index);
 456        u16 *img = (u16 *)(par->metromem_img + index);
 457
 458        /* swizzle from vm to metromem and recalc cksum at the same time*/
 459        for (i = 0; i < PAGE_SIZE/2; i++) {
 460                *(img + i) = (buf[i] << 5) & 0xE0E0;
 461                csum += *(img + i);
 462        }
 463        return csum;
 464}
 465
 466/* this is called back from the deferred io workqueue */
 467static void metronomefb_dpy_deferred_io(struct fb_info *info,
 468                                struct list_head *pagelist)
 469{
 470        u16 cksum;
 471        struct page *cur;
 472        struct fb_deferred_io *fbdefio = info->fbdefio;
 473        struct metronomefb_par *par = info->par;
 474
 475        /* walk the written page list and swizzle the data */
 476        list_for_each_entry(cur, &fbdefio->pagelist, lru) {
 477                cksum = metronomefb_dpy_update_page(par,
 478                                        (cur->index << PAGE_SHIFT));
 479                par->metromem_img_csum -= par->csum_table[cur->index];
 480                par->csum_table[cur->index] = cksum;
 481                par->metromem_img_csum += cksum;
 482        }
 483
 484        metronome_display_cmd(par);
 485}
 486
 487static void metronomefb_fillrect(struct fb_info *info,
 488                                   const struct fb_fillrect *rect)
 489{
 490        struct metronomefb_par *par = info->par;
 491
 492        sys_fillrect(info, rect);
 493        metronomefb_dpy_update(par);
 494}
 495
 496static void metronomefb_copyarea(struct fb_info *info,
 497                                   const struct fb_copyarea *area)
 498{
 499        struct metronomefb_par *par = info->par;
 500
 501        sys_copyarea(info, area);
 502        metronomefb_dpy_update(par);
 503}
 504
 505static void metronomefb_imageblit(struct fb_info *info,
 506                                const struct fb_image *image)
 507{
 508        struct metronomefb_par *par = info->par;
 509
 510        sys_imageblit(info, image);
 511        metronomefb_dpy_update(par);
 512}
 513
 514/*
 515 * this is the slow path from userspace. they can seek and write to
 516 * the fb. it is based on fb_sys_write
 517 */
 518static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
 519                                size_t count, loff_t *ppos)
 520{
 521        struct metronomefb_par *par = info->par;
 522        unsigned long p = *ppos;
 523        void *dst;
 524        int err = 0;
 525        unsigned long total_size;
 526
 527        if (info->state != FBINFO_STATE_RUNNING)
 528                return -EPERM;
 529
 530        total_size = info->fix.smem_len;
 531
 532        if (p > total_size)
 533                return -EFBIG;
 534
 535        if (count > total_size) {
 536                err = -EFBIG;
 537                count = total_size;
 538        }
 539
 540        if (count + p > total_size) {
 541                if (!err)
 542                        err = -ENOSPC;
 543
 544                count = total_size - p;
 545        }
 546
 547        dst = (void __force *)(info->screen_base + p);
 548
 549        if (copy_from_user(dst, buf, count))
 550                err = -EFAULT;
 551
 552        if  (!err)
 553                *ppos += count;
 554
 555        metronomefb_dpy_update(par);
 556
 557        return (err) ? err : count;
 558}
 559
 560static struct fb_ops metronomefb_ops = {
 561        .owner          = THIS_MODULE,
 562        .fb_write       = metronomefb_write,
 563        .fb_fillrect    = metronomefb_fillrect,
 564        .fb_copyarea    = metronomefb_copyarea,
 565        .fb_imageblit   = metronomefb_imageblit,
 566};
 567
 568static struct fb_deferred_io metronomefb_defio = {
 569        .delay          = HZ,
 570        .deferred_io    = metronomefb_dpy_deferred_io,
 571};
 572
 573static int __devinit metronomefb_probe(struct platform_device *dev)
 574{
 575        struct fb_info *info;
 576        struct metronome_board *board;
 577        int retval = -ENOMEM;
 578        int videomemorysize;
 579        unsigned char *videomemory;
 580        struct metronomefb_par *par;
 581        const struct firmware *fw_entry;
 582        int i;
 583        int panel_type;
 584        int fw, fh;
 585        int epd_dt_index;
 586
 587        /* pick up board specific routines */
 588        board = dev->dev.platform_data;
 589        if (!board)
 590                return -EINVAL;
 591
 592        /* try to count device specific driver, if can't, platform recalls */
 593        if (!try_module_get(board->owner))
 594                return -ENODEV;
 595
 596        info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
 597        if (!info)
 598                goto err;
 599
 600        /* we have two blocks of memory.
 601        info->screen_base which is vm, and is the fb used by apps.
 602        par->metromem which is physically contiguous memory and
 603        contains the display controller commands, waveform,
 604        processed image data and padding. this is the data pulled
 605        by the device's LCD controller and pushed to Metronome.
 606        the metromem memory is allocated by the board driver and
 607        is provided to us */
 608
 609        panel_type = board->get_panel_type();
 610        switch (panel_type) {
 611        case 6:
 612                epd_dt_index = 0;
 613                break;
 614        case 8:
 615                epd_dt_index = 1;
 616                break;
 617        case 97:
 618                epd_dt_index = 2;
 619                break;
 620        default:
 621                dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
 622                epd_dt_index = 0;
 623                break;
 624        }
 625
 626        fw = epd_frame_table[epd_dt_index].fw;
 627        fh = epd_frame_table[epd_dt_index].fh;
 628
 629        /* we need to add a spare page because our csum caching scheme walks
 630         * to the end of the page */
 631        videomemorysize = PAGE_SIZE + (fw * fh);
 632        videomemory = vmalloc(videomemorysize);
 633        if (!videomemory)
 634                goto err_fb_rel;
 635
 636        memset(videomemory, 0, videomemorysize);
 637
 638        info->screen_base = (char __force __iomem *)videomemory;
 639        info->fbops = &metronomefb_ops;
 640
 641        metronomefb_fix.line_length = fw;
 642        metronomefb_var.xres = fw;
 643        metronomefb_var.yres = fh;
 644        metronomefb_var.xres_virtual = fw;
 645        metronomefb_var.yres_virtual = fh;
 646        info->var = metronomefb_var;
 647        info->fix = metronomefb_fix;
 648        info->fix.smem_len = videomemorysize;
 649        par = info->par;
 650        par->info = info;
 651        par->board = board;
 652        par->dt = epd_dt_index;
 653        init_waitqueue_head(&par->waitq);
 654
 655        /* this table caches per page csum values. */
 656        par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
 657        if (!par->csum_table)
 658                goto err_vfree;
 659
 660        /* the physical framebuffer that we use is setup by
 661         * the platform device driver. It will provide us
 662         * with cmd, wfm and image memory in a contiguous area. */
 663        retval = board->setup_fb(par);
 664        if (retval) {
 665                dev_err(&dev->dev, "Failed to setup fb\n");
 666                goto err_csum_table;
 667        }
 668
 669        /* after this point we should have a framebuffer */
 670        if ((!par->metromem_wfm) ||  (!par->metromem_img) ||
 671                (!par->metromem_dma)) {
 672                dev_err(&dev->dev, "fb access failure\n");
 673                retval = -EINVAL;
 674                goto err_csum_table;
 675        }
 676
 677        info->fix.smem_start = par->metromem_dma;
 678
 679        /* load the waveform in. assume mode 3, temp 31 for now
 680                a) request the waveform file from userspace
 681                b) process waveform and decode into metromem */
 682        retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
 683        if (retval < 0) {
 684                dev_err(&dev->dev, "Failed to get waveform\n");
 685                goto err_csum_table;
 686        }
 687
 688        retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
 689                                par);
 690        release_firmware(fw_entry);
 691        if (retval < 0) {
 692                dev_err(&dev->dev, "Failed processing waveform\n");
 693                goto err_csum_table;
 694        }
 695
 696        if (board->setup_irq(info))
 697                goto err_csum_table;
 698
 699        retval = metronome_init_regs(par);
 700        if (retval < 0)
 701                goto err_free_irq;
 702
 703        info->flags = FBINFO_FLAG_DEFAULT;
 704
 705        info->fbdefio = &metronomefb_defio;
 706        fb_deferred_io_init(info);
 707
 708        retval = fb_alloc_cmap(&info->cmap, 8, 0);
 709        if (retval < 0) {
 710                dev_err(&dev->dev, "Failed to allocate colormap\n");
 711                goto err_free_irq;
 712        }
 713
 714        /* set cmap */
 715        for (i = 0; i < 8; i++)
 716                info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
 717        memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
 718        memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
 719
 720        retval = register_framebuffer(info);
 721        if (retval < 0)
 722                goto err_cmap;
 723
 724        platform_set_drvdata(dev, info);
 725
 726        dev_dbg(&dev->dev,
 727                "fb%d: Metronome frame buffer device, using %dK of video"
 728                " memory\n", info->node, videomemorysize >> 10);
 729
 730        return 0;
 731
 732err_cmap:
 733        fb_dealloc_cmap(&info->cmap);
 734err_free_irq:
 735        board->cleanup(par);
 736err_csum_table:
 737        vfree(par->csum_table);
 738err_vfree:
 739        vfree(videomemory);
 740err_fb_rel:
 741        framebuffer_release(info);
 742err:
 743        module_put(board->owner);
 744        return retval;
 745}
 746
 747static int __devexit metronomefb_remove(struct platform_device *dev)
 748{
 749        struct fb_info *info = platform_get_drvdata(dev);
 750
 751        if (info) {
 752                struct metronomefb_par *par = info->par;
 753
 754                unregister_framebuffer(info);
 755                fb_deferred_io_cleanup(info);
 756                fb_dealloc_cmap(&info->cmap);
 757                par->board->cleanup(par);
 758                vfree(par->csum_table);
 759                vfree((void __force *)info->screen_base);
 760                module_put(par->board->owner);
 761                dev_dbg(&dev->dev, "calling release\n");
 762                framebuffer_release(info);
 763        }
 764        return 0;
 765}
 766
 767static struct platform_driver metronomefb_driver = {
 768        .probe  = metronomefb_probe,
 769        .remove = metronomefb_remove,
 770        .driver = {
 771                .owner  = THIS_MODULE,
 772                .name   = "metronomefb",
 773        },
 774};
 775
 776static int __init metronomefb_init(void)
 777{
 778        return platform_driver_register(&metronomefb_driver);
 779}
 780
 781static void __exit metronomefb_exit(void)
 782{
 783        platform_driver_unregister(&metronomefb_driver);
 784}
 785
 786module_param(user_wfm_size, uint, 0);
 787MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size");
 788
 789module_init(metronomefb_init);
 790module_exit(metronomefb_exit);
 791
 792MODULE_DESCRIPTION("fbdev driver for Metronome controller");
 793MODULE_AUTHOR("Jaya Kumar");
 794MODULE_LICENSE("GPL");
 795