aboutsummaryrefslogtreecommitdiffstats
path: root/package/gspcav1
Commit message (Collapse)AuthorAgeFilesLines
* Upgrade gspcav1 to 20071224 (#2922)Florian Fainelli2008-01-061-2/+2
| | | | SVN-Revision: 10131
* rename spca5xx to gspcav1 (match upstream name change)Nicolas Thill2007-09-201-0/+39
SVN-Revision: 8868
41' href='#n41'>41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -35,6 +35,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;
@@ -42,6 +47,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)
@@ -109,9 +119,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)
@@ -224,6 +231,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 int ath79_spi_probe(struct platform_device *pdev)
 {
 	struct spi_master *master;
@@ -246,6 +357,8 @@ static int ath79_spi_probe(struct platfo
 	sp = spi_master_get_devdata(master);
 	platform_set_drvdata(pdev, sp);
 
+	sp->state = ATH79_SPI_STATE_WAIT_CMD;
+
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
 	master->setup = ath79_spi_setup;
 	master->cleanup = ath79_spi_cleanup;
@@ -255,7 +368,7 @@ static int ath79_spi_probe(struct platfo
 	sp->bitbang.master = 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);
@@ -280,7 +393,8 @@ static int ath79_spi_probe(struct platfo
 	if (ret)
 		goto err_put_master;
 
-	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 */