in s3c24xx-dma.c [1185:1363]
static int s3c24xx_dma_probe(struct platform_device *pdev)
{
const struct s3c24xx_dma_platdata *pdata = dev_get_platdata(&pdev->dev);
struct s3c24xx_dma_engine *s3cdma;
struct soc_data *sdata;
struct resource *res;
int ret;
int i;
if (!pdata) {
dev_err(&pdev->dev, "platform data missing\n");
return -ENODEV;
}
/* Basic sanity check */
if (pdata->num_phy_channels > MAX_DMA_CHANNELS) {
dev_err(&pdev->dev, "too many dma channels %d, max %d\n",
pdata->num_phy_channels, MAX_DMA_CHANNELS);
return -EINVAL;
}
sdata = s3c24xx_dma_get_soc_data(pdev);
if (!sdata)
return -EINVAL;
s3cdma = devm_kzalloc(&pdev->dev, sizeof(*s3cdma), GFP_KERNEL);
if (!s3cdma)
return -ENOMEM;
s3cdma->pdev = pdev;
s3cdma->pdata = pdata;
s3cdma->sdata = sdata;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
s3cdma->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(s3cdma->base))
return PTR_ERR(s3cdma->base);
s3cdma->phy_chans = devm_kcalloc(&pdev->dev,
pdata->num_phy_channels,
sizeof(struct s3c24xx_dma_phy),
GFP_KERNEL);
if (!s3cdma->phy_chans)
return -ENOMEM;
/* acquire irqs and clocks for all physical channels */
for (i = 0; i < pdata->num_phy_channels; i++) {
struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i];
char clk_name[6];
phy->id = i;
phy->base = s3cdma->base + (i * sdata->stride);
phy->host = s3cdma;
phy->irq = platform_get_irq(pdev, i);
if (phy->irq < 0)
continue;
ret = devm_request_irq(&pdev->dev, phy->irq, s3c24xx_dma_irq,
0, pdev->name, phy);
if (ret) {
dev_err(&pdev->dev, "Unable to request irq for channel %d, error %d\n",
i, ret);
continue;
}
if (sdata->has_clocks) {
sprintf(clk_name, "dma.%d", i);
phy->clk = devm_clk_get(&pdev->dev, clk_name);
if (IS_ERR(phy->clk) && sdata->has_clocks) {
dev_err(&pdev->dev, "unable to acquire clock for channel %d, error %lu\n",
i, PTR_ERR(phy->clk));
continue;
}
ret = clk_prepare(phy->clk);
if (ret) {
dev_err(&pdev->dev, "clock for phy %d failed, error %d\n",
i, ret);
continue;
}
}
spin_lock_init(&phy->lock);
phy->valid = true;
dev_dbg(&pdev->dev, "physical channel %d is %s\n",
i, s3c24xx_dma_phy_busy(phy) ? "BUSY" : "FREE");
}
/* Initialize memcpy engine */
dma_cap_set(DMA_MEMCPY, s3cdma->memcpy.cap_mask);
dma_cap_set(DMA_PRIVATE, s3cdma->memcpy.cap_mask);
s3cdma->memcpy.dev = &pdev->dev;
s3cdma->memcpy.device_free_chan_resources =
s3c24xx_dma_free_chan_resources;
s3cdma->memcpy.device_prep_dma_memcpy = s3c24xx_dma_prep_memcpy;
s3cdma->memcpy.device_tx_status = s3c24xx_dma_tx_status;
s3cdma->memcpy.device_issue_pending = s3c24xx_dma_issue_pending;
s3cdma->memcpy.device_config = s3c24xx_dma_set_runtime_config;
s3cdma->memcpy.device_terminate_all = s3c24xx_dma_terminate_all;
s3cdma->memcpy.device_synchronize = s3c24xx_dma_synchronize;
/* Initialize slave engine for SoC internal dedicated peripherals */
dma_cap_set(DMA_SLAVE, s3cdma->slave.cap_mask);
dma_cap_set(DMA_CYCLIC, s3cdma->slave.cap_mask);
dma_cap_set(DMA_PRIVATE, s3cdma->slave.cap_mask);
s3cdma->slave.dev = &pdev->dev;
s3cdma->slave.device_free_chan_resources =
s3c24xx_dma_free_chan_resources;
s3cdma->slave.device_tx_status = s3c24xx_dma_tx_status;
s3cdma->slave.device_issue_pending = s3c24xx_dma_issue_pending;
s3cdma->slave.device_prep_slave_sg = s3c24xx_dma_prep_slave_sg;
s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic;
s3cdma->slave.device_config = s3c24xx_dma_set_runtime_config;
s3cdma->slave.device_terminate_all = s3c24xx_dma_terminate_all;
s3cdma->slave.device_synchronize = s3c24xx_dma_synchronize;
s3cdma->slave.filter.map = pdata->slave_map;
s3cdma->slave.filter.mapcnt = pdata->slavecnt;
s3cdma->slave.filter.fn = s3c24xx_dma_filter;
/* Register as many memcpy channels as there are physical channels */
ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->memcpy,
pdata->num_phy_channels, false);
if (ret <= 0) {
dev_warn(&pdev->dev,
"%s failed to enumerate memcpy channels - %d\n",
__func__, ret);
goto err_memcpy;
}
/* Register slave channels */
ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->slave,
pdata->num_channels, true);
if (ret <= 0) {
dev_warn(&pdev->dev,
"%s failed to enumerate slave channels - %d\n",
__func__, ret);
goto err_slave;
}
ret = dma_async_device_register(&s3cdma->memcpy);
if (ret) {
dev_warn(&pdev->dev,
"%s failed to register memcpy as an async device - %d\n",
__func__, ret);
goto err_memcpy_reg;
}
ret = dma_async_device_register(&s3cdma->slave);
if (ret) {
dev_warn(&pdev->dev,
"%s failed to register slave as an async device - %d\n",
__func__, ret);
goto err_slave_reg;
}
platform_set_drvdata(pdev, s3cdma);
dev_info(&pdev->dev, "Loaded dma driver with %d physical channels\n",
pdata->num_phy_channels);
return 0;
err_slave_reg:
dma_async_device_unregister(&s3cdma->memcpy);
err_memcpy_reg:
s3c24xx_dma_free_virtual_channels(&s3cdma->slave);
err_slave:
s3c24xx_dma_free_virtual_channels(&s3cdma->memcpy);
err_memcpy:
if (sdata->has_clocks)
for (i = 0; i < pdata->num_phy_channels; i++) {
struct s3c24xx_dma_phy *phy = &s3cdma->phy_chans[i];
if (phy->valid)
clk_unprepare(phy->clk);
}
return ret;
}