forked from Minki/linux
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 <gch981213@gmail.com> Reviewed-by: NeilBrown <neil@brown.name> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
d6a0de4933
commit
108d9dd513
@ -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 @@ msg_done:
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user