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

From: Abdurrahman Hussain

Date: Tue Sep 29 2026 - 12:30:13 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.

Signed-off-by: Abdurrahman Hussain <abdurrahman@xxxxxxxxxx>
---
Tested with a 93LC86C on an 8-bit AXI Quad SPI core: 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 that part is posted
separately; nothing here depends on it.
---
drivers/misc/eeprom/eeprom_93xx46.c | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index f9c3ab52c2f9..b6d4f7b03975 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/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: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
change-id: 20260928-eeprom-93xx46-fixed-bpw-e869f3f7077a

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