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