linux/drivers/media/video/omap24xxcam-dma.c
<<
>>
Prefs
   1/*
   2 * drivers/media/video/omap24xxcam-dma.c
   3 *
   4 * Copyright (C) 2004 MontaVista Software, Inc.
   5 * Copyright (C) 2004 Texas Instruments.
   6 * Copyright (C) 2007 Nokia Corporation.
   7 *
   8 * Contact: Sakari Ailus <sakari.ailus@nokia.com>
   9 *
  10 * Based on code from Andy Lowe <source@mvista.com> and
  11 *                    David Cohen <david.cohen@indt.org.br>.
  12 *
  13 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License
  15 * version 2 as published by the Free Software Foundation.
  16 *
  17 * This program is distributed in the hope that it will be useful, but
  18 * WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20 * General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  25 * 02110-1301 USA
  26 */
  27
  28#include <linux/kernel.h>
  29#include <linux/io.h>
  30#include <linux/scatterlist.h>
  31
  32#include "omap24xxcam.h"
  33
  34/*
  35 *
  36 * DMA hardware.
  37 *
  38 */
  39
  40/* Ack all interrupt on CSR and IRQSTATUS_L0 */
  41static void omap24xxcam_dmahw_ack_all(unsigned long base)
  42{
  43        u32 csr;
  44        int i;
  45
  46        for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
  47                csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
  48                /* ack interrupt in CSR */
  49                omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
  50        }
  51        omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
  52}
  53
  54/* Ack dmach on CSR and IRQSTATUS_L0 */
  55static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
  56{
  57        u32 csr;
  58
  59        csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
  60        /* ack interrupt in CSR */
  61        omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
  62        /* ack interrupt in IRQSTATUS */
  63        omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
  64
  65        return csr;
  66}
  67
  68static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
  69{
  70        return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
  71}
  72
  73static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
  74                                             dma_addr_t start, u32 len)
  75{
  76        omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
  77                            CAMDMA_CCR_SEL_SRC_DST_SYNC
  78                            | CAMDMA_CCR_BS
  79                            | CAMDMA_CCR_DST_AMODE_POST_INC
  80                            | CAMDMA_CCR_SRC_AMODE_POST_INC
  81                            | CAMDMA_CCR_FS
  82                            | CAMDMA_CCR_WR_ACTIVE
  83                            | CAMDMA_CCR_RD_ACTIVE
  84                            | CAMDMA_CCR_SYNCHRO_CAMERA);
  85        omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
  86        omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
  87        omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
  88        omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
  89                            CAMDMA_CSDP_WRITE_MODE_POSTED
  90                            | CAMDMA_CSDP_DST_BURST_EN_32
  91                            | CAMDMA_CSDP_DST_PACKED
  92                            | CAMDMA_CSDP_SRC_BURST_EN_32
  93                            | CAMDMA_CSDP_SRC_PACKED
  94                            | CAMDMA_CSDP_DATA_TYPE_8BITS);
  95        omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
  96        omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
  97        omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
  98        omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
  99        omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
 100        omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
 101        omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
 102                            CAMDMA_CSR_MISALIGNED_ERR
 103                            | CAMDMA_CSR_SECURE_ERR
 104                            | CAMDMA_CSR_TRANS_ERR
 105                            | CAMDMA_CSR_BLOCK
 106                            | CAMDMA_CSR_DROP);
 107        omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
 108                            CAMDMA_CICR_MISALIGNED_ERR_IE
 109                            | CAMDMA_CICR_SECURE_ERR_IE
 110                            | CAMDMA_CICR_TRANS_ERR_IE
 111                            | CAMDMA_CICR_BLOCK_IE
 112                            | CAMDMA_CICR_DROP_IE);
 113}
 114
 115static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
 116{
 117        omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
 118                            CAMDMA_CCR_SEL_SRC_DST_SYNC
 119                            | CAMDMA_CCR_BS
 120                            | CAMDMA_CCR_DST_AMODE_POST_INC
 121                            | CAMDMA_CCR_SRC_AMODE_POST_INC
 122                            | CAMDMA_CCR_ENABLE
 123                            | CAMDMA_CCR_FS
 124                            | CAMDMA_CCR_SYNCHRO_CAMERA);
 125}
 126
 127static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
 128                                             int free_dmach)
 129{
 130        int prev_dmach, ch;
 131
 132        if (dmach == 0)
 133                prev_dmach = NUM_CAMDMA_CHANNELS - 1;
 134        else
 135                prev_dmach = dmach - 1;
 136        omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
 137                            CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
 138        /* Did we chain the DMA transfer before the previous one
 139         * finished?
 140         */
 141        ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
 142        while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
 143                 & CAMDMA_CCR_ENABLE)) {
 144                if (ch == dmach) {
 145                        /* The previous transfer has ended and this one
 146                         * hasn't started, so we must not have chained
 147                         * to the previous one in time.  We'll have to
 148                         * start it now.
 149                         */
 150                        omap24xxcam_dmahw_transfer_start(base, dmach);
 151                        break;
 152                } else
 153                        ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
 154        }
 155}
 156
 157/* Abort all chained DMA transfers. After all transfers have been
 158 * aborted and the DMA controller is idle, the completion routines for
 159 * any aborted transfers will be called in sequence. The DMA
 160 * controller may not be idle after this routine completes, because
 161 * the completion routines might start new transfers.
 162 */
 163static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
 164{
 165        /* mask all interrupts from this channel */
 166        omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
 167        /* unlink this channel */
 168        omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
 169                              CAMDMA_CLNK_CTRL_ENABLE_LNK);
 170        /* disable this channel */
 171        omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
 172}
 173
 174static void omap24xxcam_dmahw_init(unsigned long base)
 175{
 176        omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
 177                            CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
 178                            | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
 179                            | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
 180
 181        omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
 182                              CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
 183
 184        omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
 185}
 186
 187/*
 188 *
 189 * Individual DMA channel handling.
 190 *
 191 */
 192
 193/* Start a DMA transfer from the camera to memory.
 194 * Returns zero if the transfer was successfully started, or non-zero if all
 195 * DMA channels are already in use or starting is currently inhibited.
 196 */
 197static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
 198                                 u32 len, dma_callback_t callback, void *arg)
 199{
 200        unsigned long flags;
 201        int dmach;
 202
 203        spin_lock_irqsave(&dma->lock, flags);
 204
 205        if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
 206                spin_unlock_irqrestore(&dma->lock, flags);
 207                return -EBUSY;
 208        }
 209
 210        dmach = dma->next_dmach;
 211
 212        dma->ch_state[dmach].callback = callback;
 213        dma->ch_state[dmach].arg = arg;
 214
 215        omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
 216
 217        /* We're ready to start the DMA transfer. */
 218
 219        if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
 220                /* A transfer is already in progress, so try to chain to it. */
 221                omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
 222                                                 dma->free_dmach);
 223        } else {
 224                /* No transfer is in progress, so we'll just start this one
 225                 * now.
 226                 */
 227                omap24xxcam_dmahw_transfer_start(dma->base, dmach);
 228        }
 229
 230        dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
 231        dma->free_dmach--;
 232
 233        spin_unlock_irqrestore(&dma->lock, flags);
 234
 235        return 0;
 236}
 237
 238/* Abort all chained DMA transfers. After all transfers have been
 239 * aborted and the DMA controller is idle, the completion routines for
 240 * any aborted transfers will be called in sequence. The DMA
 241 * controller may not be idle after this routine completes, because
 242 * the completion routines might start new transfers.
 243 */
 244static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
 245{
 246        unsigned long flags;
 247        int dmach, i, free_dmach;
 248        dma_callback_t callback;
 249        void *arg;
 250
 251        spin_lock_irqsave(&dma->lock, flags);
 252
 253        /* stop any DMA transfers in progress */
 254        dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
 255        for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
 256                omap24xxcam_dmahw_abort_ch(dma->base, dmach);
 257                dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
 258        }
 259
 260        /* We have to be careful here because the callback routine
 261         * might start a new DMA transfer, and we only want to abort
 262         * transfers that were started before this routine was called.
 263         */
 264        free_dmach = dma->free_dmach;
 265        while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
 266               (free_dmach < NUM_CAMDMA_CHANNELS)) {
 267                dmach = (dma->next_dmach + dma->free_dmach)
 268                        % NUM_CAMDMA_CHANNELS;
 269                callback = dma->ch_state[dmach].callback;
 270                arg = dma->ch_state[dmach].arg;
 271                dma->free_dmach++;
 272                free_dmach++;
 273                if (callback) {
 274                        /* leave interrupts disabled during callback */
 275                        spin_unlock(&dma->lock);
 276                        (*callback) (dma, csr, arg);
 277                        spin_lock(&dma->lock);
 278                }
 279        }
 280
 281        spin_unlock_irqrestore(&dma->lock, flags);
 282}
 283
 284/* Abort all chained DMA transfers. After all transfers have been
 285 * aborted and the DMA controller is idle, the completion routines for
 286 * any aborted transfers will be called in sequence. If the completion
 287 * routines attempt to start a new DMA transfer it will fail, so the
 288 * DMA controller will be idle after this routine completes.
 289 */
 290static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
 291{
 292        atomic_inc(&dma->dma_stop);
 293        omap24xxcam_dma_abort(dma, csr);
 294        atomic_dec(&dma->dma_stop);
 295}
 296
 297/* Camera DMA interrupt service routine. */
 298void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
 299{
 300        int dmach;
 301        dma_callback_t callback;
 302        void *arg;
 303        u32 csr;
 304        const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
 305                | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
 306                | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
 307
 308        spin_lock(&dma->lock);
 309
 310        if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
 311                /* A camera DMA interrupt occurred while all channels
 312                 * are idle, so we'll acknowledge the interrupt in the
 313                 * IRQSTATUS register and exit.
 314                 */
 315                omap24xxcam_dmahw_ack_all(dma->base);
 316                spin_unlock(&dma->lock);
 317                return;
 318        }
 319
 320        while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
 321                dmach = (dma->next_dmach + dma->free_dmach)
 322                        % NUM_CAMDMA_CHANNELS;
 323                if (omap24xxcam_dmahw_running(dma->base, dmach)) {
 324                        /* This buffer hasn't finished yet, so we're done. */
 325                        break;
 326                }
 327                csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
 328                if (csr & csr_error) {
 329                        /* A DMA error occurred, so stop all DMA
 330                         * transfers in progress.
 331                         */
 332                        spin_unlock(&dma->lock);
 333                        omap24xxcam_dma_stop(dma, csr);
 334                        return;
 335                } else {
 336                        callback = dma->ch_state[dmach].callback;
 337                        arg = dma->ch_state[dmach].arg;
 338                        dma->free_dmach++;
 339                        if (callback) {
 340                                spin_unlock(&dma->lock);
 341                                (*callback) (dma, csr, arg);
 342                                spin_lock(&dma->lock);
 343                        }
 344                }
 345        }
 346
 347        spin_unlock(&dma->lock);
 348
 349        omap24xxcam_sgdma_process(
 350                container_of(dma, struct omap24xxcam_sgdma, dma));
 351}
 352
 353void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
 354{
 355        unsigned long flags;
 356
 357        spin_lock_irqsave(&dma->lock, flags);
 358
 359        omap24xxcam_dmahw_init(dma->base);
 360
 361        spin_unlock_irqrestore(&dma->lock, flags);
 362}
 363
 364static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
 365                                 unsigned long base)
 366{
 367        int ch;
 368
 369        /* group all channels on DMA IRQ0 and unmask irq */
 370        spin_lock_init(&dma->lock);
 371        dma->base = base;
 372        dma->free_dmach = NUM_CAMDMA_CHANNELS;
 373        dma->next_dmach = 0;
 374        for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
 375                dma->ch_state[ch].callback = NULL;
 376                dma->ch_state[ch].arg = NULL;
 377        }
 378}
 379
 380/*
 381 *
 382 * Scatter-gather DMA.
 383 *
 384 * High-level DMA construct for transferring whole picture frames to
 385 * memory that is discontinuous.
 386 *
 387 */
 388
 389/* DMA completion routine for the scatter-gather DMA fragments. */
 390static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
 391                                       void *arg)
 392{
 393        struct omap24xxcam_sgdma *sgdma =
 394                container_of(dma, struct omap24xxcam_sgdma, dma);
 395        int sgslot = (int)arg;
 396        struct sgdma_state *sg_state;
 397        const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
 398                | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
 399                | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
 400
 401        spin_lock(&sgdma->lock);
 402
 403        /* We got an interrupt, we can remove the timer */
 404        del_timer(&sgdma->reset_timer);
 405
 406        sg_state = sgdma->sg_state + sgslot;
 407        if (!sg_state->queued_sglist) {
 408                spin_unlock(&sgdma->lock);
 409                printk(KERN_ERR "%s: sgdma completed when none queued!\n",
 410                       __func__);
 411                return;
 412        }
 413
 414        sg_state->csr |= csr;
 415        if (!--sg_state->queued_sglist) {
 416                /* Queue for this sglist is empty, so check to see if we're
 417                 * done.
 418                 */
 419                if ((sg_state->next_sglist == sg_state->sglen)
 420                    || (sg_state->csr & csr_error)) {
 421                        sgdma_callback_t callback = sg_state->callback;
 422                        void *arg = sg_state->arg;
 423                        u32 sg_csr = sg_state->csr;
 424                        /* All done with this sglist */
 425                        sgdma->free_sgdma++;
 426                        if (callback) {
 427                                spin_unlock(&sgdma->lock);
 428                                (*callback) (sgdma, sg_csr, arg);
 429                                return;
 430                        }
 431                }
 432        }
 433
 434        spin_unlock(&sgdma->lock);
 435}
 436
 437/* Start queued scatter-gather DMA transfers. */
 438void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
 439{
 440        unsigned long flags;
 441        int queued_sgdma, sgslot;
 442        struct sgdma_state *sg_state;
 443        const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
 444                | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
 445                | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
 446
 447        spin_lock_irqsave(&sgdma->lock, flags);
 448
 449        queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
 450        sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
 451        while (queued_sgdma > 0) {
 452                sg_state = sgdma->sg_state + sgslot;
 453                while ((sg_state->next_sglist < sg_state->sglen) &&
 454                       !(sg_state->csr & csr_error)) {
 455                        const struct scatterlist *sglist;
 456                        unsigned int len;
 457
 458                        sglist = sg_state->sglist + sg_state->next_sglist;
 459                        /* try to start the next DMA transfer */
 460                        if (sg_state->next_sglist + 1 == sg_state->sglen) {
 461                                /*
 462                                 *  On the last sg, we handle the case where
 463                                 *  cam->img.pix.sizeimage % PAGE_ALIGN != 0
 464                                 */
 465                                len = sg_state->len - sg_state->bytes_read;
 466                        } else {
 467                                len = sg_dma_len(sglist);
 468                        }
 469
 470                        if (omap24xxcam_dma_start(&sgdma->dma,
 471                                                  sg_dma_address(sglist),
 472                                                  len,
 473                                                  omap24xxcam_sgdma_callback,
 474                                                  (void *)sgslot)) {
 475                                /* DMA start failed */
 476                                spin_unlock_irqrestore(&sgdma->lock, flags);
 477                                return;
 478                        } else {
 479                                unsigned long expires;
 480                                /* DMA start was successful */
 481                                sg_state->next_sglist++;
 482                                sg_state->bytes_read += len;
 483                                sg_state->queued_sglist++;
 484
 485                                /* We start the reset timer */
 486                                expires = jiffies + HZ;
 487                                mod_timer(&sgdma->reset_timer, expires);
 488                        }
 489                }
 490                queued_sgdma--;
 491                sgslot = (sgslot + 1) % NUM_SG_DMA;
 492        }
 493
 494        spin_unlock_irqrestore(&sgdma->lock, flags);
 495}
 496
 497/*
 498 * Queue a scatter-gather DMA transfer from the camera to memory.
 499 * Returns zero if the transfer was successfully queued, or non-zero
 500 * if all of the scatter-gather slots are already in use.
 501 */
 502int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
 503                            const struct scatterlist *sglist, int sglen,
 504                            int len, sgdma_callback_t callback, void *arg)
 505{
 506        unsigned long flags;
 507        struct sgdma_state *sg_state;
 508
 509        if ((sglen < 0) || ((sglen > 0) & !sglist))
 510                return -EINVAL;
 511
 512        spin_lock_irqsave(&sgdma->lock, flags);
 513
 514        if (!sgdma->free_sgdma) {
 515                spin_unlock_irqrestore(&sgdma->lock, flags);
 516                return -EBUSY;
 517        }
 518
 519        sg_state = sgdma->sg_state + sgdma->next_sgdma;
 520
 521        sg_state->sglist = sglist;
 522        sg_state->sglen = sglen;
 523        sg_state->next_sglist = 0;
 524        sg_state->bytes_read = 0;
 525        sg_state->len = len;
 526        sg_state->queued_sglist = 0;
 527        sg_state->csr = 0;
 528        sg_state->callback = callback;
 529        sg_state->arg = arg;
 530
 531        sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
 532        sgdma->free_sgdma--;
 533
 534        spin_unlock_irqrestore(&sgdma->lock, flags);
 535
 536        omap24xxcam_sgdma_process(sgdma);
 537
 538        return 0;
 539}
 540
 541/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
 542 * Any queued scatter-gather DMA transactions that have not yet been started
 543 * will remain queued.  The DMA controller will be idle after this routine
 544 * completes.  When the scatter-gather queue is restarted, the next
 545 * scatter-gather DMA transfer will begin at the start of a new transaction.
 546 */
 547void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
 548{
 549        unsigned long flags;
 550        int sgslot;
 551        struct sgdma_state *sg_state;
 552        u32 csr = CAMDMA_CSR_TRANS_ERR;
 553
 554        /* stop any DMA transfers in progress */
 555        omap24xxcam_dma_stop(&sgdma->dma, csr);
 556
 557        spin_lock_irqsave(&sgdma->lock, flags);
 558
 559        if (sgdma->free_sgdma < NUM_SG_DMA) {
 560                sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
 561                sg_state = sgdma->sg_state + sgslot;
 562                if (sg_state->next_sglist != 0) {
 563                        /* This DMA transfer was in progress, so abort it. */
 564                        sgdma_callback_t callback = sg_state->callback;
 565                        void *arg = sg_state->arg;
 566                        sgdma->free_sgdma++;
 567                        if (callback) {
 568                                /* leave interrupts masked */
 569                                spin_unlock(&sgdma->lock);
 570                                (*callback) (sgdma, csr, arg);
 571                                spin_lock(&sgdma->lock);
 572                        }
 573                }
 574        }
 575
 576        spin_unlock_irqrestore(&sgdma->lock, flags);
 577}
 578
 579void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
 580                            unsigned long base,
 581                            void (*reset_callback)(unsigned long data),
 582                            unsigned long reset_callback_data)
 583{
 584        int sg;
 585
 586        spin_lock_init(&sgdma->lock);
 587        sgdma->free_sgdma = NUM_SG_DMA;
 588        sgdma->next_sgdma = 0;
 589        for (sg = 0; sg < NUM_SG_DMA; sg++) {
 590                sgdma->sg_state[sg].sglen = 0;
 591                sgdma->sg_state[sg].next_sglist = 0;
 592                sgdma->sg_state[sg].bytes_read = 0;
 593                sgdma->sg_state[sg].queued_sglist = 0;
 594                sgdma->sg_state[sg].csr = 0;
 595                sgdma->sg_state[sg].callback = NULL;
 596                sgdma->sg_state[sg].arg = NULL;
 597        }
 598
 599        omap24xxcam_dma_init(&sgdma->dma, base);
 600        setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
 601}
 602