linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] avr32: Reduce DataFlash bus speed to 8 MHz on ATNGW100
@ 2008-08-01 15:17 Haavard Skinnemoen
       [not found] ` <1217603836-21243-1-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Haavard Skinnemoen @ 2008-08-01 15:17 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Haavard Skinnemoen, kernel-o2ulR9ObcgE/ohRxsw7f2g,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Doing this in combination with "atmel_spi: fix hang due to missed
interrupt" appears to eliminate the overruns I'm seeing when using
JFFS2-on-DataFlash as /usr filesystem on the ATNGW100.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
The "atmel" releases have been running the DataFlash at 8 MHz for a
while, so this brings mainline in sync with them.

I think the only way to increase the bus speed beyond this is to use
faster RAM. I'll look into using SRAM bounce buffers next.

I'll apply this patch to my avr32 tree. David, I'll let you decide
whether the other three patches are important/safe enough for 2.6.27.
I've verified that they don't break DataFlash on ATNGW100, but they
could use some testing on other setups, in particular AT91RM9200 and
other AT91 chips.

 arch/avr32/boards/atngw100/setup.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index c7fe94d..12b21ac 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -47,7 +47,7 @@ static struct eth_platform_data __initdata eth_data[2];
 static struct spi_board_info spi0_board_info[] __initdata = {
 	{
 		.modalias	= "mtd_dataflash",
-		.max_speed_hz	= 10000000,
+		.max_speed_hz	= 8000000,
 		.chip_select	= 0,
 	},
 };
-- 
1.5.6.3


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/4] atmel_spi: Clean up SPIv1 quirk handling
       [not found] ` <1217603836-21243-1-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2008-08-01 15:17   ` Haavard Skinnemoen
       [not found]     ` <1217603836-21243-2-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Haavard Skinnemoen @ 2008-08-01 15:17 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Haavard Skinnemoen, kernel-o2ulR9ObcgE/ohRxsw7f2g,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Currently, we have a flag called "new_1" which is basically equivalent
to cpu_is_at91rm9200(). The latter is also called directly a few places.

Clean up this mess by introducing a atmel_spi_v2() function for
determining the controller version, and move all version dependent code
over to use it. This allows us to remove the new_1 flag.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
 drivers/spi/atmel_spi.c |   40 ++++++++++++++++++++++------------------
 1 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 95190c6..88239ca 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -30,13 +30,6 @@
  * 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
  * framework provides the base clock, subdivided for each spi_device.
- *
- * Newer controllers, marked with "new_1" flag, have:
- *  - CR.LASTXFER
- *  - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
- *  - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
- *  - SPI_CSRx.CSAAT
- *  - SPI_CSRx.SBCR allows faster clocking
  */
 struct atmel_spi {
 	spinlock_t		lock;
@@ -45,7 +38,6 @@ struct atmel_spi {
 	int			irq;
 	struct clk		*clk;
 	struct platform_device	*pdev;
-	unsigned		new_1:1;
 	struct spi_device	*stay;
 
 	u8			stopping;
@@ -63,6 +55,23 @@ struct atmel_spi {
 #define INVALID_DMA_ADDRESS	0xffffffff
 
 /*
+ * Version 2 of the SPI controller has
+ *  - CR.LASTXFER
+ *  - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
+ *  - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
+ *  - SPI_CSRx.CSAAT
+ *  - SPI_CSRx.SBCR allows faster clocking
+ *
+ * We can determine the controller version by reading the VERSION
+ * register, but I haven't checked that it exists on all chips, and
+ * this is cheaper anyway.
+ */
+static bool atmel_spi_is_v2(void)
+{
+	return !cpu_is_at91rm9200();
+}
+
+/*
  * 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
  * that automagic deselection is OK.  ("NPCSx rises if no data is to be
@@ -105,7 +114,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
 			gpio, active ? " (high)" : "",
 			mr);
 
-	if (!(cpu_is_at91rm9200() && spi->chip_select == 0))
+	if (atmel_spi_is_v2() || spi->chip_select != 0)
 		gpio_set_value(gpio, active);
 	spi_writel(as, MR, mr);
 }
@@ -129,7 +138,7 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
 			gpio, active ? " (low)" : "",
 			mr);
 
-	if (!(cpu_is_at91rm9200() && spi->chip_select == 0))
+	if (atmel_spi_is_v2() || spi->chip_select != 0)
 		gpio_set_value(gpio, !active);
 }
 
@@ -536,19 +545,16 @@ static int atmel_spi_setup(struct spi_device *spi)
 	}
 
 	/* see notes above re chipselect */
-	if (cpu_is_at91rm9200()
+	if (!atmel_spi_is_v2()
 			&& spi->chip_select == 0
 			&& (spi->mode & SPI_CS_HIGH)) {
 		dev_dbg(&spi->dev, "setup: can't be active-high\n");
 		return -EINVAL;
 	}
 
-	/*
-	 * Pre-new_1 chips start out at half the peripheral
-	 * bus speed.
-	 */
+	/* v1 chips start out at half the peripheral bus speed. */
 	bus_hz = clk_get_rate(as->clk);
-	if (!as->new_1)
+	if (!atmel_spi_is_v2())
 		bus_hz /= 2;
 
 	if (spi->max_speed_hz) {
@@ -755,8 +761,6 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
 		goto out_free_buffer;
 	as->irq = irq;
 	as->clk = clk;
-	if (!cpu_is_at91rm9200())
-		as->new_1 = 1;
 
 	ret = request_irq(irq, atmel_spi_interrupt, 0,
 			pdev->dev.bus_id, master);
-- 
1.5.6.3


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/4] atmel_spi: Use CSR0 for all chip selects on V2 controllers
       [not found]     ` <1217603836-21243-2-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2008-08-01 15:17       ` Haavard Skinnemoen
       [not found]         ` <1217603836-21243-3-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Haavard Skinnemoen @ 2008-08-01 15:17 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Haavard Skinnemoen, kernel-o2ulR9ObcgE/ohRxsw7f2g,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

This solves several issues:
  * It fixes the wrong idle clock polarity issue in a cleaner and less
    expensive way.
  * It handles the AT32AP7000 errata "SPI Chip Select 0 BITS field
    overrides other Chip Selects". Other chips, e.g. AT91SAM9261, have
    similar issues.

Currently, the AT91RM9200 code path is left alone. But it might be
interesting to try the same technique on RM9200 using a different CSR
register.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
 drivers/spi/atmel_spi.c |   95 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 88239ca..f4d60ec 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -51,6 +51,12 @@ struct atmel_spi {
 	dma_addr_t		buffer_dma;
 };
 
+/* Controller-specific per-slave state */
+struct atmel_spi_device {
+	unsigned int		npcs_pin;
+	u32			csr;
+};
+
 #define BUFFER_SIZE		PAGE_SIZE
 #define INVALID_DMA_ADDRESS	0xffffffff
 
@@ -89,39 +95,54 @@ static bool atmel_spi_is_v2(void)
  * Master on Chip Select 0.")  No workaround exists for that ... so for
  * nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
  * 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.
  */
 
 static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
 {
-	unsigned gpio = (unsigned) spi->controller_data;
+	struct atmel_spi_device *asd = spi->controller_state;
 	unsigned active = spi->mode & SPI_CS_HIGH;
-	u32 mr;
-	int i;
-	u32 csr;
-	u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
-
-	/* Make sure clock polarity is correct */
-	for (i = 0; i < spi->master->num_chipselect; i++) {
-		csr = spi_readl(as, CSR0 + 4 * i);
-		if ((csr ^ cpol) & SPI_BIT(CPOL))
-			spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL));
-	}
 
-	mr = spi_readl(as, MR);
-	mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
-
-	dev_dbg(&spi->dev, "activate %u%s, mr %08x\n",
-			gpio, active ? " (high)" : "",
-			mr);
+	if (atmel_spi_is_v2()) {
+		/*
+		 * 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_readl(as, MR);
+		gpio_set_value(asd->npcs_pin, active);
+	} else {
+		u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
+		int i;
+		u32 mr;
+		u32 csr;
+
+		/* Make sure clock polarity is correct */
+		for (i = 0; i < spi->master->num_chipselect; i++) {
+			csr = spi_readl(as, CSR0 + 4 * i);
+			if ((csr ^ cpol) & SPI_BIT(CPOL))
+				spi_writel(as, CSR0 + 4 * i,
+						csr ^ SPI_BIT(CPOL));
+		}
 
-	if (atmel_spi_is_v2() || spi->chip_select != 0)
-		gpio_set_value(gpio, active);
-	spi_writel(as, MR, mr);
+		mr = spi_readl(as, MR);
+		mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
+		if (spi->chip_select != 0)
+			gpio_set_value(asd->npcs_pin, active);
+		spi_writel(as, MR, mr);
+	}
 }
 
 static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
 {
-	unsigned gpio = (unsigned) spi->controller_data;
+	struct atmel_spi_device *asd = spi->controller_state;
 	unsigned active = spi->mode & SPI_CS_HIGH;
 	u32 mr;
 
@@ -135,11 +156,11 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
 	}
 
 	dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n",
-			gpio, active ? " (low)" : "",
+			asd->npcs_pin, active ? " (low)" : "",
 			mr);
 
 	if (atmel_spi_is_v2() || spi->chip_select != 0)
-		gpio_set_value(gpio, !active);
+		gpio_set_value(asd->npcs_pin, !active);
 }
 
 static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
@@ -511,6 +532,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
 static int atmel_spi_setup(struct spi_device *spi)
 {
 	struct atmel_spi	*as;
+	struct atmel_spi_device	*asd;
 	u32			scbr, csr;
 	unsigned int		bits = spi->bits_per_word;
 	unsigned long		bus_hz;
@@ -595,11 +617,20 @@ static int atmel_spi_setup(struct spi_device *spi)
 
 	/* chipselect must have been muxed as GPIO (e.g. in board setup) */
 	npcs_pin = (unsigned int)spi->controller_data;
-	if (!spi->controller_state) {
+	asd = spi->controller_state;
+	if (!asd) {
+		asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
+		if (!asd)
+			return -ENOMEM;
+
 		ret = gpio_request(npcs_pin, spi->dev.bus_id);
-		if (ret)
+		if (ret) {
+			kfree(asd);
 			return ret;
-		spi->controller_state = (void *)npcs_pin;
+		}
+
+		asd->npcs_pin = npcs_pin;
+		spi->controller_state = asd;
 		gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
 	} else {
 		unsigned long		flags;
@@ -611,11 +642,14 @@ static int atmel_spi_setup(struct spi_device *spi)
 		spin_unlock_irqrestore(&as->lock, flags);
 	}
 
+	asd->csr = csr;
+
 	dev_dbg(&spi->dev,
 		"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
 		bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
 
-	spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
+	if (!atmel_spi_is_v2())
+		spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
 
 	return 0;
 }
@@ -690,10 +724,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 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 (!spi->controller_state)
+	if (!asd)
 		return;
 
 	spin_lock_irqsave(&as->lock, flags);
@@ -703,7 +738,9 @@ static void atmel_spi_cleanup(struct spi_device *spi)
 	}
 	spin_unlock_irqrestore(&as->lock, flags);
 
+	spi->controller_state = NULL;
 	gpio_free(gpio);
+	kfree(asd);
 }
 
 /*-------------------------------------------------------------------------*/
-- 
1.5.6.3


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 4/4] atmel_spi: Implement per-transfer protocol options
       [not found]         ` <1217603836-21243-3-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
@ 2008-08-01 15:17           ` Haavard Skinnemoen
  0 siblings, 0 replies; 4+ messages in thread
From: Haavard Skinnemoen @ 2008-08-01 15:17 UTC (permalink / raw)
  To: David Brownell
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Haavard Skinnemoen, kernel-o2ulR9ObcgE/ohRxsw7f2g,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Allow drivers to set the bits_per_word and speed_hz fields of struct
spi_transfer to nonzero values. Doing this makes the transfers somewhat
more expensive as it prevents chaining and may require a division when
the transfer is submitted.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
 drivers/spi/atmel_spi.c |  138 ++++++++++++++++++++++++++++++++++-------------
 1 files changed, 100 insertions(+), 38 deletions(-)

diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index f4d60ec..0bdb4d5 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -39,6 +39,7 @@ struct atmel_spi {
 	struct clk		*clk;
 	struct platform_device	*pdev;
 	struct spi_device	*stay;
+	unsigned long		base_hz;
 
 	u8			stopping;
 	struct list_head	queue;
@@ -102,6 +103,15 @@ static bool atmel_spi_is_v2(void)
  * field in CSR0 overrides all other CSRs.
  */
 
+static void atmel_spi_set_csr(struct atmel_spi *as,
+		struct spi_device *spi, u32 csr)
+{
+	if (atmel_spi_is_v2())
+		spi_writel(as, CSR0, csr);
+	else
+		spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
+}
+
 static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
 {
 	struct atmel_spi_device *asd = spi->controller_state;
@@ -113,7 +123,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
 		 * switches to the correct idle polarity before we
 		 * toggle the CS.
 		 */
-		spi_writel(as, CSR0, asd->csr);
+		atmel_spi_set_csr(as, spi, asd->csr);
 		spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS)
 				| SPI_BIT(MSTR));
 		spi_readl(as, MR);
@@ -169,9 +179,15 @@ static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
 	return msg->transfers.prev == &xfer->transfer_list;
 }
 
-static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+static inline bool atmel_spi_xfer_needs_preproc(struct spi_transfer *xfer)
 {
-	return xfer->delay_usecs == 0 && !xfer->cs_change;
+	return xfer->bits_per_word || xfer->speed_hz;
+}
+
+static inline bool atmel_spi_xfer_needs_postproc(struct spi_transfer *xfer)
+{
+	return xfer->delay_usecs == 0 || xfer->cs_change
+		|| xfer->bits_per_word || xfer->speed_hz;
 }
 
 static void atmel_spi_next_xfer_data(struct spi_master *master,
@@ -228,6 +244,28 @@ static void atmel_spi_next_xfer(struct spi_master *master,
 		xfer = NULL;
 
 	if (xfer) {
+		/*
+		 * Per-transfer overrides prevent chaining before and
+		 * after, so it should be safe to alter the CSR
+		 * registers here.
+		 */
+		if (atmel_spi_xfer_needs_preproc(xfer)) {
+			struct spi_device *spi = msg->spi;
+			struct atmel_spi_device *asd = spi->controller_state;
+			unsigned int bits = xfer->bits_per_word;
+			u32 csr = asd->csr;
+
+			if (bits)
+				csr = SPI_BFINS(BITS, csr, bits - 8);
+			if (xfer->speed_hz) {
+				u32 scbr = DIV_ROUND_UP(as->base_hz,
+						xfer->speed_hz);
+				csr = SPI_BFINS(SCBR, csr, scbr);
+			}
+
+			atmel_spi_set_csr(as, spi, csr);
+		}
+
 		spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
 
 		len = xfer->len;
@@ -257,10 +295,12 @@ static void atmel_spi_next_xfer(struct spi_master *master,
 	if (remaining > 0)
 		len = remaining;
 	else if (!atmel_spi_xfer_is_last(msg, xfer)
-			&& atmel_spi_xfer_can_be_chained(xfer)) {
+			&& !atmel_spi_xfer_needs_postproc(xfer)) {
 		xfer = list_entry(xfer->transfer_list.next,
 				struct spi_transfer, transfer_list);
 		len = xfer->len;
+		if (atmel_spi_xfer_needs_preproc(xfer))
+			xfer = NULL;
 	} else
 		xfer = NULL;
 
@@ -409,6 +449,45 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
 		atmel_spi_next_message(master);
 }
 
+static void atmel_spi_xfer_done(struct spi_master *master,
+		struct spi_transfer *xfer, struct spi_message *msg)
+{
+	struct atmel_spi *as = spi_master_get_devdata(master);
+	msg->actual_length += xfer->len;
+
+	if (!msg->is_dma_mapped)
+		atmel_spi_dma_unmap_xfer(master, xfer);
+
+	/* REVISIT: udelay in irq is unfriendly */
+	if (xfer->delay_usecs)
+		udelay(xfer->delay_usecs);
+
+	if (xfer->bits_per_word || xfer->speed_hz) {
+		/*
+		 * Protocol options were overridden by this transfer;
+		 * revert to default settings.
+		 */
+		struct spi_device *spi = msg->spi;
+		struct atmel_spi_device *asd = spi->controller_state;
+
+		atmel_spi_set_csr(as, spi, asd->csr);
+	}
+
+	if (atmel_spi_xfer_is_last(msg, xfer)) {
+		/* report completed message */
+		atmel_spi_msg_done(master, as, msg, 0, 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. */
+		atmel_spi_next_xfer(master, msg);
+	}
+}
+
 static irqreturn_t
 atmel_spi_interrupt(int irq, void *dev_id)
 {
@@ -484,41 +563,14 @@ atmel_spi_interrupt(int irq, void *dev_id)
 
 		spi_writel(as, IDR, pending);
 
-		if (as->current_remaining_bytes == 0) {
-			msg->actual_length += xfer->len;
-
-			if (!msg->is_dma_mapped)
-				atmel_spi_dma_unmap_xfer(master, xfer);
-
-			/* REVISIT: udelay in irq is unfriendly */
-			if (xfer->delay_usecs)
-				udelay(xfer->delay_usecs);
-
-			if (atmel_spi_xfer_is_last(msg, xfer)) {
-				/* report completed message */
-				atmel_spi_msg_done(master, as, msg, 0,
-						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);
-			}
-		} else {
+		if (as->current_remaining_bytes == 0)
+			atmel_spi_xfer_done(master, xfer, msg);
+		else
 			/*
 			 * Keep going, we still have data to send in
 			 * the current transfer.
 			 */
 			atmel_spi_next_xfer(master, msg);
-		}
 	}
 
 	spin_unlock(&as->lock);
@@ -578,6 +630,7 @@ static int atmel_spi_setup(struct spi_device *spi)
 	bus_hz = clk_get_rate(as->clk);
 	if (!atmel_spi_is_v2())
 		bus_hz /= 2;
+	as->base_hz = bus_hz;
 
 	if (spi->max_speed_hz) {
 		/*
@@ -679,10 +732,19 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 			return -EINVAL;
 		}
 
-		/* FIXME implement these protocol options!! */
-		if (xfer->bits_per_word || xfer->speed_hz) {
-			dev_dbg(&spi->dev, "no protocol options yet\n");
-			return -ENOPROTOOPT;
+		if (xfer->bits_per_word && (xfer->bits_per_word < 8
+					|| xfer->bits_per_word > 16)) {
+			dev_dbg(&spi->dev, "unsupported bits_per_word\n");
+			return -EINVAL;
+		}
+		if (xfer->speed_hz) {
+			unsigned long divider;
+			divider = DIV_ROUND_UP(as->base_hz, xfer->speed_hz);
+
+			if (divider > 255) {
+				dev_dbg(&spi->dev, "speed_hz too low\n");
+				return -EINVAL;
+			}
 		}
 
 		/*
-- 
1.5.6.3


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-08-01 15:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-08-01 15:17 [PATCH 1/4] avr32: Reduce DataFlash bus speed to 8 MHz on ATNGW100 Haavard Skinnemoen
     [not found] ` <1217603836-21243-1-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2008-08-01 15:17   ` [PATCH 2/4] atmel_spi: Clean up SPIv1 quirk handling Haavard Skinnemoen
     [not found]     ` <1217603836-21243-2-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2008-08-01 15:17       ` [PATCH 3/4] atmel_spi: Use CSR0 for all chip selects on V2 controllers Haavard Skinnemoen
     [not found]         ` <1217603836-21243-3-git-send-email-haavard.skinnemoen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
2008-08-01 15:17           ` [PATCH 4/4] atmel_spi: Implement per-transfer protocol options Haavard Skinnemoen

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).