From: Chuanhong Guo Date: Thu, 6 Dec 2018 13:15:08 +0000 (+0800) Subject: staging: mt7621-spi: drop the broken full-duplex mode X-Git-Tag: v5.0-rc1~97^2~107 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=108d9dd51363e52de92019aa2107885493ddb5f3;p=linux.git staging: mt7621-spi: drop the broken full-duplex mode According to John Crispin (aka blogic) on IRC on Nov 26 2018: so basically i made cs1 work for MTK/labs when i built the linkit smart for them. the req-sheet said that cs1 should be proper duplex spi. however .... 1) the core will always send 1 byte before any transfer, this is the m25p80 command. 2) mode 3 is broken and bit reversed (?) 3) some bit are incorrectly wired in hw for mode2/3 we wrote a test script and test for [0-0xffff] on all modes and certain bits are swizzled under certain conditions and it was not possible to fix this even using a hack. we then decided to use spi-gpio and i never removed the errornous code basically the spi is fecked for anything but half duplex spi mode0 running a sflash on it The controller will always send some data from OPCODE register under half duplex mode before starting a full-duplex transfer, so the full-duplex mode is broken. This piece of code also make CS1 unavailable since it forces the broken full-duplex mode to be used on CS1. Signed-off-by: Chuanhong Guo Reviewed-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/mt7621-spi/spi-mt7621.c b/drivers/staging/mt7621-spi/spi-mt7621.c index d045b5568e0f..a69293d43281 100644 --- a/drivers/staging/mt7621-spi/spi-mt7621.c +++ b/drivers/staging/mt7621-spi/spi-mt7621.c @@ -86,16 +86,13 @@ static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val) iowrite32(val, rs->base + reg); } -static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex) +static void mt7621_spi_reset(struct mt7621_spi *rs) { u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER); master |= 7 << 29; master |= 1 << 2; - if (duplex) - master |= 1 << 10; - else - master &= ~(1 << 10); + master &= ~(1 << 10); mt7621_spi_write(rs, MT7621_SPI_MASTER, master); rs->pending_write = 0; @@ -107,7 +104,7 @@ static void mt7621_spi_set_cs(struct spi_device *spi, int enable) int cs = spi->chip_select; u32 polar = 0; - mt7621_spi_reset(rs, cs); + mt7621_spi_reset(rs); if (enable) polar = BIT(cs); mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); @@ -261,7 +258,7 @@ static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs, rs->pending_write = len; } -static int mt7621_spi_transfer_half_duplex(struct spi_master *master, +static int mt7621_spi_transfer_one_message(struct spi_master *master, struct spi_message *m) { struct mt7621_spi *rs = spi_master_get_devdata(master); @@ -284,10 +281,20 @@ static int mt7621_spi_transfer_half_duplex(struct spi_master *master, mt7621_spi_set_cs(spi, 1); m->actual_length = 0; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->rx_buf) + if ((t->rx_buf) && (t->tx_buf)) { + /* This controller will shift some extra data out + * of spi_opcode if (mosi_bit_cnt > 0) && + * (cmd_bit_cnt == 0). So the claimed full-duplex + * support is broken since we have no way to read + * the MISO value during that bit. + */ + status = -EIO; + goto msg_done; + } else if (t->rx_buf) { mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); - else if (t->tx_buf) + } else if (t->tx_buf) { mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); + } m->actual_length += t->len; } mt7621_spi_flush(rs); @@ -300,102 +307,6 @@ static int mt7621_spi_transfer_half_duplex(struct spi_master *master, return 0; } -static int mt7621_spi_transfer_full_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, len = 0; - int rx_len = 0; - u32 data[9] = { 0 }; - u32 val = 0; - - mt7621_spi_wait_till_ready(rs); - - list_for_each_entry(t, &m->transfers, transfer_list) { - const u8 *buf = t->tx_buf; - - if (t->rx_buf) - rx_len += t->len; - - if (!buf) - continue; - - if (WARN_ON(len + t->len > 16)) { - status = -EIO; - goto msg_done; - } - - for (i = 0; i < t->len; i++, len++) - data[len / 4] |= buf[i] << (8 * (len & 3)); - if (speed > t->speed_hz) - speed = t->speed_hz; - } - - if (WARN_ON(rx_len > 16)) { - status = -EIO; - goto msg_done; - } - - if (mt7621_spi_prepare(spi, speed)) { - status = -EIO; - goto msg_done; - } - - for (i = 0; i < len; i += 4) - mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]); - - val |= len * 8; - val |= (rx_len * 8) << 12; - 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(rs); - - mt7621_spi_set_cs(spi, 0); - - for (i = 0; i < rx_len; i += 4) - data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i); - - m->actual_length = rx_len; - - len = 0; - list_for_each_entry(t, &m->transfers, transfer_list) { - u8 *buf = t->rx_buf; - - if (!buf) - continue; - - for (i = 0; i < t->len; i++, len++) - buf[i] = data[len / 4] >> (8 * (len & 3)); - } - -msg_done: - m->status = status; - spi_finalize_current_message(master); - - return 0; -} - -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; - - if (cs) - return mt7621_spi_transfer_full_duplex(master, m); - return mt7621_spi_transfer_half_duplex(master, m); -} - static int mt7621_spi_setup(struct spi_device *spi) { struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); @@ -478,7 +389,7 @@ static int mt7621_spi_probe(struct platform_device *pdev) device_reset(&pdev->dev); - mt7621_spi_reset(rs, 0); + mt7621_spi_reset(rs); return spi_register_master(master); }