From 20be064ec864086bca7a4eb62c772a397b44afb7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 7 May 2021 19:02:48 +0200 Subject: nvmem: sprd: Fix an error message 'ret' is known to be 0 here. The expected error status is stored in 'status', so use it instead. Also change %d in %u, because status is an u32, not a int. Fixes: 096030e7f449 ("nvmem: sprd: Add Spreadtrum SoCs eFuse support") Acked-by: Chunyan Zhang Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/5bc44aace2fe7e1c91d8b35c8fe31e7134ceab2c.1620406852.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sprd-efuse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c index 59523245db8a..4f1fcbfec394 100644 --- a/drivers/nvmem/sprd-efuse.c +++ b/drivers/nvmem/sprd-efuse.c @@ -234,7 +234,7 @@ static int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub, status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG); if (status) { dev_err(efuse->dev, - "write error status %d of block %d\n", ret, blk); + "write error status %u of block %d\n", status, blk); writel(SPRD_EFUSE_ERR_CLR_MASK, efuse->base + SPRD_EFUSE_ERR_CLR); -- cgit v1.2.3 From 78a005a22d5608b266eafa011b093a33284c52ce Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Fri, 11 Jun 2021 09:33:45 +0100 Subject: nvmem: sunxi_sid: Set type to OTP This device currently reports an "Unknown" type in sysfs. Since it is an eFuse hardware device, set its type to OTP. Signed-off-by: Samuel Holland Acked-by: Chen-Yu Tsai Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210611083348.20170-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/sunxi_sid.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index e26ef1bbf198..275b9155e473 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -142,6 +142,7 @@ static int sunxi_sid_probe(struct platform_device *pdev) nvmem_cfg->dev = dev; nvmem_cfg->name = "sunxi-sid"; + nvmem_cfg->type = NVMEM_TYPE_OTP; nvmem_cfg->read_only = true; nvmem_cfg->size = cfg->size; nvmem_cfg->word_size = 1; -- cgit v1.2.3 From c813bb37bd32cb967060a2c573fae4ea518d32eb Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 11 Jun 2021 09:33:46 +0100 Subject: nvmem: qfprom: minor nit fixes Fix a missed newline, change an 'if' to 'else if' and update a comment which is stale after the merge of '5a1bea2a: nvmem: qfprom: Add support for fuseblowing on sc7280' Signed-off-by: Rajendra Nayak Reviewed-by: Douglas Anderson Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210611083348.20170-8-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index d6d3f24685a8..1ba666bcb900 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -122,6 +122,7 @@ static const struct qfprom_soc_compatible_data sc7280_qfprom = { .keepout = sc7280_qfprom_keepout, .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout) }; + /** * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing. * @priv: Our driver data. @@ -195,7 +196,7 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, } /* - * Hardware requires 1.8V min for fuse blowing; this may be + * Hardware requires a min voltage for fuse blowing; this may be * a rail shared do don't specify a max--regulator constraints * will handle. */ @@ -399,7 +400,7 @@ static int qfprom_probe(struct platform_device *pdev) if (major_version == 7 && minor_version == 8) priv->soc_data = &qfprom_7_8_data; - if (major_version == 7 && minor_version == 15) + else if (major_version == 7 && minor_version == 15) priv->soc_data = &qfprom_7_15_data; priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); -- cgit v1.2.3 From 1f7b4d87874624f4beb25253900a25306a193b8b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 11 Jun 2021 09:33:47 +0100 Subject: nvmem: core: constify nvmem_cell_read_variable_common() return value The caller doesn't modify the memory pointed to by the pointer so it can be const. Suggested-by: Stephen Boyd Signed-off-by: Douglas Anderson Reviewed-by: Stephen Boyd Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210611083348.20170-9-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index bca671ff4e54..b3c28a2d4c10 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1606,9 +1606,9 @@ int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) } EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); -static void *nvmem_cell_read_variable_common(struct device *dev, - const char *cell_id, - size_t max_len, size_t *len) +static const void *nvmem_cell_read_variable_common(struct device *dev, + const char *cell_id, + size_t max_len, size_t *len) { struct nvmem_cell *cell; int nbits; @@ -1652,7 +1652,7 @@ int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, u32 *val) { size_t len; - u8 *buf; + const u8 *buf; int i; buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); @@ -1683,7 +1683,7 @@ int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, u64 *val) { size_t len; - u8 *buf; + const u8 *buf; int i; buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); -- cgit v1.2.3 From 989f77e3fdee2e8f414dd1da9b6397d8763d414e Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 11 Jun 2021 09:33:48 +0100 Subject: nvmem: qfprom: Improve the comment about regulator setting In review feedback Joe Perches found the existing comment confusing. Let's use something based on the wording proposed by Joe. Suggested-by: Joe Perches Signed-off-by: Douglas Anderson Reviewed-by: Stephen Boyd Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210611083348.20170-10-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 1ba666bcb900..81fbad5e939d 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -196,9 +196,9 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, } /* - * Hardware requires a min voltage for fuse blowing; this may be - * a rail shared do don't specify a max--regulator constraints - * will handle. + * Hardware requires a minimum voltage for fuse blowing. + * This may be a shared rail so don't specify a maximum. + * Regulator constraints will cap to the actual maximum. */ ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX); if (ret) { -- cgit v1.2.3 From fd307a4ad332ef50be5569c92490219e7cd84ce5 Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Fri, 11 Jun 2021 11:45:58 +0200 Subject: nvmem: prepare basics for FRAM support Added enum and string for FRAM (ferroelectric RAM) to expose it as file named "fram". Added documentation of sysfs file. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210611094601.95131-2-jiri.prchal@aksignal.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-spi-eeprom | 19 +++ Documentation/devicetree/bindings/eeprom/at25.yaml | 31 +++- drivers/misc/eeprom/Kconfig | 5 +- drivers/misc/eeprom/at25.c | 161 +++++++++++++++++---- drivers/nvmem/core.c | 4 + include/linux/nvmem-provider.h | 1 + 6 files changed, 183 insertions(+), 38 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-spi-eeprom (limited to 'drivers/nvmem') diff --git a/Documentation/ABI/testing/sysfs-class-spi-eeprom b/Documentation/ABI/testing/sysfs-class-spi-eeprom new file mode 100644 index 000000000000..1ff757982079 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-spi-eeprom @@ -0,0 +1,19 @@ +What: /sys/class/spi_master/spi/spi./fram +Date: June 2021 +KernelVersion: 5.14 +Contact: Jiri Prchal +Description: + Contains the FRAM binary data. Same as EEPROM, just another file + name to indicate that it employs ferroelectric process. + It performs write operations at bus speed - no write delays. + +What: /sys/class/spi_master/spi/spi./sernum +Date: May 2021 +KernelVersion: 5.14 +Contact: Jiri Prchal +Description: + Contains the serial number of the Cypress FRAM (FM25VN) if it is + present. It will be displayed as a 8 byte hex string, as read + from the device. + + This is a read-only attribute. diff --git a/Documentation/devicetree/bindings/eeprom/at25.yaml b/Documentation/devicetree/bindings/eeprom/at25.yaml index 6a2dc8b3ed14..fbf99e346966 100644 --- a/Documentation/devicetree/bindings/eeprom/at25.yaml +++ b/Documentation/devicetree/bindings/eeprom/at25.yaml @@ -4,14 +4,16 @@ $id: "http://devicetree.org/schemas/eeprom/at25.yaml#" $schema: "http://devicetree.org/meta-schemas/core.yaml#" -title: SPI EEPROMs compatible with Atmel's AT25 +title: SPI EEPROMs or FRAMs compatible with Atmel's AT25 maintainers: - Christian Eggers properties: $nodename: - pattern: "^eeprom@[0-9a-f]{1,2}$" + anyOf: + - pattern: "^eeprom@[0-9a-f]{1,2}$" + - pattern: "^fram@[0-9a-f]{1,2}$" # There are multiple known vendors who manufacture EEPROM chips compatible # with Atmel's AT25. The compatible string requires two items where the @@ -31,6 +33,7 @@ properties: - microchip,25lc040 - st,m95m02 - st,m95256 + - cypress,fm25 - const: atmel,at25 @@ -47,7 +50,7 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [1, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072] description: - Size of the eeprom page. + Size of the eeprom page. FRAMs don't have pages. size: $ref: /schemas/types.yaml#/definitions/uint32 @@ -100,9 +103,19 @@ required: - compatible - reg - spi-max-frequency - - pagesize - - size - - address-width + +allOf: + - if: + properties: + compatible: + not: + contains: + const: cypress,fm25 + then: + required: + - pagesize + - size + - address-width additionalProperties: false @@ -125,4 +138,10 @@ examples: size = <32768>; address-width = <16>; }; + + fram@1 { + compatible = "cypress,fm25", "atmel,at25"; + reg = <1>; + spi-max-frequency = <40000000>; + }; }; diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 0f791bfdc1f5..f0a7531f354c 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -32,12 +32,13 @@ config EEPROM_AT24 will be called at24. config EEPROM_AT25 - tristate "SPI EEPROMs from most vendors" + tristate "SPI EEPROMs (FRAMs) from most vendors" depends on SPI && SYSFS select NVMEM select NVMEM_SYSFS help - Enable this driver to get read/write support to most SPI EEPROMs, + Enable this driver to get read/write support to most SPI EEPROMs + and Cypress FRAMs, after you configure the board init code to know about each eeprom on your target board. diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index b76e4901b4a4..6e26de68a001 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * at25.c -- support most SPI EEPROMs, such as Atmel AT25 models + * and Cypress FRAMs FM25 models * * Copyright (C) 2006 David Brownell */ @@ -16,6 +17,9 @@ #include #include #include +#include +#include +#include /* * NOTE: this is an *EEPROM* driver. The vagaries of product naming @@ -27,6 +31,7 @@ * AT25M02, AT25128B */ +#define FM25_SN_LEN 8 /* serial number length */ struct at25_data { struct spi_device *spi; struct mutex lock; @@ -34,6 +39,7 @@ struct at25_data { unsigned addrlen; struct nvmem_config nvmem_config; struct nvmem_device *nvmem; + u8 sernum[FM25_SN_LEN]; }; #define AT25_WREN 0x06 /* latch the write enable */ @@ -42,6 +48,9 @@ struct at25_data { #define AT25_WRSR 0x01 /* write status register */ #define AT25_READ 0x03 /* read byte(s) */ #define AT25_WRITE 0x02 /* write byte(s)/sector */ +#define FM25_SLEEP 0xb9 /* enter sleep mode */ +#define FM25_RDID 0x9f /* read device ID */ +#define FM25_RDSN 0xc3 /* read S/N */ #define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */ #define AT25_SR_WEN 0x02 /* write enable (latched) */ @@ -51,6 +60,8 @@ struct at25_data { #define AT25_INSTR_BIT3 0x08 /* Additional address bit in instr */ +#define FM25_ID_LEN 9 /* ID length */ + #define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */ /* Specs often allow 5 msec for a page write, sometimes 20 msec; @@ -58,6 +69,9 @@ struct at25_data { */ #define EE_TIMEOUT 25 +#define IS_EEPROM 0 +#define IS_FRAM 1 + /*-------------------------------------------------------------------------*/ #define io_limit PAGE_SIZE /* bytes */ @@ -129,6 +143,51 @@ static int at25_ee_read(void *priv, unsigned int offset, return status; } +/* + * read extra registers as ID or serial number + */ +static int fm25_aux_read(struct at25_data *at25, u8 *buf, uint8_t command, + int len) +{ + int status; + struct spi_transfer t[2]; + struct spi_message m; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &command; + t[0].len = 1; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + mutex_lock(&at25->lock); + + status = spi_sync(at25->spi, &m); + dev_dbg(&at25->spi->dev, "read %d aux bytes --> %d\n", len, status); + + mutex_unlock(&at25->lock); + return status; +} + +static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct at25_data *at25; + + at25 = dev_get_drvdata(dev); + return sysfs_emit(buf, "%*ph\n", sizeof(at25->sernum), at25->sernum); +} +static DEVICE_ATTR_RO(sernum); + +static struct attribute *sernum_attrs[] = { + &dev_attr_sernum.attr, + NULL, +}; +ATTRIBUTE_GROUPS(sernum); + static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) { struct at25_data *at25 = priv; @@ -303,34 +362,39 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip) return 0; } +static const struct of_device_id at25_of_match[] = { + { .compatible = "atmel,at25", .data = (const void *)IS_EEPROM }, + { .compatible = "cypress,fm25", .data = (const void *)IS_FRAM }, + { } +}; +MODULE_DEVICE_TABLE(of, at25_of_match); + static int at25_probe(struct spi_device *spi) { struct at25_data *at25 = NULL; struct spi_eeprom chip; int err; int sr; - int addrlen; + u8 id[FM25_ID_LEN]; + u8 sernum[FM25_SN_LEN]; + int i; + const struct of_device_id *match; + int is_fram = 0; + + match = of_match_device(of_match_ptr(at25_of_match), &spi->dev); + if (match) + is_fram = (int)match->data; /* Chip description */ if (!spi->dev.platform_data) { - err = at25_fw_to_chip(&spi->dev, &chip); - if (err) - return err; + if (!is_fram) { + err = at25_fw_to_chip(&spi->dev, &chip); + if (err) + return err; + } } else chip = *(struct spi_eeprom *)spi->dev.platform_data; - /* For now we only support 8/16/24 bit addressing */ - if (chip.flags & EE_ADDR1) - addrlen = 1; - else if (chip.flags & EE_ADDR2) - addrlen = 2; - else if (chip.flags & EE_ADDR3) - addrlen = 3; - else { - dev_dbg(&spi->dev, "unsupported address type\n"); - return -EINVAL; - } - /* Ping the chip ... the status register is pretty portable, * unlike probing manufacturer IDs. We do expect that system * firmware didn't write it in the past few milliseconds! @@ -349,9 +413,51 @@ static int at25_probe(struct spi_device *spi) at25->chip = chip; at25->spi = spi; spi_set_drvdata(spi, at25); - at25->addrlen = addrlen; - at25->nvmem_config.type = NVMEM_TYPE_EEPROM; + if (is_fram) { + /* Get ID of chip */ + fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); + if (id[6] != 0xc2) { + dev_err(&spi->dev, + "Error: no Cypress FRAM (id %02x)\n", id[6]); + return -ENODEV; + } + /* set size found in ID */ + if (id[7] < 0x21 || id[7] > 0x26) { + dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]); + return -ENODEV; + } + chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024; + + if (at25->chip.byte_len > 64 * 1024) + at25->chip.flags |= EE_ADDR3; + else + at25->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]; + } + + at25->chip.page_size = PAGE_SIZE; + strncpy(at25->chip.name, "fm25", sizeof(at25->chip.name)); + } + + /* For now we only support 8/16/24 bit addressing */ + if (at25->chip.flags & EE_ADDR1) + at25->addrlen = 1; + else if (at25->chip.flags & EE_ADDR2) + at25->addrlen = 2; + else if (at25->chip.flags & EE_ADDR3) + at25->addrlen = 3; + else { + dev_dbg(&spi->dev, "unsupported address type\n"); + return -EINVAL; + } + + at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM; at25->nvmem_config.name = dev_name(&spi->dev); at25->nvmem_config.dev = &spi->dev; at25->nvmem_config.read_only = chip.flags & EE_READONLY; @@ -370,27 +476,22 @@ static int at25_probe(struct spi_device *spi) if (IS_ERR(at25->nvmem)) return PTR_ERR(at25->nvmem); - dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n", - (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024), - (chip.byte_len < 1024) ? "Byte" : "KByte", - at25->chip.name, - (chip.flags & EE_READONLY) ? " (readonly)" : "", - at25->chip.page_size); + dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n", + (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024), + (chip.byte_len < 1024) ? "Byte" : "KByte", + at25->chip.name, is_fram ? "fram" : "eeprom", + (chip.flags & EE_READONLY) ? " (readonly)" : "", + at25->chip.page_size); return 0; } /*-------------------------------------------------------------------------*/ -static const struct of_device_id at25_of_match[] = { - { .compatible = "atmel,at25", }, - { } -}; -MODULE_DEVICE_TABLE(of, at25_of_match); - static struct spi_driver at25_driver = { .driver = { .name = "at25", .of_match_table = at25_of_match, + .dev_groups = sernum_groups, }, .probe = at25_probe, }; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index b3c28a2d4c10..4d1c4f83b22f 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -180,6 +180,7 @@ static const char * const nvmem_type_str[] = { [NVMEM_TYPE_EEPROM] = "EEPROM", [NVMEM_TYPE_OTP] = "OTP", [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", + [NVMEM_TYPE_FRAM] = "FRAM", }; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -359,6 +360,9 @@ static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, if (!config->base_dev) return -EINVAL; + if (config->type == NVMEM_TYPE_FRAM) + bin_attr_nvmem_eeprom_compat.attr.name = "fram"; + nvmem->eeprom = bin_attr_nvmem_eeprom_compat; nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); nvmem->eeprom.size = nvmem->size; diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index e162b757b6d5..890003565761 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -25,6 +25,7 @@ enum nvmem_type { NVMEM_TYPE_EEPROM, NVMEM_TYPE_OTP, NVMEM_TYPE_BATTERY_BACKED, + NVMEM_TYPE_FRAM, }; #define NVMEM_DEVID_NONE (-1) -- cgit v1.2.3 From 63879e2964bceee2aa5bbe8b99ea58bba28bb64f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 11 Jun 2021 11:23:21 +0100 Subject: nvmem: core: add a missing of_node_put 'for_each_child_of_node' performs an of_node_get on each iteration, so a return from the middle of the loop requires an of_node_put. Fixes: e888d445ac33 ("nvmem: resolve cells from DT at registration time") Cc: Signed-off-by: Christophe JAILLET Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210611102321.11509-1-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 4d1c4f83b22f..20799e622b5b 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -690,15 +690,17 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) continue; if (len < 2 * sizeof(u32)) { dev_err(dev, "nvmem: invalid reg on %pOF\n", child); + of_node_put(child); return -EINVAL; } cell = kzalloc(sizeof(*cell), GFP_KERNEL); - if (!cell) + if (!cell) { + of_node_put(child); return -ENOMEM; + } cell->nvmem = nvmem; - cell->np = of_node_get(child); cell->offset = be32_to_cpup(addr++); cell->bytes = be32_to_cpup(addr); cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); @@ -719,11 +721,12 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) cell->name, nvmem->stride); /* Cells already added will be freed later. */ kfree_const(cell->name); - of_node_put(cell->np); kfree(cell); + of_node_put(child); return -EINVAL; } + cell->np = of_node_get(child); nvmem_cell_add(cell); } -- cgit v1.2.3