[PATCH v2] nvmem: eeprom_93xx46: send the command byte-aligned where needed

From: Abdurrahman Hussain

Date: Sat Oct 31 2026 - 12:32:18 EST


A Microwire command is three opcode bits plus the address, so it is
never a whole number of bytes. The driver asks for it with
spi_transfer::bits_per_word set to that width, which works only on
controllers that can vary their word size. Controllers synthesised
with a fixed width cannot: the Xilinx AXI Quad SPI core takes
xlnx,num-transfer-bits at synthesis time and advertises
SPI_BPW_MASK() for that one value, so every transfer is rejected
with -EINVAL and the EEPROM cannot be used at all.

A Microwire device ignores its DI pin until it sees the start bit, so
where the controller cannot do the native width, pad the command with
leading zeros to two bytes and send it eight bits at a time. Only
leading bits are added, so the data phase that follows keeps its
alignment and needs no change.

Controllers that can vary their word size still get the native width,
so there is no behaviour change for them.

Tested with a Microchip 93LC86C on a Xilinx AXI Quad SPI core
synthesised with 8-bit transfers.

Signed-off-by: Abdurrahman Hussain <abdurrahman@xxxxxxxxxx>
---
On the 93LC86C + AXI Quad SPI setup, reads over the whole array match a
reference dump taken by driving the controller by hand, and writes read
back and are restored. Support for the 93LC86C is posted separately;
nothing here depends on it.
---
Changes in v2:
- Rebased onto v7.3, where the driver moved to drivers/nvmem/; subject
prefix changed from misc: to nvmem: accordingly. No code changes.
- Retargeted at the nvmem maintainer.
- Commit message: state there is no behaviour change on controllers
that can vary the word size, and record the tested hardware.
- Link to v1: https://patch.msgid.link/20260929-eeprom-93xx46-fixed-bpw-v1-1-bc8444902279@xxxxxxxxxx

To: Srinivas Kandagatla <srini@xxxxxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
drivers/nvmem/eeprom_93xx46.c | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/nvmem/eeprom_93xx46.c b/drivers/nvmem/eeprom_93xx46.c
index f9c3ab52c2f9..b6d4f7b03975 100644
--- a/drivers/nvmem/eeprom_93xx46.c
+++ b/drivers/nvmem/eeprom_93xx46.c
@@ -102,6 +102,21 @@ static inline bool has_quirk_extra_read_cycle(struct eeprom_93xx46_dev *edev)
return edev->pdata->quirks & EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE;
}

+static void eeprom_93xx46_cmd_xfer(struct eeprom_93xx46_dev *edev,
+ struct spi_transfer *t, u16 *cmd_addr,
+ int bits)
+{
+ if (spi_is_bpw_supported(edev->spi, bits)) {
+ t->bits_per_word = bits;
+ } else {
+ cpu_to_be16s(cmd_addr);
+ t->bits_per_word = 8;
+ }
+
+ t->tx_buf = cmd_addr;
+ t->len = 2;
+}
+
static int eeprom_93xx46_read(void *priv, unsigned int off,
void *val, size_t count)
{
@@ -148,9 +163,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
bits += 1;
}

- t[0].tx_buf = (char *)&cmd_addr;
- t[0].len = 2;
- t[0].bits_per_word = bits;
+ eeprom_93xx46_cmd_xfer(edev, &t[0], &cmd_addr, bits);

t[1].rx_buf = buf;
t[1].len = count;
@@ -201,9 +214,7 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
dev_dbg(&edev->spi->dev, "ew %s cmd 0x%04x, %d bits\n",
str_enable_disable(is_on), cmd_addr, bits);

- t.tx_buf = &cmd_addr;
- t.len = 2;
- t.bits_per_word = bits;
+ eeprom_93xx46_cmd_xfer(edev, &t, &cmd_addr, bits);

spi_message_init_with_transfers(&m, &t, 1);

@@ -251,9 +262,7 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,

dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr);

- t[0].tx_buf = (char *)&cmd_addr;
- t[0].len = 2;
- t[0].bits_per_word = bits;
+ eeprom_93xx46_cmd_xfer(edev, &t[0], &cmd_addr, bits);

t[1].tx_buf = buf;
t[1].len = data_len;
@@ -334,9 +343,7 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)

dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits);

- t.tx_buf = &cmd_addr;
- t.len = 2;
- t.bits_per_word = bits;
+ eeprom_93xx46_cmd_xfer(edev, &t, &cmd_addr, bits);

spi_message_init_with_transfers(&m, &t, 1);


---
base-commit: c03c1a14507dfaf8b856c2608f9ac216021fc222
change-id: 20260928-eeprom-93xx46-fixed-bpw-e869f3f7077a

Best regards,
--
Abdurrahman Hussain <abdurrahman@xxxxxxxxxx>