Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Patch for correcting SPI interface on mt76xx chipset for running the …
…half duplex correctly
- Loading branch information
Showing
1 changed file
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
--- a/drivers/spi/spi-mt7621.c 2017-07-12 17:25:42.443742496 +0800 | ||
+++ b/drivers/spi/spi-mt7621.c 2017-07-14 19:20:48.939085943 +0800 | ||
@@ -27,6 +27,7 @@ | ||
#include <linux/swab.h> | ||
|
||
#include <ralink_regs.h> | ||
+#include <linux/delay.h> /*time*/ | ||
|
||
#define SPI_BPW_MASK(bits) BIT((bits) - 1) | ||
|
||
@@ -56,6 +57,9 @@ | ||
#define MT7621_LSB_FIRST BIT(3) | ||
|
||
#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH) | ||
+//Fix me by seven 20160614 | ||
+#define MT7621_MB_STRANS /* allow word transfer */ | ||
+//#undef MT7621_MB_STRANS | ||
|
||
struct mt7621_spi; | ||
|
||
@@ -197,10 +201,7 @@ | ||
if (!buf) | ||
continue; | ||
|
||
- if (t->speed_hz < speed) | ||
- speed = t->speed_hz; | ||
- | ||
- if (WARN_ON(len + rlen > 36)) { | ||
+ if (WARN_ON(len + t->len > 36)) { | ||
status = -EIO; | ||
goto msg_done; | ||
} | ||
@@ -264,13 +265,291 @@ | ||
return 0; | ||
} | ||
|
||
+#ifdef MT7621_MB_STRANS | ||
+/* | ||
+* more-byte-mode for reading and writing data | ||
+*/ | ||
+static int mt7621_spi_mb_transfer_half_duplex | ||
+( | ||
+ struct spi_master *master, | ||
+ struct spi_message *m | ||
+) | ||
+{ | ||
+ struct mt7621_spi *rs = spi_master_get_devdata(master); | ||
+ struct spi_device *spi = m->spi; | ||
+ unsigned int speed = spi->max_speed_hz; | ||
+ struct spi_transfer *t = NULL; | ||
+ int status = 0; | ||
+ int i = 0, len = 0; | ||
+ u8 is_write = 0; | ||
+ u32 data[9] = { 0 }; | ||
+ u32 val = 0; | ||
+ u32 transfer_len = 0; | ||
+ int cs_active = 0; | ||
+ | ||
+ mt7621_spi_wait_till_ready(spi); | ||
+ dev_dbg(&spi->dev, "seven spidev test ->cs:\n"); | ||
+ | ||
+ list_for_each_entry(t, &m->transfers, transfer_list) { | ||
+ const u8 *txbuf = t->tx_buf; | ||
+ u8 *rxbuf = t->rx_buf; | ||
+ | ||
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { | ||
+ dev_err(&spi->dev, | ||
+ "message rejected: invalid transfer data buffers\n"); | ||
+ status = -EIO; | ||
+ goto msg_done; | ||
+ } | ||
+ | ||
+ if (rxbuf) | ||
+ is_write = 0; | ||
+ else if(txbuf) | ||
+ is_write = 1; | ||
+ | ||
+ if (mt7621_spi_prepare(spi, speed)) { | ||
+ status = -EIO; | ||
+ goto msg_done; | ||
+ } | ||
+ | ||
+ transfer_len = t->len/4; | ||
+ //mt7621_spi_set_cs(spi, 1); | ||
+ if (!cs_active) { | ||
+ mt7621_spi_set_cs(spi, 1); | ||
+ cs_active = 1; | ||
+ } | ||
+ //printk("seven %s %d tlen:%d, transfer_len:%d, write:%d\n", __func__, __LINE__, t->len, transfer_len, is_write); | ||
+ | ||
+ if(transfer_len){ /* for word transfer */ | ||
+ u32 u32TxNum = 0; | ||
+ | ||
+ while ( transfer_len > 0 ) | ||
+ { | ||
+ u32TxNum = transfer_len%8; | ||
+ if ( !u32TxNum ) | ||
+ u32TxNum = 8; | ||
+ | ||
+ for ( i=0; i<u32TxNum*4; i++) | ||
+ { | ||
+ if ( is_write ){ /* for write transfer */ | ||
+ data[i / 4] |= *txbuf++ << (8 * (i & 3)); | ||
+ } | ||
+ //else /* for read transfer */ | ||
+ | ||
+ } | ||
+#if 0 | ||
+ for(i=0; i<u32TxNum*4; i += 4) | ||
+ printk("0x%x, ", data[i/4]); | ||
+ | ||
+ printk("\n"); | ||
+#endif | ||
+ data[0] = swab32(data[0]); | ||
+ val = 0; | ||
+ if(is_write){ | ||
+ for(i=0; i<u32TxNum*4; i += 4) | ||
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]); | ||
+ | ||
+ val = (min_t(int, u32TxNum*4, 4) * 8) << 24; /* must be set 32 */ | ||
+ val |= ((u32TxNum*4) - 4) * 8; /* mosi_cnt */ | ||
+ }else | ||
+ val |= ((u32TxNum*4) * 8) << 12; /* miso_cnt */ | ||
+ | ||
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); | ||
+ //mt7621_spi_set_cs(spi, 1); | ||
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); | ||
+ val |= SPI_CTL_START; | ||
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); | ||
+ | ||
+ mt7621_spi_wait_till_ready(spi); | ||
+ | ||
+ if(!is_write){ | ||
+ | ||
+ for (i = 0; i < u32TxNum*4; i += 4) | ||
+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); | ||
+ | ||
+ for (i = 0; i < u32TxNum*4; i++) | ||
+ *rxbuf++ = data[i / 4] >> (8 * (i & 3)); | ||
+ } | ||
+ | ||
+ len += u32TxNum*4; | ||
+ transfer_len -= u32TxNum; | ||
+ memset(data, 0, sizeof(data)); | ||
+ | ||
+ } | ||
+ | ||
+ } | ||
+ | ||
+ transfer_len = t->len%4; | ||
+ if(transfer_len){ /* for bytes transfer 0-3bytes*/ | ||
+ | ||
+ for ( i=0; i<transfer_len; i++ ){ | ||
+ if(is_write) | ||
+ data[i / 4] |= *txbuf++ << (8 * (i & 3)); | ||
+ } | ||
+ | ||
+ data[0] = swab32(data[0]); | ||
+ data[0] >>= (4 - transfer_len) * 8; | ||
+ | ||
+ val = 0; | ||
+ if(is_write){ | ||
+ for(i=0; i<transfer_len; i += 4) | ||
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]); | ||
+ | ||
+ val = (min_t(int, transfer_len, 4) * 8) << 24; /* must be 32 */ | ||
+ //val |= (transfer_len - 4) * 8; /* mosi_cnt */ | ||
+ }else{ | ||
+ val |= (transfer_len* 8) << 12; /* miso_cnt */ | ||
+ } | ||
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); | ||
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); | ||
+ val |= SPI_CTL_START; | ||
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); | ||
+ | ||
+ mt7621_spi_wait_till_ready(spi); | ||
+ | ||
+ if(!is_write){ | ||
+ | ||
+ for (i = 0; i < transfer_len; i += 4) | ||
+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); | ||
+ | ||
+ for (i = 0; i < transfer_len; i++) | ||
+ *rxbuf++ = data[i / 4] >> (8 * (i & 3)); | ||
+ } | ||
+ len += transfer_len; | ||
+ memset(data, 0, sizeof(data)); | ||
+ } | ||
+ | ||
+ m->actual_length = len; //+ rx_len; | ||
+ //mt7621_spi_set_cs(spi, 0); | ||
+ if (t->cs_change) { | ||
+ mt7621_spi_set_cs(spi, 0); | ||
+ cs_active = 0; | ||
+ } | ||
+ } | ||
+ | ||
+msg_done: | ||
+ if (cs_active) | ||
+ mt7621_spi_set_cs(spi, 0); | ||
+ m->status = status; | ||
+ spi_finalize_current_message(master); | ||
+ | ||
+ return 0; | ||
+} | ||
+#else | ||
+/* | ||
+* one-byte-one for reading and writing data | ||
+*/ | ||
+static int mt7621_spi_single_transfer_half_duplex | ||
+( | ||
+ struct spi_master *master, | ||
+ struct spi_message *m | ||
+) | ||
+{ | ||
+ struct mt7621_spi *rs = spi_master_get_devdata(master); | ||
+ struct spi_device *spi = m->spi; | ||
+ unsigned int speed = spi->max_speed_hz; | ||
+ struct spi_transfer *t = NULL; | ||
+ int status = 0; | ||
+ int len = 0; | ||
+ u8 is_write = 0; | ||
+ u32 data[9] = { 0 }; | ||
+ u32 val = 0; | ||
+ u32 transfer_len = 0; | ||
+ int cs_active = 0; | ||
+ dev_dbg(&spi->dev, "seven spidev test ->cs:\n"); | ||
+ mt7621_spi_wait_till_ready(spi); | ||
+ | ||
+ list_for_each_entry(t, &m->transfers, transfer_list) { | ||
+ const u8 *txbuf = t->tx_buf; | ||
+ u8 *rxbuf = t->rx_buf; | ||
+ | ||
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { | ||
+ dev_err(&spi->dev, | ||
+ "message rejected: invalid transfer data buffers\n"); | ||
+ status = -EIO; | ||
+ goto msg_done; | ||
+ } | ||
+ | ||
+ if (rxbuf) | ||
+ is_write = 0; | ||
+ else if(txbuf) | ||
+ is_write = 1; | ||
+ | ||
+ if (mt7621_spi_prepare(spi, speed)) { | ||
+ status = -EIO; | ||
+ goto msg_done; | ||
+ } | ||
+ | ||
+ //mt7621_spi_set_cs(spi, 1); | ||
+ if (!cs_active) { | ||
+ mt7621_spi_set_cs(spi, 1); | ||
+ cs_active = 1; | ||
+ } | ||
+ transfer_len = t->len; | ||
+ if(transfer_len){ /* for bytes transfer one byte one */ | ||
+ while(transfer_len){ | ||
+ memset(data, 0, sizeof(data)); | ||
+ | ||
+ if(is_write) | ||
+ data[0] = *txbuf++; | ||
+ data[0] = swab32(data[0]); | ||
+ data[0] >>= 24; | ||
+ | ||
+ val = 0; | ||
+ if(is_write){ | ||
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE, data[0]); | ||
+ | ||
+ val = 8 << 24; /* must be 8 for single byte */ | ||
+ //val |= (transfer_len - 4) * 8; /* mosi_cnt */ | ||
+ }else{ | ||
+ //val |= (transfer_len* 8) << 12; /* miso_cnt */ | ||
+ val |= 8 << 12; /* miso_cnt */ | ||
+ } | ||
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); | ||
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); | ||
+ val |= SPI_CTL_START; | ||
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); | ||
+ | ||
+ mt7621_spi_wait_till_ready(spi); | ||
+ | ||
+ if(!is_write) | ||
+ *rxbuf++ = mt7621_spi_read(rs, MT7621_SPI_DATA0); | ||
+ | ||
+ len ++; | ||
+ transfer_len--; | ||
+ } //while | ||
+ } | ||
+ | ||
+ m->actual_length = len; //+ rx_len; | ||
+ //mt7621_spi_set_cs(spi, 0); | ||
+ if (t->cs_change) { | ||
+ mt7621_spi_set_cs(spi, 0); | ||
+ cs_active = 0; | ||
+ } | ||
+ } | ||
+ | ||
+msg_done: | ||
+ if (cs_active) | ||
+ mt7621_spi_set_cs(spi, 0); | ||
+ m->status = status; | ||
+ spi_finalize_current_message(master); | ||
+ | ||
+ return 0; | ||
+} | ||
+#endif | ||
+ | ||
static int mt7621_spi_transfer_one_message(struct spi_master *master, | ||
struct spi_message *m) | ||
{ | ||
struct spi_device *spi = m->spi; | ||
int cs = spi->chip_select; | ||
|
||
- return mt7621_spi_transfer_half_duplex(master, m); | ||
+ if (cs) | ||
+#ifdef MT7621_MB_STRANS | ||
+ return mt7621_spi_mb_transfer_half_duplex(master, m); /* more bytes */ | ||
+#else | ||
+ return mt7621_spi_single_transfer_half_duplex(master, m); /* single byte transfer */ | ||
+#endif | ||
+ return mt7621_spi_transfer_half_duplex(master, m); /* only for spi-flash*/ | ||
} | ||
|
||
static int mt7621_spi_setup(struct spi_device *spi) | ||
@@ -339,7 +618,7 @@ | ||
|
||
master->setup = mt7621_spi_setup; | ||
master->transfer_one_message = mt7621_spi_transfer_one_message; | ||
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); | ||
+ master->bits_per_word_mask = SPI_BPW_MASK(8); | ||
master->dev.of_node = pdev->dev.of_node; | ||
master->num_chipselect = 2; | ||
|