@@ -808,6 +808,30 @@ static irqreturn_t chan_irqt(int irq, void *dev)
return IRQ_HANDLED;
}
+static struct dma_chan *shdma_mux_request_chan(struct dma_device *dmadev,
+ struct device *dev, enum dma_transfer_direction direction,
+ const char *name)
+{
+ struct shdma_dev *sdev = to_shdma_dev(dmadev);
+ const struct shdma_ops *ops = sdev->ops;
+ struct shdma_chan *schan;
+ int i;
+
+ if (!ops->slave_supported(sdev, dev, direction, name))
+ return NULL;
+
+ /* The DMAC supports this client, pick up the first free channel */
+ shdma_for_each_chan(schan, sdev, i)
+ if (!schan->dma_chan.client_count)
+ return &schan->dma_chan;
+
+ return NULL;
+}
+
+static const struct dma_multiplexer shdma_mux = {
+ .request_chan = shdma_mux_request_chan,
+};
+
int shdma_request_irq(struct shdma_chan *schan, int irq,
unsigned long flags, const char *name)
{
@@ -880,7 +904,8 @@ int shdma_init(struct device *dev, struct shdma_dev *sdev,
!sdev->ops->slave_addr ||
!sdev->ops->channel_busy ||
!sdev->ops->halt_channel ||
- !sdev->ops->desc_completed)
+ !sdev->ops->desc_completed ||
+ !sdev->ops->slave_supported)
return -EINVAL;
sdev->schan = kcalloc(chan_num, sizeof(*sdev->schan), GFP_KERNEL);
@@ -901,6 +926,7 @@ int shdma_init(struct device *dev, struct shdma_dev *sdev,
dma_dev->device_prep_slave_sg = shdma_prep_slave_sg;
dma_dev->device_control = shdma_control;
+ dma_dev->mux = &shdma_mux;
dma_dev->dev = dev;
return 0;
@@ -424,6 +424,27 @@ static bool sh_dmae_desc_completed(struct shdma_chan *schan,
(sh_desc->hw.sar + sh_desc->hw.tcr) == sar_buf);
}
+static bool sh_dmae_slave_supported(struct shdma_dev *sdev, struct device *dev,
+ enum dma_transfer_direction direction, const char *name)
+{
+ struct sh_dmae_device *shdev = container_of(sdev, struct sh_dmae_device,
+ shdma_dev);
+ struct sh_dmae_pdata *pdata = shdev->pdata;
+ const struct sh_dmae_slave_config *cfg;
+ int i;
+
+ if (!dev)
+ return false;
+
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->dev_id && !strcmp(cfg->dev_id, dev_name(dev)) &&
+ cfg->direction == direction &&
+ (!name || (cfg->name && !strcmp(name, cfg->name))))
+ return true;
+
+ return false;
+}
+
static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
{
/* Fast path out if NMIF is not asserted for this controller */
@@ -632,6 +653,7 @@ static const struct shdma_ops sh_dmae_shdma_ops = {
.start_xfer = sh_dmae_start_xfer,
.embedded_desc = sh_dmae_embedded_desc,
.chan_irq = sh_dmae_chan_irq,
+ .slave_supported = sh_dmae_slave_supported,
};
static int __devinit sh_dmae_probe(struct platform_device *pdev)
@@ -31,6 +31,9 @@ struct sh_dmae_slave_config {
dma_addr_t addr;
u32 chcr;
char mid_rid;
+ enum dma_transfer_direction direction;
+ const char *name;
+ const char *dev_id;
};
struct sh_dmae_channel {
@@ -70,6 +70,8 @@ struct shdma_chan {
enum shdma_pm_state pm_state;
};
+struct shdma_dev;
+
/**
* struct shdma_ops - simple DMA driver operations
* desc_completed: return true, if this is the descriptor, that just has
@@ -98,6 +100,8 @@ struct shdma_ops {
void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
struct shdma_desc *(*embedded_desc)(void *, int);
bool (*chan_irq)(struct shdma_chan *, int);
+ bool (*slave_supported)(struct shdma_dev *, struct device *,
+ enum dma_transfer_direction, const char *);
};
struct shdma_dev {
Add support for the new dmaengine multiplexer API. In shdma case the multiplexer is built-in into the DMAC, so, the multiplexer .request_chan() method only has to check, whether this client is supported by the specific DMAC instance. The routing is performed inside the .device_control() method. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> --- drivers/dma/sh/shdma-base.c | 28 +++++++++++++++++++++++++++- drivers/dma/sh/shdma.c | 22 ++++++++++++++++++++++ include/linux/sh_dma.h | 3 +++ include/linux/shdma-base.h | 4 ++++ 4 files changed, 56 insertions(+), 1 deletions(-)