* [PATCH 01/23] of: add dma-mask binding
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 02/23] of_spi: add generic binding support to specify cs gpio Richard Genoud
` (23 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
This will allow each device to specify its dma-mask for this we use the
coherent_dma_mask as pointer. By default the dma-mask will be set to
DMA_BIT_MASK(32).
The microblaze architecture hook is drop
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
drivers/of/platform.c | 23 ++++++++++++++++-------
1 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e44f8c2..11c765c 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -121,6 +121,21 @@ void of_device_make_bus_id(struct device *dev)
dev_set_name(dev, "%s.%d", node->name, magic - 1);
}
+static void of_get_dma_mask(struct device *dev, struct device_node *np)
+{
+ const __be32 *prop;
+ int len;
+
+ prop = of_get_property(np, "dma-mask", &len);
+
+ dev->dma_mask = &dev->coherent_dma_mask;
+
+ if (!prop)
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ else
+ dev->coherent_dma_mask = of_read_number(prop, len / 4);
+}
+
/**
* of_device_alloc - Allocate and initialize an of_device
* @np: device node to assign to device
@@ -161,10 +176,8 @@ struct platform_device *of_device_alloc(struct device_node *np,
WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
}
+ of_get_dma_mask(&dev->dev, np);
dev->dev.of_node = of_node_get(np);
-#if defined(CONFIG_MICROBLAZE)
- dev->dev.dma_mask = &dev->archdata.dma_mask;
-#endif
dev->dev.parent = parent;
if (bus_id)
@@ -201,10 +214,6 @@ struct platform_device *of_platform_device_create_pdata(
if (!dev)
return NULL;
-#if defined(CONFIG_MICROBLAZE)
- dev->archdata.dma_mask = 0xffffffffUL;
-#endif
- dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 02/23] of_spi: add generic binding support to specify cs gpio
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
2012-08-14 13:49 ` [PATCH 01/23] of: add dma-mask binding Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 03/23] spi/atmel_spi: trivial: change some comments Richard Genoud
` (22 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
This will allow to use gpio for chip select with no modification in the
driver binding
When use the cs-gpios, the gpio number will be passed via the cs_gpio field
and the number of chip select will automatically increased.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: devicetree-discuss at lists.ozlabs.org
Cc: spi-devel-general at lists.sourceforge.net
---
Documentation/devicetree/bindings/spi/spi-bus.txt | 6 ++
drivers/spi/spi.c | 55 +++++++++++++++++++-
include/linux/spi/spi.h | 3 +
3 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index e782add..c253379 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -12,6 +12,7 @@ The SPI master node requires the following properties:
- #size-cells - should be zero.
- compatible - name of SPI bus controller following generic names
recommended practice.
+- cs-gpios - (optional) gpios chip select.
No other properties are required in the SPI bus node. It is assumed
that a driver for an SPI bus device will understand that it is an SPI bus.
However, the binding does not attempt to define the specific method for
@@ -21,6 +22,8 @@ assumption that board specific platform code will be used to manage
chip selects. Individual drivers can define additional properties to
support describing the chip select layout.
+If cs-gpios is used the number of chip select will automatically increased.
+
SPI slave nodes must be children of the SPI master node and can
contain the following properties.
- reg - (required) chip select address of device.
@@ -34,6 +37,9 @@ contain the following properties.
- spi-cs-high - (optional) Empty property indicating device requires
chip select active high
+If a gpio chipselect is used for the SPI slave the gpio number will be passed
+via the controller_data
+
SPI example for an MPC5200 SPI bus:
spi at f00 {
#address-cells = <1>;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 84c2861..3fb5b6d 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
+#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/export.h>
#include <linux/sched.h>
@@ -327,6 +328,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master)
spi->dev.parent = &master->dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
+ spi->cs_gpio = -EINVAL;
device_initialize(&spi->dev);
return spi;
}
@@ -344,15 +346,16 @@ EXPORT_SYMBOL_GPL(spi_alloc_device);
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
- struct device *dev = spi->master->dev.parent;
+ struct spi_master *master = spi->master;
+ struct device *dev = master->dev.parent;
struct device *d;
int status;
/* Chipselects are numbered 0..max; validate. */
- if (spi->chip_select >= spi->master->num_chipselect) {
+ if (spi->chip_select >= master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
- spi->master->num_chipselect);
+ master->num_chipselect);
return -EINVAL;
}
@@ -376,6 +379,9 @@ int spi_add_device(struct spi_device *spi)
goto done;
}
+ if (master->cs_gpios)
+ spi->cs_gpio = master->cs_gpios[spi->chip_select];
+
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
@@ -946,6 +952,45 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
}
EXPORT_SYMBOL_GPL(spi_alloc_master);
+#ifdef CONFIG_OF
+static int of_spi_register_master(struct spi_master *master)
+{
+ int nb, i;
+ int *cs;
+ struct device_node *np = master->dev.of_node;
+
+ if (!np)
+ return 0;
+
+ nb = of_gpio_named_count(np, "cs-gpios");
+
+ if (nb < 1)
+ return 0;
+
+ cs = devm_kzalloc(&master->dev,
+ sizeof(int) * (master->num_chipselect + nb),
+ GFP_KERNEL);
+ master->cs_gpios = cs;
+
+ if (!master->cs_gpios)
+ return -ENOMEM;
+
+ memset(cs, -EINVAL, master->num_chipselect);
+ master->num_chipselect += nb;
+ cs += master->num_chipselect;
+
+ for (i = 0; i < nb; i++)
+ cs[i] = of_get_named_gpio(np, "cs-gpios", i);
+
+ return 0;
+}
+#else
+static int of_spi_register_master(struct spi_master *master)
+{
+ return 0;
+}
+#endif
+
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
@@ -977,6 +1022,10 @@ int spi_register_master(struct spi_master *master)
if (!dev)
return -ENODEV;
+ status = of_spi_register_master(master);
+ if (status)
+ return status;
+
/* even if it's just one always-selected device, there must
* be@least one chipselect
*/
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index fa702ae..f629189 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -90,6 +90,7 @@ struct spi_device {
void *controller_state;
void *controller_data;
char modalias[SPI_NAME_SIZE];
+ int cs_gpio; /* chip select gpio */
/*
* likely need more hooks for more protocol options affecting how
@@ -362,6 +363,8 @@ struct spi_master {
int (*transfer_one_message)(struct spi_master *master,
struct spi_message *mesg);
int (*unprepare_transfer_hardware)(struct spi_master *master);
+ /* gpio chip select */
+ int *cs_gpios;
};
static inline void *spi_master_get_devdata(struct spi_master *master)
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 03/23] spi/atmel_spi: trivial: change some comments
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
2012-08-14 13:49 ` [PATCH 01/23] of: add dma-mask binding Richard Genoud
2012-08-14 13:49 ` [PATCH 02/23] of_spi: add generic binding support to specify cs gpio Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 04/23] spi/atmel_spi: add physical base address Richard Genoud
` (21 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Ferre <nicolas.ferre@atmel.com>
To be accurate with introduction of dmaengine enabled driver.
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
drivers/spi/spi-atmel.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 16d6a83..7c41b07 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -201,6 +201,7 @@ struct atmel_spi {
struct spi_transfer *next_transfer;
unsigned long next_remaining_bytes;
+ /* scratch buffer */
void *buffer;
dma_addr_t buffer_dma;
};
@@ -364,7 +365,7 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
}
/*
- * Submit next transfer for DMA.
+ * Submit next transfer for PDC.
* lock is held, spi irq is blocked
*/
static void atmel_spi_next_xfer(struct spi_master *master,
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 04/23] spi/atmel_spi: add physical base address
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (2 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 03/23] spi/atmel_spi: trivial: change some comments Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 05/23] spi/atmel_spi: call unmapping on transfers buffers Richard Genoud
` (20 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Needed for future use with dmaengine enabled driver.
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
drivers/spi/spi-atmel.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 7c41b07..a83f470 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -188,6 +188,7 @@
struct atmel_spi {
spinlock_t lock;
+ resource_size_t phybase;
void __iomem *regs;
int irq;
struct clk *clk;
@@ -962,6 +963,7 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
as->regs = ioremap(regs->start, resource_size(regs));
if (!as->regs)
goto out_free_buffer;
+ as->phybase = regs->start;
as->irq = irq;
as->clk = clk;
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 05/23] spi/atmel_spi: call unmapping on transfers buffers
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (3 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 04/23] spi/atmel_spi: add physical base address Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 06/23] spi/atmel_spi: status information passed through controller data Richard Genoud
` (19 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
drivers/spi/spi-atmel.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index a83f470..39285ef 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1011,6 +1011,7 @@ static int __devexit atmel_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_message *msg;
+ struct spi_transfer *xfer;
/* reset the hardware and block queue progress */
spin_lock_irq(&as->lock);
@@ -1022,9 +1023,10 @@ static int __devexit atmel_spi_remove(struct platform_device *pdev)
/* Terminate remaining queued transfers */
list_for_each_entry(msg, &as->queue, queue) {
- /* REVISIT unmapping the dma is a NOP on ARM and AVR32
- * but we shouldn't depend on that...
- */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!msg->is_dma_mapped)
+ atmel_spi_dma_unmap_xfer(master, xfer);
+ }
msg->status = -ESHUTDOWN;
msg->complete(msg->context);
}
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 06/23] spi/atmel_spi: status information passed through controller data
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (4 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 05/23] spi/atmel_spi: call unmapping on transfers buffers Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 07/23] spi/atmel_spi: add flag to controller data for lock operations Richard Genoud
` (18 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Ferre <nicolas.ferre@atmel.com>
The status of transfer is stored in controller data structure
so that it can be used not only by atmel_spi_msg_done() function.
This will be useful for upcoming dmaengine enabled driver.
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
drivers/spi/spi-atmel.c | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 39285ef..49a7f4f 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -201,6 +201,7 @@ struct atmel_spi {
unsigned long current_remaining_bytes;
struct spi_transfer *next_transfer;
unsigned long next_remaining_bytes;
+ int done_status;
/* scratch buffer */
void *buffer;
@@ -545,15 +546,15 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
static void
atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
- struct spi_message *msg, int status, int stay)
+ struct spi_message *msg, int stay)
{
- if (!stay || status < 0)
+ if (!stay || as->done_status < 0)
cs_deactivate(as, msg->spi);
else
as->stay = msg->spi;
list_del(&msg->queue);
- msg->status = status;
+ msg->status = as->done_status;
dev_dbg(master->dev.parent,
"xfer complete: %u bytes transferred\n",
@@ -565,6 +566,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
as->current_transfer = NULL;
as->next_transfer = NULL;
+ as->done_status = 0;
/* continue if needed */
if (list_empty(&as->queue) || as->stopping)
@@ -642,7 +644,8 @@ atmel_spi_interrupt(int irq, void *dev_id)
/* Clear any overrun happening while cleaning up */
spi_readl(as, SR);
- atmel_spi_msg_done(master, as, msg, -EIO, 0);
+ as->done_status = -EIO;
+ atmel_spi_msg_done(master, as, msg, 0);
} else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) {
ret = IRQ_HANDLED;
@@ -660,7 +663,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (atmel_spi_xfer_is_last(msg, xfer)) {
/* report completed message */
- atmel_spi_msg_done(master, as, msg, 0,
+ atmel_spi_msg_done(master, as, msg,
xfer->cs_change);
} else {
if (xfer->cs_change) {
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 07/23] spi/atmel_spi: add flag to controller data for lock operations
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (5 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 06/23] spi/atmel_spi: status information passed through controller data Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 08/23] spi/atmel: add DT support Richard Genoud
` (17 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Will allow to drop the lock during DMA operations.
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
drivers/spi/spi-atmel.c | 31 +++++++++++++++++++------------
1 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 49a7f4f..70f7bfa 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -187,6 +187,7 @@
*/
struct atmel_spi {
spinlock_t lock;
+ unsigned long flags;
resource_size_t phybase;
void __iomem *regs;
@@ -324,6 +325,16 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
gpio_set_value(asd->npcs_pin, !active);
}
+static void atmel_spi_lock(struct atmel_spi *as)
+{
+ spin_lock_irqsave(&as->lock, as->flags);
+}
+
+static void atmel_spi_unlock(struct atmel_spi *as)
+{
+ spin_unlock_irqrestore(&as->lock, as->flags);
+}
+
static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
struct spi_transfer *xfer)
{
@@ -560,9 +571,9 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
"xfer complete: %u bytes transferred\n",
msg->actual_length);
- spin_unlock(&as->lock);
+ atmel_spi_unlock(as);
msg->complete(msg->context);
- spin_lock(&as->lock);
+ atmel_spi_lock(as);
as->current_transfer = NULL;
as->next_transfer = NULL;
@@ -789,13 +800,11 @@ static int atmel_spi_setup(struct spi_device *spi)
spi->controller_state = asd;
gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
} else {
- unsigned long flags;
-
- spin_lock_irqsave(&as->lock, flags);
+ atmel_spi_lock(as);
if (as->stay == spi)
as->stay = NULL;
cs_deactivate(as, spi);
- spin_unlock_irqrestore(&as->lock, flags);
+ atmel_spi_unlock(as);
}
asd->csr = csr;
@@ -814,7 +823,6 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct atmel_spi *as;
struct spi_transfer *xfer;
- unsigned long flags;
struct device *controller = spi->master->dev.parent;
u8 bits;
struct atmel_spi_device *asd;
@@ -879,11 +887,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
msg->status = -EINPROGRESS;
msg->actual_length = 0;
- spin_lock_irqsave(&as->lock, flags);
+ atmel_spi_lock(as);
list_add_tail(&msg->queue, &as->queue);
if (!as->current_transfer)
atmel_spi_next_message(spi->master);
- spin_unlock_irqrestore(&as->lock, flags);
+ atmel_spi_unlock(as);
return 0;
}
@@ -893,17 +901,16 @@ static void atmel_spi_cleanup(struct spi_device *spi)
struct atmel_spi *as = spi_master_get_devdata(spi->master);
struct atmel_spi_device *asd = spi->controller_state;
unsigned gpio = (unsigned) spi->controller_data;
- unsigned long flags;
if (!asd)
return;
- spin_lock_irqsave(&as->lock, flags);
+ atmel_spi_lock(as);
if (as->stay == spi) {
as->stay = NULL;
cs_deactivate(as, spi);
}
- spin_unlock_irqrestore(&as->lock, flags);
+ atmel_spi_unlock(as);
spi->controller_state = NULL;
gpio_free(gpio);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 08/23] spi/atmel: add DT support
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (6 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 07/23] spi/atmel_spi: add flag to controller data for lock operations Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 09/23] spi/atmel_spi: add dmaengine support Richard Genoud
` (16 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
The atmel_spi use only gpio for chip select.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: devicetree-discuss at lists.ozlabs.org
Cc: spi-devel-general at lists.sourceforge.net
---
.../devicetree/bindings/spi/spi_atmel.txt | 6 +++++
drivers/spi/spi-atmel.c | 21 ++++++++++++++++---
2 files changed, 23 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/spi/spi_atmel.txt
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
new file mode 100644
index 0000000..7ec3d8d
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
@@ -0,0 +1,6 @@
+Atmel SPI device
+
+Required properties:
+- compatible : should be "atmel,at91rm9200-spi".
+- reg: Address and length of the register set for the device
+- interrupts: Should contain macb interrupt
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 70f7bfa..ad47b6d 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <asm/io.h>
#include <mach/board.h>
@@ -711,7 +712,7 @@ static int atmel_spi_setup(struct spi_device *spi)
u32 scbr, csr;
unsigned int bits = spi->bits_per_word;
unsigned long bus_hz;
- unsigned int npcs_pin;
+ int npcs_pin;
int ret;
as = spi_master_get_devdata(spi->master);
@@ -783,7 +784,9 @@ static int atmel_spi_setup(struct spi_device *spi)
csr |= SPI_BF(DLYBCT, 0);
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
- npcs_pin = (unsigned int)spi->controller_data;
+ if (!gpio_is_valid(spi->cs_gpio))
+ spi->cs_gpio = (int)spi->controller_data;
+ npcs_pin = spi->cs_gpio;
asd = spi->controller_state;
if (!asd) {
asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
@@ -900,7 +903,7 @@ static void atmel_spi_cleanup(struct spi_device *spi)
{
struct atmel_spi *as = spi_master_get_devdata(spi->master);
struct atmel_spi_device *asd = spi->controller_state;
- unsigned gpio = (unsigned) spi->controller_data;
+ unsigned gpio = spi->cs_gpio;
if (!asd)
return;
@@ -950,7 +953,8 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bus_num = pdev->id;
- master->num_chipselect = 4;
+ master->dev.of_node = pdev->dev.of_node;
+ master->num_chipselect = master->dev.of_node ? 0 : 4;
master->setup = atmel_spi_setup;
master->transfer = atmel_spi_transfer;
master->cleanup = atmel_spi_cleanup;
@@ -1079,11 +1083,20 @@ static int atmel_spi_resume(struct platform_device *pdev)
#define atmel_spi_resume NULL
#endif
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_spi_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-spi" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
+#endif
static struct platform_driver atmel_spi_driver = {
.driver = {
.name = "atmel_spi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_spi_dt_ids),
},
.suspend = atmel_spi_suspend,
.resume = atmel_spi_resume,
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 09/23] spi/atmel_spi: add dmaengine support
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (7 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 08/23] spi/atmel: add DT support Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 10/23] spi-atmel: update with dmaengine interface Richard Genoud
` (15 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
drivers/spi/Kconfig | 9 +
drivers/spi/spi-atmel.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 482 insertions(+), 10 deletions(-)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5f84b55..169592a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -74,6 +74,15 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
+config SPI_ATMEL_DMA
+ bool "Atmel SPI DMA support"
+ depends on SPI_ATMEL && (ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5) && DMA_ENGINE && EXPERIMENTAL
+ default y
+ help
+ Say Y here if you want the Atmel SPI driver to use the DMA engine. Data transfers
+ will be handled by the DMA controller: it will increase throughput and reduce
+ CPU utilization.
+
config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index ad47b6d..9456fca 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
@@ -25,6 +26,7 @@
#include <mach/board.h>
#include <asm/gpio.h>
#include <mach/cpu.h>
+#include <mach/at_hdmac.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -181,6 +183,22 @@
__raw_writel((value), (port)->regs + SPI_##reg)
+#if defined(CONFIG_SPI_ATMEL_DMA)
+/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
+ * cache operations; better heuristics consider wordsize and bitrate.
+ */
+#define DMA_MIN_BYTES 16
+
+struct atmel_spi_dma {
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct scatterlist sgrx;
+ struct scatterlist sgtx;
+ struct dma_async_tx_descriptor *data_desc_rx;
+ struct dma_async_tx_descriptor *data_desc_tx;
+};
+#endif
+
/*
* The core SPI transfer engine just talks to a register bank to set up
* DMA transfers; transfer queue progress is driven by IRQs. The clock
@@ -199,6 +217,7 @@ struct atmel_spi {
u8 stopping;
struct list_head queue;
+ struct tasklet_struct tasklet;
struct spi_transfer *current_transfer;
unsigned long current_remaining_bytes;
struct spi_transfer *next_transfer;
@@ -208,6 +227,11 @@ struct atmel_spi {
/* scratch buffer */
void *buffer;
dma_addr_t buffer_dma;
+
+#if defined(CONFIG_SPI_ATMEL_DMA)
+ /* dmaengine data */
+ struct atmel_spi_dma dma;
+#endif
};
/* Controller-specific per-slave state */
@@ -336,6 +360,17 @@ static void atmel_spi_unlock(struct atmel_spi *as)
spin_unlock_irqrestore(&as->lock, as->flags);
}
+static inline bool atmel_spi_use_dma(struct spi_transfer *xfer)
+{
+#if defined(CONFIG_SPI_ATMEL_DMA)
+ if (xfer->len < DMA_MIN_BYTES)
+ return false;
+ return true;
+#else
+ return false;
+#endif
+}
+
static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
struct spi_transfer *xfer)
{
@@ -347,6 +382,258 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
return xfer->delay_usecs == 0 && !xfer->cs_change;
}
+#if defined(CONFIG_SPI_ATMEL_DMA)
+static bool __init filter(struct dma_chan *chan, void *slave)
+{
+ struct at_dma_slave *sl = slave;
+
+ if (sl->dma_dev == chan->device->dev) {
+ chan->private = sl;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static int __init atmel_spi_configure_dma(struct spi_master *master)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct device *controller = master->dev.parent;
+ struct at_dma_slave *sdata;
+
+ sdata = controller->platform_data;
+
+ if (sdata && sdata->dma_dev) {
+ dma_cap_mask_t mask;
+
+ /* setup DMA addresses */
+ sdata->rx_reg = (dma_addr_t)as->phybase + SPI_RDR;
+ sdata->tx_reg = (dma_addr_t)as->phybase + SPI_TDR;
+
+ /* Try to grab two DMA channels */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ as->dma.chan_tx = dma_request_channel(mask, filter, sdata);
+ if (as->dma.chan_tx)
+ as->dma.chan_rx = dma_request_channel(mask, filter, sdata);
+ }
+ if (!as->dma.chan_rx || !as->dma.chan_tx) {
+ if (as->dma.chan_rx)
+ dma_release_channel(as->dma.chan_rx);
+ if (as->dma.chan_tx)
+ dma_release_channel(as->dma.chan_tx);
+ dev_err(&as->pdev->dev, "DMA channel not available, "
+ "unable to use SPI\n");
+ return -EBUSY;
+ }
+
+ dev_info(&as->pdev->dev, "Using %s (tx) and "
+ " %s (rx) for DMA transfers\n",
+ dma_chan_name(as->dma.chan_tx),
+ dma_chan_name(as->dma.chan_rx));
+
+ return 0;
+}
+
+static void atmel_spi_stop_dma(struct atmel_spi *as)
+{
+ if (as->dma.chan_rx)
+ as->dma.chan_rx->device->device_control(as->dma.chan_rx,
+ DMA_TERMINATE_ALL, 0);
+ if (as->dma.chan_tx)
+ as->dma.chan_tx->device->device_control(as->dma.chan_tx,
+ DMA_TERMINATE_ALL, 0);
+}
+
+static void atmel_spi_release_dma(struct atmel_spi *as)
+{
+ if (as->dma.chan_rx)
+ dma_release_channel(as->dma.chan_rx);
+ if (as->dma.chan_tx)
+ dma_release_channel(as->dma.chan_tx);
+}
+
+/* This function is called by the DMA driver from tasklet context */
+static void dma_callback(void *data)
+{
+ struct spi_master *master = data;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ /* trigger SPI tasklet */
+ tasklet_schedule(&as->tasklet);
+}
+
+/*
+ * Next transfer using PIO.
+ * lock is held, spi tasklet is blocked
+ */
+static void atmel_spi_next_xfer_pio(struct spi_master *master,
+ struct spi_transfer *xfer)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n");
+
+ as->current_remaining_bytes = xfer->len;
+
+ /* Make sure data is not remaining in RDR */
+ spi_readl(as, RDR);
+ while (spi_readl(as, SR) & SPI_BIT(RDRF)) {
+ spi_readl(as, RDR);
+ cpu_relax();
+ }
+
+ if (xfer->tx_buf)
+ spi_writel(as, TDR, *(u8 *)(xfer->tx_buf));
+ else
+ spi_writel(as, TDR, 0);
+
+ dev_dbg(master->dev.parent,
+ " start pio xfer %p: len %u tx %p rx %p\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->rx_buf);
+
+ /* Enable relevant interrupts */
+ spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES));
+}
+
+/*
+ * Submit next transfer for DMA.
+ * lock is held, spi tasklet is blocked
+ */
+static int atmel_spi_next_xfer_dma(struct spi_master *master,
+ struct spi_transfer *xfer)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct dma_chan *rxchan = as->dma.chan_rx;
+ struct dma_chan *txchan = as->dma.chan_tx;
+ struct dma_async_tx_descriptor *rxdesc;
+ struct dma_async_tx_descriptor *txdesc;
+ dma_cookie_t cookie;
+
+ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma\n");
+
+ /* Check that the channels are available */
+ if (!rxchan || !txchan)
+ return -ENODEV;
+
+ /* release lock for DMA operations */
+ atmel_spi_unlock(as);
+
+ /* prepare the RX dma transfer */
+ sg_init_table(&as->dma.sgrx, 1);
+ sg_dma_len(&as->dma.sgrx) = xfer->len;
+ if (xfer->rx_buf)
+ as->dma.sgrx.dma_address = xfer->rx_dma;
+ else
+ as->dma.sgrx.dma_address = as->buffer_dma;
+
+ /* prepare the TX dma transfer */
+ sg_init_table(&as->dma.sgtx, 1);
+ sg_dma_len(&as->dma.sgtx) = xfer->len;
+ if (xfer->tx_buf) {
+ as->dma.sgtx.dma_address = xfer->tx_dma;
+ } else {
+ as->dma.sgtx.dma_address = as->buffer_dma;
+ memset(as->buffer, 0, xfer->len);
+ }
+
+ /* Send both scatterlists */
+ rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+ &as->dma.sgrx,
+ 1,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!rxdesc)
+ goto err_dma;
+
+ txdesc = txchan->device->device_prep_slave_sg(txchan,
+ &as->dma.sgtx,
+ 1,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc)
+ goto err_dma;
+
+ dev_dbg(master->dev.parent,
+ " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+
+ /* Enable relevant interrupts */
+ spi_writel(as, IER, SPI_BIT(OVRES));
+
+ /* Put the callback on the RX transfer only, that should finish last */
+ rxdesc->callback = dma_callback;
+ rxdesc->callback_param = master;
+
+ /* Submit and fire RX and TX with TX last so we're ready to read! */
+ cookie = rxdesc->tx_submit(rxdesc);
+ if (dma_submit_error(cookie))
+ goto err_dma;
+ cookie = txdesc->tx_submit(txdesc);
+ if (dma_submit_error(cookie))
+ goto err_dma;
+ rxchan->device->device_issue_pending(rxchan);
+ txchan->device->device_issue_pending(txchan);
+
+ /* take back lock */
+ atmel_spi_lock(as);
+ return 0;
+
+err_dma:
+ spi_writel(as, IDR, SPI_BIT(OVRES));
+ atmel_spi_stop_dma(as);
+ atmel_spi_lock(as);
+ return -ENOMEM;
+}
+
+/*
+ * Choose way to submit next transfer and start it.
+ * lock is held, spi tasklet is blocked
+ */
+static void atmel_spi_next_xfer(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+
+ dev_vdbg(&msg->spi->dev, "atmel_spi_next_xfer\n");
+
+ if (!as->current_transfer)
+ xfer = list_entry(msg->transfers.next,
+ struct spi_transfer, transfer_list);
+ else
+ xfer = list_entry(as->current_transfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+
+ as->current_transfer = xfer;
+
+ if (atmel_spi_use_dma(xfer)) {
+ if (!atmel_spi_next_xfer_dma(master, xfer))
+ return;
+ else
+ dev_err(&msg->spi->dev, "unable to use DMA, fallback to PIO\n");
+ }
+
+ /* use PIO if xfer is short or error appened using DMA */
+ atmel_spi_next_xfer_pio(master, xfer);
+}
+
+static void atmel_spi_disable_dma_irq(struct atmel_spi *as) {}
+#else
+static void atmel_spi_disable_dma_irq(struct atmel_spi *as)
+{
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+}
+
+static int __init atmel_spi_configure_dma(struct spi_master *master)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ atmel_spi_disable_dma_irq(as);
+ return 0;
+}
+
static void atmel_spi_next_xfer_data(struct spi_master *master,
struct spi_transfer *xfer,
dma_addr_t *tx_dma,
@@ -479,6 +766,10 @@ static void atmel_spi_next_xfer(struct spi_master *master,
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
+static void atmel_spi_stop_dma(struct atmel_spi *as) {}
+static void atmel_spi_release_dma(struct atmel_spi *as) {}
+#endif
+
static void atmel_spi_next_message(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -582,11 +873,175 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
/* continue if needed */
if (list_empty(&as->queue) || as->stopping)
- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+ atmel_spi_disable_dma_irq(as);
else
atmel_spi_next_message(master);
}
+#if defined(CONFIG_SPI_ATMEL_DMA)
+/* Called from IRQ
+ * lock is held
+ *
+ * Must update "current_remaining_bytes" to keep track of data
+ * to transfer.
+ */
+static void
+atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
+{
+ u8 *txp;
+ u8 *rxp;
+ unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
+
+ if (xfer->rx_buf) {
+ rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
+ *rxp = spi_readl(as, RDR);
+ } else {
+ spi_readl(as, RDR);
+ }
+
+ as->current_remaining_bytes--;
+
+ if (as->current_remaining_bytes) {
+ if (xfer->tx_buf) {
+ txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1;
+ spi_writel(as, TDR, *txp);
+ } else {
+ spi_writel(as, TDR, 0);
+ }
+ }
+}
+
+/* Tasklet
+ * Called from DMA callback + pio transfer and overrun IRQ.
+ */
+static void atmel_spi_tasklet_func(unsigned long data)
+{
+ struct spi_master *master = (struct spi_master *)data;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
+
+ dev_vdbg(master->dev.parent, "atmel_spi_tasklet_func\n");
+
+ atmel_spi_lock(as);
+
+ xfer = as->current_transfer;
+
+ if (xfer == NULL)
+ /* already been there */
+ goto tasklet_out;
+
+ msg = list_entry(as->queue.next, struct spi_message, queue);
+
+ if (as->done_status < 0) {
+ /* error happened (overrun) */
+ if (atmel_spi_use_dma(xfer))
+ atmel_spi_stop_dma(as);
+ } else {
+ /* only update length if no error */
+ msg->actual_length += xfer->len;
+ }
+
+ if (atmel_spi_use_dma(xfer)) {
+ if (!msg->is_dma_mapped)
+ atmel_spi_dma_unmap_xfer(master, xfer);
+ }
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (atmel_spi_xfer_is_last(msg, xfer) || as->done_status < 0) {
+ /* report completed (or erroneous) message */
+ atmel_spi_msg_done(master, as, msg, xfer->cs_change);
+ } else {
+ if (xfer->cs_change) {
+ cs_deactivate(as, msg->spi);
+ udelay(1);
+ cs_activate(as, msg->spi);
+ }
+
+ /*
+ * Not done yet. Submit the next transfer.
+ *
+ * FIXME handle protocol options for xfer
+ */
+ atmel_spi_next_xfer(master, msg);
+ }
+
+tasklet_out:
+ atmel_spi_unlock(as);
+}
+
+
+/* Interrupt with DMA engine management
+ *
+ * No need for locking in this Interrupt handler: done_status is the
+ * only information modified. What we need is the update of this field
+ * before tasklet runs. This is ensured by using barrier.
+ */
+static irqreturn_t
+atmel_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ u32 status, pending, imr;
+ struct spi_transfer *xfer;
+ int ret = IRQ_NONE;
+
+ imr = spi_readl(as, IMR);
+ status = spi_readl(as, SR);
+ pending = status & imr;
+
+ if (pending & SPI_BIT(OVRES)) {
+ ret = IRQ_HANDLED;
+ spi_writel(as, IDR, SPI_BIT(OVRES));
+ dev_warn(master->dev.parent, "overrun\n");
+
+ /*
+ * When we get an overrun, we disregard the current
+ * transfer. Data will not be copied back from any
+ * bounce buffer and msg->actual_len will not be
+ * updated with the last xfer.
+ *
+ * We will also not process any remaning transfers in
+ * the message.
+ *
+ * All actions are done in tasklet with done_status indication
+ */
+ as->done_status = -EIO;
+ smp_wmb();
+
+ /* Clear any overrun happening while cleaning up */
+ spi_readl(as, SR);
+
+ tasklet_schedule(&as->tasklet);
+
+ } else if (pending & SPI_BIT(RDRF)) {
+ atmel_spi_lock(as);
+
+ if (as->current_remaining_bytes) {
+ ret = IRQ_HANDLED;
+ xfer = as->current_transfer;
+ atmel_spi_pump_pio_data(as, xfer);
+ if (!as->current_remaining_bytes) {
+ /* no more data to xfer, kick tasklet */
+ spi_writel(as, IDR, pending);
+ tasklet_schedule(&as->tasklet);
+ }
+ }
+
+ atmel_spi_unlock(as);
+ } else {
+ WARN_ONCE(pending, "IRQ not handled, pending = %x\n", pending);
+ ret = IRQ_HANDLED;
+ spi_writel(as, IDR, pending);
+ }
+
+ return ret;
+}
+#else
+static void atmel_spi_tasklet_func(unsigned long data) {}
+
static irqreturn_t
atmel_spi_interrupt(int irq, void *dev_id)
{
@@ -704,6 +1159,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
return ret;
}
+#endif
static int atmel_spi_setup(struct spi_device *spi)
{
@@ -865,13 +1321,9 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
/*
* DMA map early, for performance (empties dcache ASAP) and
- * better fault reporting. This is a DMA-only driver.
- *
- * NOTE that if dma_unmap_single() ever starts to do work on
- * platforms supported by this driver, we would need to clean
- * up mappings for previously-mapped transfers.
+ * better fault reporting.
*/
- if (!msg->is_dma_mapped) {
+ if (!msg->is_dma_mapped && atmel_spi_use_dma(xfer)) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
}
@@ -973,6 +1425,7 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
spin_lock_init(&as->lock);
INIT_LIST_HEAD(&as->queue);
+ tasklet_init(&as->tasklet, atmel_spi_tasklet_func, (unsigned long)master);
as->pdev = pdev;
as->regs = ioremap(regs->start, resource_size(regs));
if (!as->regs)
@@ -991,7 +1444,11 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+
+ ret = atmel_spi_configure_dma(master);
+ if (ret)
+ goto out_reset_hw;
+
spi_writel(as, CR, SPI_BIT(SPIEN));
/* go! */
@@ -1000,10 +1457,12 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
ret = spi_register_master(master);
if (ret)
- goto out_reset_hw;
+ goto out_free_dma;
return 0;
+out_free_dma:
+ atmel_spi_release_dma(as);
out_reset_hw:
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
@@ -1012,6 +1471,7 @@ out_reset_hw:
out_unmap_regs:
iounmap(as->regs);
out_free_buffer:
+ tasklet_kill(&as->tasklet);
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
out_free:
@@ -1030,6 +1490,8 @@ static int __devexit atmel_spi_remove(struct platform_device *pdev)
/* reset the hardware and block queue progress */
spin_lock_irq(&as->lock);
as->stopping = 1;
+ atmel_spi_stop_dma(as);
+ atmel_spi_release_dma(as);
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_readl(as, SR);
@@ -1038,13 +1500,14 @@ static int __devexit atmel_spi_remove(struct platform_device *pdev)
/* Terminate remaining queued transfers */
list_for_each_entry(msg, &as->queue, queue) {
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (!msg->is_dma_mapped)
+ if (!msg->is_dma_mapped && atmel_spi_use_dma(xfer))
atmel_spi_dma_unmap_xfer(master, xfer);
}
msg->status = -ESHUTDOWN;
msg->complete(msg->context);
}
+ tasklet_kill(&as->tasklet);
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 10/23] spi-atmel: update with dmaengine interface
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (8 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 09/23] spi/atmel_spi: add dmaengine support Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 11/23] spi-atmel: fix __init/__devinit sections mismatch Richard Genoud
` (14 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
commit 185ecb5f4fd43911c35956d4cc7d94a1da30417f changed dmaengine
interface.
=> we have to update spi-atmel accordingly
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
drivers/spi/spi-atmel.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 9456fca..48bf3bc 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -542,7 +542,8 @@ static int atmel_spi_next_xfer_dma(struct spi_master *master,
&as->dma.sgrx,
1,
DMA_FROM_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+ NULL);
if (!rxdesc)
goto err_dma;
@@ -550,7 +551,8 @@ static int atmel_spi_next_xfer_dma(struct spi_master *master,
&as->dma.sgtx,
1,
DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+ NULL);
if (!txdesc)
goto err_dma;
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 11/23] spi-atmel: fix __init/__devinit sections mismatch
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (9 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 10/23] spi-atmel: update with dmaengine interface Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 12/23] spi-atmel: Fix spi-atmel driver to adapt to slave_config changes Richard Genoud
` (13 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
drivers/spi/spi-atmel.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 48bf3bc..d90e8fb 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -383,7 +383,7 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
}
#if defined(CONFIG_SPI_ATMEL_DMA)
-static bool __init filter(struct dma_chan *chan, void *slave)
+static bool filter(struct dma_chan *chan, void *slave)
{
struct at_dma_slave *sl = slave;
@@ -395,7 +395,7 @@ static bool __init filter(struct dma_chan *chan, void *slave)
}
}
-static int __init atmel_spi_configure_dma(struct spi_master *master)
+static int __devinit atmel_spi_configure_dma(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct device *controller = master->dev.parent;
@@ -628,7 +628,7 @@ static void atmel_spi_disable_dma_irq(struct atmel_spi *as)
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
}
-static int __init atmel_spi_configure_dma(struct spi_master *master)
+static int __devinit atmel_spi_configure_dma(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 12/23] spi-atmel: Fix spi-atmel driver to adapt to slave_config changes
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (10 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 11/23] spi-atmel: fix __init/__devinit sections mismatch Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 13/23] AT91 DMA OF support Richard Genoud
` (12 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
This is the following of the patch e2b35f3dbfc080f15b72834d08f04f0269dbe9be
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
drivers/spi/spi-atmel.c | 45 ++++++++++++++++++++++++++++++++++++---------
1 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index d90e8fb..28a00ab 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -399,17 +399,24 @@ static int __devinit atmel_spi_configure_dma(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct device *controller = master->dev.parent;
+ struct dma_slave_config slave_config;
struct at_dma_slave *sdata;
+ int err;
sdata = controller->platform_data;
+ memset(&slave_config, 0, sizeof(slave_config));
+ slave_config.dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
+ slave_config.src_addr = (dma_addr_t)as->phybase + SPI_RDR;
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.src_maxburst = 1;
+ slave_config.dst_maxburst = 1;
+ slave_config.device_fc = false;
+
if (sdata && sdata->dma_dev) {
dma_cap_mask_t mask;
- /* setup DMA addresses */
- sdata->rx_reg = (dma_addr_t)as->phybase + SPI_RDR;
- sdata->tx_reg = (dma_addr_t)as->phybase + SPI_TDR;
-
/* Try to grab two DMA channels */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -417,14 +424,28 @@ static int __devinit atmel_spi_configure_dma(struct spi_master *master)
if (as->dma.chan_tx)
as->dma.chan_rx = dma_request_channel(mask, filter, sdata);
}
+
if (!as->dma.chan_rx || !as->dma.chan_tx) {
- if (as->dma.chan_rx)
- dma_release_channel(as->dma.chan_rx);
- if (as->dma.chan_tx)
- dma_release_channel(as->dma.chan_tx);
dev_err(&as->pdev->dev, "DMA channel not available, "
"unable to use SPI\n");
- return -EBUSY;
+ err = -EBUSY;
+ goto error;
+ }
+
+ slave_config.direction = DMA_TO_DEVICE;
+ if (dmaengine_slave_config(as->dma.chan_tx, &slave_config)) {
+ dev_err(&as->pdev->dev,
+ "failed to configure tx dma channel\n");
+ err = -EINVAL;
+ goto error;
+ }
+
+ slave_config.direction = DMA_FROM_DEVICE;
+ if (dmaengine_slave_config(as->dma.chan_rx, &slave_config)) {
+ dev_err(&as->pdev->dev,
+ "failed to configure rx dma channel\n");
+ err = -EINVAL;
+ goto error;
}
dev_info(&as->pdev->dev, "Using %s (tx) and "
@@ -433,6 +454,12 @@ static int __devinit atmel_spi_configure_dma(struct spi_master *master)
dma_chan_name(as->dma.chan_rx));
return 0;
+error:
+ if (as->dma.chan_rx)
+ dma_release_channel(as->dma.chan_rx);
+ if (as->dma.chan_tx)
+ dma_release_channel(as->dma.chan_tx);
+ return err;
}
static void atmel_spi_stop_dma(struct atmel_spi *as)
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 13/23] AT91 DMA OF support
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (11 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 12/23] spi-atmel: Fix spi-atmel driver to adapt to slave_config changes Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 14:47 ` Nicolas Ferre
2012-08-14 13:49 ` [PATCH 14/23] add at91sam9x5 Kconfig ARCH/SOC link Richard Genoud
` (11 subsequent siblings)
24 siblings, 1 reply; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
arch/arm/mach-at91/include/mach/at_hdmac.h | 1 +
drivers/of/Kconfig | 4 +
drivers/of/Makefile | 1 +
drivers/of/of_atmel.c | 112 ++++++++++++++++++++++++++++
include/linux/of_atmel.h | 29 +++++++
5 files changed, 147 insertions(+), 0 deletions(-)
create mode 100644 drivers/of/of_atmel.c
create mode 100644 include/linux/of_atmel.h
diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
index cab0997..35667bd 100644
--- a/arch/arm/mach-at91/include/mach/at_hdmac.h
+++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
@@ -52,6 +52,7 @@ struct at_dma_slave {
#define ATC_LOCK_IF_L_CHUNK (0x0 << 22)
#define ATC_LOCK_IF_L_BUFFER (0x1 << 22)
#define ATC_AHB_PROT_MASK (0x7 << 24) /* AHB Protection */
+#define ATC_AHB_PROT(h) (((h) << 24) && ATC_AHB_PROT_MASK)
#define ATC_FIFOCFG_MASK (0x3 << 28) /* FIFO Request Configuration */
#define ATC_FIFOCFG_LARGESTBURST (0x0 << 28)
#define ATC_FIFOCFG_HALFFIFO (0x1 << 28)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index dfba3e6..4667960 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -83,4 +83,8 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_ATMEL
+ depends on AT_HDMAC
+ def_bool y
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index e027f44..897de3b 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_ATMEL) += of_atmel.o
diff --git a/drivers/of/of_atmel.c b/drivers/of/of_atmel.c
new file mode 100644
index 0000000..bcd3c54a
--- /dev/null
+++ b/drivers/of/of_atmel.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 Richard Genoud, Paratronic S.A.
+ * <richard.genoud@gmail.com>
+ *
+ * Atmel specifics OF helpers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/printk.h>
+#include <linux/byteorder/generic.h>
+#include <mach/at_hdmac.h>
+#include <linux/of.h>
+
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+/**
+ * of_create_at_dma_slave - Alloc and initialize the struct at_dma_slave
+ * @np: pointer to node to create the struct for
+ * @bus: pointer to the bus type of the DMA device.
+ *
+ * Returns pointer to created DMA slave structure, or NULL in case of error.
+ */
+struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
+ struct bus_type *bus)
+{
+ struct at_dma_slave *atslave;
+ struct device_node *n;
+ struct property *prop;
+ const __be32 *dma_list;
+ phandle phandle;
+ int size;
+ int err = -1;
+ u32 val;
+
+ atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL);
+ if (unlikely(!atslave)) {
+ pr_err("cannot allocate memory\n");
+ goto error;
+ }
+
+ atslave->cfg |= of_property_read_bool(np, "atc_src_rep") ? ATC_SRC_REP : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_dst_rep") ? ATC_DST_REP : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_src_h2sel_hw") ? ATC_SRC_H2SEL_HW : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_dst_h2sel_hw") ? ATC_DST_H2SEL_HW : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_sod") ? ATC_SOD : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_lock_if") ? ATC_LOCK_IF : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_lock_b") ? ATC_LOCK_B : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_lock_if_l") ? ATC_LOCK_IF_L : 0;
+ atslave->cfg |= of_property_read_bool(np, "atc_lock_if_l_buffer") ? ATC_LOCK_IF_L_BUFFER : 0;
+ if (of_property_read_bool(np, "atc_fifocfg_halffifo"))
+ atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_HALFFIFO;
+ if (of_property_read_bool(np, "atc_fifocfg_enoughspace"))
+ atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_ENOUGHSPACE;
+ if (of_property_read_bool(np, "atc_fifocfg_largestburst"))
+ atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_LARGESTBURST;
+ if (!of_property_read_u32(np, "atc_ahb_prot", &val))
+ atslave->cfg |= ATC_AHB_PROT(val);
+ if (!of_property_read_u32(np, "atc_src_per", &val))
+ atslave->cfg |= ATC_SRC_PER(val);
+ if (!of_property_read_u32(np, "atc_dst_per", &val))
+ atslave->cfg |= ATC_DST_PER(val);
+
+ /* we need to associate the wanted dma struct device to
+ * atslave->dma_dev. This is needed when searching for
+ * a free dma channel
+ */
+ prop = of_find_property(np, "dma", &size);
+ if (!prop) {
+ pr_err("can't find the dma child node\n");
+ goto error;
+ }
+ dma_list = prop->value;
+ size /= sizeof(*dma_list);
+ if (size != 1) {
+ pr_err("only one dma handle is supported\n");
+ goto error;
+ }
+
+ phandle = be32_to_cpup(dma_list);
+ n = of_find_node_by_phandle(phandle);
+ if (!n) {
+ pr_err("unable to find dma device: invalid phandle %s\n",
+ prop->name);
+ goto error;
+ }
+
+ atslave->dma_dev = bus_find_device(bus, NULL, n, of_dev_node_match);
+ if (!atslave->dma_dev) {
+ pr_err("can't find struct device for DMA %s\n", prop->name);
+ goto error;
+ }
+
+ pr_debug("DMA cfg register=0x%x DMA device path=%s\n",
+ atslave->cfg, prop->name);
+ err = 0;
+error:
+ if (err)
+ kfree(atslave);
+ return atslave;
+}
+EXPORT_SYMBOL_GPL(of_create_at_dma_slave);
+
diff --git a/include/linux/of_atmel.h b/include/linux/of_atmel.h
new file mode 100644
index 0000000..256f336
--- /dev/null
+++ b/include/linux/of_atmel.h
@@ -0,0 +1,29 @@
+#ifndef _LINUX_OF_ATMEL_H
+#define _LINUX_OF_ATMEL_H
+/*
+ * Copyright (C) 2012 Richard Genoud, Paratronic S.A.
+ * <richard.genoud@gmail.com>
+ *
+ * Atmel specifics OF helpers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/of.h>
+#include <linux/device.h>
+#include <mach/at_hdmac.h>
+
+#ifdef CONFIG_OF_ATMEL
+extern struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
+ struct bus_type *bus);
+#else
+static struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
+ struct bus_type *bus)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF_ATMEL */
+
+#endif /* _LINUX_OF_ATMEL_H */
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 13/23] AT91 DMA OF support
2012-08-14 13:49 ` [PATCH 13/23] AT91 DMA OF support Richard Genoud
@ 2012-08-14 14:47 ` Nicolas Ferre
0 siblings, 0 replies; 30+ messages in thread
From: Nicolas Ferre @ 2012-08-14 14:47 UTC (permalink / raw)
To: linux-arm-kernel
Hi Richard,
I am not sure that this one will go further: there is an initiative to
build a pretty generic DMA OF support... It takes time but it is
progressing...
Anyway, there may have some bits to integrate in at_hdmac.c driver: I
will have a closer look later.
Thanks,
On 08/14/2012 03:49 PM, Richard Genoud :
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> ---
> arch/arm/mach-at91/include/mach/at_hdmac.h | 1 +
> drivers/of/Kconfig | 4 +
> drivers/of/Makefile | 1 +
> drivers/of/of_atmel.c | 112 ++++++++++++++++++++++++++++
> include/linux/of_atmel.h | 29 +++++++
> 5 files changed, 147 insertions(+), 0 deletions(-)
> create mode 100644 drivers/of/of_atmel.c
> create mode 100644 include/linux/of_atmel.h
>
> diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
> index cab0997..35667bd 100644
> --- a/arch/arm/mach-at91/include/mach/at_hdmac.h
> +++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
> @@ -52,6 +52,7 @@ struct at_dma_slave {
> #define ATC_LOCK_IF_L_CHUNK (0x0 << 22)
> #define ATC_LOCK_IF_L_BUFFER (0x1 << 22)
> #define ATC_AHB_PROT_MASK (0x7 << 24) /* AHB Protection */
> +#define ATC_AHB_PROT(h) (((h) << 24) && ATC_AHB_PROT_MASK)
> #define ATC_FIFOCFG_MASK (0x3 << 28) /* FIFO Request Configuration */
> #define ATC_FIFOCFG_LARGESTBURST (0x0 << 28)
> #define ATC_FIFOCFG_HALFFIFO (0x1 << 28)
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index dfba3e6..4667960 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -83,4 +83,8 @@ config OF_MTD
> depends on MTD
> def_bool y
>
> +config OF_ATMEL
> + depends on AT_HDMAC
> + def_bool y
> +
> endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index e027f44..897de3b 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
> obj-$(CONFIG_OF_PCI) += of_pci.o
> obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> obj-$(CONFIG_OF_MTD) += of_mtd.o
> +obj-$(CONFIG_OF_ATMEL) += of_atmel.o
> diff --git a/drivers/of/of_atmel.c b/drivers/of/of_atmel.c
> new file mode 100644
> index 0000000..bcd3c54a
> --- /dev/null
> +++ b/drivers/of/of_atmel.c
> @@ -0,0 +1,112 @@
> +/*
> + * Copyright (C) 2012 Richard Genoud, Paratronic S.A.
> + * <richard.genoud@gmail.com>
> + *
> + * Atmel specifics OF helpers
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#include <linux/kernel.h>
> +#include <linux/export.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <linux/printk.h>
> +#include <linux/byteorder/generic.h>
> +#include <mach/at_hdmac.h>
> +#include <linux/of.h>
> +
> +static int of_dev_node_match(struct device *dev, void *data)
> +{
> + return dev->of_node == data;
> +}
> +
> +/**
> + * of_create_at_dma_slave - Alloc and initialize the struct at_dma_slave
> + * @np: pointer to node to create the struct for
> + * @bus: pointer to the bus type of the DMA device.
> + *
> + * Returns pointer to created DMA slave structure, or NULL in case of error.
> + */
> +struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
> + struct bus_type *bus)
> +{
> + struct at_dma_slave *atslave;
> + struct device_node *n;
> + struct property *prop;
> + const __be32 *dma_list;
> + phandle phandle;
> + int size;
> + int err = -1;
> + u32 val;
> +
> + atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL);
> + if (unlikely(!atslave)) {
> + pr_err("cannot allocate memory\n");
> + goto error;
> + }
> +
> + atslave->cfg |= of_property_read_bool(np, "atc_src_rep") ? ATC_SRC_REP : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_dst_rep") ? ATC_DST_REP : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_src_h2sel_hw") ? ATC_SRC_H2SEL_HW : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_dst_h2sel_hw") ? ATC_DST_H2SEL_HW : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_sod") ? ATC_SOD : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_lock_if") ? ATC_LOCK_IF : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_lock_b") ? ATC_LOCK_B : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_lock_if_l") ? ATC_LOCK_IF_L : 0;
> + atslave->cfg |= of_property_read_bool(np, "atc_lock_if_l_buffer") ? ATC_LOCK_IF_L_BUFFER : 0;
> + if (of_property_read_bool(np, "atc_fifocfg_halffifo"))
> + atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_HALFFIFO;
> + if (of_property_read_bool(np, "atc_fifocfg_enoughspace"))
> + atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_ENOUGHSPACE;
> + if (of_property_read_bool(np, "atc_fifocfg_largestburst"))
> + atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_LARGESTBURST;
> + if (!of_property_read_u32(np, "atc_ahb_prot", &val))
> + atslave->cfg |= ATC_AHB_PROT(val);
> + if (!of_property_read_u32(np, "atc_src_per", &val))
> + atslave->cfg |= ATC_SRC_PER(val);
> + if (!of_property_read_u32(np, "atc_dst_per", &val))
> + atslave->cfg |= ATC_DST_PER(val);
> +
> + /* we need to associate the wanted dma struct device to
> + * atslave->dma_dev. This is needed when searching for
> + * a free dma channel
> + */
> + prop = of_find_property(np, "dma", &size);
> + if (!prop) {
> + pr_err("can't find the dma child node\n");
> + goto error;
> + }
> + dma_list = prop->value;
> + size /= sizeof(*dma_list);
> + if (size != 1) {
> + pr_err("only one dma handle is supported\n");
> + goto error;
> + }
> +
> + phandle = be32_to_cpup(dma_list);
> + n = of_find_node_by_phandle(phandle);
> + if (!n) {
> + pr_err("unable to find dma device: invalid phandle %s\n",
> + prop->name);
> + goto error;
> + }
> +
> + atslave->dma_dev = bus_find_device(bus, NULL, n, of_dev_node_match);
> + if (!atslave->dma_dev) {
> + pr_err("can't find struct device for DMA %s\n", prop->name);
> + goto error;
> + }
> +
> + pr_debug("DMA cfg register=0x%x DMA device path=%s\n",
> + atslave->cfg, prop->name);
> + err = 0;
> +error:
> + if (err)
> + kfree(atslave);
> + return atslave;
> +}
> +EXPORT_SYMBOL_GPL(of_create_at_dma_slave);
> +
> diff --git a/include/linux/of_atmel.h b/include/linux/of_atmel.h
> new file mode 100644
> index 0000000..256f336
> --- /dev/null
> +++ b/include/linux/of_atmel.h
> @@ -0,0 +1,29 @@
> +#ifndef _LINUX_OF_ATMEL_H
> +#define _LINUX_OF_ATMEL_H
> +/*
> + * Copyright (C) 2012 Richard Genoud, Paratronic S.A.
> + * <richard.genoud@gmail.com>
> + *
> + * Atmel specifics OF helpers
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#include <linux/of.h>
> +#include <linux/device.h>
> +#include <mach/at_hdmac.h>
> +
> +#ifdef CONFIG_OF_ATMEL
> +extern struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
> + struct bus_type *bus);
> +#else
> +static struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
> + struct bus_type *bus)
> +{
> + return NULL;
> +}
> +#endif /* CONFIG_OF_ATMEL */
> +
> +#endif /* _LINUX_OF_ATMEL_H */
>
--
Nicolas Ferre
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 14/23] add at91sam9x5 Kconfig ARCH/SOC link
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (12 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 13/23] AT91 DMA OF support Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 15/23] spi-atmel: add DMA OF support Richard Genoud
` (10 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
---
arch/arm/mach-at91/Kconfig | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index c8050b1..c6eb877 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -141,6 +141,10 @@ config ARCH_AT91SAM9G45
bool "AT91SAM9G45"
select SOC_AT91SAM9G45
+config ARCH_AT91SAM9X5
+ bool "AT91SAM9x5"
+ select SOC_AT91SAM9X5
+
config ARCH_AT91X40
bool "AT91x40"
depends on !MMU
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 15/23] spi-atmel: add DMA OF support
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (13 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 14/23] add at91sam9x5 Kconfig ARCH/SOC link Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 16/23] [BUG] SPI: array out of bound => no CS Richard Genoud
` (9 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
drivers/of/of_atmel.c | 1 -
drivers/spi/spi-atmel.c | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 1 deletions(-)
diff --git a/drivers/of/of_atmel.c b/drivers/of/of_atmel.c
index bcd3c54a..a59b9ced 100644
--- a/drivers/of/of_atmel.c
+++ b/drivers/of/of_atmel.c
@@ -55,7 +55,6 @@ struct at_dma_slave *of_create_at_dma_slave(struct device_node *np,
atslave->cfg |= of_property_read_bool(np, "atc_sod") ? ATC_SOD : 0;
atslave->cfg |= of_property_read_bool(np, "atc_lock_if") ? ATC_LOCK_IF : 0;
atslave->cfg |= of_property_read_bool(np, "atc_lock_b") ? ATC_LOCK_B : 0;
- atslave->cfg |= of_property_read_bool(np, "atc_lock_if_l") ? ATC_LOCK_IF_L : 0;
atslave->cfg |= of_property_read_bool(np, "atc_lock_if_l_buffer") ? ATC_LOCK_IF_L_BUFFER : 0;
if (of_property_read_bool(np, "atc_fifocfg_halffifo"))
atslave->cfg = (atslave->cfg & ~ATC_FIFOCFG_MASK) | ATC_FIFOCFG_HALFFIFO;
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 28a00ab..d629422 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -21,6 +21,7 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/of_atmel.h>
#include <asm/io.h>
#include <mach/board.h>
@@ -1411,6 +1412,8 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
int ret;
struct spi_master *master;
struct atmel_spi *as;
+ struct bus_type *bus = pdev->dev.bus;
+ struct device_node *of = pdev->dev.of_node;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
@@ -1430,6 +1433,17 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
if (!master)
goto out_free;
+
+ /* populate platform_data from device tree */
+ if (of) {
+ pdev->dev.platform_data = of_create_at_dma_slave(of, bus);
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "could not get DMA\n");
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1504,6 +1518,10 @@ out_free_buffer:
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
out_free:
+ if (of) {
+ kfree((struct at_dma_slave*)(pdev->dev.platform_data));
+ pdev->dev.platform_data = NULL;
+ }
clk_put(clk);
spi_master_put(master);
return ret;
@@ -1546,6 +1564,10 @@ static int __devexit atmel_spi_remove(struct platform_device *pdev)
iounmap(as->regs);
spi_unregister_master(master);
+ if (pdev->dev.of_node) {
+ kfree((struct at_dma_slave*)(pdev->dev.platform_data));
+ pdev->dev.platform_data = NULL;
+ }
return 0;
}
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 16/23] [BUG] SPI: array out of bound => no CS
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (14 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 15/23] spi-atmel: add DMA OF support Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 17/23] [BUG] atmel-spi && DMA: OOPS if buffer > 4400 bytes Richard Genoud
` (8 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
---
drivers/spi/spi.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 3fb5b6d..74e6577 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -976,8 +976,8 @@ static int of_spi_register_master(struct spi_master *master)
return -ENOMEM;
memset(cs, -EINVAL, master->num_chipselect);
- master->num_chipselect += nb;
cs += master->num_chipselect;
+ master->num_chipselect += nb;
for (i = 0; i < nb; i++)
cs[i] = of_get_named_gpio(np, "cs-gpios", i);
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 17/23] [BUG] atmel-spi && DMA: OOPS if buffer > 4400 bytes
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (15 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 16/23] [BUG] SPI: array out of bound => no CS Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 18/23] sam9x5: declare SPI clocks Richard Genoud
` (7 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
this is just a quick and suboptimal workaround
---
drivers/spi/spi-atmel.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index d629422..0899da2 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -638,7 +638,8 @@ static void atmel_spi_next_xfer(struct spi_master *master,
as->current_transfer = xfer;
- if (atmel_spi_use_dma(xfer)) {
+ /* quick (and *really* not optimal) workaround for DMA BUG */
+ if (atmel_spi_use_dma(xfer) && (xfer->len < BUFFER_SIZE)) {
if (!atmel_spi_next_xfer_dma(master, xfer))
return;
else
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 18/23] sam9x5: declare SPI clocks
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (16 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 17/23] [BUG] atmel-spi && DMA: OOPS if buffer > 4400 bytes Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 19/23] spi-atmel: add sam9x5 SPI in device tree Richard Genoud
` (6 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
arch/arm/mach-at91/at91sam9x5.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index bbd2f8e..e213e2d 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -16,6 +16,7 @@
#include <mach/at91_pmc.h>
#include <mach/cpu.h>
#include <mach/board.h>
+#include <mach/gpio.h>
#include "soc.h"
#include "generic.h"
@@ -231,6 +232,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "f0000000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi1_clk),
CLKDEV_CON_ID("pioA", &pioAB_clk),
CLKDEV_CON_ID("pioB", &pioAB_clk),
CLKDEV_CON_ID("pioC", &pioCD_clk),
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 19/23] spi-atmel: add sam9x5 SPI in device tree
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (17 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 18/23] sam9x5: declare SPI clocks Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 20/23] spi-atmel: add dma support in sam9x5 " Richard Genoud
` (5 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
arch/arm/boot/dts/at91sam9x5.dtsi | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index e58965d6..8cb8b0d 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -344,6 +344,36 @@
trigger-value = <0x6>;
};
};
+
+ spi0: spi at f0000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0000000 0x100>;
+ interrupts = <13 4 3>;
+ cs-gpios = <&pioA 14 0
+ &pioA 7 0 /* conflicts with TXD2 */
+ &pioA 1 0 /* conflicts with RXD0 */
+ &pioB 3 0 /* conflicts with ERXDV */
+ >;
+ dma-mask = <0xffffffff>;
+ status = "disabled";
+ };
+
+ spi1: spi at f0004000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0004000 0x100>;
+ interrupts = <14 4 3>;
+ cs-gpios = <&pioA 8 0 /* conflitcs with RXD2 */
+ &pioA 0 0 /* conflitcs with TXD0 */
+ &pioA 31 0 /* conflitcs with TWCK0 */
+ &pioA 30 0 /* conflitcs with TWD0 */
+ >;
+ dma-mask = <0xffffffff>;
+ status = "disabled";
+ };
};
nand0: nand at 40000000 {
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 20/23] spi-atmel: add dma support in sam9x5 device tree
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (18 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 19/23] spi-atmel: add sam9x5 SPI in device tree Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 21/23] spi-atmel OF: complete documentation Richard Genoud
` (4 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
arch/arm/boot/dts/at91sam9x5.dtsi | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 8cb8b0d..ef09816 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -357,6 +357,12 @@
&pioB 3 0 /* conflicts with ERXDV */
>;
dma-mask = <0xffffffff>;
+ dma = <&dma0>;
+ atc_src_per = <2>; /* AT_DMA_ID_SPI0_RX */
+ atc_dst_per = <1>; /* AT_DMA_ID_SPI0_TX */
+ atc_fifocfg_halffifo;
+ atc_src_h2sel_hw;
+ atc_dst_h2sel_hw;
status = "disabled";
};
@@ -372,6 +378,12 @@
&pioA 30 0 /* conflitcs with TWD0 */
>;
dma-mask = <0xffffffff>;
+ dma = <&dma0>;
+ atc_src_per = <4>; /* AT_DMA_ID_SPI1_RX */
+ atc_dst_per = <3>; /* AT_DMA_ID_SPI1_TX */
+ atc_fifocfg_halffifo;
+ atc_src_h2sel_hw;
+ atc_dst_h2sel_hw;
status = "disabled";
};
};
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 21/23] spi-atmel OF: complete documentation
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (19 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 20/23] spi-atmel: add dma support in sam9x5 " Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 22/23] spi-atmel: complete DMA slave OF documentation Richard Genoud
` (3 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
.../devicetree/bindings/spi/spi_atmel.txt | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
index 7ec3d8d..6d2e5e1 100644
--- a/Documentation/devicetree/bindings/spi/spi_atmel.txt
+++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
@@ -4,3 +4,18 @@ Required properties:
- compatible : should be "atmel,at91rm9200-spi".
- reg: Address and length of the register set for the device
- interrupts: Should contain macb interrupt
+- cs-gpio: Should contain the GPIOs used for chipselect.
+
+spi0: spi at f0000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0000000 0x100>;
+ interrupts = <13 4>;
+ cs-gpios = <&pioA 14 0
+ &pioA 7 0 /* conflicts with TXD2 */
+ &pioA 1 0 /* conflicts with RXD0 */
+ &pioB 3 0 /* conflicts with ERXDV */
+ >;
+ status = "disabled";
+};
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 22/23] spi-atmel: complete DMA slave OF documentation
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (20 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 21/23] spi-atmel OF: complete documentation Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 13:49 ` [PATCH 23/23] sam9x5ek DTS: enable SPI dataflash Richard Genoud
` (2 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
.../devicetree/bindings/spi/spi_atmel.txt | 25 ++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
index 6d2e5e1..b5d8082 100644
--- a/Documentation/devicetree/bindings/spi/spi_atmel.txt
+++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
@@ -5,6 +5,24 @@ Required properties:
- reg: Address and length of the register set for the device
- interrupts: Should contain macb interrupt
- cs-gpio: Should contain the GPIOs used for chipselect.
+- dma-mask: device coherent dma mask.
+/* dma transfer configuration. Cf DMA Channel configuration register */
+- dma: handle to the dma controller that should be used.
+- atc_src_per: source channel for DMA operation.
+- atc_dst_per: destination channel for DMA operation.
+- atc_src_h2sel_hw: Hardware handshaking interface is used to trigger a
+transfer request.
+- atc_dst_h2sel_hw: Hardware handshaking interface is used to trigger a
+transfer request.
+- atc_sod: STOP ON DONE activated.
+- atc_lock_if: Interface Lock capability is enabled.
+- atc_lock_b: AHB Bus Locking capability is enabled.
+- atc_lock_if_l_buffer: The Master Interface Arbiter is locked by the channel x for a buffer transfer.
+- atc_fifocfg_halffifo: When half FIFO size is available/filled, a source/destination request is serviced.
+- atc_fifocfg_enoughspace: When there is enough space/data available to perform a single AHB access, then the request is serviced.
+- atc_fifocfg_largestburst: The largest defined length AHB burst is performed on the destination AHB interface.
+- atc_ahb_prot: AHB Protection value. (cf release manual)
+
spi0: spi at f0000000 {
#address-cells = <1>;
@@ -17,5 +35,12 @@ spi0: spi at f0000000 {
&pioA 1 0 /* conflicts with RXD0 */
&pioB 3 0 /* conflicts with ERXDV */
>;
+ dma-mask = <0xffffffff>;
+ dma = <&dma0>;
+ atc_src_per = <2>; /* AT_DMA_ID_SPI0_RX */
+ atc_dst_per = <1>; /* AT_DMA_ID_SPI0_TX */
+ atc_fifocfg_halffifo;
+ atc_src_h2sel_hw;
+ atc_dst_h2sel_hw;
status = "disabled";
};
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 23/23] sam9x5ek DTS: enable SPI dataflash
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (21 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 22/23] spi-atmel: complete DMA slave OF documentation Richard Genoud
@ 2012-08-14 13:49 ` Richard Genoud
2012-08-14 14:16 ` [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
2012-08-14 15:29 ` Nicolas Ferre
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
arch/arm/boot/dts/at91sam9x5ek.dtsi | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
index e5000a7..c99f1cc 100644
--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -30,6 +30,16 @@
phy-mode = "rmii";
status = "okay";
};
+
+ spi0: spi at f0000000 {
+ status = "okay";
+ cs-gpios = <&pioA 14 0>;
+ m25p80 at 0 {
+ compatible = "atmel,at25df321a";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+ };
};
usb0: ohci at 00600000 {
--
1.7.2.5
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (22 preceding siblings ...)
2012-08-14 13:49 ` [PATCH 23/23] sam9x5ek DTS: enable SPI dataflash Richard Genoud
@ 2012-08-14 14:16 ` Richard Genoud
2012-08-14 15:29 ` Nicolas Ferre
24 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-14 14:16 UTC (permalink / raw)
To: linux-arm-kernel
2012/8/14 Richard Genoud <richard.genoud@gmail.com>:
> Nicolas,
> I said that I had some work done on sam9g35-ek, here is the spi part, based
> on your and Jean-Christophe work.
> You have to enable CONFIG_ARCH_AT91SAM9X5 to get it work.
I forgot something:
As I didn't get pinctrl to work, on top of this patchset, I did a
revert of "ARM: at91: add pinctrl support"
and I made this change :
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index e213e2d..bc3fdbf 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -313,6 +313,13 @@ static void __init at91sam9x5_map_io(void)
at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
}
+
+void __init at91sam9x5_initialize(void)
+{
+ /* Register GPIO subsystem (using DT) */
+ at91_gpio_init(NULL, 0);
+}
+
/* --------------------------------------------------------------------
* Interrupt initialization
* -------------------------------------------------------------------- */
@@ -320,4 +327,5 @@ static void __init at91sam9x5_map_io(void)
struct at91_init_soc __initdata at91sam9x5_soc = {
.map_io = at91sam9x5_map_io,
.register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
};
I also enabled the spi controller in the DTS:
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi
b/arch/arm/boot/dts/at91sam9x5.dtsi
index ef09816..cc1c830 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -363,7 +363,7 @@
atc_fifocfg_halffifo;
atc_src_h2sel_hw;
atc_dst_h2sel_hw;
- status = "disabled";
+ status = "okay";
};
spi1: spi at f0004000 {
--
for me, ck means con kolivas and not calvin klein... does it mean I'm a geek ?
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5
2012-08-14 13:49 [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
` (23 preceding siblings ...)
2012-08-14 14:16 ` [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5 Richard Genoud
@ 2012-08-14 15:29 ` Nicolas Ferre
2012-08-14 17:44 ` Jean-Christophe PLAGNIOL-VILLARD
24 siblings, 1 reply; 30+ messages in thread
From: Nicolas Ferre @ 2012-08-14 15:29 UTC (permalink / raw)
To: linux-arm-kernel
On 08/14/2012 03:49 PM, Richard Genoud :
> Nicolas,
> I said that I had some work done on sam9g35-ek, here is the spi part, based
> on your and Jean-Christophe work.
> You have to enable CONFIG_ARCH_AT91SAM9X5 to get it work.
>
> The goal of this patchset is to share the work I've done, it's not ready
> for upstream, but it may save some time.
>
> It's based on 3.6-rc1 + Jean-Christophe's pinctrl patchset.
>
> Best Regards,
Richard,
Thanks a lot for updating this material: We really appreciate.
We will try to review this material together with Jean-Christophe and
colleagues @ Atmel. I hope that we will go forward with this collected
material in the near future.
Maybe DMA OF part will not be upstreamed as-is because of an ongoing
initiative to build a generic dmaengine OF support.
> Jean-Christophe PLAGNIOL-VILLARD (3):
> of: add dma-mask binding
> of_spi: add generic binding support to specify cs gpio
I know that Jean-Christophe has had difficulties to have feedback on
there parts...
> spi/atmel: add DT support
>
> Nicolas Ferre (6):
> spi/atmel_spi: trivial: change some comments
> spi/atmel_spi: add physical base address
> spi/atmel_spi: call unmapping on transfers buffers
> spi/atmel_spi: status information passed through controller data
> spi/atmel_spi: add flag to controller data for lock operations
> spi/atmel_spi: add dmaengine support
>
> Richard Genoud (14):
> spi-atmel: update with dmaengine interface
This will certainly be squashed in previous path.
> spi-atmel: fix __init/__devinit sections mismatch
This one also: but it is good to have them separated at fist.
> spi-atmel: Fix spi-atmel driver to adapt to slave_config changes
> AT91 DMA OF support
> add at91sam9x5 Kconfig ARCH/SOC link
Is it fixup for a bug? Jean-Christophe, a though about this one?
> spi-atmel: add DMA OF support
> [BUG] SPI: array out of bound => no CS
> [BUG] atmel-spi && DMA: OOPS if buffer > 4400 bytes
> sam9x5: declare SPI clocks
> spi-atmel: add sam9x5 SPI in device tree
> spi-atmel: add dma support in sam9x5 device tree
> spi-atmel OF: complete documentation
Maybe documentation has to be folded in the patch that actually adds the
OF support.
> spi-atmel: complete DMA slave OF documentation
> sam9x5ek DTS: enable SPI dataflash
>
> Documentation/devicetree/bindings/spi/spi-bus.txt | 6 +
> .../devicetree/bindings/spi/spi_atmel.txt | 46 ++
> arch/arm/boot/dts/at91sam9x5.dtsi | 42 ++
> arch/arm/boot/dts/at91sam9x5ek.dtsi | 10 +
> arch/arm/mach-at91/Kconfig | 4 +
> arch/arm/mach-at91/at91sam9x5.c | 3 +
> arch/arm/mach-at91/include/mach/at_hdmac.h | 1 +
> drivers/of/Kconfig | 4 +
> drivers/of/Makefile | 1 +
> drivers/of/of_atmel.c | 111 ++++
> drivers/of/platform.c | 23 +-
> drivers/spi/Kconfig | 9 +
> drivers/spi/spi-atmel.c | 611 ++++++++++++++++++--
> drivers/spi/spi.c | 55 ++-
> include/linux/of_atmel.h | 29 +
> include/linux/spi/spi.h | 3 +
> 16 files changed, 914 insertions(+), 44 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/spi/spi_atmel.txt
> create mode 100644 drivers/of/of_atmel.c
> create mode 100644 include/linux/of_atmel.h
>
--
Nicolas Ferre
^ permalink raw reply [flat|nested] 30+ messages in thread* [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5
2012-08-14 15:29 ` Nicolas Ferre
@ 2012-08-14 17:44 ` Jean-Christophe PLAGNIOL-VILLARD
2012-08-14 17:48 ` Nicolas Ferre
0 siblings, 1 reply; 30+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-08-14 17:44 UTC (permalink / raw)
To: linux-arm-kernel
On 17:29 Tue 14 Aug , Nicolas Ferre wrote:
> On 08/14/2012 03:49 PM, Richard Genoud :
> > Nicolas,
> > I said that I had some work done on sam9g35-ek, here is the spi part, based
> > on your and Jean-Christophe work.
> > You have to enable CONFIG_ARCH_AT91SAM9X5 to get it work.
> >
> > The goal of this patchset is to share the work I've done, it's not ready
> > for upstream, but it may save some time.
> >
> > It's based on 3.6-rc1 + Jean-Christophe's pinctrl patchset.
> >
> > Best Regards,
>
> Richard,
>
> Thanks a lot for updating this material: We really appreciate.
>
> We will try to review this material together with Jean-Christophe and
> colleagues @ Atmel. I hope that we will go forward with this collected
> material in the near future.
>
> Maybe DMA OF part will not be upstreamed as-is because of an ongoing
> initiative to build a generic dmaengine OF support.
>
> > Jean-Christophe PLAGNIOL-VILLARD (3):
> > of: add dma-mask binding
> > of_spi: add generic binding support to specify cs gpio
>
> I know that Jean-Christophe has had difficulties to have feedback on
> there parts...
yes I need to re-write it as suggest by Grant
will take a look later next week on this
>
> > spi/atmel: add DT support
> >
> > Nicolas Ferre (6):
> > spi/atmel_spi: trivial: change some comments
> > spi/atmel_spi: add physical base address
> > spi/atmel_spi: call unmapping on transfers buffers
> > spi/atmel_spi: status information passed through controller data
> > spi/atmel_spi: add flag to controller data for lock operations
> > spi/atmel_spi: add dmaengine support
> >
> > Richard Genoud (14):
> > spi-atmel: update with dmaengine interface
>
> This will certainly be squashed in previous path.
>
> > spi-atmel: fix __init/__devinit sections mismatch
>
> This one also: but it is good to have them separated at fist.
>
> > spi-atmel: Fix spi-atmel driver to adapt to slave_config changes
> > AT91 DMA OF support
> > add at91sam9x5 Kconfig ARCH/SOC link
>
> Is it fixup for a bug? Jean-Christophe, a though about this one?
no the ARCH_xxx is old style can not be used on DT only soc
this patch need to be droped
Best Regards,
J.
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5
2012-08-14 17:44 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-08-14 17:48 ` Nicolas Ferre
2012-08-16 7:07 ` Richard Genoud
0 siblings, 1 reply; 30+ messages in thread
From: Nicolas Ferre @ 2012-08-14 17:48 UTC (permalink / raw)
To: linux-arm-kernel
On 08/14/2012 07:44 PM, Jean-Christophe PLAGNIOL-VILLARD :
> On 17:29 Tue 14 Aug , Nicolas Ferre wrote:
>> On 08/14/2012 03:49 PM, Richard Genoud :
>>> Nicolas,
>>> I said that I had some work done on sam9g35-ek, here is the spi part, based
>>> on your and Jean-Christophe work.
>>> You have to enable CONFIG_ARCH_AT91SAM9X5 to get it work.
>>>
>>> The goal of this patchset is to share the work I've done, it's not ready
>>> for upstream, but it may save some time.
>>>
>>> It's based on 3.6-rc1 + Jean-Christophe's pinctrl patchset.
>>>
>>> Best Regards,
>>
>> Richard,
>>
>> Thanks a lot for updating this material: We really appreciate.
>>
>> We will try to review this material together with Jean-Christophe and
>> colleagues @ Atmel. I hope that we will go forward with this collected
>> material in the near future.
>>
>> Maybe DMA OF part will not be upstreamed as-is because of an ongoing
>> initiative to build a generic dmaengine OF support.
>>
>>> Jean-Christophe PLAGNIOL-VILLARD (3):
>>> of: add dma-mask binding
>>> of_spi: add generic binding support to specify cs gpio
>>
>> I know that Jean-Christophe has had difficulties to have feedback on
>> there parts...
> yes I need to re-write it as suggest by Grant
>
> will take a look later next week on this
>>
>>> spi/atmel: add DT support
>>>
>>> Nicolas Ferre (6):
>>> spi/atmel_spi: trivial: change some comments
>>> spi/atmel_spi: add physical base address
>>> spi/atmel_spi: call unmapping on transfers buffers
>>> spi/atmel_spi: status information passed through controller data
>>> spi/atmel_spi: add flag to controller data for lock operations
>>> spi/atmel_spi: add dmaengine support
>>>
>>> Richard Genoud (14):
>>> spi-atmel: update with dmaengine interface
>>
>> This will certainly be squashed in previous path.
>>
>>> spi-atmel: fix __init/__devinit sections mismatch
>>
>> This one also: but it is good to have them separated at fist.
>>
>>> spi-atmel: Fix spi-atmel driver to adapt to slave_config changes
>>> AT91 DMA OF support
>>> add at91sam9x5 Kconfig ARCH/SOC link
>>
>> Is it fixup for a bug? Jean-Christophe, a though about this one?
> no the ARCH_xxx is old style can not be used on DT only soc
>
> this patch need to be droped
That is what I suspected, thanks J.
Bye,
--
Nicolas Ferre
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 00/23] work in progress: SPI controller w/DMA SAM9X5
2012-08-14 17:48 ` Nicolas Ferre
@ 2012-08-16 7:07 ` Richard Genoud
0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2012-08-16 7:07 UTC (permalink / raw)
To: linux-arm-kernel
2012/8/14 Nicolas Ferre <nicolas.ferre@atmel.com>:
>>>> add at91sam9x5 Kconfig ARCH/SOC link
>>>
>>> Is it fixup for a bug? Jean-Christophe, a though about this one?
>> no the ARCH_xxx is old style can not be used on DT only soc
>>
>> this patch need to be droped
>
> That is what I suspected, thanks J.
Yes, Jean-Christophe is right. This patch needs to be dropped, and
this one should be applied instead:
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 169592a..f45d823 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -76,7 +76,7 @@ config SPI_ATMEL
config SPI_ATMEL_DMA
bool "Atmel SPI DMA support"
- depends on SPI_ATMEL && (ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5) &&
DMA_ENGINE && EXPERIMENTAL
+ depends on SPI_ATMEL && (SOC_AT91SAM9G45 || SOC_AT91SAM9X5) &&
DMA_ENGINE && EXPERIMENTAL
default y
help
Say Y here if you want the Atmel SPI driver to use the DMA engine.
Data transfers
Richard.
--
for me, ck means con kolivas and not calvin klein... does it mean I'm a geek ?
^ permalink raw reply related [flat|nested] 30+ messages in thread