linux/drivers/video/pxa3xx-gcu.c
<<
>>
Prefs
   1/*
   2 *  pxa3xx-gcu.c - Linux kernel module for PXA3xx graphics controllers
   3 *
   4 *  This driver needs a DirectFB counterpart in user space, communication
   5 *  is handled via mmap()ed memory areas and an ioctl.
   6 *
   7 *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
   8 *  Copyright (c) 2009 Janine Kropp <nin@directfb.org>
   9 *  Copyright (c) 2009 Denis Oliver Kropp <dok@directfb.org>
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License as published by
  13 *  the Free Software Foundation; either version 2 of the License, or
  14 *  (at your option) any later version.
  15 *
  16 *  This program is distributed in the hope that it will be useful,
  17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 *  GNU General Public License for more details.
  20 *
  21 *  You should have received a copy of the GNU General Public License
  22 *  along with this program; if not, write to the Free Software
  23 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 */
  25
  26/*
  27 * WARNING: This controller is attached to System Bus 2 of the PXA which
  28 * needs its arbiter to be enabled explicitly (CKENB & 1<<9).
  29 * There is currently no way to do this from Linux, so you need to teach
  30 * your bootloader for now.
  31 */
  32
  33#include <linux/module.h>
  34#include <linux/platform_device.h>
  35#include <linux/dma-mapping.h>
  36#include <linux/miscdevice.h>
  37#include <linux/interrupt.h>
  38#include <linux/spinlock.h>
  39#include <linux/uaccess.h>
  40#include <linux/ioctl.h>
  41#include <linux/delay.h>
  42#include <linux/sched.h>
  43#include <linux/slab.h>
  44#include <linux/clk.h>
  45#include <linux/fs.h>
  46#include <linux/io.h>
  47
  48#include "pxa3xx-gcu.h"
  49
  50#define DRV_NAME        "pxa3xx-gcu"
  51#define MISCDEV_MINOR   197
  52
  53#define REG_GCCR        0x00
  54#define GCCR_SYNC_CLR   (1 << 9)
  55#define GCCR_BP_RST     (1 << 8)
  56#define GCCR_ABORT      (1 << 6)
  57#define GCCR_STOP       (1 << 4)
  58
  59#define REG_GCISCR      0x04
  60#define REG_GCIECR      0x08
  61#define REG_GCRBBR      0x20
  62#define REG_GCRBLR      0x24
  63#define REG_GCRBHR      0x28
  64#define REG_GCRBTR      0x2C
  65#define REG_GCRBEXHR    0x30
  66
  67#define IE_EOB          (1 << 0)
  68#define IE_EEOB         (1 << 5)
  69#define IE_ALL          0xff
  70
  71#define SHARED_SIZE     PAGE_ALIGN(sizeof(struct pxa3xx_gcu_shared))
  72
  73/* #define PXA3XX_GCU_DEBUG */
  74/* #define PXA3XX_GCU_DEBUG_TIMER */
  75
  76#ifdef PXA3XX_GCU_DEBUG
  77#define QDUMP(msg)                                      \
  78        do {                                            \
  79                QPRINT(priv, KERN_DEBUG, msg);          \
  80        } while (0)
  81#else
  82#define QDUMP(msg)      do {} while (0)
  83#endif
  84
  85#define QERROR(msg)                                     \
  86        do {                                            \
  87                QPRINT(priv, KERN_ERR, msg);            \
  88        } while (0)
  89
  90struct pxa3xx_gcu_batch {
  91        struct pxa3xx_gcu_batch *next;
  92        u32                     *ptr;
  93        dma_addr_t               phys;
  94        unsigned long            length;
  95};
  96
  97struct pxa3xx_gcu_priv {
  98        void __iomem             *mmio_base;
  99        struct clk               *clk;
 100        struct pxa3xx_gcu_shared *shared;
 101        dma_addr_t                shared_phys;
 102        struct resource          *resource_mem;
 103        struct miscdevice         misc_dev;
 104        struct file_operations    misc_fops;
 105        wait_queue_head_t         wait_idle;
 106        wait_queue_head_t         wait_free;
 107        spinlock_t                spinlock;
 108        struct timeval            base_time;
 109
 110        struct pxa3xx_gcu_batch *free;
 111
 112        struct pxa3xx_gcu_batch *ready;
 113        struct pxa3xx_gcu_batch *ready_last;
 114        struct pxa3xx_gcu_batch *running;
 115};
 116
 117static inline unsigned long
 118gc_readl(struct pxa3xx_gcu_priv *priv, unsigned int off)
 119{
 120        return __raw_readl(priv->mmio_base + off);
 121}
 122
 123static inline void
 124gc_writel(struct pxa3xx_gcu_priv *priv, unsigned int off, unsigned long val)
 125{
 126        __raw_writel(val, priv->mmio_base + off);
 127}
 128
 129#define QPRINT(priv, level, msg)                                        \
 130        do {                                                            \
 131                struct timeval tv;                                      \
 132                struct pxa3xx_gcu_shared *shared = priv->shared;        \
 133                u32 base = gc_readl(priv, REG_GCRBBR);                  \
 134                                                                        \
 135                do_gettimeofday(&tv);                                   \
 136                                                                        \
 137                printk(level "%ld.%03ld.%03ld - %-17s: %-21s (%s, "     \
 138                        "STATUS "                                       \
 139                        "0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, "    \
 140                        "T %5ld)\n",                                    \
 141                        tv.tv_sec - priv->base_time.tv_sec,             \
 142                        tv.tv_usec / 1000, tv.tv_usec % 1000,           \
 143                        __func__, msg,                                  \
 144                        shared->hw_running ? "running" : "   idle",     \
 145                        gc_readl(priv, REG_GCISCR),                     \
 146                        gc_readl(priv, REG_GCRBBR),                     \
 147                        gc_readl(priv, REG_GCRBLR),                     \
 148                        (gc_readl(priv, REG_GCRBEXHR) - base) / 4,      \
 149                        (gc_readl(priv, REG_GCRBHR) - base) / 4,        \
 150                        (gc_readl(priv, REG_GCRBTR) - base) / 4);       \
 151        } while (0)
 152
 153static void
 154pxa3xx_gcu_reset(struct pxa3xx_gcu_priv *priv)
 155{
 156        QDUMP("RESET");
 157
 158        /* disable interrupts */
 159        gc_writel(priv, REG_GCIECR, 0);
 160
 161        /* reset hardware */
 162        gc_writel(priv, REG_GCCR, GCCR_ABORT);
 163        gc_writel(priv, REG_GCCR, 0);
 164
 165        memset(priv->shared, 0, SHARED_SIZE);
 166        priv->shared->buffer_phys = priv->shared_phys;
 167        priv->shared->magic = PXA3XX_GCU_SHARED_MAGIC;
 168
 169        do_gettimeofday(&priv->base_time);
 170
 171        /* set up the ring buffer pointers */
 172        gc_writel(priv, REG_GCRBLR, 0);
 173        gc_writel(priv, REG_GCRBBR, priv->shared_phys);
 174        gc_writel(priv, REG_GCRBTR, priv->shared_phys);
 175
 176        /* enable all IRQs except EOB */
 177        gc_writel(priv, REG_GCIECR, IE_ALL & ~IE_EOB);
 178}
 179
 180static void
 181dump_whole_state(struct pxa3xx_gcu_priv *priv)
 182{
 183        struct pxa3xx_gcu_shared *sh = priv->shared;
 184        u32 base = gc_readl(priv, REG_GCRBBR);
 185
 186        QDUMP("DUMP");
 187
 188        printk(KERN_DEBUG "== PXA3XX-GCU DUMP ==\n"
 189                "%s, STATUS 0x%02lx, B 0x%08lx [%ld], E %5ld, H %5ld, T %5ld\n",
 190                sh->hw_running ? "running" : "idle   ",
 191                gc_readl(priv, REG_GCISCR),
 192                gc_readl(priv, REG_GCRBBR),
 193                gc_readl(priv, REG_GCRBLR),
 194                (gc_readl(priv, REG_GCRBEXHR) - base) / 4,
 195                (gc_readl(priv, REG_GCRBHR) - base) / 4,
 196                (gc_readl(priv, REG_GCRBTR) - base) / 4);
 197}
 198
 199static void
 200flush_running(struct pxa3xx_gcu_priv *priv)
 201{
 202        struct pxa3xx_gcu_batch *running = priv->running;
 203        struct pxa3xx_gcu_batch *next;
 204
 205        while (running) {
 206                next = running->next;
 207                running->next = priv->free;
 208                priv->free = running;
 209                running = next;
 210        }
 211
 212        priv->running = NULL;
 213}
 214
 215static void
 216run_ready(struct pxa3xx_gcu_priv *priv)
 217{
 218        unsigned int num = 0;
 219        struct pxa3xx_gcu_shared *shared = priv->shared;
 220        struct pxa3xx_gcu_batch *ready = priv->ready;
 221
 222        QDUMP("Start");
 223
 224        BUG_ON(!ready);
 225
 226        shared->buffer[num++] = 0x05000000;
 227
 228        while (ready) {
 229                shared->buffer[num++] = 0x00000001;
 230                shared->buffer[num++] = ready->phys;
 231                ready = ready->next;
 232        }
 233
 234        shared->buffer[num++] = 0x05000000;
 235        priv->running = priv->ready;
 236        priv->ready = priv->ready_last = NULL;
 237        gc_writel(priv, REG_GCRBLR, 0);
 238        shared->hw_running = 1;
 239
 240        /* ring base address */
 241        gc_writel(priv, REG_GCRBBR, shared->buffer_phys);
 242
 243        /* ring tail address */
 244        gc_writel(priv, REG_GCRBTR, shared->buffer_phys + num * 4);
 245
 246        /* ring length */
 247        gc_writel(priv, REG_GCRBLR, ((num + 63) & ~63) * 4);
 248}
 249
 250static irqreturn_t
 251pxa3xx_gcu_handle_irq(int irq, void *ctx)
 252{
 253        struct pxa3xx_gcu_priv *priv = ctx;
 254        struct pxa3xx_gcu_shared *shared = priv->shared;
 255        u32 status = gc_readl(priv, REG_GCISCR) & IE_ALL;
 256
 257        QDUMP("-Interrupt");
 258
 259        if (!status)
 260                return IRQ_NONE;
 261
 262        spin_lock(&priv->spinlock);
 263        shared->num_interrupts++;
 264
 265        if (status & IE_EEOB) {
 266                QDUMP(" [EEOB]");
 267
 268                flush_running(priv);
 269                wake_up_all(&priv->wait_free);
 270
 271                if (priv->ready) {
 272                        run_ready(priv);
 273                } else {
 274                        /* There is no more data prepared by the userspace.
 275                         * Set hw_running = 0 and wait for the next userspace
 276                         * kick-off */
 277                        shared->num_idle++;
 278                        shared->hw_running = 0;
 279
 280                        QDUMP(" '-> Idle.");
 281
 282                        /* set ring buffer length to zero */
 283                        gc_writel(priv, REG_GCRBLR, 0);
 284
 285                        wake_up_all(&priv->wait_idle);
 286                }
 287
 288                shared->num_done++;
 289        } else {
 290                QERROR(" [???]");
 291                dump_whole_state(priv);
 292        }
 293
 294        /* Clear the interrupt */
 295        gc_writel(priv, REG_GCISCR, status);
 296        spin_unlock(&priv->spinlock);
 297
 298        return IRQ_HANDLED;
 299}
 300
 301static int
 302pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv)
 303{
 304        int ret = 0;
 305
 306        QDUMP("Waiting for idle...");
 307
 308        /* Does not need to be atomic. There's a lock in user space,
 309         * but anyhow, this is just for statistics. */
 310        priv->shared->num_wait_idle++;
 311
 312        while (priv->shared->hw_running) {
 313                int num = priv->shared->num_interrupts;
 314                u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
 315
 316                ret = wait_event_interruptible_timeout(priv->wait_idle,
 317                                        !priv->shared->hw_running, HZ*4);
 318
 319                if (ret != 0)
 320                        break;
 321
 322                if (gc_readl(priv, REG_GCRBEXHR) == rbexhr &&
 323                    priv->shared->num_interrupts == num) {
 324                        QERROR("TIMEOUT");
 325                        ret = -ETIMEDOUT;
 326                        break;
 327                }
 328        }
 329
 330        QDUMP("done");
 331
 332        return ret;
 333}
 334
 335static int
 336pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv)
 337{
 338        int ret = 0;
 339
 340        QDUMP("Waiting for free...");
 341
 342        /* Does not need to be atomic. There's a lock in user space,
 343         * but anyhow, this is just for statistics. */
 344        priv->shared->num_wait_free++;
 345
 346        while (!priv->free) {
 347                u32 rbexhr = gc_readl(priv, REG_GCRBEXHR);
 348
 349                ret = wait_event_interruptible_timeout(priv->wait_free,
 350                                                       priv->free, HZ*4);
 351
 352                if (ret < 0)
 353                        break;
 354
 355                if (ret > 0)
 356                        continue;
 357
 358                if (gc_readl(priv, REG_GCRBEXHR) == rbexhr) {
 359                        QERROR("TIMEOUT");
 360                        ret = -ETIMEDOUT;
 361                        break;
 362                }
 363        }
 364
 365        QDUMP("done");
 366
 367        return ret;
 368}
 369
 370/* Misc device layer */
 371
 372static ssize_t
 373pxa3xx_gcu_misc_write(struct file *filp, const char *buff,
 374                      size_t count, loff_t *offp)
 375{
 376        int ret;
 377        unsigned long flags;
 378        struct pxa3xx_gcu_batch *buffer;
 379        struct pxa3xx_gcu_priv *priv =
 380                container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
 381
 382        int words = count / 4;
 383
 384        /* Does not need to be atomic. There's a lock in user space,
 385         * but anyhow, this is just for statistics. */
 386        priv->shared->num_writes++;
 387
 388        priv->shared->num_words += words;
 389
 390        /* Last word reserved for batch buffer end command */
 391        if (words >= PXA3XX_GCU_BATCH_WORDS)
 392                return -E2BIG;
 393
 394        /* Wait for a free buffer */
 395        if (!priv->free) {
 396                ret = pxa3xx_gcu_wait_free(priv);
 397                if (ret < 0)
 398                        return ret;
 399        }
 400
 401        /*
 402         * Get buffer from free list
 403         */
 404        spin_lock_irqsave(&priv->spinlock, flags);
 405
 406        buffer = priv->free;
 407        priv->free = buffer->next;
 408
 409        spin_unlock_irqrestore(&priv->spinlock, flags);
 410
 411
 412        /* Copy data from user into buffer */
 413        ret = copy_from_user(buffer->ptr, buff, words * 4);
 414        if (ret) {
 415                spin_lock_irqsave(&priv->spinlock, flags);
 416                buffer->next = priv->free;
 417                priv->free = buffer;
 418                spin_unlock_irqrestore(&priv->spinlock, flags);
 419                return -EFAULT;
 420        }
 421
 422        buffer->length = words;
 423
 424        /* Append batch buffer end command */
 425        buffer->ptr[words] = 0x01000000;
 426
 427        /*
 428         * Add buffer to ready list
 429         */
 430        spin_lock_irqsave(&priv->spinlock, flags);
 431
 432        buffer->next = NULL;
 433
 434        if (priv->ready) {
 435                BUG_ON(priv->ready_last == NULL);
 436
 437                priv->ready_last->next = buffer;
 438        } else
 439                priv->ready = buffer;
 440
 441        priv->ready_last = buffer;
 442
 443        if (!priv->shared->hw_running)
 444                run_ready(priv);
 445
 446        spin_unlock_irqrestore(&priv->spinlock, flags);
 447
 448        return words * 4;
 449}
 450
 451
 452static long
 453pxa3xx_gcu_misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 454{
 455        unsigned long flags;
 456        struct pxa3xx_gcu_priv *priv =
 457                container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
 458
 459        switch (cmd) {
 460        case PXA3XX_GCU_IOCTL_RESET:
 461                spin_lock_irqsave(&priv->spinlock, flags);
 462                pxa3xx_gcu_reset(priv);
 463                spin_unlock_irqrestore(&priv->spinlock, flags);
 464                return 0;
 465
 466        case PXA3XX_GCU_IOCTL_WAIT_IDLE:
 467                return pxa3xx_gcu_wait_idle(priv);
 468        }
 469
 470        return -ENOSYS;
 471}
 472
 473static int
 474pxa3xx_gcu_misc_mmap(struct file *filp, struct vm_area_struct *vma)
 475{
 476        unsigned int size = vma->vm_end - vma->vm_start;
 477        struct pxa3xx_gcu_priv *priv =
 478                container_of(filp->f_op, struct pxa3xx_gcu_priv, misc_fops);
 479
 480        switch (vma->vm_pgoff) {
 481        case 0:
 482                /* hand out the shared data area */
 483                if (size != SHARED_SIZE)
 484                        return -EINVAL;
 485
 486                return dma_mmap_coherent(NULL, vma,
 487                        priv->shared, priv->shared_phys, size);
 488
 489        case SHARED_SIZE >> PAGE_SHIFT:
 490                /* hand out the MMIO base for direct register access
 491                 * from userspace */
 492                if (size != resource_size(priv->resource_mem))
 493                        return -EINVAL;
 494
 495                vma->vm_flags |= VM_IO;
 496                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 497
 498                return io_remap_pfn_range(vma, vma->vm_start,
 499                                priv->resource_mem->start >> PAGE_SHIFT,
 500                                size, vma->vm_page_prot);
 501        }
 502
 503        return -EINVAL;
 504}
 505
 506
 507#ifdef PXA3XX_GCU_DEBUG_TIMER
 508static struct timer_list pxa3xx_gcu_debug_timer;
 509
 510static void pxa3xx_gcu_debug_timedout(unsigned long ptr)
 511{
 512        struct pxa3xx_gcu_priv *priv = (struct pxa3xx_gcu_priv *) ptr;
 513
 514        QERROR("Timer DUMP");
 515
 516        /* init the timer structure */
 517        init_timer(&pxa3xx_gcu_debug_timer);
 518        pxa3xx_gcu_debug_timer.function = pxa3xx_gcu_debug_timedout;
 519        pxa3xx_gcu_debug_timer.data = ptr;
 520        pxa3xx_gcu_debug_timer.expires = jiffies + 5*HZ; /* one second */
 521
 522        add_timer(&pxa3xx_gcu_debug_timer);
 523}
 524
 525static void pxa3xx_gcu_init_debug_timer(void)
 526{
 527        pxa3xx_gcu_debug_timedout((unsigned long) &pxa3xx_gcu_debug_timer);
 528}
 529#else
 530static inline void pxa3xx_gcu_init_debug_timer(void) {}
 531#endif
 532
 533static int
 534add_buffer(struct platform_device *dev,
 535           struct pxa3xx_gcu_priv *priv)
 536{
 537        struct pxa3xx_gcu_batch *buffer;
 538
 539        buffer = kzalloc(sizeof(struct pxa3xx_gcu_batch), GFP_KERNEL);
 540        if (!buffer)
 541                return -ENOMEM;
 542
 543        buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4,
 544                                         &buffer->phys, GFP_KERNEL);
 545        if (!buffer->ptr) {
 546                kfree(buffer);
 547                return -ENOMEM;
 548        }
 549
 550        buffer->next = priv->free;
 551
 552        priv->free = buffer;
 553
 554        return 0;
 555}
 556
 557static void
 558free_buffers(struct platform_device *dev,
 559             struct pxa3xx_gcu_priv *priv)
 560{
 561        struct pxa3xx_gcu_batch *next, *buffer = priv->free;
 562
 563        while (buffer) {
 564                next = buffer->next;
 565
 566                dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4,
 567                                  buffer->ptr, buffer->phys);
 568
 569                kfree(buffer);
 570
 571                buffer = next;
 572        }
 573
 574        priv->free = NULL;
 575}
 576
 577static int pxa3xx_gcu_probe(struct platform_device *dev)
 578{
 579        int i, ret, irq;
 580        struct resource *r;
 581        struct pxa3xx_gcu_priv *priv;
 582
 583        priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL);
 584        if (!priv)
 585                return -ENOMEM;
 586
 587        for (i = 0; i < 8; i++) {
 588                ret = add_buffer(dev, priv);
 589                if (ret) {
 590                        dev_err(&dev->dev, "failed to allocate DMA memory\n");
 591                        goto err_free_priv;
 592                }
 593        }
 594
 595        init_waitqueue_head(&priv->wait_idle);
 596        init_waitqueue_head(&priv->wait_free);
 597        spin_lock_init(&priv->spinlock);
 598
 599        /* we allocate the misc device structure as part of our own allocation,
 600         * so we can get a pointer to our priv structure later on with
 601         * container_of(). This isn't really necessary as we have a fixed minor
 602         * number anyway, but this is to avoid statics. */
 603
 604        priv->misc_fops.owner   = THIS_MODULE;
 605        priv->misc_fops.write   = pxa3xx_gcu_misc_write;
 606        priv->misc_fops.unlocked_ioctl = pxa3xx_gcu_misc_ioctl;
 607        priv->misc_fops.mmap    = pxa3xx_gcu_misc_mmap;
 608
 609        priv->misc_dev.minor    = MISCDEV_MINOR,
 610        priv->misc_dev.name     = DRV_NAME,
 611        priv->misc_dev.fops     = &priv->misc_fops,
 612
 613        /* register misc device */
 614        ret = misc_register(&priv->misc_dev);
 615        if (ret < 0) {
 616                dev_err(&dev->dev, "misc_register() for minor %d failed\n",
 617                        MISCDEV_MINOR);
 618                goto err_free_priv;
 619        }
 620
 621        /* handle IO resources */
 622        r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 623        if (r == NULL) {
 624                dev_err(&dev->dev, "no I/O memory resource defined\n");
 625                ret = -ENODEV;
 626                goto err_misc_deregister;
 627        }
 628
 629        if (!request_mem_region(r->start, resource_size(r), dev->name)) {
 630                dev_err(&dev->dev, "failed to request I/O memory\n");
 631                ret = -EBUSY;
 632                goto err_misc_deregister;
 633        }
 634
 635        priv->mmio_base = ioremap_nocache(r->start, resource_size(r));
 636        if (!priv->mmio_base) {
 637                dev_err(&dev->dev, "failed to map I/O memory\n");
 638                ret = -EBUSY;
 639                goto err_free_mem_region;
 640        }
 641
 642        /* allocate dma memory */
 643        priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE,
 644                                          &priv->shared_phys, GFP_KERNEL);
 645
 646        if (!priv->shared) {
 647                dev_err(&dev->dev, "failed to allocate DMA memory\n");
 648                ret = -ENOMEM;
 649                goto err_free_io;
 650        }
 651
 652        /* enable the clock */
 653        priv->clk = clk_get(&dev->dev, NULL);
 654        if (IS_ERR(priv->clk)) {
 655                dev_err(&dev->dev, "failed to get clock\n");
 656                ret = -ENODEV;
 657                goto err_free_dma;
 658        }
 659
 660        ret = clk_enable(priv->clk);
 661        if (ret < 0) {
 662                dev_err(&dev->dev, "failed to enable clock\n");
 663                goto err_put_clk;
 664        }
 665
 666        /* request the IRQ */
 667        irq = platform_get_irq(dev, 0);
 668        if (irq < 0) {
 669                dev_err(&dev->dev, "no IRQ defined\n");
 670                ret = -ENODEV;
 671                goto err_put_clk;
 672        }
 673
 674        ret = request_irq(irq, pxa3xx_gcu_handle_irq,
 675                          0, DRV_NAME, priv);
 676        if (ret) {
 677                dev_err(&dev->dev, "request_irq failed\n");
 678                ret = -EBUSY;
 679                goto err_put_clk;
 680        }
 681
 682        platform_set_drvdata(dev, priv);
 683        priv->resource_mem = r;
 684        pxa3xx_gcu_reset(priv);
 685        pxa3xx_gcu_init_debug_timer();
 686
 687        dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n",
 688                        (void *) r->start, (void *) priv->shared_phys,
 689                        SHARED_SIZE, irq);
 690        return 0;
 691
 692err_put_clk:
 693        clk_disable(priv->clk);
 694        clk_put(priv->clk);
 695
 696err_free_dma:
 697        dma_free_coherent(&dev->dev, SHARED_SIZE,
 698                        priv->shared, priv->shared_phys);
 699
 700err_free_io:
 701        iounmap(priv->mmio_base);
 702
 703err_free_mem_region:
 704        release_mem_region(r->start, resource_size(r));
 705
 706err_misc_deregister:
 707        misc_deregister(&priv->misc_dev);
 708
 709err_free_priv:
 710        platform_set_drvdata(dev, NULL);
 711        free_buffers(dev, priv);
 712        kfree(priv);
 713        return ret;
 714}
 715
 716static int pxa3xx_gcu_remove(struct platform_device *dev)
 717{
 718        struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev);
 719        struct resource *r = priv->resource_mem;
 720
 721        pxa3xx_gcu_wait_idle(priv);
 722
 723        misc_deregister(&priv->misc_dev);
 724        dma_free_coherent(&dev->dev, SHARED_SIZE,
 725                        priv->shared, priv->shared_phys);
 726        iounmap(priv->mmio_base);
 727        release_mem_region(r->start, resource_size(r));
 728        platform_set_drvdata(dev, NULL);
 729        clk_disable(priv->clk);
 730        free_buffers(dev, priv);
 731        kfree(priv);
 732
 733        return 0;
 734}
 735
 736static struct platform_driver pxa3xx_gcu_driver = {
 737        .probe    = pxa3xx_gcu_probe,
 738        .remove  = pxa3xx_gcu_remove,
 739        .driver  = {
 740                .owner  = THIS_MODULE,
 741                .name   = DRV_NAME,
 742        },
 743};
 744
 745module_platform_driver(pxa3xx_gcu_driver);
 746
 747MODULE_DESCRIPTION("PXA3xx graphics controller unit driver");
 748MODULE_LICENSE("GPL");
 749MODULE_ALIAS_MISCDEV(MISCDEV_MINOR);
 750MODULE_AUTHOR("Janine Kropp <nin@directfb.org>, "
 751                "Denis Oliver Kropp <dok@directfb.org>, "
 752                "Daniel Mack <daniel@caiaq.de>");
 753
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.