2 * Renesas SUDMAC support
4 * Copyright (C) 2013 Renesas Solutions Corp.
6 * based on drivers/dma/sh/shdma.c:
7 * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
8 * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
9 * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
10 * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
12 * This is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
17 #include <linux/dmaengine.h>
18 #include <linux/err.h>
19 #include <linux/init.h>
20 #include <linux/interrupt.h>
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/sudmac.h>
27 struct shdma_chan shdma_chan
;
29 char dev_id
[16]; /* unique name per DMAC of channel */
31 u32 offset
; /* for CFG, BA, BBC, CA, CBC, DEN */
36 struct sudmac_device
{
37 struct shdma_dev shdma_dev
;
38 struct sudmac_pdata
*pdata
;
39 void __iomem
*chan_reg
;
48 struct sudmac_regs hw
;
49 struct shdma_desc shdma_desc
;
52 #define to_chan(schan) container_of(schan, struct sudmac_chan, shdma_chan)
53 #define to_desc(sdesc) container_of(sdesc, struct sudmac_desc, shdma_desc)
54 #define to_sdev(sc) container_of(sc->shdma_chan.dma_chan.device, \
55 struct sudmac_device, shdma_dev.dma_dev)
58 #define SUDMAC_CH0CFG 0x00
59 #define SUDMAC_CH0BA 0x10
60 #define SUDMAC_CH0BBC 0x18
61 #define SUDMAC_CH0CA 0x20
62 #define SUDMAC_CH0CBC 0x28
63 #define SUDMAC_CH0DEN 0x30
64 #define SUDMAC_DSTSCLR 0x38
65 #define SUDMAC_DBUFCTRL 0x3C
66 #define SUDMAC_DINTCTRL 0x40
67 #define SUDMAC_DINTSTS 0x44
68 #define SUDMAC_DINTSTSCLR 0x48
69 #define SUDMAC_CH0SHCTRL 0x50
71 /* Definitions for the sudmac_channel.config */
72 #define SUDMAC_SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */
73 #define SUDMAC_RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */
74 #define SUDMAC_LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */
76 /* Definitions for the sudmac_channel.dint_end_bit */
77 #define SUDMAC_CH1ENDE 0x0002 /* b1: Ch1 DMA Transfer End Int Enable */
78 #define SUDMAC_CH0ENDE 0x0001 /* b0: Ch0 DMA Transfer End Int Enable */
80 #define SUDMAC_DRV_NAME "sudmac"
82 static void sudmac_writel(struct sudmac_chan
*sc
, u32 data
, u32 reg
)
84 iowrite32(data
, sc
->base
+ reg
);
87 static u32
sudmac_readl(struct sudmac_chan
*sc
, u32 reg
)
89 return ioread32(sc
->base
+ reg
);
92 static bool sudmac_is_busy(struct sudmac_chan
*sc
)
94 u32 den
= sudmac_readl(sc
, SUDMAC_CH0DEN
+ sc
->offset
);
97 return true; /* working */
99 return false; /* waiting */
102 static void sudmac_set_reg(struct sudmac_chan
*sc
, struct sudmac_regs
*hw
,
103 struct shdma_desc
*sdesc
)
105 sudmac_writel(sc
, sc
->cfg
, SUDMAC_CH0CFG
+ sc
->offset
);
106 sudmac_writel(sc
, hw
->base_addr
, SUDMAC_CH0BA
+ sc
->offset
);
107 sudmac_writel(sc
, hw
->base_byte_count
, SUDMAC_CH0BBC
+ sc
->offset
);
110 static void sudmac_start(struct sudmac_chan
*sc
)
112 u32 dintctrl
= sudmac_readl(sc
, SUDMAC_DINTCTRL
);
114 sudmac_writel(sc
, dintctrl
| sc
->dint_end_bit
, SUDMAC_DINTCTRL
);
115 sudmac_writel(sc
, 1, SUDMAC_CH0DEN
+ sc
->offset
);
118 static void sudmac_start_xfer(struct shdma_chan
*schan
,
119 struct shdma_desc
*sdesc
)
121 struct sudmac_chan
*sc
= to_chan(schan
);
122 struct sudmac_desc
*sd
= to_desc(sdesc
);
124 sudmac_set_reg(sc
, &sd
->hw
, sdesc
);
128 static bool sudmac_channel_busy(struct shdma_chan
*schan
)
130 struct sudmac_chan
*sc
= to_chan(schan
);
132 return sudmac_is_busy(sc
);
135 static void sudmac_setup_xfer(struct shdma_chan
*schan
, int slave_id
)
139 static const struct sudmac_slave_config
*sudmac_find_slave(
140 struct sudmac_chan
*sc
, int slave_id
)
142 struct sudmac_device
*sdev
= to_sdev(sc
);
143 struct sudmac_pdata
*pdata
= sdev
->pdata
;
144 const struct sudmac_slave_config
*cfg
;
147 for (i
= 0, cfg
= pdata
->slave
; i
< pdata
->slave_num
; i
++, cfg
++)
148 if (cfg
->slave_id
== slave_id
)
154 static int sudmac_set_slave(struct shdma_chan
*schan
, int slave_id
,
155 dma_addr_t slave_addr
, bool try)
157 struct sudmac_chan
*sc
= to_chan(schan
);
158 const struct sudmac_slave_config
*cfg
= sudmac_find_slave(sc
, slave_id
);
166 static inline void sudmac_dma_halt(struct sudmac_chan
*sc
)
168 u32 dintctrl
= sudmac_readl(sc
, SUDMAC_DINTCTRL
);
170 sudmac_writel(sc
, 0, SUDMAC_CH0DEN
+ sc
->offset
);
171 sudmac_writel(sc
, dintctrl
& ~sc
->dint_end_bit
, SUDMAC_DINTCTRL
);
172 sudmac_writel(sc
, sc
->dint_end_bit
, SUDMAC_DINTSTSCLR
);
175 static int sudmac_desc_setup(struct shdma_chan
*schan
,
176 struct shdma_desc
*sdesc
,
177 dma_addr_t src
, dma_addr_t dst
, size_t *len
)
179 struct sudmac_chan
*sc
= to_chan(schan
);
180 struct sudmac_desc
*sd
= to_desc(sdesc
);
182 dev_dbg(sc
->shdma_chan
.dev
, "%s: src=%pad, dst=%pad, len=%zu\n",
183 __func__
, &src
, &dst
, *len
);
185 if (*len
> schan
->max_xfer_len
)
186 *len
= schan
->max_xfer_len
;
189 sd
->hw
.base_addr
= dst
;
191 sd
->hw
.base_addr
= src
;
192 sd
->hw
.base_byte_count
= *len
;
197 static void sudmac_halt(struct shdma_chan
*schan
)
199 struct sudmac_chan
*sc
= to_chan(schan
);
204 static bool sudmac_chan_irq(struct shdma_chan
*schan
, int irq
)
206 struct sudmac_chan
*sc
= to_chan(schan
);
207 u32 dintsts
= sudmac_readl(sc
, SUDMAC_DINTSTS
);
209 if (!(dintsts
& sc
->dint_end_bit
))
218 static size_t sudmac_get_partial(struct shdma_chan
*schan
,
219 struct shdma_desc
*sdesc
)
221 struct sudmac_chan
*sc
= to_chan(schan
);
222 struct sudmac_desc
*sd
= to_desc(sdesc
);
223 u32 current_byte_count
= sudmac_readl(sc
, SUDMAC_CH0CBC
+ sc
->offset
);
225 return sd
->hw
.base_byte_count
- current_byte_count
;
228 static bool sudmac_desc_completed(struct shdma_chan
*schan
,
229 struct shdma_desc
*sdesc
)
231 struct sudmac_chan
*sc
= to_chan(schan
);
232 struct sudmac_desc
*sd
= to_desc(sdesc
);
233 u32 current_addr
= sudmac_readl(sc
, SUDMAC_CH0CA
+ sc
->offset
);
235 return sd
->hw
.base_addr
+ sd
->hw
.base_byte_count
== current_addr
;
238 static int sudmac_chan_probe(struct sudmac_device
*su_dev
, int id
, int irq
,
241 struct shdma_dev
*sdev
= &su_dev
->shdma_dev
;
242 struct platform_device
*pdev
= to_platform_device(sdev
->dma_dev
.dev
);
243 struct sudmac_chan
*sc
;
244 struct shdma_chan
*schan
;
247 sc
= devm_kzalloc(&pdev
->dev
, sizeof(struct sudmac_chan
), GFP_KERNEL
);
251 schan
= &sc
->shdma_chan
;
252 schan
->max_xfer_len
= 64 * 1024 * 1024 - 1;
254 shdma_chan_probe(sdev
, schan
, id
);
256 sc
->base
= su_dev
->chan_reg
;
258 /* get platform_data */
259 sc
->offset
= su_dev
->pdata
->channel
->offset
;
260 if (su_dev
->pdata
->channel
->config
& SUDMAC_TX_BUFFER_MODE
)
261 sc
->cfg
|= SUDMAC_SENDBUFM
;
262 if (su_dev
->pdata
->channel
->config
& SUDMAC_RX_END_MODE
)
263 sc
->cfg
|= SUDMAC_RCVENDM
;
264 sc
->cfg
|= (su_dev
->pdata
->channel
->wait
<< 4) & SUDMAC_LBA_WAIT
;
266 if (su_dev
->pdata
->channel
->dint_end_bit
& SUDMAC_DMA_BIT_CH0
)
267 sc
->dint_end_bit
|= SUDMAC_CH0ENDE
;
268 if (su_dev
->pdata
->channel
->dint_end_bit
& SUDMAC_DMA_BIT_CH1
)
269 sc
->dint_end_bit
|= SUDMAC_CH1ENDE
;
271 /* set up channel irq */
273 snprintf(sc
->dev_id
, sizeof(sc
->dev_id
), "sudmac%d.%d",
276 snprintf(sc
->dev_id
, sizeof(sc
->dev_id
), "sudmac%d", id
);
278 err
= shdma_request_irq(schan
, irq
, flags
, sc
->dev_id
);
280 dev_err(sdev
->dma_dev
.dev
,
281 "DMA channel %d request_irq failed %d\n", id
, err
);
288 /* remove from dmaengine device node */
289 shdma_chan_remove(schan
);
293 static void sudmac_chan_remove(struct sudmac_device
*su_dev
)
295 struct shdma_chan
*schan
;
298 shdma_for_each_chan(schan
, &su_dev
->shdma_dev
, i
) {
301 shdma_chan_remove(schan
);
305 static dma_addr_t
sudmac_slave_addr(struct shdma_chan
*schan
)
307 /* SUDMAC doesn't need the address */
311 static struct shdma_desc
*sudmac_embedded_desc(void *buf
, int i
)
313 return &((struct sudmac_desc
*)buf
)[i
].shdma_desc
;
316 static const struct shdma_ops sudmac_shdma_ops
= {
317 .desc_completed
= sudmac_desc_completed
,
318 .halt_channel
= sudmac_halt
,
319 .channel_busy
= sudmac_channel_busy
,
320 .slave_addr
= sudmac_slave_addr
,
321 .desc_setup
= sudmac_desc_setup
,
322 .set_slave
= sudmac_set_slave
,
323 .setup_xfer
= sudmac_setup_xfer
,
324 .start_xfer
= sudmac_start_xfer
,
325 .embedded_desc
= sudmac_embedded_desc
,
326 .chan_irq
= sudmac_chan_irq
,
327 .get_partial
= sudmac_get_partial
,
330 static int sudmac_probe(struct platform_device
*pdev
)
332 struct sudmac_pdata
*pdata
= dev_get_platdata(&pdev
->dev
);
334 struct sudmac_device
*su_dev
;
335 struct dma_device
*dma_dev
;
336 struct resource
*chan
, *irq_res
;
338 /* get platform data */
342 irq_res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
347 su_dev
= devm_kzalloc(&pdev
->dev
, sizeof(struct sudmac_device
),
352 dma_dev
= &su_dev
->shdma_dev
.dma_dev
;
354 chan
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
355 su_dev
->chan_reg
= devm_ioremap_resource(&pdev
->dev
, chan
);
356 if (IS_ERR(su_dev
->chan_reg
))
357 return PTR_ERR(su_dev
->chan_reg
);
359 dma_cap_set(DMA_SLAVE
, dma_dev
->cap_mask
);
361 su_dev
->shdma_dev
.ops
= &sudmac_shdma_ops
;
362 su_dev
->shdma_dev
.desc_size
= sizeof(struct sudmac_desc
);
363 err
= shdma_init(&pdev
->dev
, &su_dev
->shdma_dev
, pdata
->channel_num
);
368 su_dev
->pdata
= dev_get_platdata(&pdev
->dev
);
370 platform_set_drvdata(pdev
, su_dev
);
372 /* Create DMA Channel */
373 for (i
= 0; i
< pdata
->channel_num
; i
++) {
374 err
= sudmac_chan_probe(su_dev
, i
, irq_res
->start
, IRQF_SHARED
);
379 err
= dma_async_device_register(&su_dev
->shdma_dev
.dma_dev
);
386 sudmac_chan_remove(su_dev
);
388 shdma_cleanup(&su_dev
->shdma_dev
);
393 static int sudmac_remove(struct platform_device
*pdev
)
395 struct sudmac_device
*su_dev
= platform_get_drvdata(pdev
);
396 struct dma_device
*dma_dev
= &su_dev
->shdma_dev
.dma_dev
;
398 dma_async_device_unregister(dma_dev
);
399 sudmac_chan_remove(su_dev
);
400 shdma_cleanup(&su_dev
->shdma_dev
);
405 static struct platform_driver sudmac_driver
= {
407 .name
= SUDMAC_DRV_NAME
,
409 .probe
= sudmac_probe
,
410 .remove
= sudmac_remove
,
412 module_platform_driver(sudmac_driver
);
414 MODULE_AUTHOR("Yoshihiro Shimoda");
415 MODULE_DESCRIPTION("Renesas SUDMAC driver");
416 MODULE_LICENSE("GPL v2");
417 MODULE_ALIAS("platform:" SUDMAC_DRV_NAME
);