[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <7b5df03ebd6151cdbfda372da74d996d225198cf.camel@siemens.com>
Date: Wed, 21 Jan 2026 08:58:24 +0000
From: "Sverdlin, Alexander" <alexander.sverdlin@...mens.com>
To: "patrick@...set.ch" <patrick@...set.ch>, "linux-kernel@...r.kernel.org"
<linux-kernel@...r.kernel.org>
CC: "Wicki, Patrick" <patrick.wicki@...mens.com>
Subject: Re: [PATCH 2/2] eeprom: at25: expose JEDEC ID via sysfs
On Tue, 2026-01-20 at 14:06 +0100, patrick@...set.ch wrote:
> From: Patrick Wicki <patrick.wicki@...mens.com>
>
> Return the raw JEDEC ID bytes as returned by the RDID command, even for
> variations that have the bytes in reverse order. This way we can avoid
> ambiguity if the manufacturer ever releases a new chip that returns them
> according to standard.
>
> Signed-off-by: Patrick Wicki <patrick.wicki@...mens.com>
Tested with CY15B204QSN:
Reviewed-by: Alexander Sverdlin <alexander.sverdlin@...mens.com>
Tested-by: Alexander Sverdlin <alexander.sverdlin@...mens.com>
> ---
> .../ABI/testing/sysfs-class-spi-eeprom | 11 ++++++
> drivers/misc/eeprom/at25.c | 38 +++++++++++++++----
> 2 files changed, 41 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-spi-eeprom b/Documentation/ABI/testing/sysfs-class-spi-eeprom
> index 1ff7579820798..f4bc7d9454cfb 100644
> --- a/Documentation/ABI/testing/sysfs-class-spi-eeprom
> +++ b/Documentation/ABI/testing/sysfs-class-spi-eeprom
> @@ -17,3 +17,14 @@ Description:
> from the device.
>
> This is a read-only attribute.
> +
> +What: /sys/class/spi_master/spi<bus>/spi<bus>.<dev>/jedec_id
> +Date: January 2026
> +KernelVersion: 6.19
> +Contact: Patrick Wicki <patrick.wicki@...mens.com>
> +Description:
> + Contains the raw JEDEC ID bytes returned by the RDID (0x9f) command. The
> + bytes are exposed as a hex string in big-endian order as read from the
> + device.
> +
> + This is a read-only attribute.
> diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
> index 5b00921d07d2e..bc2cfb75d9bb4 100644
> --- a/drivers/misc/eeprom/at25.c
> +++ b/drivers/misc/eeprom/at25.c
> @@ -34,6 +34,7 @@
> */
>
> #define FM25_SN_LEN 8 /* serial number length */
> +#define FM25_MAX_ID_LEN 9 /* ID length */
> #define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
>
> struct at25_data {
> @@ -44,6 +45,8 @@ struct at25_data {
> struct nvmem_config nvmem_config;
> struct nvmem_device *nvmem;
> u8 sernum[FM25_SN_LEN];
> + u8 id[FM25_MAX_ID_LEN];
> + u8 id_len;
> };
>
> #define AT25_WREN 0x06 /* latch the write enable */
> @@ -64,8 +67,6 @@ struct at25_data {
>
> #define AT25_INSTR_BIT3 0x08 /* additional address bit in instr */
>
> -#define FM25_ID_LEN 9 /* ID length */
> -
> /*
> * Specs often allow 5ms for a page write, sometimes 20ms;
> * it's important to recover from write timeouts.
> @@ -180,11 +181,25 @@ static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, ch
> }
> static DEVICE_ATTR_RO(sernum);
>
> -static struct attribute *sernum_attrs[] = {
> +static ssize_t jedec_id_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct at25_data *at25;
> +
> + at25 = dev_get_drvdata(dev);
> +
> + if (!at25->id_len)
> + return -EOPNOTSUPP;
> +
> + return sysfs_emit(buf, "%*phN\n", at25->id_len, at25->id);
> +}
> +static DEVICE_ATTR_RO(jedec_id);
> +
> +static struct attribute *at25_attrs[] = {
> &dev_attr_sernum.attr,
> + &dev_attr_jedec_id.attr,
> NULL,
> };
> -ATTRIBUTE_GROUPS(sernum);
> +ATTRIBUTE_GROUPS(at25);
>
> /*
> * Poll Read Status Register with timeout
> @@ -378,7 +393,7 @@ 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];
> + u8 id[FM25_MAX_ID_LEN];
> u32 val;
> int i;
>
> @@ -388,7 +403,12 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
> chip->byte_len = val;
> } else {
> /* Get ID of chip */
> - fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN);
> + fm25_aux_read(at25, id, FM25_RDID, FM25_MAX_ID_LEN);
> +
> + /* Store the unprocessed ID for exposing via sysfs */
> + memcpy(at25->id, id, FM25_MAX_ID_LEN);
> + at25->id_len = FM25_MAX_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++) {
> @@ -400,6 +420,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
> }
>
> if (id[6] == 0xc2) {
> + at25->id_len = 9;
> switch (id[7]) {
> case 0x21 ... 0x26:
> chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024;
> @@ -413,6 +434,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
> return -ENODEV;
> }
> } else if (id[2] == 0x82 && id[3] == 0x06) {
> + at25->id_len = 8;
> switch (id[1]) {
> case 0x51 ... 0x54:
> /* CY15B102QSN ... CY15B204QSN */
> @@ -424,7 +446,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
> }
> } else {
> dev_err(dev, "Error: unrecognized JEDEC ID format: %*ph\n",
> - FM25_ID_LEN, id);
> + FM25_MAX_ID_LEN, id);
> return -ENODEV;
> }
>
> @@ -549,7 +571,7 @@ static struct spi_mem_driver at25_driver = {
> .driver = {
> .name = "at25",
> .of_match_table = at25_of_match,
> - .dev_groups = sernum_groups,
> + .dev_groups = at25_groups,
> },
> .id_table = at25_spi_ids,
> },
--
Alexander Sverdlin
Siemens AG
www.siemens.com
Powered by blists - more mailing lists