summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/microchip
diff options
context:
space:
mode:
authorDavid Mosberger-Tang <davidm@egauge.net>2021-02-27 17:29:46 +0000
committerKalle Valo <kvalo@codeaurora.org>2021-04-17 20:47:30 +0300
commitce3b933832b6286d181c30f646449d6ccc2a2c8c (patch)
tree6aa4368c34127b125be42ec52aef28a2c4a73ea5 /drivers/net/wireless/microchip
parent5ee2d9dd73fc7b371d208bea0971f81585b5ad3d (diff)
wilc1000: Check for errors at end of DMA write
After a DMA write to the WILC chip, check for and report any errors. This is based on code from the wilc driver in the linux-at91 repository. Signed-off-by: David Mosberger-Tang <davidm@egauge.net> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20210227172818.1711071-3-davidm@egauge.net
Diffstat (limited to 'drivers/net/wireless/microchip')
-rw-r--r--drivers/net/wireless/microchip/wilc1000/spi.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index fca34d1999ec..0be93eabad69 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -47,6 +47,17 @@ static const struct wilc_hif_func wilc_hif_spi;
#define SPI_ENABLE_VMM_RETRY_LIMIT 2
+/* SPI response fields (section 11.1.2 in ATWILC1000 User Guide): */
+#define RSP_START_FIELD GENMASK(7, 4)
+#define RSP_TYPE_FIELD GENMASK(3, 0)
+
+/* SPI response values for the response fields: */
+#define RSP_START_TAG 0xc
+#define RSP_TYPE_FIRST_PACKET 0x1
+#define RSP_TYPE_INNER_PACKET 0x2
+#define RSP_TYPE_LAST_PACKET 0x3
+#define RSP_STATE_NO_ERROR 0x00
+
#define PROTOCOL_REG_PKT_SZ_MASK GENMASK(6, 4)
#define PROTOCOL_REG_CRC16_MASK GENMASK(3, 3)
#define PROTOCOL_REG_CRC7_MASK GENMASK(2, 2)
@@ -750,6 +761,52 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
return 0;
}
+static int spi_data_rsp(struct wilc *wilc, u8 cmd)
+{
+ struct spi_device *spi = to_spi_device(wilc->dev);
+ int result, i;
+ u8 rsp[4];
+
+ /*
+ * The response to data packets is two bytes long. For
+ * efficiency's sake, wilc_spi_write() wisely ignores the
+ * responses for all packets but the final one. The downside
+ * of that optimization is that when the final data packet is
+ * short, we may receive (part of) the response to the
+ * second-to-last packet before the one for the final packet.
+ * To handle this, we always read 4 bytes and then search for
+ * the last byte that contains the "Response Start" code (0xc
+ * in the top 4 bits). We then know that this byte is the
+ * first response byte of the final data packet.
+ */
+ result = wilc_spi_rx(wilc, rsp, sizeof(rsp));
+ if (result) {
+ dev_err(&spi->dev, "Failed bus error...\n");
+ return result;
+ }
+
+ for (i = sizeof(rsp) - 2; i >= 0; --i)
+ if (FIELD_GET(RSP_START_FIELD, rsp[i]) == RSP_START_TAG)
+ break;
+
+ if (i < 0) {
+ dev_err(&spi->dev,
+ "Data packet response missing (%02x %02x %02x %02x)\n",
+ rsp[0], rsp[1], rsp[2], rsp[3]);
+ return -1;
+ }
+
+ /* rsp[i] is the last response start byte */
+
+ if (FIELD_GET(RSP_TYPE_FIELD, rsp[i]) != RSP_TYPE_LAST_PACKET
+ || rsp[i + 1] != RSP_STATE_NO_ERROR) {
+ dev_err(&spi->dev, "Data response error (%02x %02x)\n",
+ rsp[i], rsp[i + 1]);
+ return -1;
+ }
+ return 0;
+}
+
static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
struct spi_device *spi = to_spi_device(wilc->dev);
@@ -777,7 +834,10 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
return result;
}
- return 0;
+ /*
+ * Data response
+ */
+ return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE);
}
/********************************************