Skip to content

Commit

Permalink
Patch for correcting SPI interface on mt76xx chipset for running the …
Browse files Browse the repository at this point in the history
…half duplex correctly
  • Loading branch information
narioinc committed Jul 30, 2017
1 parent 3c4be02 commit 580ce29
Showing 1 changed file with 334 additions and 0 deletions.
334 changes: 334 additions & 0 deletions 0999-SPI-ralink-mt7621-half-transfer.patch
@@ -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;

0 comments on commit 580ce29

Please sign in to comment.