[PATCH RFC 2/2] eeprom: eeprom_93xx46: Add support for ignoring the dummy bit preceding data during read transfer

From: Aswath Govindraju
Date: Wed Dec 09 2020 - 12:58:43 EST


A dummy zero bit is sent by eeprom preceding the data of every read
transfer. This results in right shift of data during a read. In order to
ignore the dummy bits preceding the data, extra zero bits are transferred
after the read address.

This feature can be added by including the property read-op-dummy-cycles
with the number of zero bits to be transferred as the value, in device tree
node.

Fix read by sending extra zero bits after the read address to ignore the
zero bits sent by eeprom before data.

Suggested-by: Vignesh Raghavendra <vigneshr@xxxxxx>
Signed-off-by: Aswath Govindraju <a-govindraju@xxxxxx>
---
drivers/misc/eeprom/eeprom_93xx46.c | 23 +++++++++++++++++++++++
include/linux/eeprom_93xx46.h | 6 ++++++
2 files changed, 29 insertions(+)

diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 7c45f82b4302..e778ae54a6f1 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -55,6 +55,16 @@ static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev)
return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
}

+static inline bool needs_extra_read_cycle(struct eeprom_93xx46_dev *edev)
+{
+ return edev->pdata->flags & EE_EXTRA_CYCLE_READ;
+}
+
+static inline u32 get_read_op_dummy_cycles(struct eeprom_93xx46_dev *edev)
+{
+ return edev->pdata->read_op_dummy_cycles;
+}
+
static int eeprom_93xx46_read(void *priv, unsigned int off,
void *val, size_t count)
{
@@ -80,6 +90,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
u16 cmd_addr = OP_READ << edev->addrlen;
size_t nbytes = count;
int bits;
+ u32 read_op_dummy_cycles;

if (edev->addrlen == 7) {
cmd_addr |= off & 0x7f;
@@ -93,6 +104,12 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
nbytes = 2;
}

+ if (needs_extra_read_cycle(edev)) {
+ read_op_dummy_cycles = get_read_op_dummy_cycles(edev);
+ cmd_addr = cmd_addr << read_op_dummy_cycles;
+ bits += read_op_dummy_cycles;
+ }
+
dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
cmd_addr, edev->spi->max_speed_hz);

@@ -398,6 +415,12 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi)
if (of_property_read_bool(np, "read-only"))
pd->flags |= EE_READONLY;

+ ret = of_property_read_u32(np, "read-op-dummy-cycles", &tmp);
+ if (ret == 0) {
+ pd->flags |= EE_EXTRA_CYCLE_READ;
+ pd->read_op_dummy_cycles = tmp;
+ }
+
pd->select = devm_gpiod_get_optional(&spi->dev, "select",
GPIOD_OUT_LOW);
if (IS_ERR(pd->select))
diff --git a/include/linux/eeprom_93xx46.h b/include/linux/eeprom_93xx46.h
index eec7928ff8fe..f0d37e921aba 100644
--- a/include/linux/eeprom_93xx46.h
+++ b/include/linux/eeprom_93xx46.h
@@ -11,6 +11,12 @@ struct eeprom_93xx46_platform_data {
#define EE_ADDR16 0x02 /* 16 bit addr. cfg */
#define EE_READONLY 0x08 /* forbid writing */

+/* Add extra zero bits of data after the address during read transfer
+ * to ignore the dummy bits sent before data
+ */
+#define EE_EXTRA_CYCLE_READ 0x04
+ u32 read_op_dummy_cycles;
+
unsigned int quirks;
/* Single word read transfers only; no sequential read. */
#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0)
--
2.17.1