xref: /openbmc/linux/arch/sh/drivers/dma/dma-sh.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1ff4a7481SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * arch/sh/drivers/dma/dma-sh.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * SuperH On-chip DMAC Support
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 2000 Takashi YOSHII
81da177e4SLinus Torvalds  * Copyright (C) 2003, 2004 Paul Mundt
90d831770SPaul Mundt  * Copyright (C) 2005 Andriy Skulysh
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds #include <linux/init.h>
121da177e4SLinus Torvalds #include <linux/interrupt.h>
131da177e4SLinus Torvalds #include <linux/module.h>
147f47c718SPaul Mundt #include <linux/io.h>
1571b8064eSPaul Mundt #include <mach-dreamcast/mach/dma.h>
161da177e4SLinus Torvalds #include <asm/dma.h>
177f47c718SPaul Mundt #include <asm/dma-register.h>
187f47c718SPaul Mundt #include <cpu/dma-register.h>
197f47c718SPaul Mundt #include <cpu/dma.h>
201da177e4SLinus Torvalds 
217f47c718SPaul Mundt /*
22*e82e4758SArtur Rojek  * Some of the SoCs feature two DMAC modules. In such a case, the channels are
23*e82e4758SArtur Rojek  * distributed equally among them.
24*e82e4758SArtur Rojek  */
25*e82e4758SArtur Rojek #ifdef	SH_DMAC_BASE1
26*e82e4758SArtur Rojek #define	SH_DMAC_NR_MD_CH	(CONFIG_NR_ONCHIP_DMA_CHANNELS / 2)
27*e82e4758SArtur Rojek #else
28*e82e4758SArtur Rojek #define	SH_DMAC_NR_MD_CH	CONFIG_NR_ONCHIP_DMA_CHANNELS
29*e82e4758SArtur Rojek #endif
30*e82e4758SArtur Rojek 
31*e82e4758SArtur Rojek #define	SH_DMAC_CH_SZ		0x10
32*e82e4758SArtur Rojek 
33*e82e4758SArtur Rojek /*
347f47c718SPaul Mundt  * Define the default configuration for dual address memory-memory transfer.
357f47c718SPaul Mundt  * The 0x400 value represents auto-request, external->external.
367f47c718SPaul Mundt  */
3728564f08SGeert Uytterhoeven #define RS_DUAL	(DM_INC | SM_INC | RS_AUTO | TS_INDEX2VAL(XMIT_SZ_32BIT))
387f47c718SPaul Mundt 
dma_find_base(unsigned int chan)397f47c718SPaul Mundt static unsigned long dma_find_base(unsigned int chan)
407f47c718SPaul Mundt {
417f47c718SPaul Mundt 	unsigned long base = SH_DMAC_BASE0;
427f47c718SPaul Mundt 
437f47c718SPaul Mundt #ifdef SH_DMAC_BASE1
44*e82e4758SArtur Rojek 	if (chan >= SH_DMAC_NR_MD_CH)
457f47c718SPaul Mundt 		base = SH_DMAC_BASE1;
46bd71ab88SJamie Lenehan #endif
4771b973a4SNobuhiro Iwamatsu 
487f47c718SPaul Mundt 	return base;
497f47c718SPaul Mundt }
507f47c718SPaul Mundt 
dma_base_addr(unsigned int chan)517f47c718SPaul Mundt static unsigned long dma_base_addr(unsigned int chan)
527f47c718SPaul Mundt {
537f47c718SPaul Mundt 	unsigned long base = dma_find_base(chan);
547f47c718SPaul Mundt 
55*e82e4758SArtur Rojek 	chan = (chan % SH_DMAC_NR_MD_CH) * SH_DMAC_CH_SZ;
567f47c718SPaul Mundt 
57*e82e4758SArtur Rojek 	/* DMAOR is placed inside the channel register space. Step over it. */
58*e82e4758SArtur Rojek 	if (chan >= DMAOR)
59*e82e4758SArtur Rojek 		base += SH_DMAC_CH_SZ;
60*e82e4758SArtur Rojek 
61*e82e4758SArtur Rojek 	return base + chan;
627f47c718SPaul Mundt }
637f47c718SPaul Mundt 
647f47c718SPaul Mundt #ifdef CONFIG_SH_DMA_IRQ_MULTI
get_dmte_irq(unsigned int chan)657f47c718SPaul Mundt static inline unsigned int get_dmte_irq(unsigned int chan)
667f47c718SPaul Mundt {
677f47c718SPaul Mundt 	return chan >= 6 ? DMTE6_IRQ : DMTE0_IRQ;
687f47c718SPaul Mundt }
697f47c718SPaul Mundt #else
707f47c718SPaul Mundt 
717f47c718SPaul Mundt static unsigned int dmte_irq_map[] = {
727f47c718SPaul Mundt 	DMTE0_IRQ, DMTE0_IRQ + 1, DMTE0_IRQ + 2, DMTE0_IRQ + 3,
737f47c718SPaul Mundt 
747f47c718SPaul Mundt #ifdef DMTE4_IRQ
757f47c718SPaul Mundt 	DMTE4_IRQ, DMTE4_IRQ + 1,
767f47c718SPaul Mundt #endif
777f47c718SPaul Mundt 
787f47c718SPaul Mundt #ifdef DMTE6_IRQ
797f47c718SPaul Mundt 	DMTE6_IRQ, DMTE6_IRQ + 1,
807f47c718SPaul Mundt #endif
817f47c718SPaul Mundt 
827f47c718SPaul Mundt #ifdef DMTE8_IRQ
837f47c718SPaul Mundt 	DMTE8_IRQ, DMTE9_IRQ, DMTE10_IRQ, DMTE11_IRQ,
847f47c718SPaul Mundt #endif
85bd71ab88SJamie Lenehan };
861da177e4SLinus Torvalds 
get_dmte_irq(unsigned int chan)87bd71ab88SJamie Lenehan static inline unsigned int get_dmte_irq(unsigned int chan)
88bd71ab88SJamie Lenehan {
897f47c718SPaul Mundt 	return dmte_irq_map[chan];
901da177e4SLinus Torvalds }
917f47c718SPaul Mundt #endif
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds /*
941da177e4SLinus Torvalds  * We determine the correct shift size based off of the CHCR transmit size
951da177e4SLinus Torvalds  * for the given channel. Since we know that it will take:
961da177e4SLinus Torvalds  *
971da177e4SLinus Torvalds  *	info->count >> ts_shift[transmit_size]
981da177e4SLinus Torvalds  *
991da177e4SLinus Torvalds  * iterations to complete the transfer.
1001da177e4SLinus Torvalds  */
101623b4ac4SGuennadi Liakhovetski static unsigned int ts_shift[] = TS_SHIFT;
1027f47c718SPaul Mundt 
calc_xmit_shift(struct dma_channel * chan)1031da177e4SLinus Torvalds static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
1041da177e4SLinus Torvalds {
1057f47c718SPaul Mundt 	u32 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
106623b4ac4SGuennadi Liakhovetski 	int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) |
107623b4ac4SGuennadi Liakhovetski 		((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT);
1081da177e4SLinus Torvalds 
109623b4ac4SGuennadi Liakhovetski 	return ts_shift[cnt];
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds /*
1131da177e4SLinus Torvalds  * The transfer end interrupt must read the chcr register to end the
1141da177e4SLinus Torvalds  * hardware interrupt active condition.
1151da177e4SLinus Torvalds  * Besides that it needs to waken any waiting process, which should handle
1161da177e4SLinus Torvalds  * setting up the next transfer.
1171da177e4SLinus Torvalds  */
dma_tei(int irq,void * dev_id)11835f3c518SPaul Mundt static irqreturn_t dma_tei(int irq, void *dev_id)
1191da177e4SLinus Torvalds {
12035f3c518SPaul Mundt 	struct dma_channel *chan = dev_id;
1211da177e4SLinus Torvalds 	u32 chcr;
1221da177e4SLinus Torvalds 
1237f47c718SPaul Mundt 	chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	if (!(chcr & CHCR_TE))
1261da177e4SLinus Torvalds 		return IRQ_NONE;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	chcr &= ~(CHCR_IE | CHCR_DE);
1297f47c718SPaul Mundt 	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	wake_up(&chan->wait_queue);
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 	return IRQ_HANDLED;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
sh_dmac_request_dma(struct dma_channel * chan)1361da177e4SLinus Torvalds static int sh_dmac_request_dma(struct dma_channel *chan)
1371da177e4SLinus Torvalds {
138b2d7c7f7SJulia Lawall 	if (unlikely(!(chan->flags & DMA_TEI_CAPABLE)))
1399e3043c0SPaul Mundt 		return 0;
1409e3043c0SPaul Mundt 
1417f47c718SPaul Mundt 	return request_irq(get_dmte_irq(chan->chan), dma_tei, IRQF_SHARED,
14271b973a4SNobuhiro Iwamatsu 			   chan->dev_id, chan);
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
sh_dmac_free_dma(struct dma_channel * chan)1451da177e4SLinus Torvalds static void sh_dmac_free_dma(struct dma_channel *chan)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds 	free_irq(get_dmte_irq(chan->chan), chan);
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds 
1509f8a5e3aSManuel Lauss static int
sh_dmac_configure_channel(struct dma_channel * chan,unsigned long chcr)1510d831770SPaul Mundt sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	if (!chcr)
1540d831770SPaul Mundt 		chcr = RS_DUAL | CHCR_IE;
1550d831770SPaul Mundt 
1560d831770SPaul Mundt 	if (chcr & CHCR_IE) {
1570d831770SPaul Mundt 		chcr &= ~CHCR_IE;
1580d831770SPaul Mundt 		chan->flags |= DMA_TEI_CAPABLE;
1590d831770SPaul Mundt 	} else {
1600d831770SPaul Mundt 		chan->flags &= ~DMA_TEI_CAPABLE;
1610d831770SPaul Mundt 	}
1621da177e4SLinus Torvalds 
1637f47c718SPaul Mundt 	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	chan->flags |= DMA_CONFIGURED;
1669f8a5e3aSManuel Lauss 	return 0;
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds 
sh_dmac_enable_dma(struct dma_channel * chan)1691da177e4SLinus Torvalds static void sh_dmac_enable_dma(struct dma_channel *chan)
1701da177e4SLinus Torvalds {
1710d831770SPaul Mundt 	int irq;
1721da177e4SLinus Torvalds 	u32 chcr;
1731da177e4SLinus Torvalds 
1747f47c718SPaul Mundt 	chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
1750d831770SPaul Mundt 	chcr |= CHCR_DE;
1760d831770SPaul Mundt 
1770d831770SPaul Mundt 	if (chan->flags & DMA_TEI_CAPABLE)
1780d831770SPaul Mundt 		chcr |= CHCR_IE;
1790d831770SPaul Mundt 
1807f47c718SPaul Mundt 	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
1811da177e4SLinus Torvalds 
1820d831770SPaul Mundt 	if (chan->flags & DMA_TEI_CAPABLE) {
1830d831770SPaul Mundt 		irq = get_dmte_irq(chan->chan);
1841da177e4SLinus Torvalds 		enable_irq(irq);
1851da177e4SLinus Torvalds 	}
1860d831770SPaul Mundt }
1871da177e4SLinus Torvalds 
sh_dmac_disable_dma(struct dma_channel * chan)1881da177e4SLinus Torvalds static void sh_dmac_disable_dma(struct dma_channel *chan)
1891da177e4SLinus Torvalds {
1900d831770SPaul Mundt 	int irq;
1911da177e4SLinus Torvalds 	u32 chcr;
1921da177e4SLinus Torvalds 
1930d831770SPaul Mundt 	if (chan->flags & DMA_TEI_CAPABLE) {
1940d831770SPaul Mundt 		irq = get_dmte_irq(chan->chan);
1951da177e4SLinus Torvalds 		disable_irq(irq);
1960d831770SPaul Mundt 	}
1971da177e4SLinus Torvalds 
1987f47c718SPaul Mundt 	chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
1991da177e4SLinus Torvalds 	chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
2007f47c718SPaul Mundt 	__raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
sh_dmac_xfer_dma(struct dma_channel * chan)2031da177e4SLinus Torvalds static int sh_dmac_xfer_dma(struct dma_channel *chan)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	/*
2061da177e4SLinus Torvalds 	 * If we haven't pre-configured the channel with special flags, use
2071da177e4SLinus Torvalds 	 * the defaults.
2081da177e4SLinus Torvalds 	 */
2090d831770SPaul Mundt 	if (unlikely(!(chan->flags & DMA_CONFIGURED)))
2101da177e4SLinus Torvalds 		sh_dmac_configure_channel(chan, 0);
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	sh_dmac_disable_dma(chan);
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/*
2151da177e4SLinus Torvalds 	 * Single-address mode usage note!
2161da177e4SLinus Torvalds 	 *
2171da177e4SLinus Torvalds 	 * It's important that we don't accidentally write any value to SAR/DAR
2181da177e4SLinus Torvalds 	 * (this includes 0) that hasn't been directly specified by the user if
2191da177e4SLinus Torvalds 	 * we're in single-address mode.
2201da177e4SLinus Torvalds 	 *
2211da177e4SLinus Torvalds 	 * In this case, only one address can be defined, anything else will
2221da177e4SLinus Torvalds 	 * result in a DMA address error interrupt (at least on the SH-4),
2231da177e4SLinus Torvalds 	 * which will subsequently halt the transfer.
2241da177e4SLinus Torvalds 	 *
2251da177e4SLinus Torvalds 	 * Channel 2 on the Dreamcast is a special case, as this is used for
2261da177e4SLinus Torvalds 	 * cascading to the PVR2 DMAC. In this case, we still need to write
2271da177e4SLinus Torvalds 	 * SAR and DAR, regardless of value, in order for cascading to work.
2281da177e4SLinus Torvalds 	 */
2290d831770SPaul Mundt 	if (chan->sar || (mach_is_dreamcast() &&
2300d831770SPaul Mundt 			  chan->chan == PVR2_CASCADE_CHAN))
2317f47c718SPaul Mundt 		__raw_writel(chan->sar, (dma_base_addr(chan->chan) + SAR));
2320d831770SPaul Mundt 	if (chan->dar || (mach_is_dreamcast() &&
2330d831770SPaul Mundt 			  chan->chan == PVR2_CASCADE_CHAN))
2347f47c718SPaul Mundt 		__raw_writel(chan->dar, (dma_base_addr(chan->chan) + DAR));
2351da177e4SLinus Torvalds 
2369d56dd3bSPaul Mundt 	__raw_writel(chan->count >> calc_xmit_shift(chan),
2377f47c718SPaul Mundt 		(dma_base_addr(chan->chan) + TCR));
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	sh_dmac_enable_dma(chan);
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds 	return 0;
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds 
sh_dmac_get_dma_residue(struct dma_channel * chan)2441da177e4SLinus Torvalds static int sh_dmac_get_dma_residue(struct dma_channel *chan)
2451da177e4SLinus Torvalds {
2467f47c718SPaul Mundt 	if (!(__raw_readl(dma_base_addr(chan->chan) + CHCR) & CHCR_DE))
2471da177e4SLinus Torvalds 		return 0;
2481da177e4SLinus Torvalds 
2497f47c718SPaul Mundt 	return __raw_readl(dma_base_addr(chan->chan) + TCR)
25071b973a4SNobuhiro Iwamatsu 		 << calc_xmit_shift(chan);
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds 
2537f47c718SPaul Mundt /*
2547f47c718SPaul Mundt  * DMAOR handling
2557f47c718SPaul Mundt  */
2567f47c718SPaul Mundt #if defined(CONFIG_CPU_SUBTYPE_SH7723)	|| \
2577f47c718SPaul Mundt     defined(CONFIG_CPU_SUBTYPE_SH7724)	|| \
2587f47c718SPaul Mundt     defined(CONFIG_CPU_SUBTYPE_SH7780)	|| \
2597f47c718SPaul Mundt     defined(CONFIG_CPU_SUBTYPE_SH7785)
2607f47c718SPaul Mundt #define NR_DMAOR	2
2617f47c718SPaul Mundt #else
2627f47c718SPaul Mundt #define NR_DMAOR	1
2637f47c718SPaul Mundt #endif
2647f47c718SPaul Mundt 
265*e82e4758SArtur Rojek #define dmaor_read_reg(n)		__raw_readw(dma_find_base((n) * \
266*e82e4758SArtur Rojek 						    SH_DMAC_NR_MD_CH) + DMAOR)
267*e82e4758SArtur Rojek #define dmaor_write_reg(n, data)	__raw_writew(data, \
268*e82e4758SArtur Rojek 						     dma_find_base((n) * \
269*e82e4758SArtur Rojek 						     SH_DMAC_NR_MD_CH) + DMAOR)
2707f47c718SPaul Mundt 
dmaor_reset(int no)27171b973a4SNobuhiro Iwamatsu static inline int dmaor_reset(int no)
2720d831770SPaul Mundt {
27371b973a4SNobuhiro Iwamatsu 	unsigned long dmaor = dmaor_read_reg(no);
2740d831770SPaul Mundt 
2750d831770SPaul Mundt 	/* Try to clear the error flags first, incase they are set */
2760d831770SPaul Mundt 	dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
27771b973a4SNobuhiro Iwamatsu 	dmaor_write_reg(no, dmaor);
2780d831770SPaul Mundt 
2790d831770SPaul Mundt 	dmaor |= DMAOR_INIT;
28071b973a4SNobuhiro Iwamatsu 	dmaor_write_reg(no, dmaor);
2810d831770SPaul Mundt 
2820d831770SPaul Mundt 	/* See if we got an error again */
28371b973a4SNobuhiro Iwamatsu 	if ((dmaor_read_reg(no) & (DMAOR_AE | DMAOR_NMIF))) {
2840d831770SPaul Mundt 		printk(KERN_ERR "dma-sh: Can't initialize DMAOR.\n");
2850d831770SPaul Mundt 		return -EINVAL;
2860d831770SPaul Mundt 	}
2870d831770SPaul Mundt 
2880d831770SPaul Mundt 	return 0;
2890d831770SPaul Mundt }
2900d831770SPaul Mundt 
2917f47c718SPaul Mundt /*
2927f47c718SPaul Mundt  * DMAE handling
2937f47c718SPaul Mundt  */
2947f47c718SPaul Mundt #ifdef CONFIG_CPU_SH4
2957f47c718SPaul Mundt 
2967f47c718SPaul Mundt #if defined(DMAE1_IRQ)
2977f47c718SPaul Mundt #define NR_DMAE		2
2987f47c718SPaul Mundt #else
2997f47c718SPaul Mundt #define NR_DMAE		1
30071b973a4SNobuhiro Iwamatsu #endif
3017f47c718SPaul Mundt 
3027f47c718SPaul Mundt static const char *dmae_name[] = {
3037f47c718SPaul Mundt 	"DMAC Address Error0",
3047f47c718SPaul Mundt 	"DMAC Address Error1"
3057f47c718SPaul Mundt };
3067f47c718SPaul Mundt 
3077f47c718SPaul Mundt #ifdef CONFIG_SH_DMA_IRQ_MULTI
get_dma_error_irq(int n)3087f47c718SPaul Mundt static inline unsigned int get_dma_error_irq(int n)
3097f47c718SPaul Mundt {
3107f47c718SPaul Mundt 	return get_dmte_irq(n * 6);
31171b973a4SNobuhiro Iwamatsu }
31271b973a4SNobuhiro Iwamatsu #else
3137f47c718SPaul Mundt 
3147f47c718SPaul Mundt static unsigned int dmae_irq_map[] = {
3157f47c718SPaul Mundt 	DMAE0_IRQ,
3167f47c718SPaul Mundt 
3177f47c718SPaul Mundt #ifdef DMAE1_IRQ
3187f47c718SPaul Mundt 	DMAE1_IRQ,
31971b973a4SNobuhiro Iwamatsu #endif
3207f47c718SPaul Mundt };
3217f47c718SPaul Mundt 
get_dma_error_irq(int n)3227f47c718SPaul Mundt static inline unsigned int get_dma_error_irq(int n)
3237f47c718SPaul Mundt {
3247f47c718SPaul Mundt 	return dmae_irq_map[n];
3257f47c718SPaul Mundt }
3267f47c718SPaul Mundt #endif
3277f47c718SPaul Mundt 
dma_err(int irq,void * dummy)3287f47c718SPaul Mundt static irqreturn_t dma_err(int irq, void *dummy)
3297f47c718SPaul Mundt {
3307f47c718SPaul Mundt 	int i;
3317f47c718SPaul Mundt 
3327f47c718SPaul Mundt 	for (i = 0; i < NR_DMAOR; i++)
3337f47c718SPaul Mundt 		dmaor_reset(i);
3347f47c718SPaul Mundt 
3351da177e4SLinus Torvalds 	disable_irq(irq);
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	return IRQ_HANDLED;
3387f47c718SPaul Mundt }
3397f47c718SPaul Mundt 
dmae_irq_init(void)3407f47c718SPaul Mundt static int dmae_irq_init(void)
3417f47c718SPaul Mundt {
3427f47c718SPaul Mundt 	int n;
3437f47c718SPaul Mundt 
3447f47c718SPaul Mundt 	for (n = 0; n < NR_DMAE; n++) {
3457f47c718SPaul Mundt 		int i = request_irq(get_dma_error_irq(n), dma_err,
346800fb3ddSMike Frysinger 				    IRQF_SHARED, dmae_name[n], (void *)dmae_name[n]);
3477f47c718SPaul Mundt 		if (unlikely(i < 0)) {
3487f47c718SPaul Mundt 			printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
3497f47c718SPaul Mundt 			return i;
3507f47c718SPaul Mundt 		}
3517f47c718SPaul Mundt 	}
3527f47c718SPaul Mundt 
3537f47c718SPaul Mundt 	return 0;
3547f47c718SPaul Mundt }
3557f47c718SPaul Mundt 
dmae_irq_free(void)3567f47c718SPaul Mundt static void dmae_irq_free(void)
3577f47c718SPaul Mundt {
3587f47c718SPaul Mundt 	int n;
3597f47c718SPaul Mundt 
3607f47c718SPaul Mundt 	for (n = 0; n < NR_DMAE; n++)
3617f47c718SPaul Mundt 		free_irq(get_dma_error_irq(n), NULL);
3627f47c718SPaul Mundt }
3637f47c718SPaul Mundt #else
dmae_irq_init(void)3647f47c718SPaul Mundt static inline int dmae_irq_init(void)
3657f47c718SPaul Mundt {
3667f47c718SPaul Mundt 	return 0;
3677f47c718SPaul Mundt }
3687f47c718SPaul Mundt 
dmae_irq_free(void)3697f47c718SPaul Mundt static void dmae_irq_free(void)
3707f47c718SPaul Mundt {
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds #endif
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds static struct dma_ops sh_dmac_ops = {
3751da177e4SLinus Torvalds 	.request	= sh_dmac_request_dma,
3761da177e4SLinus Torvalds 	.free		= sh_dmac_free_dma,
3771da177e4SLinus Torvalds 	.get_residue	= sh_dmac_get_dma_residue,
3781da177e4SLinus Torvalds 	.xfer		= sh_dmac_xfer_dma,
3791da177e4SLinus Torvalds 	.configure	= sh_dmac_configure_channel,
3801da177e4SLinus Torvalds };
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds static struct dma_info sh_dmac_info = {
3830d831770SPaul Mundt 	.name		= "sh_dmac",
3840d831770SPaul Mundt 	.nr_channels	= CONFIG_NR_ONCHIP_DMA_CHANNELS,
3851da177e4SLinus Torvalds 	.ops		= &sh_dmac_ops,
3861da177e4SLinus Torvalds 	.flags		= DMAC_CHANNELS_TEI_CAPABLE,
3871da177e4SLinus Torvalds };
3881da177e4SLinus Torvalds 
sh_dmac_init(void)3891da177e4SLinus Torvalds static int __init sh_dmac_init(void)
3901da177e4SLinus Torvalds {
3911da177e4SLinus Torvalds 	struct dma_info *info = &sh_dmac_info;
3927f47c718SPaul Mundt 	int i, rc;
3931da177e4SLinus Torvalds 
3947f47c718SPaul Mundt 	/*
3957f47c718SPaul Mundt 	 * Initialize DMAE, for parts that support it.
3967f47c718SPaul Mundt 	 */
3977f47c718SPaul Mundt 	rc = dmae_irq_init();
3987f47c718SPaul Mundt 	if (unlikely(rc != 0))
3997f47c718SPaul Mundt 		return rc;
4001da177e4SLinus Torvalds 
4010d831770SPaul Mundt 	/*
4020d831770SPaul Mundt 	 * Initialize DMAOR, and clean up any error flags that may have
4030d831770SPaul Mundt 	 * been set.
4040d831770SPaul Mundt 	 */
4057f47c718SPaul Mundt 	for (i = 0; i < NR_DMAOR; i++) {
4067f47c718SPaul Mundt 		rc = dmaor_reset(i);
4077f47c718SPaul Mundt 		if (unlikely(rc != 0))
4087f47c718SPaul Mundt 			return rc;
4097f47c718SPaul Mundt 	}
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	return register_dmac(info);
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
sh_dmac_exit(void)4141da177e4SLinus Torvalds static void __exit sh_dmac_exit(void)
4151da177e4SLinus Torvalds {
4167f47c718SPaul Mundt 	dmae_irq_free();
4170d831770SPaul Mundt 	unregister_dmac(&sh_dmac_info);
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds subsys_initcall(sh_dmac_init);
4211da177e4SLinus Torvalds module_exit(sh_dmac_exit);
4221da177e4SLinus Torvalds 
4230d831770SPaul Mundt MODULE_AUTHOR("Takashi YOSHII, Paul Mundt, Andriy Skulysh");
4240d831770SPaul Mundt MODULE_DESCRIPTION("SuperH On-Chip DMAC Support");
425ff4a7481SKuninori Morimoto MODULE_LICENSE("GPL v2");
426