6.17-stable review patch. If anyone has any objections, please let me know.
------------------
From: Markus Heidelberg m.heidelberg@cab.de
[ Upstream commit 1b434ed000cd474f074e62e8ab876f87449bb4ac ]
Not all FRAM chips have a device ID and implement the corresponding read command. For such chips this led to the following error on module loading:
at25 spi2.0: Error: no Cypress FRAM (id 00)
The device ID contains the memory size, so devices without this ID are supported now by setting the size manually in Devicetree using the "size" property.
Tested with FM25L16B and "size = <2048>;":
at25 spi2.0: 2 KByte fm25 fram, pagesize 4096
According to Infineon/Cypress datasheets, these FRAMs have a device ID:
FM25V01A FM25V02A FM25V05 FM25V10 FM25V20A FM25VN10
but these do not:
FM25040B FM25640B FM25C160B FM25CL64B FM25L04B FM25L16B FM25W256
So all "FM25V*" FRAMs and only these have a device ID. The letter after "FM25" (V/C/L/W) only describes the voltage range, though.
Link: https://lore.kernel.org/all/20250401133148.38330-1-m.heidelberg@cab.de/ Signed-off-by: Markus Heidelberg m.heidelberg@cab.de Reviewed-by: Alexander Sverdlin alexander.sverdlin@gmail.com Link: https://lore.kernel.org/r/20250815095839.4219-3-m.heidelberg@cab.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/eeprom/at25.c | 67 ++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 31 deletions(-)
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 2d0492867054f..c90150f728369 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -379,37 +379,49 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip) struct at25_data *at25 = container_of(chip, struct at25_data, chip); u8 sernum[FM25_SN_LEN]; u8 id[FM25_ID_LEN]; + u32 val; int i;
strscpy(chip->name, "fm25", sizeof(chip->name));
- /* Get ID of chip */ - fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); - /* There are inside-out FRAM variations, detect them and reverse the ID bytes */ - if (id[6] == 0x7f && id[2] == 0xc2) - for (i = 0; i < ARRAY_SIZE(id) / 2; i++) { - u8 tmp = id[i]; - int j = ARRAY_SIZE(id) - i - 1; + if (!device_property_read_u32(dev, "size", &val)) { + chip->byte_len = val; + } else { + /* Get ID of chip */ + fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); + /* There are inside-out FRAM variations, detect them and reverse the ID bytes */ + if (id[6] == 0x7f && id[2] == 0xc2) + for (i = 0; i < ARRAY_SIZE(id) / 2; i++) { + u8 tmp = id[i]; + int j = ARRAY_SIZE(id) - i - 1; + + id[i] = id[j]; + id[j] = tmp; + } + if (id[6] != 0xc2) { + dev_err(dev, "Error: no Cypress FRAM (id %02x)\n", id[6]); + return -ENODEV; + }
- id[i] = id[j]; - id[j] = tmp; + switch (id[7]) { + case 0x21 ... 0x26: + chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024; + break; + case 0x2a ... 0x30: + /* CY15B116QN ... CY15B116QN */ + chip->byte_len = BIT(((id[7] >> 1) & 0xf) + 13); + break; + default: + dev_err(dev, "Error: unsupported size (id %02x)\n", id[7]); + return -ENODEV; } - if (id[6] != 0xc2) { - dev_err(dev, "Error: no Cypress FRAM (id %02x)\n", id[6]); - return -ENODEV; - }
- switch (id[7]) { - case 0x21 ... 0x26: - chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024; - break; - case 0x2a ... 0x30: - /* CY15B116QN ... CY15B116QN */ - chip->byte_len = BIT(((id[7] >> 1) & 0xf) + 13); - break; - default: - dev_err(dev, "Error: unsupported size (id %02x)\n", id[7]); - return -ENODEV; + if (id[8]) { + fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN); + /* Swap byte order */ + for (i = 0; i < FM25_SN_LEN; i++) + at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i]; + } }
if (chip->byte_len > 64 * 1024) @@ -417,13 +429,6 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip) else chip->flags |= EE_ADDR2;
- if (id[8]) { - fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN); - /* Swap byte order */ - for (i = 0; i < FM25_SN_LEN; i++) - at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i]; - } - chip->page_size = PAGE_SIZE; return 0; }