ar71xx: boost SPI flash read performance
mtd_speedtest results: page read speed old new delta DB120 929 KiB/s 2597 KiB/s +179.55% TL-WR1043ND v1 754 KiB/s 2166 KiB/s +187.27% TL-WR703N v1 745 KiB/s 2176 KiB/s +192.08% TL-MR3220 v1 752 KiB/s 2154 KiB/s +186.44% TL-WR2543ND v1 564 KiB/s 2130 KiB/s +277.66% TL-WR741ND v2 525 KiB/s 1767 KiB/s +236.57% ALFA-AP96 702 KiB/s 1977 KiB/s +181.62% WNDR3700 697 KiB/s 1965 KiB/s +181.92% SVN-Revision: 31118
This commit is contained in:
parent
102c6df148
commit
b77217d963
11 changed files with 504 additions and 1 deletions
|
@ -51,6 +51,7 @@ void __init ath79_register_m25p80(struct flash_platform_data *pdata)
|
|||
{
|
||||
ath79_spi_data.bus_num = 0;
|
||||
ath79_spi_data.num_chipselect = 1;
|
||||
ath79_spi0_cdata.is_flash = true;
|
||||
ath79_spi_info[0].platform_data = pdata;
|
||||
ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ static struct mmc_spi_platform_data alfa_ap96_mmc_data = {
|
|||
static struct ath79_spi_controller_data ap96_spi0_cdata = {
|
||||
.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
|
||||
.cs_line = 0,
|
||||
.is_flash = true,
|
||||
};
|
||||
|
||||
static struct ath79_spi_controller_data ap96_spi1_cdata = {
|
||||
|
|
|
@ -40,7 +40,6 @@ static const char *tl_wr2543n_part_probes[] = {
|
|||
|
||||
static struct flash_platform_data tl_wr2543n_flash_data = {
|
||||
.part_probes = tl_wr2543n_part_probes,
|
||||
.max_read_len = 64,
|
||||
};
|
||||
|
||||
static struct gpio_led tl_wr2543n_leds_gpio[] __initdata = {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
--- a/drivers/spi/spi-bitbang.c
|
||||
+++ b/drivers/spi/spi-bitbang.c
|
||||
@@ -234,13 +234,14 @@ void spi_bitbang_cleanup(struct spi_devi
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
|
||||
|
||||
-static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
+int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
{
|
||||
struct spi_bitbang_cs *cs = spi->controller_state;
|
||||
unsigned nsecs = cs->nsecs;
|
||||
|
||||
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(spi_bitbang_bufs);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
--- a/include/linux/spi/spi_bitbang.h
|
||||
+++ b/include/linux/spi/spi_bitbang.h
|
||||
@@ -44,6 +44,7 @@ extern void spi_bitbang_cleanup(struct s
|
||||
extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
|
||||
extern int spi_bitbang_setup_transfer(struct spi_device *spi,
|
||||
struct spi_transfer *t);
|
||||
+extern int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t);
|
||||
|
||||
/* start or stop queue processing */
|
||||
extern int spi_bitbang_start(struct spi_bitbang *spi);
|
|
@ -0,0 +1,23 @@
|
|||
--- a/include/linux/spi/spi.h
|
||||
+++ b/include/linux/spi/spi.h
|
||||
@@ -344,6 +344,12 @@ extern struct spi_master *spi_busnum_to_
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
+enum spi_transfer_type {
|
||||
+ SPI_TRANSFER_GENERIC = 0,
|
||||
+ SPI_TRANSFER_FLASH_READ_CMD,
|
||||
+ SPI_TRANSFER_FLASH_READ_DATA,
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* I/O INTERFACE between SPI controller and protocol drivers
|
||||
*
|
||||
@@ -446,6 +452,7 @@ struct spi_transfer {
|
||||
u8 bits_per_word;
|
||||
u16 delay_usecs;
|
||||
u32 speed_hz;
|
||||
+ enum spi_transfer_type type;
|
||||
|
||||
struct list_head transfer_list;
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -372,10 +372,12 @@ static int m25p80_read(struct mtd_info *
|
||||
* OPCODE_FAST_READ (if available) is faster.
|
||||
* Should add 1 byte DUMMY_BYTE.
|
||||
*/
|
||||
+ t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
|
||||
t[0].tx_buf = flash->command;
|
||||
t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
|
||||
+ t[1].type = SPI_TRANSFER_FLASH_READ_DATA;
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
/* Byte count starts at zero. */
|
|
@ -0,0 +1,185 @@
|
|||
--- a/drivers/spi/spi-ath79.c
|
||||
+++ b/drivers/spi/spi-ath79.c
|
||||
@@ -37,6 +37,11 @@
|
||||
|
||||
#define ATH79_SPI_CS_LINE_MAX 2
|
||||
|
||||
+enum ath79_spi_state {
|
||||
+ ATH79_SPI_STATE_WAIT_CMD = 0,
|
||||
+ ATH79_SPI_STATE_WAIT_READ,
|
||||
+};
|
||||
+
|
||||
struct ath79_spi {
|
||||
struct spi_bitbang bitbang;
|
||||
u32 ioc_base;
|
||||
@@ -44,6 +49,11 @@ struct ath79_spi {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned rrw_delay;
|
||||
+
|
||||
+ enum ath79_spi_state state;
|
||||
+ u32 clk_div;
|
||||
+ unsigned long read_addr;
|
||||
+ unsigned long ahb_rate;
|
||||
};
|
||||
|
||||
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
|
||||
@@ -108,9 +118,6 @@ static void ath79_spi_enable(struct ath7
|
||||
/* save CTRL register */
|
||||
sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
|
||||
sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
|
||||
-
|
||||
- /* TODO: setup speed? */
|
||||
- ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
|
||||
}
|
||||
|
||||
static void ath79_spi_disable(struct ath79_spi *sp)
|
||||
@@ -222,6 +229,110 @@ static u32 ath79_spi_txrx_mode0(struct s
|
||||
return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
|
||||
}
|
||||
|
||||
+static int ath79_spi_do_read_flash_data(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+
|
||||
+ /* disable GPIO mode */
|
||||
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
|
||||
+
|
||||
+ memcpy_fromio(t->rx_buf, sp->base + sp->read_addr, t->len);
|
||||
+
|
||||
+ /* enable GPIO mode */
|
||||
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
|
||||
+
|
||||
+ /* restore IOC register */
|
||||
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
|
||||
+
|
||||
+ return t->len;
|
||||
+}
|
||||
+
|
||||
+static int ath79_spi_do_read_flash_cmd(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+ int len;
|
||||
+ const u8 *p;
|
||||
+
|
||||
+ sp->read_addr = 0;
|
||||
+
|
||||
+ len = t->len - 1;
|
||||
+ p = t->tx_buf;
|
||||
+
|
||||
+ while (len--) {
|
||||
+ p++;
|
||||
+ sp->read_addr <<= 8;
|
||||
+ sp->read_addr |= *p;
|
||||
+ }
|
||||
+
|
||||
+ return t->len;
|
||||
+}
|
||||
+
|
||||
+static bool ath79_spi_is_read_cmd(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ return t->type == SPI_TRANSFER_FLASH_READ_CMD;
|
||||
+}
|
||||
+
|
||||
+static bool ath79_spi_is_data_read(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ return t->type == SPI_TRANSFER_FLASH_READ_DATA;
|
||||
+}
|
||||
+
|
||||
+static int ath79_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (sp->state) {
|
||||
+ case ATH79_SPI_STATE_WAIT_CMD:
|
||||
+ if (ath79_spi_is_read_cmd(spi, t)) {
|
||||
+ ret = ath79_spi_do_read_flash_cmd(spi, t);
|
||||
+ sp->state = ATH79_SPI_STATE_WAIT_READ;
|
||||
+ } else {
|
||||
+ ret = spi_bitbang_bufs(spi, t);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case ATH79_SPI_STATE_WAIT_READ:
|
||||
+ if (ath79_spi_is_data_read(spi, t)) {
|
||||
+ ret = ath79_spi_do_read_flash_data(spi, t);
|
||||
+ } else {
|
||||
+ dev_warn(&spi->dev, "flash data read expected\n");
|
||||
+ ret = -EIO;
|
||||
+ }
|
||||
+ sp->state = ATH79_SPI_STATE_WAIT_CMD;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ BUG();
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int ath79_spi_setup_transfer(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+ struct ath79_spi_controller_data *cdata;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = spi_bitbang_setup_transfer(spi, t);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ cdata = spi->controller_data;
|
||||
+ if (cdata->is_flash)
|
||||
+ sp->bitbang.txrx_bufs = ath79_spi_txrx_bufs;
|
||||
+ else
|
||||
+ sp->bitbang.txrx_bufs = spi_bitbang_bufs;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static __devinit int ath79_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
@@ -244,6 +355,8 @@ static __devinit int ath79_spi_probe(str
|
||||
sp = spi_master_get_devdata(master);
|
||||
platform_set_drvdata(pdev, sp);
|
||||
|
||||
+ sp->state = ATH79_SPI_STATE_WAIT_CMD;
|
||||
+
|
||||
master->setup = ath79_spi_setup;
|
||||
master->cleanup = ath79_spi_cleanup;
|
||||
master->bus_num = pdata->bus_num;
|
||||
@@ -252,7 +365,7 @@ static __devinit int ath79_spi_probe(str
|
||||
sp->bitbang.master = spi_master_get(master);
|
||||
sp->bitbang.chipselect = ath79_spi_chipselect;
|
||||
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
|
||||
- sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
|
||||
+ sp->bitbang.setup_transfer = ath79_spi_setup_transfer;
|
||||
sp->bitbang.flags = SPI_CS_HIGH;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@@ -277,7 +390,8 @@ static __devinit int ath79_spi_probe(str
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
||||
- rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
|
||||
+ sp->ahb_rate = clk_get_rate(sp->clk);
|
||||
+ rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
|
||||
if (!rate) {
|
||||
ret = -EINVAL;
|
||||
goto err_clk_disable;
|
||||
--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
|
||||
+++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
|
||||
@@ -24,6 +24,7 @@ enum ath79_spi_cs_type {
|
||||
struct ath79_spi_controller_data {
|
||||
enum ath79_spi_cs_type cs_type;
|
||||
unsigned cs_line;
|
||||
+ bool is_flash;
|
||||
};
|
||||
|
||||
#endif /* _ATH79_SPI_PLATFORM_H */
|
|
@ -0,0 +1,28 @@
|
|||
--- a/drivers/spi/spi-bitbang.c
|
||||
+++ b/drivers/spi/spi-bitbang.c
|
||||
@@ -234,13 +234,14 @@ void spi_bitbang_cleanup(struct spi_devi
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
|
||||
|
||||
-static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
+int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
{
|
||||
struct spi_bitbang_cs *cs = spi->controller_state;
|
||||
unsigned nsecs = cs->nsecs;
|
||||
|
||||
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(spi_bitbang_bufs);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
--- a/include/linux/spi/spi_bitbang.h
|
||||
+++ b/include/linux/spi/spi_bitbang.h
|
||||
@@ -44,6 +44,7 @@ extern void spi_bitbang_cleanup(struct s
|
||||
extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
|
||||
extern int spi_bitbang_setup_transfer(struct spi_device *spi,
|
||||
struct spi_transfer *t);
|
||||
+extern int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t);
|
||||
|
||||
/* start or stop queue processing */
|
||||
extern int spi_bitbang_start(struct spi_bitbang *spi);
|
|
@ -0,0 +1,23 @@
|
|||
--- a/include/linux/spi/spi.h
|
||||
+++ b/include/linux/spi/spi.h
|
||||
@@ -355,6 +355,12 @@ extern struct spi_master *spi_busnum_to_
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
+enum spi_transfer_type {
|
||||
+ SPI_TRANSFER_GENERIC = 0,
|
||||
+ SPI_TRANSFER_FLASH_READ_CMD,
|
||||
+ SPI_TRANSFER_FLASH_READ_DATA,
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* I/O INTERFACE between SPI controller and protocol drivers
|
||||
*
|
||||
@@ -457,6 +463,7 @@ struct spi_transfer {
|
||||
u8 bits_per_word;
|
||||
u16 delay_usecs;
|
||||
u32 speed_hz;
|
||||
+ enum spi_transfer_type type;
|
||||
|
||||
struct list_head transfer_list;
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -372,10 +372,12 @@ static int m25p80_read(struct mtd_info *
|
||||
* OPCODE_FAST_READ (if available) is faster.
|
||||
* Should add 1 byte DUMMY_BYTE.
|
||||
*/
|
||||
+ t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
|
||||
t[0].tx_buf = flash->command;
|
||||
t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
|
||||
+ t[1].type = SPI_TRANSFER_FLASH_READ_DATA;
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
/* Byte count starts at zero. */
|
|
@ -0,0 +1,185 @@
|
|||
--- a/drivers/spi/spi-ath79.c
|
||||
+++ b/drivers/spi/spi-ath79.c
|
||||
@@ -37,6 +37,11 @@
|
||||
|
||||
#define ATH79_SPI_CS_LINE_MAX 2
|
||||
|
||||
+enum ath79_spi_state {
|
||||
+ ATH79_SPI_STATE_WAIT_CMD = 0,
|
||||
+ ATH79_SPI_STATE_WAIT_READ,
|
||||
+};
|
||||
+
|
||||
struct ath79_spi {
|
||||
struct spi_bitbang bitbang;
|
||||
u32 ioc_base;
|
||||
@@ -44,6 +49,11 @@ struct ath79_spi {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned rrw_delay;
|
||||
+
|
||||
+ enum ath79_spi_state state;
|
||||
+ u32 clk_div;
|
||||
+ unsigned long read_addr;
|
||||
+ unsigned long ahb_rate;
|
||||
};
|
||||
|
||||
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
|
||||
@@ -108,9 +118,6 @@ static void ath79_spi_enable(struct ath7
|
||||
/* save CTRL register */
|
||||
sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
|
||||
sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
|
||||
-
|
||||
- /* TODO: setup speed? */
|
||||
- ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
|
||||
}
|
||||
|
||||
static void ath79_spi_disable(struct ath79_spi *sp)
|
||||
@@ -222,6 +229,110 @@ static u32 ath79_spi_txrx_mode0(struct s
|
||||
return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
|
||||
}
|
||||
|
||||
+static int ath79_spi_do_read_flash_data(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+
|
||||
+ /* disable GPIO mode */
|
||||
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
|
||||
+
|
||||
+ memcpy_fromio(t->rx_buf, sp->base + sp->read_addr, t->len);
|
||||
+
|
||||
+ /* enable GPIO mode */
|
||||
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
|
||||
+
|
||||
+ /* restore IOC register */
|
||||
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
|
||||
+
|
||||
+ return t->len;
|
||||
+}
|
||||
+
|
||||
+static int ath79_spi_do_read_flash_cmd(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+ int len;
|
||||
+ const u8 *p;
|
||||
+
|
||||
+ sp->read_addr = 0;
|
||||
+
|
||||
+ len = t->len - 1;
|
||||
+ p = t->tx_buf;
|
||||
+
|
||||
+ while (len--) {
|
||||
+ p++;
|
||||
+ sp->read_addr <<= 8;
|
||||
+ sp->read_addr |= *p;
|
||||
+ }
|
||||
+
|
||||
+ return t->len;
|
||||
+}
|
||||
+
|
||||
+static bool ath79_spi_is_read_cmd(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ return t->type == SPI_TRANSFER_FLASH_READ_CMD;
|
||||
+}
|
||||
+
|
||||
+static bool ath79_spi_is_data_read(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ return t->type == SPI_TRANSFER_FLASH_READ_DATA;
|
||||
+}
|
||||
+
|
||||
+static int ath79_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (sp->state) {
|
||||
+ case ATH79_SPI_STATE_WAIT_CMD:
|
||||
+ if (ath79_spi_is_read_cmd(spi, t)) {
|
||||
+ ret = ath79_spi_do_read_flash_cmd(spi, t);
|
||||
+ sp->state = ATH79_SPI_STATE_WAIT_READ;
|
||||
+ } else {
|
||||
+ ret = spi_bitbang_bufs(spi, t);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case ATH79_SPI_STATE_WAIT_READ:
|
||||
+ if (ath79_spi_is_data_read(spi, t)) {
|
||||
+ ret = ath79_spi_do_read_flash_data(spi, t);
|
||||
+ } else {
|
||||
+ dev_warn(&spi->dev, "flash data read expected\n");
|
||||
+ ret = -EIO;
|
||||
+ }
|
||||
+ sp->state = ATH79_SPI_STATE_WAIT_CMD;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ BUG();
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int ath79_spi_setup_transfer(struct spi_device *spi,
|
||||
+ struct spi_transfer *t)
|
||||
+{
|
||||
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
+ struct ath79_spi_controller_data *cdata;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = spi_bitbang_setup_transfer(spi, t);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ cdata = spi->controller_data;
|
||||
+ if (cdata->is_flash)
|
||||
+ sp->bitbang.txrx_bufs = ath79_spi_txrx_bufs;
|
||||
+ else
|
||||
+ sp->bitbang.txrx_bufs = spi_bitbang_bufs;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static __devinit int ath79_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
@@ -244,6 +355,8 @@ static __devinit int ath79_spi_probe(str
|
||||
sp = spi_master_get_devdata(master);
|
||||
platform_set_drvdata(pdev, sp);
|
||||
|
||||
+ sp->state = ATH79_SPI_STATE_WAIT_CMD;
|
||||
+
|
||||
master->setup = ath79_spi_setup;
|
||||
master->cleanup = ath79_spi_cleanup;
|
||||
master->bus_num = pdata->bus_num;
|
||||
@@ -252,7 +365,7 @@ static __devinit int ath79_spi_probe(str
|
||||
sp->bitbang.master = spi_master_get(master);
|
||||
sp->bitbang.chipselect = ath79_spi_chipselect;
|
||||
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
|
||||
- sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
|
||||
+ sp->bitbang.setup_transfer = ath79_spi_setup_transfer;
|
||||
sp->bitbang.flags = SPI_CS_HIGH;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@@ -277,7 +390,8 @@ static __devinit int ath79_spi_probe(str
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
||||
- rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
|
||||
+ sp->ahb_rate = clk_get_rate(sp->clk);
|
||||
+ rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
|
||||
if (!rate) {
|
||||
ret = -EINVAL;
|
||||
goto err_clk_disable;
|
||||
--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
|
||||
+++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
|
||||
@@ -24,6 +24,7 @@ enum ath79_spi_cs_type {
|
||||
struct ath79_spi_controller_data {
|
||||
enum ath79_spi_cs_type cs_type;
|
||||
unsigned cs_line;
|
||||
+ bool is_flash;
|
||||
};
|
||||
|
||||
#endif /* _ATH79_SPI_PLATFORM_H */
|
Loading…
Reference in a new issue