diff mbox

dmaengine: at_hdmac: add device tree probe

Message ID 1312549120-22266-1-git-send-email-nicolas.ferre@atmel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nicolas Ferre Aug. 5, 2011, 12:58 p.m. UTC
Add device tree probe support for atmel at_hdmac DMA driver.
Bindings are added to specify the number of channels that the implementation of
the controller actually has. They also allow to tell if the peripherals/DMA
transfer is supported by the IP.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 .../devicetree/bindings/dma/atmel-hdmac.txt        |   23 +++++++++
 drivers/dma/at_hdmac.c                             |   51 ++++++++++++++++----
 2 files changed, 65 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/dma/atmel-hdmac.txt

Comments

Grant Likely Aug. 7, 2011, 4:09 a.m. UTC | #1
On Fri, Aug 05, 2011 at 01:58:40PM +0100, Nicolas Ferre wrote:
> Add device tree probe support for atmel at_hdmac DMA driver.
> Bindings are added to specify the number of channels that the implementation of
> the controller actually has. They also allow to tell if the peripherals/DMA
> transfer is supported by the IP.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
>  .../devicetree/bindings/dma/atmel-hdmac.txt        |   23 +++++++++
>  drivers/dma/at_hdmac.c                             |   51 ++++++++++++++++----
>  2 files changed, 65 insertions(+), 9 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/dma/atmel-hdmac.txt
> 
> diff --git a/Documentation/devicetree/bindings/dma/atmel-hdmac.txt b/Documentation/devicetree/bindings/dma/atmel-hdmac.txt
> new file mode 100644
> index 0000000..0e48553
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/atmel-hdmac.txt
> @@ -0,0 +1,23 @@
> +* Atmel Direct Memory Access Controller
> +
> +Required properties:
> +- compatible: Should be "atmel,<chip>-hdmac"
> +- reg: Should contain DMA registers location and length
> +- interrupts: Should contain DMA interrupt
> +- atmel,hdmac-nr-channels: Should contain number of channels
> +  available in the controller
> +
> +Optional properties:
> +- atmel,hdmac-cap-memcpy: Chip can do memory to memory transfers
> +- atmel,hdmac-cap-slave: Chip can do peripherals/memory transfers

Heh, ignore my comments on the other patch about missing documentation
for the dma engine.  :-)

Otherwise the patch looks pretty good.  I suspect there is a thing or
two that won't compile correctly when !CONFIG_OF, but I haven't
checked closely.  Just make sure !CONFIG_OF is tested.  :-)

g.


> +
> +Examples:
> +
> +dma@ffffec00 {
> +	compatible = "atmel,at91sam9g45-hdmac";
> +	reg = <0xffffec00 0x200>;
> +	interrupts = <21>;
> +	atmel,hdmac-nr-channels = <8>;
> +	atmel,hdmac-cap-memcpy;
> +	atmel,hdmac-cap-slave;
> +};
> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
> index 8f1d2ee..4a0cefe 100644
> --- a/drivers/dma/at_hdmac.c
> +++ b/drivers/dma/at_hdmac.c
> @@ -23,6 +23,8 @@
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
>  
>  #include "at_hdmac_regs.h"
>  
> @@ -1167,6 +1169,18 @@ static void atc_free_chan_resources(struct dma_chan *chan)
>  
>  /*--  Module Management  -----------------------------------------------*/
>  
> +#if defined(CONFIG_OF)
> +static const struct of_device_id atmel_dma_dt_ids[] = {
> +	{ .compatible = "atmel,at91sam9rl-hdmac" },
> +	{ .compatible = "atmel,at91sam9g45-hdmac" },
> +	{ /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, atmel_dma_dt_ids);
> +#else
> +#define atmel_dma_dt_ids NULL
> +#endif
> +
>  /**
>   * at_dma_off - disable DMA controller
>   * @atdma: the Atmel HDAMC device
> @@ -1185,17 +1199,36 @@ static void at_dma_off(struct at_dma *atdma)
>  
>  static int __init at_dma_probe(struct platform_device *pdev)
>  {
> -	struct at_dma_platform_data *pdata;
> +	const struct of_device_id *of_id =
> +			of_match_device(atmel_dma_dt_ids, &pdev->dev);
> +	struct device_node	*np = pdev->dev.of_node;
> +	struct at_dma_platform_data *pdata = pdev->dev.platform_data;
>  	struct resource		*io;
>  	struct at_dma		*atdma;
>  	size_t			size;
>  	int			irq;
>  	int			err;
>  	int			i;
> +	u32			nr_channels;
> +	dma_cap_mask_t		cap_mask = {};
> +
> +	/* get DMA Controller parameters */
> +	if (of_id) {
> +		if (of_property_read_u32(np, "atmel,hdmac-nr-channels",
> +					&nr_channels))
> +			return -EINVAL;
> +		if (of_find_property(np, "atmel,hdmac-cap-memcpy", NULL))
> +			dma_cap_set(DMA_MEMCPY, cap_mask);
> +		if (of_find_property(np, "atmel,hdmac-cap-slave", NULL))
> +			dma_cap_set(DMA_SLAVE, cap_mask);
> +	} else if (pdata) {
> +		nr_channels = pdata->nr_channels;
> +		cap_mask = pdata->cap_mask;
> +	} else {
> +		return -EINVAL;
> +	}
>  
> -	/* get DMA Controller parameters from platform */
> -	pdata = pdev->dev.platform_data;
> -	if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS)
> +	if (!nr_channels || nr_channels > AT_DMA_MAX_NR_CHANNELS)
>  		return -EINVAL;
>  
>  	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> @@ -1207,14 +1240,13 @@ static int __init at_dma_probe(struct platform_device *pdev)
>  		return irq;
>  
>  	size = sizeof(struct at_dma);
> -	size += pdata->nr_channels * sizeof(struct at_dma_chan);
> +	size += nr_channels * sizeof(struct at_dma_chan);
>  	atdma = kzalloc(size, GFP_KERNEL);
>  	if (!atdma)
>  		return -ENOMEM;
>  
> -	/* discover transaction capabilites from the platform data */
> -	atdma->dma_common.cap_mask = pdata->cap_mask;
> -	atdma->all_chan_mask = (1 << pdata->nr_channels) - 1;
> +	atdma->dma_common.cap_mask = cap_mask;
> +	atdma->all_chan_mask = (1 << nr_channels) - 1;
>  
>  	size = io->end - io->start + 1;
>  	if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
> @@ -1260,7 +1292,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
>  
>  	/* initialize channels related values */
>  	INIT_LIST_HEAD(&atdma->dma_common.channels);
> -	for (i = 0; i < pdata->nr_channels; i++, atdma->dma_common.chancnt++) {
> +	for (i = 0; i < nr_channels; i++, atdma->dma_common.chancnt++) {
>  		struct at_dma_chan	*atchan = &atdma->chan[i];
>  
>  		atchan->chan_common.device = &atdma->dma_common;
> @@ -1406,6 +1438,7 @@ static struct platform_driver at_dma_driver = {
>  	.driver = {
>  		.name	= "at_hdmac",
>  		.pm	= &at_dma_dev_pm_ops,
> +		.of_match_table	= atmel_dma_dt_ids,
>  	},
>  };
>  
> -- 
> 1.7.4.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Nicolas Ferre Aug. 16, 2011, 4:33 p.m. UTC | #2
Le 07/08/2011 06:09, Grant Likely :
> On Fri, Aug 05, 2011 at 01:58:40PM +0100, Nicolas Ferre wrote:
>> Add device tree probe support for atmel at_hdmac DMA driver.
>> Bindings are added to specify the number of channels that the implementation of
>> the controller actually has. They also allow to tell if the peripherals/DMA
>> transfer is supported by the IP.
>>
>> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
>> ---
>>  .../devicetree/bindings/dma/atmel-hdmac.txt        |   23 +++++++++
>>  drivers/dma/at_hdmac.c                             |   51 ++++++++++++++++----
>>  2 files changed, 65 insertions(+), 9 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/dma/atmel-hdmac.txt
>>
>> diff --git a/Documentation/devicetree/bindings/dma/atmel-hdmac.txt b/Documentation/devicetree/bindings/dma/atmel-hdmac.txt
>> new file mode 100644
>> index 0000000..0e48553
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/dma/atmel-hdmac.txt
>> @@ -0,0 +1,23 @@
>> +* Atmel Direct Memory Access Controller
>> +
>> +Required properties:
>> +- compatible: Should be "atmel,<chip>-hdmac"
>> +- reg: Should contain DMA registers location and length
>> +- interrupts: Should contain DMA interrupt
>> +- atmel,hdmac-nr-channels: Should contain number of channels
>> +  available in the controller
>> +
>> +Optional properties:
>> +- atmel,hdmac-cap-memcpy: Chip can do memory to memory transfers
>> +- atmel,hdmac-cap-slave: Chip can do peripherals/memory transfers
> 
> Heh, ignore my comments on the other patch about missing documentation
> for the dma engine.  :-)
> 
> Otherwise the patch looks pretty good.

[..]

Grant, Vinod,

Don't you think it would make sense to generalize nr-channels and maybe
also the capabilities properties for other dmaengine drivers?
I have seen other dmaengine drivers taking the number of channels from
platform data so that would make sense.
It would be new dmaengine device tree properties, but on the other hand,
I do not know if code can also be centralized for handling of those
properties... maybe it is better to let drivers deal with them if
required...

Your thoughts?

Best regards,
Vinod Koul Aug. 23, 2011, 4:55 a.m. UTC | #3
On Tue, 2011-08-16 at 18:33 +0200, Nicolas Ferre wrote:
> [..]
> 
> Grant, Vinod,
> 
> Don't you think it would make sense to generalize nr-channels and maybe
> also the capabilities properties for other dmaengine drivers?
> I have seen other dmaengine drivers taking the number of channels from
> platform data so that would make sense.
> It would be new dmaengine device tree properties, but on the other hand,
> I do not know if code can also be centralized for handling of those
> properties... maybe it is better to let drivers deal with them if
> required...
> 
We already having this discussion and how to change capabilities etc to
make thing more easy and transparent, See the approaches taken by Jassi
and Linus W
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/dma/atmel-hdmac.txt b/Documentation/devicetree/bindings/dma/atmel-hdmac.txt
new file mode 100644
index 0000000..0e48553
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/atmel-hdmac.txt
@@ -0,0 +1,23 @@ 
+* Atmel Direct Memory Access Controller
+
+Required properties:
+- compatible: Should be "atmel,<chip>-hdmac"
+- reg: Should contain DMA registers location and length
+- interrupts: Should contain DMA interrupt
+- atmel,hdmac-nr-channels: Should contain number of channels
+  available in the controller
+
+Optional properties:
+- atmel,hdmac-cap-memcpy: Chip can do memory to memory transfers
+- atmel,hdmac-cap-slave: Chip can do peripherals/memory transfers
+
+Examples:
+
+dma@ffffec00 {
+	compatible = "atmel,at91sam9g45-hdmac";
+	reg = <0xffffec00 0x200>;
+	interrupts = <21>;
+	atmel,hdmac-nr-channels = <8>;
+	atmel,hdmac-cap-memcpy;
+	atmel,hdmac-cap-slave;
+};
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 8f1d2ee..4a0cefe 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -23,6 +23,8 @@ 
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include "at_hdmac_regs.h"
 
@@ -1167,6 +1169,18 @@  static void atc_free_chan_resources(struct dma_chan *chan)
 
 /*--  Module Management  -----------------------------------------------*/
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_dma_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9rl-hdmac" },
+	{ .compatible = "atmel,at91sam9g45-hdmac" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_dma_dt_ids);
+#else
+#define atmel_dma_dt_ids NULL
+#endif
+
 /**
  * at_dma_off - disable DMA controller
  * @atdma: the Atmel HDAMC device
@@ -1185,17 +1199,36 @@  static void at_dma_off(struct at_dma *atdma)
 
 static int __init at_dma_probe(struct platform_device *pdev)
 {
-	struct at_dma_platform_data *pdata;
+	const struct of_device_id *of_id =
+			of_match_device(atmel_dma_dt_ids, &pdev->dev);
+	struct device_node	*np = pdev->dev.of_node;
+	struct at_dma_platform_data *pdata = pdev->dev.platform_data;
 	struct resource		*io;
 	struct at_dma		*atdma;
 	size_t			size;
 	int			irq;
 	int			err;
 	int			i;
+	u32			nr_channels;
+	dma_cap_mask_t		cap_mask = {};
+
+	/* get DMA Controller parameters */
+	if (of_id) {
+		if (of_property_read_u32(np, "atmel,hdmac-nr-channels",
+					&nr_channels))
+			return -EINVAL;
+		if (of_find_property(np, "atmel,hdmac-cap-memcpy", NULL))
+			dma_cap_set(DMA_MEMCPY, cap_mask);
+		if (of_find_property(np, "atmel,hdmac-cap-slave", NULL))
+			dma_cap_set(DMA_SLAVE, cap_mask);
+	} else if (pdata) {
+		nr_channels = pdata->nr_channels;
+		cap_mask = pdata->cap_mask;
+	} else {
+		return -EINVAL;
+	}
 
-	/* get DMA Controller parameters from platform */
-	pdata = pdev->dev.platform_data;
-	if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS)
+	if (!nr_channels || nr_channels > AT_DMA_MAX_NR_CHANNELS)
 		return -EINVAL;
 
 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1207,14 +1240,13 @@  static int __init at_dma_probe(struct platform_device *pdev)
 		return irq;
 
 	size = sizeof(struct at_dma);
-	size += pdata->nr_channels * sizeof(struct at_dma_chan);
+	size += nr_channels * sizeof(struct at_dma_chan);
 	atdma = kzalloc(size, GFP_KERNEL);
 	if (!atdma)
 		return -ENOMEM;
 
-	/* discover transaction capabilites from the platform data */
-	atdma->dma_common.cap_mask = pdata->cap_mask;
-	atdma->all_chan_mask = (1 << pdata->nr_channels) - 1;
+	atdma->dma_common.cap_mask = cap_mask;
+	atdma->all_chan_mask = (1 << nr_channels) - 1;
 
 	size = io->end - io->start + 1;
 	if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
@@ -1260,7 +1292,7 @@  static int __init at_dma_probe(struct platform_device *pdev)
 
 	/* initialize channels related values */
 	INIT_LIST_HEAD(&atdma->dma_common.channels);
-	for (i = 0; i < pdata->nr_channels; i++, atdma->dma_common.chancnt++) {
+	for (i = 0; i < nr_channels; i++, atdma->dma_common.chancnt++) {
 		struct at_dma_chan	*atchan = &atdma->chan[i];
 
 		atchan->chan_common.device = &atdma->dma_common;
@@ -1406,6 +1438,7 @@  static struct platform_driver at_dma_driver = {
 	.driver = {
 		.name	= "at_hdmac",
 		.pm	= &at_dma_dev_pm_ops,
+		.of_match_table	= atmel_dma_dt_ids,
 	},
 };