openwrtv3/target/linux/ar71xx/patches-3.2/201-spi-ath79-add-delay-between-SCK-changes.patch
Gabor Juhos 102c6df148 ar71xx: improve SPI flash read/write performance
mtd_speedtest results:

                        page write speed
                    old         new       delta
DB120            209 KiB/s   226 KiB/s     +8.13%
TL-WR1043ND v1   122 KiB/s   148 KiB/s    +21.31%
TL-WR703N v1     153 KiB/s   194 KiB/s    +26.80%
TL-MR3220 v1     130 KiB/s   156 KiB/s    +20.00%
TL-WR2543ND v1   158 KiB/s   202 KiB/s    +27.85%
TL-WR741ND v2    122 KiB/s   152 KiB/s    +24.59%
ALFA AP96        229 KiB/s   260 KiB/s    +13.54%
WNDR3700         202 KiB/s   223 KiB/s    +10.40%

                         page read speed
                    old        new       delta
DB120            691 KiB/s   929 KiB/s    +34.44%
TL-WR1043ND v1   372 KiB/s   754 KiB/s   +102.69%
TL-WR703N v1     375 KiB/s   745 KiB/s    +98.67%
TL-MR3220 v1     372 KiB/s   752 KiB/s   +102.15%
TL-WR2543ND v1   307 KiB/s   564 KiB/s    +83.71%
TL-WR741ND v2    315 KiB/s   525 KiB/s    +66.67%
ALFA AP96        515 KiB/s   702 KiB/s    +36.31%
WNDR3700         515 KiB/s   697 KiB/s    +35.34%

SVN-Revision: 31117
2012-03-27 19:38:15 +00:00

122 lines
3.2 KiB
Diff

From 8e948c035dd7983eccc3a889f2497e64044f3a31 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Wed, 11 Jan 2012 20:06:35 +0100
Subject: [PATCH 1/7] spi/ath79: add delay between SCK changes
The driver uses the "as fast as it can" approach
to drive the SCK signal. However this does not
work with certain low speed SPI chips (e.g. the
PCF2123 RTC chip). Add per-bit slowdowns in order
to be able to use the driver with such chips as
well.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
drivers/spi/spi-ath79.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 43 insertions(+), 1 deletions(-)
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -24,17 +24,24 @@
#include <linux/spi/spi_bitbang.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/mach-ath79/ar71xx_regs.h>
#include <asm/mach-ath79/ath79_spi_platform.h>
#define DRV_NAME "ath79-spi"
+#define ATH79_SPI_RRW_DELAY_FACTOR 12000
+#define MHZ (1000 * 1000)
+
struct ath79_spi {
struct spi_bitbang bitbang;
u32 ioc_base;
u32 reg_ctrl;
void __iomem *base;
+ struct clk *clk;
+ unsigned rrw_delay;
};
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
@@ -52,6 +59,12 @@ static inline struct ath79_spi *ath79_sp
return spi_master_get_devdata(spi->master);
}
+static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
+{
+ if (nsecs > sp->rrw_delay)
+ ndelay(nsecs - sp->rrw_delay);
+}
+
static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
{
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
@@ -184,7 +197,9 @@ static u32 ath79_spi_txrx_mode0(struct s
/* setup MSB (to slave) on trailing edge */
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
+ ath79_spi_delay(sp, nsecs);
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
+ ath79_spi_delay(sp, nsecs);
word <<= 1;
}
@@ -198,6 +213,7 @@ static __devinit int ath79_spi_probe(str
struct ath79_spi *sp;
struct ath79_spi_platform_data *pdata;
struct resource *r;
+ unsigned long rate;
int ret;
master = spi_alloc_master(&pdev->dev, sizeof(*sp));
@@ -239,12 +255,36 @@ static __devinit int ath79_spi_probe(str
goto err_put_master;
}
+ sp->clk = clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sp->clk)) {
+ ret = PTR_ERR(sp->clk);
+ goto err_unmap;
+ }
+
+ ret = clk_enable(sp->clk);
+ if (ret)
+ goto err_clk_put;
+
+ rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
+ if (!rate) {
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
+ dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
+ sp->rrw_delay);
+
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
- goto err_unmap;
+ goto err_clk_disable;
return 0;
+err_clk_disable:
+ clk_disable(sp->clk);
+err_clk_put:
+ clk_put(sp->clk);
err_unmap:
iounmap(sp->base);
err_put_master:
@@ -259,6 +299,8 @@ static __devexit int ath79_spi_remove(st
struct ath79_spi *sp = platform_get_drvdata(pdev);
spi_bitbang_stop(&sp->bitbang);
+ clk_disable(sp->clk);
+ clk_put(sp->clk);
iounmap(sp->base);
platform_set_drvdata(pdev, NULL);
spi_master_put(sp->bitbang.master);