• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/media/video/
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