* [v2 PATCH 02/14] of_spi: add generic binding support to specify cs gpio
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2012-12-04 7:53 ` Wenyou Yang
[not found] ` <1354607640-13229-3-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-04 7:53 ` [v2 PATCH 03/14] spi/atmel_spi: add physical base address Wenyou Yang
` (8 subsequent siblings)
9 siblings, 1 reply; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
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-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org
Cc: rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
---
Hi, Richard,
This patch based on the original patch from Jean-Christophe,
[PATCH] of_spi: add generic binding support to specify cs gpio
and merge the patch from Richard Genoud,
[PATCH] [BUG] SPI: array out of bound => no CS
Could you sign your signature in this patch?
Best Regards,
Wenyou Yang
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 d2c33d0..7f59ae30 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.
+
Optional property:
- num-cs : total number of chipselects
@@ -37,6 +40,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@f00 {
#address-cells = <1>;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 84c2861..74e6577 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);
+ cs += master->num_chipselect;
+ master->num_chipselect += nb;
+
+ 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 at 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.9.5
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 03/14] spi/atmel_spi: add physical base address
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-04 7:53 ` [v2 PATCH 02/14] of_spi: add generic binding support to specify cs gpio Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 04/14] spi/atmel_spi: call unmapping on transfers buffers Wenyou Yang
` (7 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Needed for future use with dmaengine enabled driver.
Signed-off-by: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 16d6a83..2e040be 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;
@@ -961,6 +962,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.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 04/14] spi/atmel_spi: call unmapping on transfers buffers
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-04 7:53 ` [v2 PATCH 02/14] of_spi: add generic binding support to specify cs gpio Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 03/14] spi/atmel_spi: add physical base address Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 05/14] spi/atmel_spi: status information passed through controller data Wenyou Yang
` (6 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Signed-off-by: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 2e040be..fc1222a 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1010,6 +1010,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);
@@ -1021,9 +1022,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.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 05/14] spi/atmel_spi: status information passed through controller data
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (2 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 04/14] spi/atmel_spi: call unmapping on transfers buffers Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 06/14] spi/atmel_spi: add flag to controller data for lock operations Wenyou Yang
` (5 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
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-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index fc1222a..76a1baf 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;
void *buffer;
dma_addr_t buffer_dma;
@@ -544,15 +545,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",
@@ -564,6 +565,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)
@@ -641,7 +643,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;
@@ -659,7 +662,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.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 06/14] spi/atmel_spi: add flag to controller data for lock operations
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (3 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 05/14] spi/atmel_spi: status information passed through controller data Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 07/14] spi/atmel_spi: add DT support Wenyou Yang
` (4 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Will allow to drop the lock during DMA operations.
Signed-off-by: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 76a1baf..37f54c3 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;
@@ -323,6 +324,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)
{
@@ -559,9 +570,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;
@@ -788,13 +799,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;
@@ -813,7 +822,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;
@@ -878,11 +886,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;
}
@@ -892,17 +900,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.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 07/14] spi/atmel_spi: add DT support
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (4 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 06/14] spi/atmel_spi: add flag to controller data for lock operations Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
[not found] ` <1354607640-13229-8-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-04 7:53 ` [v2 PATCH 08/14] spi/atmel_spi: add dmaengine support Wenyou Yang
` (3 subsequent siblings)
9 siblings, 1 reply; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA, JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
The atmel_spi use only gpio for chip select.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
[wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org: Add driver data and compatible "atmel,at91sam9260-spi", "atmel,at91sam9x5-spi"]
Signed-off-by: Wenyou Yang <wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org
Cc: rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org
Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
---
Hi, Richard,
This patches is based on the original patch from Jean-Christophe
[PATCH] spi/atmel: add DT support
and merge the patch from Richard Genoud
[PATCH] spi-atmel OF: complete documentation
ane wenyou yang add more compatible "atmel,at91sam9260-spi", "atmel,at91sam9x5-spi",
add driver data to get IP version and dma support.
Could you sign your signature in this patch?
Best Regards,
Wenyou Yang
.../devicetree/bindings/spi/spi_atmel.txt | 23 +++++
drivers/spi/spi-atmel.c | 102 +++++++++++++++++---
2 files changed, 113 insertions(+), 12 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..20cdc91
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
@@ -0,0 +1,23 @@
+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
+- cs-gpio: Should contain the GPIOs used for chipselect.
+- dma-mask: device coherent dma mask.
+
+spi0: spi@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 */
+ >;
+ dma-mask = <0xffffffff>;
+ status = "disabled";
+};
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 37f54c3..e032e3d 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>
@@ -185,6 +186,10 @@
* DMA transfers; transfer queue progress is driven by IRQs. The clock
* framework provides the base clock, subdivided for each spi_device.
*/
+struct atmel_spi_pdata {
+ u8 version;
+};
+
struct atmel_spi {
spinlock_t lock;
unsigned long flags;
@@ -203,6 +208,7 @@ struct atmel_spi {
struct spi_transfer *next_transfer;
unsigned long next_remaining_bytes;
int done_status;
+ struct atmel_spi_pdata *pdata;
void *buffer;
dma_addr_t buffer_dma;
@@ -217,6 +223,51 @@ struct atmel_spi_device {
#define BUFFER_SIZE PAGE_SIZE
#define INVALID_DMA_ADDRESS 0xffffffff
+static struct atmel_spi_pdata at91rm9200_config = {
+ .version = 1,
+};
+
+static struct atmel_spi_pdata at91sam9260_config = {
+ .version = 2,
+};
+
+static struct atmel_spi_pdata at91sam9x5_config = {
+ .version = 2,
+};
+
+static const struct platform_device_id atmel_spi_devtypes[] = {
+ {
+ .name = "spi-at91rm9200",
+ .driver_data = (unsigned long) &at91rm9200_config,
+ }, {
+ .name = "spi-at91sam9260",
+ .driver_data = (unsigned long) &at91sam9260_config,
+ }, {
+ .name = "spi-at91sam9x5",
+ .driver_data = (unsigned long) &at91sam9x5_config,
+ }, {
+ /* sentinel */
+ }
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_spi_dt_ids[] = {
+ {
+ .compatible = "atmel,at91rm9200-spi",
+ .data = &at91rm9200_config,
+ } , {
+ .compatible = "atmel,at91sam9260-spi",
+ .data = &at91sam9260_config,
+ } , {
+ .compatible = "atmel,at91sam9x5-spi",
+ .data = &at91sam9x5_config,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
+#endif
+
/*
* Version 2 of the SPI controller has
* - CR.LASTXFER
@@ -229,11 +280,15 @@ struct atmel_spi_device {
* register, but I haven't checked that it exists on all chips, and
* this is cheaper anyway.
*/
-static bool atmel_spi_is_v2(void)
+static bool atmel_spi_is_v2(struct atmel_spi *as)
{
- return !cpu_is_at91rm9200();
+ if (as->pdata->version == 2)
+ return true;
+ else
+ return false;
}
+
/*
* Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
* they assume that spi slave device state will not change on deselect, so
@@ -265,7 +320,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;
- if (atmel_spi_is_v2()) {
+ if (atmel_spi_is_v2(as)) {
/*
* Always use CSR0. This ensures that the clock
* switches to the correct idle polarity before we
@@ -320,7 +375,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
asd->npcs_pin, active ? " (low)" : "",
mr);
- if (atmel_spi_is_v2() || spi->chip_select != 0)
+ if (atmel_spi_is_v2(as) || spi->chip_select != 0)
gpio_set_value(asd->npcs_pin, !active);
}
@@ -710,7 +765,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);
@@ -733,7 +788,7 @@ static int atmel_spi_setup(struct spi_device *spi)
}
/* see notes above re chipselect */
- if (!atmel_spi_is_v2()
+ if (!atmel_spi_is_v2(as)
&& spi->chip_select == 0
&& (spi->mode & SPI_CS_HIGH)) {
dev_dbg(&spi->dev, "setup: can't be active-high\n");
@@ -742,7 +797,7 @@ static int atmel_spi_setup(struct spi_device *spi)
/* v1 chips start out at half the peripheral bus speed. */
bus_hz = clk_get_rate(as->clk);
- if (!atmel_spi_is_v2())
+ if (!atmel_spi_is_v2(as))
bus_hz /= 2;
if (spi->max_speed_hz) {
@@ -782,7 +837,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);
@@ -812,7 +869,7 @@ static int atmel_spi_setup(struct spi_device *spi)
"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
- if (!atmel_spi_is_v2())
+ if (!atmel_spi_is_v2(as))
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
return 0;
@@ -899,7 +956,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;
@@ -916,6 +973,21 @@ static void atmel_spi_cleanup(struct spi_device *spi)
kfree(asd);
}
+static struct atmel_spi_pdata * __devinit atmel_spi_get_driver_data(
+ struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(atmel_spi_dt_ids, pdev->dev.of_node);
+ if (!match)
+ return NULL;
+ return (struct atmel_spi_pdata *) match->data;
+ }
+
+ return (struct atmel_spi_pdata *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
/*-------------------------------------------------------------------------*/
static int __devinit atmel_spi_probe(struct platform_device *pdev)
@@ -949,7 +1021,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;
@@ -981,6 +1054,10 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
if (ret)
goto out_unmap_regs;
+ as->pdata = atmel_spi_get_driver_data(pdev);
+ if (!as->pdata)
+ goto out_unmap_regs;
+
/* Initialize the hardware */
clk_enable(clk);
spi_writel(as, CR, SPI_BIT(SWRST));
@@ -1078,12 +1155,13 @@ static int atmel_spi_resume(struct platform_device *pdev)
#define atmel_spi_resume NULL
#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),
},
+ .id_table = atmel_spi_devtypes,
.suspend = atmel_spi_suspend,
.resume = atmel_spi_resume,
.probe = atmel_spi_probe,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 08/14] spi/atmel_spi: add dmaengine support
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (5 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 07/14] spi/atmel_spi: add DT support Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 09/14] spi/atmel_spi: Fix spi-atmel driver to adapt to slave_config changes Wenyou Yang
` (2 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Add dmaengine support.
The has_dma_support to select DMA as the SPI xfer mode.
Signed-off-by: Nicolas Ferre <nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
[wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org: add has_dma_support to select DMA as the SPI xfer mode]
[wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org: add support NPCS1,2,3 chip select other than NPCS0]
[wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org: fix DMA: OOPS if buffer > 4096 bytes]
Signed-off-by: Wenyou Yang <wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
---
Hi, Richard,
This patch is based on the original patch from Nicolas
[PATCH] spi/atmel_spi: add dmaengine support
and merge the patches from Richard Genoud,
[PATCH] spi-atmel: update with dmaengine interface
[PATCH] spi-atmel: fix __init/__devinit sections mismatch
and Wenyou Yang add the code to support DTS section for selecting the SPI xfer mode,
add support NPCS1,2,3 chip select other than NPCS0.
fix DMA: OOPS if buffer > 4096 bytes.
Could you sign your signature in this patch?
Best Regards,
Wenyou Yang
drivers/spi/spi-atmel.c | 564 ++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 532 insertions(+), 32 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index e032e3d..1de45c2 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 <linux/platform_data/dma-atmel.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -180,6 +182,19 @@
#define spi_writel(port,reg,value) \
__raw_writel((value), (port)->regs + SPI_##reg)
+/* 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;
+};
/*
* The core SPI transfer engine just talks to a register bank to set up
@@ -188,6 +203,8 @@
*/
struct atmel_spi_pdata {
u8 version;
+ bool has_dma_support;
+ struct at_dma_slave dma_slave;
};
struct atmel_spi {
@@ -203,6 +220,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;
@@ -210,8 +228,15 @@ struct atmel_spi {
int done_status;
struct atmel_spi_pdata *pdata;
+ bool use_dma;
+ bool use_pdc;
+
+ /* scratch buffer */
void *buffer;
dma_addr_t buffer_dma;
+
+ /* dmaengine data */
+ struct atmel_spi_dma dma;
};
/* Controller-specific per-slave state */
@@ -225,14 +250,17 @@ struct atmel_spi_device {
static struct atmel_spi_pdata at91rm9200_config = {
.version = 1,
+ .has_dma_support = false,
};
static struct atmel_spi_pdata at91sam9260_config = {
.version = 2,
+ .has_dma_support = false,
};
static struct atmel_spi_pdata at91sam9x5_config = {
.version = 2,
+ .has_dma_support = true,
};
static const struct platform_device_id atmel_spi_devtypes[] = {
@@ -309,9 +337,7 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
* and (c) will trigger that first erratum in some cases.
*
* TODO: Test if the atmel_spi_is_v2() branch below works on
- * AT91RM9200 if we use some other register than CSR0. However, don't
- * do this unconditionally since AP7000 has an errata where the BITS
- * field in CSR0 overrides all other CSRs.
+ * AT91RM9200 if we use some other register than CSR0.
*/
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
@@ -321,14 +347,9 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
u32 mr;
if (atmel_spi_is_v2(as)) {
- /*
- * Always use CSR0. This ensures that the clock
- * switches to the correct idle polarity before we
- * toggle the CS.
- */
- spi_writel(as, CSR0, asd->csr);
- spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS)
- | SPI_BIT(MSTR));
+ spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr);
+ spi_writel(as, MR, SPI_BF(PCS, ~(0x01 << spi->chip_select))
+ | SPI_BIT(MODFDIS) | SPI_BIT(MSTR));
mr = spi_readl(as, MR);
gpio_set_value(asd->npcs_pin, active);
} else {
@@ -389,6 +410,23 @@ static void atmel_spi_unlock(struct atmel_spi *as)
spin_unlock_irqrestore(&as->lock, as->flags);
}
+static inline bool atmel_spi_use_dma(struct atmel_spi *as,
+ struct spi_transfer *xfer)
+{
+ if ((as->use_dma) && (xfer->len >= DMA_MIN_BYTES))
+ return true;
+ else
+ return false;
+}
+
+static inline bool atmel_spi_use_pdc(struct atmel_spi *as)
+{
+ if (as->use_pdc)
+ return true;
+ else
+ return false;
+}
+
static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
struct spi_transfer *xfer)
{
@@ -400,6 +438,220 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
return xfer->delay_usecs == 0 && !xfer->cs_change;
}
+static bool 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 __devinit atmel_spi_configure_dma(struct atmel_spi *as)
+{
+ struct at_dma_slave *sdata
+ = (struct at_dma_slave *)&as->pdata->dma_slave;
+
+ 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_submit(struct spi_master *master,
+ struct spi_transfer *xfer,
+ u32 *plen)
+{
+ 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;
+ u32 len = *plen;
+
+ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\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);
+ if (xfer->rx_buf)
+ as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;
+ else {
+ as->dma.sgrx.dma_address = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ }
+
+ /* prepare the TX dma transfer */
+ sg_init_table(&as->dma.sgtx, 1);
+ if (xfer->tx_buf) {
+ as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen;
+ } else {
+ as->dma.sgtx.dma_address = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ memset(as->buffer, 0, len);
+ }
+
+ sg_dma_len(&as->dma.sgtx) = len;
+ sg_dma_len(&as->dma.sgrx) = len;
+
+ *plen = 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,
+ NULL);
+ 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,
+ NULL);
+ 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;
+}
+
static void atmel_spi_next_xfer_data(struct spi_master *master,
struct spi_transfer *xfer,
dma_addr_t *tx_dma,
@@ -432,10 +684,10 @@ 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,
+static void atmel_spi_next_xfer_pdc(struct spi_master *master,
struct spi_message *msg)
{
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -532,6 +784,49 @@ static void atmel_spi_next_xfer(struct spi_master *master,
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
+/*
+ * Choose way to submit next transfer and start it.
+ * lock is held, spi tasklet is blocked
+ */
+static void atmel_spi_next_xfer_dma(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ u32 remaining, len;
+
+ dev_vdbg(&msg->spi->dev, "atmel_spi_next_xfer\n");
+
+ remaining = as->current_remaining_bytes;
+ if (remaining) {
+ xfer = as->current_transfer;
+ len = remaining;
+ } else {
+ 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;
+ len = xfer->len;
+ }
+
+ if (atmel_spi_use_dma(as, xfer)) {
+ u32 total = len;
+ if (!atmel_spi_next_xfer_dma_submit(master, xfer, &len)) {
+ as->current_remaining_bytes = total - len;
+ return;
+ } else
+ dev_err(&msg->spi->dev, "unable to use DMA, fallback to PIO\n");
+ }
+
+ /* use PIO if error appened using DMA */
+ atmel_spi_next_xfer_pio(master, xfer);
+}
+
static void atmel_spi_next_message(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -556,7 +851,10 @@ static void atmel_spi_next_message(struct spi_master *master)
} else
cs_activate(as, spi);
- atmel_spi_next_xfer(master, msg);
+ if (atmel_spi_use_pdc(as))
+ atmel_spi_next_xfer_pdc(master, msg);
+ else
+ atmel_spi_next_xfer_dma(master, msg);
}
/*
@@ -609,6 +907,11 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
xfer->len, DMA_FROM_DEVICE);
}
+static void atmel_spi_disable_pdc_transfer(struct atmel_spi *as)
+{
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+}
+
static void
atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
struct spi_message *msg, int stay)
@@ -634,19 +937,175 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
as->done_status = 0;
/* continue if needed */
- if (list_empty(&as->queue) || as->stopping)
- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
- else
+ if (list_empty(&as->queue) || as->stopping) {
+ if (atmel_spi_use_pdc(as))
+ atmel_spi_disable_pdc_transfer(as);
+ } else
atmel_spi_next_message(master);
}
-static irqreturn_t
-atmel_spi_interrupt(int irq, void *dev_id)
+/* 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)
{
- struct spi_master *master = dev_id;
+ 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->current_remaining_bytes == 0) {
+ if (as->done_status < 0) {
+ /* error happened (overrun) */
+ if (atmel_spi_use_dma(as, xfer))
+ atmel_spi_stop_dma(as);
+ } else
+ /* only update length if no error */
+ msg->actual_length += xfer->len;
+
+ if (atmel_spi_use_dma(as, 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_dma(master, msg);
+ }
+ } else
+ /*
+ * Keep going, we still have data to send in
+ * the current transfer.
+ */
+ atmel_spi_next_xfer_dma(master, msg);
+
+tasklet_out:
+ atmel_spi_unlock(as);
+}
+
+static int atmel_spi_interrupt_dma(struct atmel_spi *as,
+ struct spi_master *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;
+}
+
+static int atmel_spi_interrupt_pdc(struct atmel_spi *as,
+ struct spi_master *master)
+{
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
u32 status, pending, imr;
int ret = IRQ_NONE;
@@ -742,14 +1201,14 @@ atmel_spi_interrupt(int irq, void *dev_id)
*
* FIXME handle protocol options for xfer
*/
- atmel_spi_next_xfer(master, msg);
+ atmel_spi_next_xfer_pdc(master, msg);
}
} else {
/*
* Keep going, we still have data to send in
* the current transfer.
*/
- atmel_spi_next_xfer(master, msg);
+ atmel_spi_next_xfer_pdc(master, msg);
}
}
@@ -758,6 +1217,27 @@ atmel_spi_interrupt(int irq, void *dev_id)
return ret;
}
+/* Interrupt
+ *
+ * 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);
+ int ret;
+
+ if (atmel_spi_use_pdc(as))
+ ret = atmel_spi_interrupt_pdc(as, master);
+ else
+ ret = atmel_spi_interrupt_dma(as, master);
+
+ return ret;
+}
+
static int atmel_spi_setup(struct spi_device *spi)
{
struct atmel_spi *as;
@@ -918,13 +1398,10 @@ 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(as, xfer)
+ || atmel_spi_use_pdc(as))) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
}
@@ -1041,6 +1518,8 @@ 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)
@@ -1063,7 +1542,16 @@ 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));
+
+ as->use_dma = false;
+ as->use_pdc = false;
+
+ if (as->pdata->has_dma_support) {
+ if (atmel_spi_configure_dma(as) == 0)
+ as->use_dma = true;
+ } else
+ as->use_pdc = true;
+
spi_writel(as, CR, SPI_BIT(SPIEN));
/* go! */
@@ -1072,11 +1560,14 @@ 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_reset_hw:
+out_free_dma:
+ if (as->use_dma)
+ atmel_spi_release_dma(as);
+
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
clk_disable(clk);
@@ -1084,6 +1575,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:
@@ -1102,6 +1594,11 @@ 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;
+ if (as->use_dma) {
+ 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);
@@ -1110,13 +1607,16 @@ 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(as, xfer)
+ || atmel_spi_use_pdc(as)))
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.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 09/14] spi/atmel_spi: Fix spi-atmel driver to adapt to slave_config changes
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (6 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 08/14] spi/atmel_spi: add dmaengine support Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 10/14] spi/atmel_spi: correct 16 bits transfers using PIO Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 11/14] spi/atmel_spi: correct 16 bits transfer with DMA Wenyou Yang
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Richard Genoud <richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This is the following of the patch e2b35f3dbfc080f15b72834d08f04f0269dbe9be
Signed-off-by: Richard Genoud <richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
[wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org: fix DMA: when enable both spi0 and spi1, spi0 doesn't work]
Signed-off-by: Wenyou Yang <wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 60 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 51 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 1de45c2..7f624b6 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -438,6 +438,37 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
return xfer->delay_usecs == 0 && !xfer->cs_change;
}
+static int atmel_spi_dma_slave_config(struct atmel_spi *as,
+ struct dma_slave_config *slave_config)
+{
+ int err = 0;
+
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+
+ slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
+ slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR;
+ slave_config->src_maxburst = 1;
+ slave_config->dst_maxburst = 1;
+ slave_config->device_fc = false;
+
+ slave_config->direction = DMA_MEM_TO_DEV;
+ if (dmaengine_slave_config(as->dma.chan_tx, slave_config)) {
+ dev_err(&as->pdev->dev,
+ "failed to configure tx dma channel\n");
+ err = -EINVAL;
+ }
+
+ slave_config->direction = DMA_DEV_TO_MEM;
+ if (dmaengine_slave_config(as->dma.chan_rx, slave_config)) {
+ dev_err(&as->pdev->dev,
+ "failed to configure rx dma channel\n");
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
static bool filter(struct dma_chan *chan, void *slave)
{
struct at_dma_slave *sl = slave;
@@ -454,14 +485,12 @@ static int __devinit atmel_spi_configure_dma(struct atmel_spi *as)
{
struct at_dma_slave *sdata
= (struct at_dma_slave *)&as->pdata->dma_slave;
+ struct dma_slave_config slave_config;
+ int err;
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);
@@ -471,21 +500,28 @@ static int __devinit atmel_spi_configure_dma(struct atmel_spi *as)
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;
}
+ err = atmel_spi_dma_slave_config(as, &slave_config);
+ if (err)
+ goto error;
+
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;
+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)
@@ -562,6 +598,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
struct dma_chan *txchan = as->dma.chan_tx;
struct dma_async_tx_descriptor *rxdesc;
struct dma_async_tx_descriptor *txdesc;
+ struct dma_slave_config slave_config;
dma_cookie_t cookie;
u32 len = *plen;
@@ -600,6 +637,10 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
*plen = len;
+ if (atmel_spi_dma_slave_config(as, &slave_config))
+ goto err_exit;
+
+
/* Send both scatterlists */
rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
&as->dma.sgrx,
@@ -648,6 +689,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
err_dma:
spi_writel(as, IDR, SPI_BIT(OVRES));
atmel_spi_stop_dma(as);
+err_exit:
atmel_spi_lock(as);
return -ENOMEM;
}
--
1.7.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 10/14] spi/atmel_spi: correct 16 bits transfers using PIO
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (7 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 09/14] spi/atmel_spi: Fix spi-atmel driver to adapt to slave_config changes Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 11/14] spi/atmel_spi: correct 16 bits transfer with DMA Wenyou Yang
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Richard Genoud <richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Richard Genoud <richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 46 +++++++++++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 7f624b6..9616fab 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -573,13 +573,17 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
}
if (xfer->tx_buf)
- spi_writel(as, TDR, *(u8 *)(xfer->tx_buf));
+ if (xfer->bits_per_word > 8)
+ spi_writel(as, TDR, *(u16 *)(xfer->tx_buf));
+ else
+ 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);
+ " start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
+ xfer->bits_per_word);
/* Enable relevant interrupts */
spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES));
@@ -997,21 +1001,39 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
{
u8 *txp;
u8 *rxp;
+ u16 *txp16;
+ u16 *rxp16;
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);
+ if (xfer->bits_per_word > 8) {
+ rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos);
+ *rxp16 = spi_readl(as, RDR);
+ } else {
+ rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
+ *rxp = spi_readl(as, RDR);
+ }
} else {
spi_readl(as, RDR);
}
-
- as->current_remaining_bytes--;
+ if (xfer->bits_per_word > 8) {
+ as->current_remaining_bytes -= 2;
+ if (as->current_remaining_bytes < 0)
+ as->current_remaining_bytes = 0;
+ } else {
+ 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);
+ if (xfer->bits_per_word > 8) {
+ txp16 = (u16 *)(((u8 *)xfer->tx_buf)
+ + xfer_pos + 2);
+ spi_writel(as, TDR, *txp16);
+ } else {
+ txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1;
+ spi_writel(as, TDR, *txp);
+ }
} else {
spi_writel(as, TDR, 0);
}
@@ -1431,6 +1453,12 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
return -ENOPROTOOPT;
}
}
+ if (xfer->bits_per_word > 8) {
+ if (xfer->len % 2) {
+ dev_dbg(&spi->dev, "buffer len should be 16 bits aligned\n");
+ return -EINVAL;
+ }
+ }
/* FIXME implement these protocol options!! */
if (xfer->speed_hz) {
--
1.7.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [v2 PATCH 11/14] spi/atmel_spi: correct 16 bits transfer with DMA
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
` (8 preceding siblings ...)
2012-12-04 7:53 ` [v2 PATCH 10/14] spi/atmel_spi: correct 16 bits transfers using PIO Wenyou Yang
@ 2012-12-04 7:53 ` Wenyou Yang
9 siblings, 0 replies; 12+ messages in thread
From: Wenyou Yang @ 2012-12-04 7:53 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w
From: Richard Genoud <richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Richard Genoud <richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
---
drivers/spi/spi-atmel.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 9616fab..61452a5 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -439,12 +439,18 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
}
static int atmel_spi_dma_slave_config(struct atmel_spi *as,
- struct dma_slave_config *slave_config)
+ struct dma_slave_config *slave_config,
+ u8 bits_per_word)
{
int err = 0;
- slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ if (bits_per_word > 8) {
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ } else {
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR;
@@ -506,7 +512,7 @@ static int __devinit atmel_spi_configure_dma(struct atmel_spi *as)
goto error;
}
- err = atmel_spi_dma_slave_config(as, &slave_config);
+ err = atmel_spi_dma_slave_config(as, &slave_config, 8);
if (err)
goto error;
@@ -641,10 +647,9 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
*plen = len;
- if (atmel_spi_dma_slave_config(as, &slave_config))
+ if (atmel_spi_dma_slave_config(as, &slave_config, 8))
goto err_exit;
-
/* Send both scatterlists */
rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
&as->dma.sgrx,
--
1.7.9.5
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [v2 PATCH 02/14] of_spi: add generic binding support to specify cs gpio
[not found] ` <1354607640-13229-3-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2012-12-05 23:28 ` Grant Likely
0 siblings, 0 replies; 12+ messages in thread
From: Grant Likely @ 2012-12-05 23:28 UTC (permalink / raw)
To: Wenyou Yang, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w,
JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w, rob-VoJi6FS/r0vR7s880joybQ,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
plagnioj-sclMFOaUSTBWk0Htik3J/w,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
On Tue, 4 Dec 2012 15:53:48 +0800, Wenyou Yang <wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org> wrote:
> From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
>
> 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-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
> Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
> Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
> Cc: rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org
> Cc: rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org
> Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
> ---
> Hi, Richard,
>
> This patch based on the original patch from Jean-Christophe,
> [PATCH] of_spi: add generic binding support to specify cs gpio
> and merge the patch from Richard Genoud,
> [PATCH] [BUG] SPI: array out of bound => no CS
>
> Could you sign your signature in this patch?
>
> Best Regards,
> Wenyou Yang
I've already merged a version of this patch. Please check against the
version that is in linux-next.
g.
------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [v2 PATCH 07/14] spi/atmel_spi: add DT support
[not found] ` <1354607640-13229-8-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2012-12-07 6:58 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 0 replies; 12+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-12-07 6:58 UTC (permalink / raw)
To: Wenyou Yang
Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA, JM.Lin-AIFe0yeh4nAAvxtiuMwx3w,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On 15:53 Tue 04 Dec , Wenyou Yang wrote:
> From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
>
> The atmel_spi use only gpio for chip select.
no this patch need go on the TOP of mine
that is plan for 3.8
Best Regards,
J.
>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj-sclMFOaUSTBWk0Htik3J/w@public.gmane.org>
> [wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org: Add driver data and compatible "atmel,at91sam9260-spi", "atmel,at91sam9x5-spi"]
> Signed-off-by: Wenyou Yang <wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
> Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
> Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
> Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org
> Cc: rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org
> Cc: rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org
> Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: richard.genoud-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
> ---
> Hi, Richard,
>
> This patches is based on the original patch from Jean-Christophe
> [PATCH] spi/atmel: add DT support
> and merge the patch from Richard Genoud
> [PATCH] spi-atmel OF: complete documentation
> ane wenyou yang add more compatible "atmel,at91sam9260-spi", "atmel,at91sam9x5-spi",
> add driver data to get IP version and dma support.
>
> Could you sign your signature in this patch?
>
> Best Regards,
> Wenyou Yang
>
> .../devicetree/bindings/spi/spi_atmel.txt | 23 +++++
> drivers/spi/spi-atmel.c | 102 +++++++++++++++++---
> 2 files changed, 113 insertions(+), 12 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..20cdc91
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
> @@ -0,0 +1,23 @@
> +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
> +- cs-gpio: Should contain the GPIOs used for chipselect.
> +- dma-mask: device coherent dma mask.
> +
> +spi0: spi@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 */
> + >;
> + dma-mask = <0xffffffff>;
> + status = "disabled";
> +};
> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
> index 37f54c3..e032e3d 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>
> @@ -185,6 +186,10 @@
> * DMA transfers; transfer queue progress is driven by IRQs. The clock
> * framework provides the base clock, subdivided for each spi_device.
> */
> +struct atmel_spi_pdata {
> + u8 version;
> +};
> +
> struct atmel_spi {
> spinlock_t lock;
> unsigned long flags;
> @@ -203,6 +208,7 @@ struct atmel_spi {
> struct spi_transfer *next_transfer;
> unsigned long next_remaining_bytes;
> int done_status;
> + struct atmel_spi_pdata *pdata;
>
> void *buffer;
> dma_addr_t buffer_dma;
> @@ -217,6 +223,51 @@ struct atmel_spi_device {
> #define BUFFER_SIZE PAGE_SIZE
> #define INVALID_DMA_ADDRESS 0xffffffff
>
> +static struct atmel_spi_pdata at91rm9200_config = {
> + .version = 1,
> +};
> +
> +static struct atmel_spi_pdata at91sam9260_config = {
> + .version = 2,
> +};
> +
> +static struct atmel_spi_pdata at91sam9x5_config = {
> + .version = 2,
> +};
> +
> +static const struct platform_device_id atmel_spi_devtypes[] = {
> + {
> + .name = "spi-at91rm9200",
> + .driver_data = (unsigned long) &at91rm9200_config,
> + }, {
> + .name = "spi-at91sam9260",
> + .driver_data = (unsigned long) &at91sam9260_config,
> + }, {
> + .name = "spi-at91sam9x5",
> + .driver_data = (unsigned long) &at91sam9x5_config,
> + }, {
> + /* sentinel */
> + }
> +};
> +
> +#if defined(CONFIG_OF)
> +static const struct of_device_id atmel_spi_dt_ids[] = {
> + {
> + .compatible = "atmel,at91rm9200-spi",
> + .data = &at91rm9200_config,
> + } , {
> + .compatible = "atmel,at91sam9260-spi",
> + .data = &at91sam9260_config,
> + } , {
> + .compatible = "atmel,at91sam9x5-spi",
> + .data = &at91sam9x5_config,
> + }, {
> + /* sentinel */
> + }
> +};
> +MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
> +#endif
> +
> /*
> * Version 2 of the SPI controller has
> * - CR.LASTXFER
> @@ -229,11 +280,15 @@ struct atmel_spi_device {
> * register, but I haven't checked that it exists on all chips, and
> * this is cheaper anyway.
> */
> -static bool atmel_spi_is_v2(void)
> +static bool atmel_spi_is_v2(struct atmel_spi *as)
> {
> - return !cpu_is_at91rm9200();
> + if (as->pdata->version == 2)
> + return true;
> + else
> + return false;
> }
>
> +
> /*
> * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
> * they assume that spi slave device state will not change on deselect, so
> @@ -265,7 +320,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
> unsigned active = spi->mode & SPI_CS_HIGH;
> u32 mr;
>
> - if (atmel_spi_is_v2()) {
> + if (atmel_spi_is_v2(as)) {
> /*
> * Always use CSR0. This ensures that the clock
> * switches to the correct idle polarity before we
> @@ -320,7 +375,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
> asd->npcs_pin, active ? " (low)" : "",
> mr);
>
> - if (atmel_spi_is_v2() || spi->chip_select != 0)
> + if (atmel_spi_is_v2(as) || spi->chip_select != 0)
> gpio_set_value(asd->npcs_pin, !active);
> }
>
> @@ -710,7 +765,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);
> @@ -733,7 +788,7 @@ static int atmel_spi_setup(struct spi_device *spi)
> }
>
> /* see notes above re chipselect */
> - if (!atmel_spi_is_v2()
> + if (!atmel_spi_is_v2(as)
> && spi->chip_select == 0
> && (spi->mode & SPI_CS_HIGH)) {
> dev_dbg(&spi->dev, "setup: can't be active-high\n");
> @@ -742,7 +797,7 @@ static int atmel_spi_setup(struct spi_device *spi)
>
> /* v1 chips start out at half the peripheral bus speed. */
> bus_hz = clk_get_rate(as->clk);
> - if (!atmel_spi_is_v2())
> + if (!atmel_spi_is_v2(as))
> bus_hz /= 2;
>
> if (spi->max_speed_hz) {
> @@ -782,7 +837,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);
> @@ -812,7 +869,7 @@ static int atmel_spi_setup(struct spi_device *spi)
> "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
> bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
>
> - if (!atmel_spi_is_v2())
> + if (!atmel_spi_is_v2(as))
> spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
>
> return 0;
> @@ -899,7 +956,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;
> @@ -916,6 +973,21 @@ static void atmel_spi_cleanup(struct spi_device *spi)
> kfree(asd);
> }
>
> +static struct atmel_spi_pdata * __devinit atmel_spi_get_driver_data(
> + struct platform_device *pdev)
> +{
> + if (pdev->dev.of_node) {
> + const struct of_device_id *match;
> + match = of_match_node(atmel_spi_dt_ids, pdev->dev.of_node);
> + if (!match)
> + return NULL;
> + return (struct atmel_spi_pdata *) match->data;
> + }
> +
> + return (struct atmel_spi_pdata *)
> + platform_get_device_id(pdev)->driver_data;
> +}
> +
> /*-------------------------------------------------------------------------*/
>
> static int __devinit atmel_spi_probe(struct platform_device *pdev)
> @@ -949,7 +1021,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;
> @@ -981,6 +1054,10 @@ static int __devinit atmel_spi_probe(struct platform_device *pdev)
> if (ret)
> goto out_unmap_regs;
>
> + as->pdata = atmel_spi_get_driver_data(pdev);
> + if (!as->pdata)
> + goto out_unmap_regs;
> +
> /* Initialize the hardware */
> clk_enable(clk);
> spi_writel(as, CR, SPI_BIT(SWRST));
> @@ -1078,12 +1155,13 @@ static int atmel_spi_resume(struct platform_device *pdev)
> #define atmel_spi_resume NULL
> #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),
> },
> + .id_table = atmel_spi_devtypes,
> .suspend = atmel_spi_suspend,
> .resume = atmel_spi_resume,
> .probe = atmel_spi_probe,
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2012-12-07 6:58 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <1354607640-13229-1-git-send-email-wenyou.yang@atmel.com>
[not found] ` <1354607640-13229-1-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-04 7:53 ` [v2 PATCH 02/14] of_spi: add generic binding support to specify cs gpio Wenyou Yang
[not found] ` <1354607640-13229-3-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-05 23:28 ` Grant Likely
2012-12-04 7:53 ` [v2 PATCH 03/14] spi/atmel_spi: add physical base address Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 04/14] spi/atmel_spi: call unmapping on transfers buffers Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 05/14] spi/atmel_spi: status information passed through controller data Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 06/14] spi/atmel_spi: add flag to controller data for lock operations Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 07/14] spi/atmel_spi: add DT support Wenyou Yang
[not found] ` <1354607640-13229-8-git-send-email-wenyou.yang-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2012-12-07 6:58 ` Jean-Christophe PLAGNIOL-VILLARD
2012-12-04 7:53 ` [v2 PATCH 08/14] spi/atmel_spi: add dmaengine support Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 09/14] spi/atmel_spi: Fix spi-atmel driver to adapt to slave_config changes Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 10/14] spi/atmel_spi: correct 16 bits transfers using PIO Wenyou Yang
2012-12-04 7:53 ` [v2 PATCH 11/14] spi/atmel_spi: correct 16 bits transfer with DMA Wenyou Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).