summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>2026-07-29 10:46:43 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-31 14:15:53 +0200
commitcf09b7a05618bea99468b67fe80202efba1b48ad (patch)
tree808f953f4bbc4bcd54b1475a3ca38ccf49c458fd /drivers/misc
parentb594cbb7e8cfc8e2faeebf6b7b11b4a6990fc732 (diff)
eeprom: move nvmem EEPROM drivers to drivers/nvmem/
For historical reasons EEPROM drivers have lived under drivers/misc/eeprom/. Also for historical reasons changes to most of them would go through the char-misc tree while some would be queued through the I2C tree. Over the years some of them have also been converted to using nvmem - the dedicated subsystem for non-volatile memory - while get_maintainer.pl does not Cc the maintainer of nvmem on patches changing them. Move the EEPROM drivers using nvmem under drivers/nvmem/ for consistency of the review process and path upstream. Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com> Signed-off-by: Srinivas Kandagatla <srini@kernel.org> Link: https://patch.msgid.link/20260729094647.111468-11-srini@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/eeprom/Kconfig93
-rw-r--r--drivers/misc/eeprom/Makefile5
-rw-r--r--drivers/misc/eeprom/at24.c871
-rw-r--r--drivers/misc/eeprom/at25.c585
-rw-r--r--drivers/misc/eeprom/ee1004.c351
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c560
-rw-r--r--drivers/misc/eeprom/m24lr.c606
7 files changed, 0 insertions, 3071 deletions
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 4d0ce47aa282..d6af02588c66 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -1,52 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "EEPROM support"
-config EEPROM_AT24
- tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
- depends on I2C && SYSFS
- select NVMEM
- select NVMEM_SYSFS
- select REGMAP
- select REGMAP_I2C
- help
- Enable this driver to get read/write support to most I2C EEPROMs
- and compatible devices like FRAMs, SRAMs, ROMs etc. After you
- configure the driver to know about each chip on your target
- board. Use these generic chip names, instead of vendor-specific
- ones like at24c64, 24lc02 or fm24c04:
-
- 24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
- 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024, 24c2048
-
- Unless you like data loss puzzles, always be sure that any chip
- you configure as a 24c32 (32 kbit) or larger is NOT really a
- 24c16 (16 kbit) or smaller, and vice versa. Marking the chip
- as read-only won't help recover from this. Also, if your chip
- has any software write-protect mechanism you may want to review the
- code to make sure this driver won't turn it on by accident.
-
- If you use this with an SMBus adapter instead of an I2C adapter,
- full functionality is not available. Only smaller devices are
- supported (24c16 and below, max 4 kByte).
-
- This driver can also be built as a module. If so, the module
- will be called at24.
-
-config EEPROM_AT25
- tristate "SPI EEPROMs (FRAMs) from most vendors"
- depends on SPI && SYSFS
- select NVMEM
- select NVMEM_SYSFS
- select SPI_MEM
- help
- 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.
-
- This driver can also be built as a module. If so, the module
- will be called at25.
-
config EEPROM_MAX6875
tristate "Maxim MAX6874/5 power supply supervisor"
depends on I2C
@@ -69,22 +23,6 @@ config EEPROM_93CX6
If unsure, say N.
-config EEPROM_93XX46
- tristate "Microwire EEPROM 93XX46 support"
- depends on SPI && SYSFS
- select REGMAP
- select NVMEM
- select NVMEM_SYSFS
- help
- Driver for the microwire EEPROM chipsets 93xx46x. The driver
- supports both read and write commands and also the command to
- erase the whole EEPROM.
-
- This driver can also be built as a module. If so, the module
- will be called eeprom_93xx46.
-
- If unsure, say N.
-
config EEPROM_DIGSY_MTC_CFG
bool "DigsyMTC display configuration EEPROMs device"
depends on GPIO_MPC5200 && SPI_GPIO
@@ -107,35 +45,4 @@ config EEPROM_IDT_89HPESX
This driver can also be built as a module. If so, the module
will be called idt_89hpesx.
-config EEPROM_EE1004
- tristate "SPD EEPROMs on DDR4 memory modules"
- depends on I2C && SYSFS
- select NVMEM
- select NVMEM_SYSFS
- help
- Enable this driver to get read support to SPD EEPROMs following
- the JEDEC EE1004 standard. These are typically found on DDR4
- SDRAM memory modules.
-
- This driver can also be built as a module. If so, the module
- will be called ee1004.
-
-config EEPROM_M24LR
- tristate "STMicroelectronics M24LR RFID/NFC EEPROM support"
- depends on I2C && SYSFS
- select REGMAP_I2C
- select NVMEM
- select NVMEM_SYSFS
- help
- This enables support for STMicroelectronics M24LR RFID/NFC EEPROM
- chips. These dual-interface devices expose two I2C addresses:
- one for EEPROM memory access and another for control and system
- configuration (e.g. UID, password handling).
-
- This driver provides a sysfs interface for control functions and
- integrates with the nvmem subsystem for EEPROM access.
-
- To compile this driver as a module, choose M here: the
- module will be called m24lr.
-
endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 8f311fd6a4ce..44a20cf025a1 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -1,10 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_EEPROM_AT24) += at24.o
-obj-$(CONFIG_EEPROM_AT25) += at25.o
obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
-obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o
-obj-$(CONFIG_EEPROM_EE1004) += ee1004.o
-obj-$(CONFIG_EEPROM_M24LR) += m24lr.o
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
deleted file mode 100644
index 772c4d9fa651..000000000000
--- a/drivers/misc/eeprom/at24.c
+++ /dev/null
@@ -1,871 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * at24.c - handle most I2C EEPROMs
- *
- * Copyright (C) 2005-2007 David Brownell
- * Copyright (C) 2008 Wolfram Sang, Pengutronix
- */
-
-#include <linux/acpi.h>
-#include <linux/bitops.h>
-#include <linux/capability.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/nvmem-provider.h>
-#include <linux/pm_runtime.h>
-#include <linux/property.h>
-#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-
-/* Address pointer is 16 bit. */
-#define AT24_FLAG_ADDR16 BIT(7)
-/* sysfs-entry will be read-only. */
-#define AT24_FLAG_READONLY BIT(6)
-/* sysfs-entry will be world-readable. */
-#define AT24_FLAG_IRUGO BIT(5)
-/* Take always 8 addresses (24c00). */
-#define AT24_FLAG_TAKE8ADDR BIT(4)
-/* Factory-programmed serial number. */
-#define AT24_FLAG_SERIAL BIT(3)
-/* Factory-programmed mac address. */
-#define AT24_FLAG_MAC BIT(2)
-/* Does not auto-rollover reads to the next slave address. */
-#define AT24_FLAG_NO_RDROL BIT(1)
-
-/*
- * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
- * Differences between different vendor product lines (like Atmel AT24C or
- * MicroChip 24LC, etc) won't much matter for typical read/write access.
- * There are also I2C RAM chips, likewise interchangeable. One example
- * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
- *
- * However, misconfiguration can lose data. "Set 16-bit memory address"
- * to a part with 8-bit addressing will overwrite data. Writing with too
- * big a page size also loses data. And it's not safe to assume that the
- * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
- * uses 0x51, for just one example.
- *
- * Accordingly, explicit board-specific configuration data should be used
- * in almost all cases. (One partial exception is an SMBus used to access
- * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
- *
- * So this driver uses "new style" I2C driver binding, expecting to be
- * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
- * similar kernel-resident tables; or, configuration data coming from
- * a bootloader.
- *
- * Other than binding model, current differences from "eeprom" driver are
- * that this one handles write access and isn't restricted to 24c02 devices.
- * It also handles larger devices (32 kbit and up) with two-byte addresses,
- * which won't work on pure SMBus systems.
- */
-
-struct at24_data {
- /*
- * Lock protects against activities from other Linux tasks,
- * but not from changes by other I2C masters.
- */
- struct mutex lock;
-
- unsigned int write_max;
- unsigned int num_addresses;
- unsigned int offset_adj;
-
- u32 byte_len;
- u16 page_size;
- u8 flags;
-
- struct nvmem_device *nvmem;
- struct regulator *vcc_reg;
- void (*read_post)(unsigned int off, char *buf, size_t count);
-
- /*
- * Some chips tie up multiple I2C addresses; dummy devices reserve
- * them for us.
- */
- u8 bank_addr_shift;
- struct regmap *client_regmaps[] __counted_by(num_addresses);
-};
-
-/*
- * This parameter is to help this driver avoid blocking other drivers out
- * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
- * clock, one 256 byte read takes about 1/43 second which is excessive;
- * but the 1/170 second it takes at 400 kHz may be quite reasonable; and
- * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
- *
- * This value is forced to be a power of two so that writes align on pages.
- */
-static unsigned int at24_io_limit = 128;
-module_param_named(io_limit, at24_io_limit, uint, 0);
-MODULE_PARM_DESC(at24_io_limit, "Maximum bytes per I/O (default 128)");
-
-/*
- * Specs often allow 5 msec for a page write, sometimes 20 msec;
- * it's important to recover from write timeouts.
- */
-static unsigned int at24_write_timeout = 25;
-module_param_named(write_timeout, at24_write_timeout, uint, 0);
-MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
-
-struct at24_chip_data {
- u32 byte_len;
- u8 flags;
- u8 bank_addr_shift;
- void (*read_post)(unsigned int off, char *buf, size_t count);
-};
-
-#define AT24_CHIP_DATA(_name, _len, _flags) \
- static const struct at24_chip_data _name = { \
- .byte_len = _len, .flags = _flags, \
- }
-
-#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \
- static const struct at24_chip_data _name = { \
- .byte_len = _len, .flags = _flags, \
- .read_post = _read_post, \
- }
-
-#define AT24_CHIP_DATA_BS(_name, _len, _flags, _bank_addr_shift) \
- static const struct at24_chip_data _name = { \
- .byte_len = _len, .flags = _flags, \
- .bank_addr_shift = _bank_addr_shift \
- }
-
-static void at24_read_post_vaio(unsigned int off, char *buf, size_t count)
-{
- int i;
-
- if (capable(CAP_SYS_ADMIN))
- return;
-
- /*
- * Hide VAIO private settings to regular users:
- * - BIOS passwords: bytes 0x00 to 0x0f
- * - UUID: bytes 0x10 to 0x1f
- * - Serial number: 0xc0 to 0xdf
- */
- for (i = 0; i < count; i++) {
- if ((off + i <= 0x1f) ||
- (off + i >= 0xc0 && off + i <= 0xdf))
- buf[i] = 0;
- }
-}
-
-/* needs 8 addresses as A0-A2 are ignored */
-AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR);
-/* old variants can't be handled with this generic entry! */
-AT24_CHIP_DATA(at24_data_24c01, 1024 / 8, 0);
-AT24_CHIP_DATA(at24_data_24cs01, 16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24c02, 2048 / 8, 0);
-AT24_CHIP_DATA(at24_data_24cs02, 16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24mac402, 48 / 8,
- AT24_FLAG_MAC | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24mac602, 64 / 8,
- AT24_FLAG_MAC | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24aa025e48, 48 / 8,
- AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24aa025e64, 64 / 8,
- AT24_FLAG_READONLY);
-/* spd is a 24c02 in memory DIMMs */
-AT24_CHIP_DATA(at24_data_spd, 2048 / 8,
- AT24_FLAG_READONLY | AT24_FLAG_IRUGO);
-/* 24c02_vaio is a 24c02 on some Sony laptops */
-AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8,
- AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
- at24_read_post_vaio);
-AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0);
-AT24_CHIP_DATA(at24_data_24cs04, 16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-/* 24rf08 quirk is handled at i2c-core */
-AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, 0);
-AT24_CHIP_DATA(at24_data_24cs08, 16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, 0);
-AT24_CHIP_DATA(at24_data_24cs16, 16,
- AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16);
-/* M24C32-D Additional Write lockable page (M24C32-D order codes) */
-AT24_CHIP_DATA(at24_data_24c32d_wlp, 32, AT24_FLAG_ADDR16);
-AT24_CHIP_DATA(at24_data_24cs32, 16,
- AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16);
-/* M24C64-D Additional Write lockable page (M24C64-D order codes) */
-AT24_CHIP_DATA(at24_data_24c64d_wlp, 32, AT24_FLAG_ADDR16);
-AT24_CHIP_DATA(at24_data_24cs64, 16,
- AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
-AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16);
-AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16);
-/* M24256E Additional Write lockable page (M24256E-F order codes) */
-AT24_CHIP_DATA(at24_data_24256e_wlp, 64, AT24_FLAG_ADDR16);
-AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16);
-AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16);
-AT24_CHIP_DATA_BS(at24_data_24c1025, 1048576 / 8, AT24_FLAG_ADDR16, 2);
-AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16);
-/* identical to 24c08 ? */
-AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
-
-static const struct i2c_device_id at24_ids[] = {
- { .name = "24c00", .driver_data = (kernel_ulong_t)&at24_data_24c00 },
- { .name = "24c01", .driver_data = (kernel_ulong_t)&at24_data_24c01 },
- { .name = "24cs01", .driver_data = (kernel_ulong_t)&at24_data_24cs01 },
- { .name = "24c02", .driver_data = (kernel_ulong_t)&at24_data_24c02 },
- { .name = "24cs02", .driver_data = (kernel_ulong_t)&at24_data_24cs02 },
- { .name = "24mac402", .driver_data = (kernel_ulong_t)&at24_data_24mac402 },
- { .name = "24mac602", .driver_data = (kernel_ulong_t)&at24_data_24mac602 },
- { .name = "24aa025e48", .driver_data = (kernel_ulong_t)&at24_data_24aa025e48 },
- { .name = "24aa025e64", .driver_data = (kernel_ulong_t)&at24_data_24aa025e64 },
- { .name = "spd", .driver_data = (kernel_ulong_t)&at24_data_spd },
- { .name = "24c02-vaio", .driver_data = (kernel_ulong_t)&at24_data_24c02_vaio },
- { .name = "24c04", .driver_data = (kernel_ulong_t)&at24_data_24c04 },
- { .name = "24cs04", .driver_data = (kernel_ulong_t)&at24_data_24cs04 },
- { .name = "24c08", .driver_data = (kernel_ulong_t)&at24_data_24c08 },
- { .name = "24cs08", .driver_data = (kernel_ulong_t)&at24_data_24cs08 },
- { .name = "24c16", .driver_data = (kernel_ulong_t)&at24_data_24c16 },
- { .name = "24cs16", .driver_data = (kernel_ulong_t)&at24_data_24cs16 },
- { .name = "24c32", .driver_data = (kernel_ulong_t)&at24_data_24c32 },
- { .name = "24c32d-wl", .driver_data = (kernel_ulong_t)&at24_data_24c32d_wlp },
- { .name = "24cs32", .driver_data = (kernel_ulong_t)&at24_data_24cs32 },
- { .name = "24c64", .driver_data = (kernel_ulong_t)&at24_data_24c64 },
- { .name = "24c64-wl", .driver_data = (kernel_ulong_t)&at24_data_24c64d_wlp },
- { .name = "24cs64", .driver_data = (kernel_ulong_t)&at24_data_24cs64 },
- { .name = "24c128", .driver_data = (kernel_ulong_t)&at24_data_24c128 },
- { .name = "24c256", .driver_data = (kernel_ulong_t)&at24_data_24c256 },
- { .name = "24256e-wl", .driver_data = (kernel_ulong_t)&at24_data_24256e_wlp },
- { .name = "24c512", .driver_data = (kernel_ulong_t)&at24_data_24c512 },
- { .name = "24c1024", .driver_data = (kernel_ulong_t)&at24_data_24c1024 },
- { .name = "24c1025", .driver_data = (kernel_ulong_t)&at24_data_24c1025 },
- { .name = "24c2048", .driver_data = (kernel_ulong_t)&at24_data_24c2048 },
- { .name = "at24", .driver_data = 0 },
- { /* END OF LIST */ }
-};
-MODULE_DEVICE_TABLE(i2c, at24_ids);
-
-static const struct of_device_id at24_of_match[] = {
- { .compatible = "atmel,24c00", .data = &at24_data_24c00 },
- { .compatible = "atmel,24c01", .data = &at24_data_24c01 },
- { .compatible = "atmel,24cs01", .data = &at24_data_24cs01 },
- { .compatible = "atmel,24c02", .data = &at24_data_24c02 },
- { .compatible = "atmel,24cs02", .data = &at24_data_24cs02 },
- { .compatible = "atmel,24mac402", .data = &at24_data_24mac402 },
- { .compatible = "atmel,24mac602", .data = &at24_data_24mac602 },
- { .compatible = "atmel,spd", .data = &at24_data_spd },
- { .compatible = "atmel,24c04", .data = &at24_data_24c04 },
- { .compatible = "atmel,24cs04", .data = &at24_data_24cs04 },
- { .compatible = "atmel,24c08", .data = &at24_data_24c08 },
- { .compatible = "atmel,24cs08", .data = &at24_data_24cs08 },
- { .compatible = "atmel,24c16", .data = &at24_data_24c16 },
- { .compatible = "atmel,24cs16", .data = &at24_data_24cs16 },
- { .compatible = "atmel,24c32", .data = &at24_data_24c32 },
- { .compatible = "atmel,24c32d-wl", .data = &at24_data_24c32d_wlp },
- { .compatible = "atmel,24cs32", .data = &at24_data_24cs32 },
- { .compatible = "atmel,24c64", .data = &at24_data_24c64 },
- { .compatible = "atmel,24c64d-wl", .data = &at24_data_24c64d_wlp },
- { .compatible = "atmel,24cs64", .data = &at24_data_24cs64 },
- { .compatible = "atmel,24c128", .data = &at24_data_24c128 },
- { .compatible = "atmel,24c256", .data = &at24_data_24c256 },
- { .compatible = "atmel,24c512", .data = &at24_data_24c512 },
- { .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
- { .compatible = "atmel,24c1025", .data = &at24_data_24c1025 },
- { .compatible = "atmel,24c2048", .data = &at24_data_24c2048 },
- { .compatible = "microchip,24aa025e48", .data = &at24_data_24aa025e48 },
- { .compatible = "microchip,24aa025e64", .data = &at24_data_24aa025e64 },
- { .compatible = "st,24256e-wl", .data = &at24_data_24256e_wlp },
- { /* END OF LIST */ },
-};
-MODULE_DEVICE_TABLE(of, at24_of_match);
-
-static const struct acpi_device_id at24_acpi_ids[] = {
- { "INT3499", (kernel_ulong_t)&at24_data_INT3499 },
- { "TPF0001", (kernel_ulong_t)&at24_data_24c1024 },
- { /* END OF LIST */ }
-};
-MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
-
-/*
- * This routine supports chips which consume multiple I2C addresses. It
- * computes the addressing information to be used for a given r/w request.
- * Assumes that sanity checks for offset happened at sysfs-layer.
- *
- * Slave address and byte offset derive from the offset. Always
- * set the byte address; on a multi-master board, another master
- * may have changed the chip's "current" address pointer.
- */
-static struct regmap *at24_translate_offset(struct at24_data *at24,
- unsigned int *offset)
-{
- unsigned int i;
-
- if (at24->flags & AT24_FLAG_ADDR16) {
- i = *offset >> 16;
- *offset &= 0xffff;
- } else {
- i = *offset >> 8;
- *offset &= 0xff;
- }
-
- return at24->client_regmaps[i];
-}
-
-static struct device *at24_base_client_dev(struct at24_data *at24)
-{
- return regmap_get_device(at24->client_regmaps[0]);
-}
-
-static size_t at24_adjust_read_count(struct at24_data *at24,
- unsigned int offset, size_t count)
-{
- unsigned int bits;
- size_t remainder;
-
- /*
- * In case of multi-address chips that don't rollover reads to
- * the next slave address: truncate the count to the slave boundary,
- * so that the read never straddles slaves.
- */
- if (at24->flags & AT24_FLAG_NO_RDROL) {
- bits = (at24->flags & AT24_FLAG_ADDR16) ? 16 : 8;
- remainder = BIT(bits) - offset;
- if (count > remainder)
- count = remainder;
- }
-
- if (count > at24_io_limit)
- count = at24_io_limit;
-
- return count;
-}
-
-static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
- unsigned int offset, size_t count)
-{
- unsigned long timeout, read_time;
- struct regmap *regmap;
- int ret;
-
- regmap = at24_translate_offset(at24, &offset);
- count = at24_adjust_read_count(at24, offset, count);
-
- /* adjust offset for mac and serial read ops */
- offset += at24->offset_adj;
-
- timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
- do {
- /*
- * The timestamp shall be taken before the actual operation
- * to avoid a premature timeout in case of high CPU load.
- */
- read_time = jiffies;
-
- ret = regmap_bulk_read(regmap, offset, buf, count);
- dev_dbg(regmap_get_device(regmap), "read %zu@%d --> %d (%ld)\n",
- count, offset, ret, jiffies);
- if (!ret)
- return count;
-
- usleep_range(1000, 1500);
- } while (time_before(read_time, timeout));
-
- return -ETIMEDOUT;
-}
-
-/*
- * Note that if the hardware write-protect pin is pulled high, the whole
- * chip is normally write protected. But there are plenty of product
- * variants here, including OTP fuses and partial chip protect.
- *
- * We only use page mode writes; the alternative is sloooow. These routines
- * write at most one page.
- */
-
-static size_t at24_adjust_write_count(struct at24_data *at24,
- unsigned int offset, size_t count)
-{
- unsigned int next_page;
-
- /* write_max is at most a page */
- if (count > at24->write_max)
- count = at24->write_max;
-
- /* Never roll over backwards, to the start of this page */
- next_page = roundup(offset + 1, at24->page_size);
- if (offset + count > next_page)
- count = next_page - offset;
-
- return count;
-}
-
-static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
- unsigned int offset, size_t count)
-{
- unsigned long timeout, write_time;
- struct regmap *regmap;
- int ret;
-
- regmap = at24_translate_offset(at24, &offset);
- count = at24_adjust_write_count(at24, offset, count);
- timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
-
- do {
- /*
- * The timestamp shall be taken before the actual operation
- * to avoid a premature timeout in case of high CPU load.
- */
- write_time = jiffies;
-
- ret = regmap_bulk_write(regmap, offset, buf, count);
- dev_dbg(regmap_get_device(regmap), "write %zu@%d --> %d (%ld)\n",
- count, offset, ret, jiffies);
- if (!ret)
- return count;
-
- usleep_range(1000, 1500);
- } while (time_before(write_time, timeout));
-
- return -ETIMEDOUT;
-}
-
-static int at24_read(void *priv, unsigned int off, void *val, size_t count)
-{
- struct at24_data *at24;
- struct device *dev;
- char *buf = val;
- int i, ret;
-
- at24 = priv;
- dev = at24_base_client_dev(at24);
-
- if (unlikely(!count))
- return count;
-
- if (off + count > at24->byte_len)
- return -EINVAL;
-
- ret = pm_runtime_resume_and_get(dev);
- if (ret)
- return ret;
- /*
- * Read data from chip, protecting against concurrent updates
- * from this host, but not from other I2C masters.
- */
- mutex_lock(&at24->lock);
-
- for (i = 0; count; i += ret, count -= ret) {
- ret = at24_regmap_read(at24, buf + i, off + i, count);
- if (ret < 0) {
- mutex_unlock(&at24->lock);
- pm_runtime_put(dev);
- return ret;
- }
- }
-
- mutex_unlock(&at24->lock);
-
- pm_runtime_put(dev);
-
- if (unlikely(at24->read_post))
- at24->read_post(off, buf, i);
-
- return 0;
-}
-
-static int at24_write(void *priv, unsigned int off, void *val, size_t count)
-{
- struct at24_data *at24;
- struct device *dev;
- char *buf = val;
- int ret;
-
- at24 = priv;
- dev = at24_base_client_dev(at24);
-
- if (unlikely(!count))
- return -EINVAL;
-
- if (off + count > at24->byte_len)
- return -EINVAL;
-
- ret = pm_runtime_resume_and_get(dev);
- if (ret)
- return ret;
- /*
- * Write data to chip, protecting against concurrent updates
- * from this host, but not from other I2C masters.
- */
- mutex_lock(&at24->lock);
-
- while (count) {
- ret = at24_regmap_write(at24, buf, off, count);
- if (ret < 0) {
- mutex_unlock(&at24->lock);
- pm_runtime_put(dev);
- return ret;
- }
- buf += ret;
- off += ret;
- count -= ret;
- }
-
- mutex_unlock(&at24->lock);
-
- pm_runtime_put(dev);
-
- return 0;
-}
-
-static int at24_make_dummy_client(struct at24_data *at24, unsigned int index,
- struct i2c_client *base_client,
- struct regmap_config *regmap_config)
-{
- struct i2c_client *dummy_client;
- struct regmap *regmap;
-
- dummy_client = devm_i2c_new_dummy_device(&base_client->dev,
- base_client->adapter,
- base_client->addr +
- (index << at24->bank_addr_shift));
- if (IS_ERR(dummy_client))
- return PTR_ERR(dummy_client);
-
- regmap = devm_regmap_init_i2c(dummy_client, regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- at24->client_regmaps[index] = regmap;
-
- return 0;
-}
-
-static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
-{
- if (flags & AT24_FLAG_MAC) {
- /* EUI-48 starts from 0x9a, EUI-64 from 0x98 */
- return 0xa0 - byte_len;
- } else if (flags & AT24_FLAG_SERIAL && flags & AT24_FLAG_ADDR16) {
- /*
- * For 16 bit address pointers, the word address must contain
- * a '10' sequence in bits 11 and 10 regardless of the
- * intended position of the address pointer.
- */
- return 0x0800;
- } else if (flags & AT24_FLAG_SERIAL) {
- /*
- * Otherwise the word address must begin with a '10' sequence,
- * regardless of the intended address.
- */
- return 0x0080;
- } else {
- return 0;
- }
-}
-
-static void at24_probe_temp_sensor(struct i2c_client *client)
-{
- struct at24_data *at24 = i2c_get_clientdata(client);
- struct i2c_board_info info = { .type = "jc42" };
- int ret;
- u8 val;
-
- /*
- * Byte 2 has value 11 for DDR3, earlier versions don't
- * support the thermal sensor present flag
- */
- ret = at24_read(at24, 2, &val, 1);
- if (ret || val != 11)
- return;
-
- /* Byte 32, bit 7 is set if temp sensor is present */
- ret = at24_read(at24, 32, &val, 1);
- if (ret || !(val & BIT(7)))
- return;
-
- info.addr = 0x18 | (client->addr & 7);
-
- i2c_new_client_device(client->adapter, &info);
-}
-
-static int at24_probe(struct i2c_client *client)
-{
- struct regmap_config regmap_config = { };
- struct nvmem_config nvmem_config = { };
- u32 byte_len, page_size, flags, addrw;
- const struct at24_chip_data *cdata;
- struct device *dev = &client->dev;
- bool i2c_fn_i2c, i2c_fn_block;
- unsigned int i, num_addresses;
- struct at24_data *at24;
- bool full_power;
- struct regmap *regmap;
- bool writable;
- u8 test_byte;
- int err;
-
- i2c_fn_i2c = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
- i2c_fn_block = i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK);
-
- cdata = i2c_get_match_data(client);
- if (!cdata)
- return -ENODEV;
-
- err = device_property_read_u32(dev, "pagesize", &page_size);
- if (err)
- /*
- * This is slow, but we can't know all eeproms, so we better
- * play safe. Specifying custom eeprom-types via device tree
- * or properties is recommended anyhow.
- */
- page_size = 1;
-
- flags = cdata->flags;
- if (device_property_present(dev, "read-only"))
- flags |= AT24_FLAG_READONLY;
- if (device_property_present(dev, "no-read-rollover"))
- flags |= AT24_FLAG_NO_RDROL;
-
- err = device_property_read_u32(dev, "address-width", &addrw);
- if (!err) {
- switch (addrw) {
- case 8:
- if (flags & AT24_FLAG_ADDR16)
- dev_warn(dev,
- "Override address width to be 8, while default is 16\n");
- flags &= ~AT24_FLAG_ADDR16;
- break;
- case 16:
- flags |= AT24_FLAG_ADDR16;
- break;
- default:
- dev_warn(dev, "Bad \"address-width\" property: %u\n",
- addrw);
- }
- }
-
- err = device_property_read_u32(dev, "size", &byte_len);
- if (err)
- byte_len = cdata->byte_len;
-
- if (!i2c_fn_i2c && !i2c_fn_block)
- page_size = 1;
-
- if (!page_size)
- return dev_err_probe(dev, -EINVAL, "page_size must not be 0!\n");
-
- if (!is_power_of_2(page_size))
- dev_warn(dev, "page_size looks suspicious (no power of 2)!\n");
-
- err = device_property_read_u32(dev, "num-addresses", &num_addresses);
- if (err) {
- if (flags & AT24_FLAG_TAKE8ADDR)
- num_addresses = 8;
- else
- num_addresses = DIV_ROUND_UP(byte_len,
- (flags & AT24_FLAG_ADDR16) ? 65536 : 256);
- }
-
- if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC))
- return dev_err_probe(dev, -EINVAL,
- "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
-
- regmap_config.val_bits = 8;
- regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8;
- regmap_config.disable_locking = true;
-
- regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- at24 = devm_kzalloc(dev, struct_size(at24, client_regmaps, num_addresses),
- GFP_KERNEL);
- if (!at24)
- return -ENOMEM;
-
- mutex_init(&at24->lock);
- at24->byte_len = byte_len;
- at24->page_size = page_size;
- at24->flags = flags;
- at24->read_post = cdata->read_post;
- at24->bank_addr_shift = cdata->bank_addr_shift;
- at24->num_addresses = num_addresses;
- at24->offset_adj = at24_get_offset_adj(flags, byte_len);
- at24->client_regmaps[0] = regmap;
-
- at24->vcc_reg = devm_regulator_get(dev, "vcc");
- if (IS_ERR(at24->vcc_reg))
- return PTR_ERR(at24->vcc_reg);
-
- writable = !(flags & AT24_FLAG_READONLY);
- if (writable) {
- at24->write_max = min_t(unsigned int,
- page_size, at24_io_limit);
- if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX)
- at24->write_max = I2C_SMBUS_BLOCK_MAX;
- }
-
- /* use dummy devices for multiple-address chips */
- for (i = 1; i < num_addresses; i++) {
- err = at24_make_dummy_client(at24, i, client, &regmap_config);
- if (err)
- return err;
- }
-
- /*
- * We initialize nvmem_config.id to NVMEM_DEVID_AUTO even if the
- * label property is set as some platform can have multiple eeproms
- * with same label and we can not register each of those with same
- * label. Failing to register those eeproms trigger cascade failure
- * on such platform.
- */
- nvmem_config.id = NVMEM_DEVID_AUTO;
-
- if (device_property_present(dev, "label")) {
- err = device_property_read_string(dev, "label",
- &nvmem_config.name);
- if (err)
- return err;
- } else {
- nvmem_config.name = dev_name(dev);
- }
-
- nvmem_config.type = NVMEM_TYPE_EEPROM;
- nvmem_config.dev = dev;
- nvmem_config.read_only = !writable;
- nvmem_config.root_only = !(flags & AT24_FLAG_IRUGO);
- nvmem_config.owner = THIS_MODULE;
- nvmem_config.compat = true;
- nvmem_config.base_dev = dev;
- nvmem_config.reg_read = at24_read;
- nvmem_config.reg_write = at24_write;
- nvmem_config.priv = at24;
- nvmem_config.stride = 1;
- nvmem_config.word_size = 1;
- nvmem_config.size = byte_len;
-
- i2c_set_clientdata(client, at24);
-
- full_power = acpi_dev_state_d0(&client->dev);
- if (full_power) {
- err = regulator_enable(at24->vcc_reg);
- if (err)
- return dev_err_probe(dev, err, "Failed to enable vcc regulator\n");
-
- pm_runtime_set_active(dev);
- }
- pm_runtime_enable(dev);
-
- /*
- * Perform a one-byte test read to verify that the chip is functional,
- * unless powering on the device is to be avoided during probe (i.e.
- * it's powered off right now).
- */
- if (full_power) {
- err = at24_read(at24, 0, &test_byte, 1);
- if (err) {
- pm_runtime_disable(dev);
- if (!pm_runtime_status_suspended(dev))
- regulator_disable(at24->vcc_reg);
- return -ENODEV;
- }
- }
-
- at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
- if (IS_ERR(at24->nvmem)) {
- pm_runtime_disable(dev);
- if (!pm_runtime_status_suspended(dev))
- regulator_disable(at24->vcc_reg);
- return dev_err_probe(dev, PTR_ERR(at24->nvmem),
- "failed to register nvmem\n");
- }
-
- /* If this a SPD EEPROM, probe for DDR3 thermal sensor */
- if (cdata == &at24_data_spd)
- at24_probe_temp_sensor(client);
-
- pm_runtime_idle(dev);
-
- if (writable)
- dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n",
- byte_len, client->name, at24->write_max);
- else
- dev_info(dev, "%u byte %s EEPROM, read-only\n",
- byte_len, client->name);
-
- return 0;
-}
-
-static void at24_remove(struct i2c_client *client)
-{
- struct at24_data *at24 = i2c_get_clientdata(client);
-
- pm_runtime_disable(&client->dev);
- if (acpi_dev_state_d0(&client->dev)) {
- if (!pm_runtime_status_suspended(&client->dev))
- regulator_disable(at24->vcc_reg);
- pm_runtime_set_suspended(&client->dev);
- }
-}
-
-static int __maybe_unused at24_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct at24_data *at24 = i2c_get_clientdata(client);
-
- return regulator_disable(at24->vcc_reg);
-}
-
-static int __maybe_unused at24_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct at24_data *at24 = i2c_get_clientdata(client);
-
- return regulator_enable(at24->vcc_reg);
-}
-
-static const struct dev_pm_ops at24_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL)
-};
-
-static struct i2c_driver at24_driver = {
- .driver = {
- .name = "at24",
- .pm = &at24_pm_ops,
- .of_match_table = at24_of_match,
- .acpi_match_table = at24_acpi_ids,
- },
- .probe = at24_probe,
- .remove = at24_remove,
- .id_table = at24_ids,
- .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
-};
-
-static int __init at24_init(void)
-{
- if (!at24_io_limit) {
- pr_err("at24: at24_io_limit must not be 0!\n");
- return -EINVAL;
- }
-
- at24_io_limit = rounddown_pow_of_two(at24_io_limit);
- return i2c_add_driver(&at24_driver);
-}
-module_init(at24_init);
-
-static void __exit at24_exit(void)
-{
- i2c_del_driver(&at24_driver);
-}
-module_exit(at24_exit);
-
-MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
-MODULE_AUTHOR("David Brownell and Wolfram Sang");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
deleted file mode 100644
index bc2cfb75d9bb..000000000000
--- a/drivers/misc/eeprom/at25.c
+++ /dev/null
@@ -1,585 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for most of the SPI EEPROMs, such as Atmel AT25 models
- * and Cypress FRAMs FM25 models.
- *
- * Copyright (C) 2006 David Brownell
- */
-
-#include <linux/bits.h>
-#include <linux/cleanup.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/property.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <linux/spi/eeprom.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi-mem.h>
-
-#include <linux/nvmem-provider.h>
-
-/*
- * NOTE: this is an *EEPROM* driver. The vagaries of product naming
- * mean that some AT25 products are EEPROMs, and others are FLASH.
- * Handle FLASH chips with the drivers/mtd/devices/m25p80.c driver,
- * not this one!
- *
- * EEPROMs that can be used with this driver include, for example:
- * AT25M02, AT25128B
- */
-
-#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 {
- struct spi_eeprom chip;
- struct spi_mem *spimem;
- struct mutex lock;
- unsigned addrlen;
- 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 */
-#define AT25_WRDI 0x04 /* reset the write enable */
-#define AT25_RDSR 0x05 /* read status register */
-#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) */
-#define AT25_SR_BP0 0x04 /* BP for software writeprotect */
-#define AT25_SR_BP1 0x08
-#define AT25_SR_WPEN 0x80 /* writeprotect enable */
-
-#define AT25_INSTR_BIT3 0x08 /* additional address bit in instr */
-
-/*
- * Specs often allow 5ms for a page write, sometimes 20ms;
- * it's important to recover from write timeouts.
- */
-#define EE_TIMEOUT 25
-
-/*-------------------------------------------------------------------------*/
-
-#define io_limit PAGE_SIZE /* bytes */
-
-/* Handle the address MSB as part of instruction byte */
-static u8 at25_instr(struct at25_data *at25, u8 instr, unsigned int off)
-{
- if (!(at25->chip.flags & EE_INSTR_BIT3_IS_ADDR))
- return instr;
- if (off < BIT(at25->addrlen * 8))
- return instr;
- return instr | AT25_INSTR_BIT3;
-}
-
-static int at25_ee_read(void *priv, unsigned int offset,
- void *val, size_t count)
-{
- u8 *bounce __free(kfree) = kmalloc(min(count, io_limit), GFP_KERNEL);
- struct at25_data *at25 = priv;
- char *buf = val;
- unsigned int msg_offset = offset;
- size_t bytes_left = count;
- size_t segment;
- int status;
-
- if (!bounce)
- return -ENOMEM;
-
- if (unlikely(offset >= at25->chip.byte_len))
- return -EINVAL;
- if ((offset + count) > at25->chip.byte_len)
- count = at25->chip.byte_len - offset;
- if (unlikely(!count))
- return -EINVAL;
-
- do {
- struct spi_mem_op op;
-
- segment = min(bytes_left, io_limit);
-
- op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(at25_instr(at25, AT25_READ,
- msg_offset), 1),
- SPI_MEM_OP_ADDR(at25->addrlen, msg_offset, 1),
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(segment, bounce, 1));
-
- status = spi_mem_adjust_op_size(at25->spimem, &op);
- if (status)
- return status;
- segment = op.data.nbytes;
-
- mutex_lock(&at25->lock);
- status = spi_mem_exec_op(at25->spimem, &op);
- mutex_unlock(&at25->lock);
- if (status)
- return status;
- memcpy(buf, bounce, segment);
-
- msg_offset += segment;
- buf += segment;
- bytes_left -= segment;
- } while (bytes_left > 0);
-
- dev_dbg(&at25->spimem->spi->dev, "read %zu bytes at %d\n",
- count, offset);
- return 0;
-}
-
-/*
- * Read extra registers as ID or serial number
- *
- * Allow for the callers to provide @buf on stack (not necessary DMA-capable)
- * by allocating a bounce buffer internally.
- */
-static int fm25_aux_read(struct at25_data *at25, u8 *buf, uint8_t command,
- int len)
-{
- u8 *bounce __free(kfree) = kmalloc(len, GFP_KERNEL);
- struct spi_mem_op op;
- int status;
-
- if (!bounce)
- return -ENOMEM;
-
- op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(command, 1),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(len, bounce, 1));
-
- status = spi_mem_exec_op(at25->spimem, &op);
- dev_dbg(&at25->spimem->spi->dev, "read %d aux bytes --> %d\n", len, status);
- if (status)
- return status;
-
- memcpy(buf, bounce, len);
-
- return 0;
-}
-
-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", (int)sizeof(at25->sernum), at25->sernum);
-}
-static DEVICE_ATTR_RO(sernum);
-
-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(at25);
-
-/*
- * Poll Read Status Register with timeout
- *
- * Return:
- * 0, if the chip is ready
- * [positive] Status Register value as-is, if the chip is busy
- * [negative] error code in case of read failure
- */
-static int at25_wait_ready(struct at25_data *at25)
-{
- u8 *bounce __free(kfree) = kmalloc(1, GFP_KERNEL);
- struct spi_mem_op op;
- int status;
-
- if (!bounce)
- return -ENOMEM;
-
- op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(AT25_RDSR, 1),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_IN(1, bounce, 1));
-
- read_poll_timeout(spi_mem_exec_op, status,
- status || !(bounce[0] & AT25_SR_nRDY), false,
- USEC_PER_MSEC, USEC_PER_MSEC * EE_TIMEOUT,
- at25->spimem, &op);
- if (status < 0)
- return status;
- if (!(bounce[0] & AT25_SR_nRDY))
- return 0;
-
- return bounce[0];
-}
-
-static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
-{
- u8 *bounce __free(kfree) = kmalloc(min(count, io_limit), GFP_KERNEL);
- struct at25_data *at25 = priv;
- const char *buf = val;
- unsigned int buf_size;
- int status;
-
- if (unlikely(off >= at25->chip.byte_len))
- return -EFBIG;
- if ((off + count) > at25->chip.byte_len)
- count = at25->chip.byte_len - off;
- if (unlikely(!count))
- return -EINVAL;
-
- buf_size = at25->chip.page_size;
-
- if (!bounce)
- return -ENOMEM;
-
- /*
- * For write, rollover is within the page ... so we write at
- * most one page, then manually roll over to the next page.
- */
- guard(mutex)(&at25->lock);
- do {
- struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(AT25_WREN, 1),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_NO_DATA);
- unsigned int segment;
-
- status = spi_mem_exec_op(at25->spimem, &op);
- if (status < 0) {
- dev_dbg(&at25->spimem->spi->dev, "WREN --> %d\n", status);
- return status;
- }
-
- /* Write as much of a page as we can */
- segment = buf_size - (off % buf_size);
- if (segment > count)
- segment = count;
- if (segment > io_limit)
- segment = io_limit;
-
- op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(at25_instr(at25, AT25_WRITE, off),
- 1),
- SPI_MEM_OP_ADDR(at25->addrlen, off, 1),
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(segment, bounce, 1));
-
- status = spi_mem_adjust_op_size(at25->spimem, &op);
- if (status)
- return status;
- segment = op.data.nbytes;
-
- memcpy(bounce, buf, segment);
-
- status = spi_mem_exec_op(at25->spimem, &op);
- dev_dbg(&at25->spimem->spi->dev, "write %u bytes at %u --> %d\n",
- segment, off, status);
- if (status)
- return status;
-
- /*
- * REVISIT this should detect (or prevent) failed writes
- * to read-only sections of the EEPROM...
- */
-
- status = at25_wait_ready(at25);
- if (status < 0) {
- dev_err_probe(&at25->spimem->spi->dev, status,
- "Read Status Redister command failed\n");
- return status;
- }
- if (status) {
- dev_dbg(&at25->spimem->spi->dev,
- "Status %02x\n", status);
- dev_err(&at25->spimem->spi->dev,
- "write %u bytes offset %u, timeout after %u msecs\n",
- segment, off, EE_TIMEOUT);
- return -ETIMEDOUT;
- }
-
- off += segment;
- buf += segment;
- count -= segment;
-
- } while (count > 0);
-
- return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
-{
- u32 val;
- int err;
-
- strscpy(chip->name, "at25", sizeof(chip->name));
-
- err = device_property_read_u32(dev, "size", &val);
- if (err)
- err = device_property_read_u32(dev, "at25,byte-len", &val);
- if (err) {
- dev_err(dev, "Error: missing \"size\" property\n");
- return err;
- }
- chip->byte_len = val;
-
- err = device_property_read_u32(dev, "pagesize", &val);
- if (err)
- err = device_property_read_u32(dev, "at25,page-size", &val);
- if (err) {
- dev_err(dev, "Error: missing \"pagesize\" property\n");
- return err;
- }
- chip->page_size = val;
-
- err = device_property_read_u32(dev, "address-width", &val);
- if (err) {
- err = device_property_read_u32(dev, "at25,addr-mode", &val);
- if (err) {
- dev_err(dev, "Error: missing \"address-width\" property\n");
- return err;
- }
- chip->flags = (u16)val;
- } else {
- switch (val) {
- case 9:
- chip->flags |= EE_INSTR_BIT3_IS_ADDR;
- fallthrough;
- case 8:
- chip->flags |= EE_ADDR1;
- break;
- case 16:
- chip->flags |= EE_ADDR2;
- break;
- case 24:
- chip->flags |= EE_ADDR3;
- break;
- default:
- dev_err(dev,
- "Error: bad \"address-width\" property: %u\n",
- val);
- return -ENODEV;
- }
- if (device_property_present(dev, "read-only"))
- chip->flags |= EE_READONLY;
- }
- return 0;
-}
-
-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_MAX_ID_LEN];
- u32 val;
- int i;
-
- strscpy(chip->name, "fm25", sizeof(chip->name));
-
- 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_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++) {
- u8 tmp = id[i];
- int j = ARRAY_SIZE(id) - i - 1;
-
- id[i] = id[j];
- id[j] = tmp;
- }
-
- if (id[6] == 0xc2) {
- at25->id_len = 9;
- switch (id[7]) {
- case 0x21 ... 0x26:
- chip->byte_len = BIT(id[7] - 0x21 + 4) * 1024;
- break;
- case 0x2a ... 0x30:
- /* CY15B102QN ... 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;
- }
- } else if (id[2] == 0x82 && id[3] == 0x06) {
- at25->id_len = 8;
- switch (id[1]) {
- case 0x51 ... 0x54:
- /* CY15B102QSN ... CY15B204QSN */
- chip->byte_len = BIT(((id[0] >> 3) & 0x1F) + 9);
- break;
- default:
- dev_err(dev, "Error: unsupported product id %02x\n", id[1]);
- return -ENODEV;
- }
- } else {
- dev_err(dev, "Error: unrecognized JEDEC ID format: %*ph\n",
- FM25_MAX_ID_LEN, id);
- return -ENODEV;
- }
-
- 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)
- chip->flags |= EE_ADDR3;
- else
- chip->flags |= EE_ADDR2;
-
- chip->page_size = PAGE_SIZE;
- return 0;
-}
-
-static const struct of_device_id at25_of_match[] = {
- { .compatible = "atmel,at25" },
- { .compatible = "cypress,fm25" },
- { }
-};
-MODULE_DEVICE_TABLE(of, at25_of_match);
-
-static const struct spi_device_id at25_spi_ids[] = {
- { .name = "at25" },
- { .name = "fm25" },
- { }
-};
-MODULE_DEVICE_TABLE(spi, at25_spi_ids);
-
-static int at25_probe(struct spi_mem *mem)
-{
- struct spi_device *spi = mem->spi;
- struct spi_eeprom *pdata;
- struct at25_data *at25;
- bool is_fram;
- int err;
-
- at25 = devm_kzalloc(&spi->dev, sizeof(*at25), GFP_KERNEL);
- if (!at25)
- return -ENOMEM;
-
- at25->spimem = mem;
-
- /*
- * Ping the chip ... the status register is pretty portable,
- * unlike probing manufacturer IDs.
- */
- err = at25_wait_ready(at25);
- if (err < 0)
- return dev_err_probe(&spi->dev, err, "Read Status Register command failed\n");
- if (err) {
- dev_err(&spi->dev, "Not ready (%02x)\n", err);
- return -ENXIO;
- }
-
- mutex_init(&at25->lock);
- spi_set_drvdata(spi, at25);
-
- is_fram = fwnode_device_is_compatible(dev_fwnode(&spi->dev), "cypress,fm25");
-
- /* Chip description */
- pdata = dev_get_platdata(&spi->dev);
- if (pdata) {
- at25->chip = *pdata;
- } else {
- if (is_fram)
- err = at25_fram_to_chip(&spi->dev, &at25->chip);
- else
- err = at25_fw_to_chip(&spi->dev, &at25->chip);
- if (err)
- return err;
- }
-
- /* 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 = at25->chip.flags & EE_READONLY;
- at25->nvmem_config.root_only = true;
- at25->nvmem_config.owner = THIS_MODULE;
- at25->nvmem_config.compat = true;
- at25->nvmem_config.base_dev = &spi->dev;
- at25->nvmem_config.reg_read = at25_ee_read;
- at25->nvmem_config.reg_write = at25_ee_write;
- at25->nvmem_config.priv = at25;
- at25->nvmem_config.stride = 1;
- at25->nvmem_config.word_size = 1;
- at25->nvmem_config.size = at25->chip.byte_len;
-
- at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
- if (IS_ERR(at25->nvmem))
- return PTR_ERR(at25->nvmem);
-
- dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
- (at25->chip.byte_len < 1024) ?
- at25->chip.byte_len : (at25->chip.byte_len / 1024),
- (at25->chip.byte_len < 1024) ? "Byte" : "KByte",
- at25->chip.name, is_fram ? "fram" : "eeprom",
- (at25->chip.flags & EE_READONLY) ? " (readonly)" : "",
- at25->chip.page_size);
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static struct spi_mem_driver at25_driver = {
- .spidrv = {
- .driver = {
- .name = "at25",
- .of_match_table = at25_of_match,
- .dev_groups = at25_groups,
- },
- .id_table = at25_spi_ids,
- },
- .probe = at25_probe,
-};
-
-module_spi_mem_driver(at25_driver);
-
-MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
-MODULE_AUTHOR("David Brownell");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
deleted file mode 100644
index 923f404a44c0..000000000000
--- a/drivers/misc/eeprom/ee1004.c
+++ /dev/null
@@ -1,351 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * ee1004 - driver for DDR4 SPD EEPROMs
- *
- * Copyright (C) 2017-2019 Jean Delvare
- *
- * Based on the at24 driver:
- * Copyright (C) 2005-2007 David Brownell
- * Copyright (C) 2008 Wolfram Sang, Pengutronix
- */
-
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/nvmem-provider.h>
-
-/*
- * DDR4 memory modules use special EEPROMs following the Jedec EE1004
- * specification. These are 512-byte EEPROMs using a single I2C address
- * in the 0x50-0x57 range for data. One of two 256-byte page is selected
- * by writing a command to I2C address 0x36 or 0x37 on the same I2C bus.
- *
- * Therefore we need to request these 2 additional addresses, and serialize
- * access to all such EEPROMs with a single mutex.
- *
- * We assume it is safe to read up to 32 bytes at once from these EEPROMs.
- * We use SMBus access even if I2C is available, these EEPROMs are small
- * enough, and reading from them infrequent enough, that we favor simplicity
- * over performance.
- */
-
-#define EE1004_MAX_BUSSES 8
-#define EE1004_ADDR_SET_PAGE 0x36
-#define EE1004_NUM_PAGES 2
-#define EE1004_PAGE_SIZE 256
-#define EE1004_PAGE_SHIFT 8
-#define EE1004_EEPROM_SIZE (EE1004_PAGE_SIZE * EE1004_NUM_PAGES)
-
-/*
- * Mutex protects ee1004_set_page and ee1004_dev_count, and must be held
- * from page selection to end of read.
- */
-static DEFINE_MUTEX(ee1004_bus_lock);
-
-static struct ee1004_bus_data {
- struct i2c_adapter *adap;
- struct i2c_client *set_page[EE1004_NUM_PAGES];
- unsigned int dev_count;
- int current_page;
-} ee1004_bus_data[EE1004_MAX_BUSSES];
-
-static const struct i2c_device_id ee1004_ids[] = {
- { "ee1004" },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ee1004_ids);
-
-/*-------------------------------------------------------------------------*/
-
-static struct ee1004_bus_data *ee1004_get_bus_data(struct i2c_adapter *adap)
-{
- int i;
-
- for (i = 0; i < EE1004_MAX_BUSSES; i++)
- if (ee1004_bus_data[i].adap == adap)
- return ee1004_bus_data + i;
-
- /* If not existent yet, create new entry */
- for (i = 0; i < EE1004_MAX_BUSSES; i++)
- if (!ee1004_bus_data[i].adap) {
- ee1004_bus_data[i].adap = adap;
- return ee1004_bus_data + i;
- }
-
- return NULL;
-}
-
-static int ee1004_get_current_page(struct ee1004_bus_data *bd)
-{
- int err;
-
- err = i2c_smbus_read_byte(bd->set_page[0]);
- if (err == -ENXIO) {
- /* Nack means page 1 is selected */
- return 1;
- }
- if (err < 0) {
- /* Anything else is a real error, bail out */
- return err;
- }
-
- /* Ack means page 0 is selected, returned value meaningless */
- return 0;
-}
-
-static int ee1004_set_current_page(struct i2c_client *client, int page)
-{
- struct ee1004_bus_data *bd = i2c_get_clientdata(client);
- int ret;
-
- if (page == bd->current_page)
- return 0;
-
- /* Data is ignored */
- ret = i2c_smbus_write_byte(bd->set_page[page], 0x00);
- /*
- * Don't give up just yet. Some memory modules will select the page
- * but not ack the command. Check which page is selected now.
- */
- if (ret == -ENXIO && ee1004_get_current_page(bd) == page)
- ret = 0;
- if (ret < 0) {
- dev_err(&client->dev, "Failed to select page %d (%d)\n", page, ret);
- return ret;
- }
-
- dev_dbg(&client->dev, "Selected page %d\n", page);
- bd->current_page = page;
-
- return 0;
-}
-
-static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
- unsigned int offset, size_t count)
-{
- int status, page;
-
- page = offset >> EE1004_PAGE_SHIFT;
- offset &= (1 << EE1004_PAGE_SHIFT) - 1;
-
- status = ee1004_set_current_page(client, page);
- if (status)
- return status;
-
- /* Can't cross page boundaries */
- if (offset + count > EE1004_PAGE_SIZE)
- count = EE1004_PAGE_SIZE - offset;
-
- if (count > I2C_SMBUS_BLOCK_MAX)
- count = I2C_SMBUS_BLOCK_MAX;
-
- return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf);
-}
-
-static int ee1004_read(void *priv, unsigned int off, void *val, size_t count)
-{
- struct i2c_client *client = priv;
- char *buf = val;
- int ret;
-
- if (unlikely(!count))
- return count;
-
- if (off + count > EE1004_EEPROM_SIZE)
- return -EINVAL;
-
- /*
- * Read data from chip, protecting against concurrent access to
- * other EE1004 SPD EEPROMs on the same adapter.
- */
- mutex_lock(&ee1004_bus_lock);
-
- while (count) {
- ret = ee1004_eeprom_read(client, buf, off, count);
- if (ret < 0) {
- mutex_unlock(&ee1004_bus_lock);
- return ret;
- }
-
- buf += ret;
- off += ret;
- count -= ret;
- }
-
- mutex_unlock(&ee1004_bus_lock);
-
- return 0;
-}
-
-static void ee1004_probe_temp_sensor(struct i2c_client *client)
-{
- struct i2c_board_info info = { .type = "jc42" };
- unsigned short addr = 0x18 | (client->addr & 7);
- unsigned short addr_list[] = { addr, I2C_CLIENT_END };
- u8 data[2];
- int ret;
-
- /* byte 14, bit 7 is set if temp sensor is present */
- ret = ee1004_eeprom_read(client, data, 14, 1);
- if (ret != 1)
- return;
-
- if (!(data[0] & BIT(7))) {
- /*
- * If the SPD data suggests that there is no temperature
- * sensor, it may still be there for SPD revision 1.0.
- * See SPD Annex L, Revision 1 and 2, for details.
- * Check DIMM type and SPD revision; if it is a DDR4
- * with SPD revision 1.0, check the thermal sensor address
- * and instantiate the jc42 driver if a chip is found at
- * that address.
- * It is not necessary to check if there is a chip at the
- * temperature sensor address since i2c_new_scanned_device()
- * will do that and return silently if no chip is found.
- */
- ret = ee1004_eeprom_read(client, data, 1, 2);
- if (ret != 2 || data[0] != 0x10 || data[1] != 0x0c)
- return;
- }
- i2c_new_scanned_device(client->adapter, &info, addr_list, NULL);
-}
-
-static void ee1004_cleanup(int idx, struct ee1004_bus_data *bd)
-{
- if (--bd->dev_count == 0) {
- while (--idx >= 0)
- i2c_unregister_device(bd->set_page[idx]);
- memset(bd, 0, sizeof(struct ee1004_bus_data));
- }
-}
-
-static void ee1004_cleanup_bus_data(void *data)
-{
- struct ee1004_bus_data *bd = data;
-
- /* Remove page select clients if this is the last device */
- mutex_lock(&ee1004_bus_lock);
- ee1004_cleanup(EE1004_NUM_PAGES, bd);
- mutex_unlock(&ee1004_bus_lock);
-}
-
-static int ee1004_init_bus_data(struct i2c_client *client)
-{
- struct ee1004_bus_data *bd;
- int err, cnr = 0;
-
- bd = ee1004_get_bus_data(client->adapter);
- if (!bd)
- return dev_err_probe(&client->dev, -ENOSPC, "Only %d busses supported",
- EE1004_MAX_BUSSES);
-
- i2c_set_clientdata(client, bd);
-
- if (++bd->dev_count == 1) {
- /* Use 2 dummy devices for page select command */
- for (cnr = 0; cnr < EE1004_NUM_PAGES; cnr++) {
- struct i2c_client *cl;
-
- cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr);
- if (IS_ERR(cl)) {
- err = PTR_ERR(cl);
- goto err_out;
- }
-
- bd->set_page[cnr] = cl;
- }
-
- /* Remember current page to avoid unneeded page select */
- err = ee1004_get_current_page(bd);
- if (err < 0)
- goto err_out;
-
- dev_dbg(&client->dev, "Currently selected page: %d\n", err);
- bd->current_page = err;
- }
-
- return 0;
-
-err_out:
- ee1004_cleanup(cnr, bd);
-
- return err;
-}
-
-static int ee1004_probe(struct i2c_client *client)
-{
- struct nvmem_config config = {
- .dev = &client->dev,
- .name = dev_name(&client->dev),
- .id = NVMEM_DEVID_NONE,
- .owner = THIS_MODULE,
- .type = NVMEM_TYPE_EEPROM,
- .read_only = true,
- .root_only = false,
- .reg_read = ee1004_read,
- .size = EE1004_EEPROM_SIZE,
- .word_size = 1,
- .stride = 1,
- .priv = client,
- .compat = true,
- .base_dev = &client->dev,
- };
- struct nvmem_device *ndev;
- int err;
-
- /* Make sure we can operate on this adapter */
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_I2C_BLOCK) &&
- !i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA))
- return -EPFNOSUPPORT;
-
- err = i2c_smbus_read_byte(client);
- if (err < 0)
- return -ENODEV;
-
- mutex_lock(&ee1004_bus_lock);
-
- err = ee1004_init_bus_data(client);
- if (err < 0) {
- mutex_unlock(&ee1004_bus_lock);
- return err;
- }
-
- ee1004_probe_temp_sensor(client);
-
- mutex_unlock(&ee1004_bus_lock);
-
- err = devm_add_action_or_reset(&client->dev, ee1004_cleanup_bus_data,
- i2c_get_clientdata(client));
- if (err < 0)
- return err;
-
- ndev = devm_nvmem_register(&client->dev, &config);
- if (IS_ERR(ndev))
- return PTR_ERR(ndev);
-
- dev_info(&client->dev,
- "%u byte EE1004-compliant SPD EEPROM, read-only\n",
- EE1004_EEPROM_SIZE);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static struct i2c_driver ee1004_driver = {
- .driver = {
- .name = "ee1004",
- },
- .probe = ee1004_probe,
- .id_table = ee1004_ids,
-};
-module_i2c_driver(ee1004_driver);
-
-MODULE_DESCRIPTION("Driver for EE1004-compliant DDR4 SPD EEPROMs");
-MODULE_AUTHOR("Jean Delvare");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
deleted file mode 100644
index f9c3ab52c2f9..000000000000
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ /dev/null
@@ -1,560 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for 93xx46 EEPROMs
- *
- * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
- */
-
-#include <linux/array_size.h>
-#include <linux/bits.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/kstrtox.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/property.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
-#include <linux/string_choices.h>
-
-#include <linux/nvmem-provider.h>
-
-struct eeprom_93xx46_platform_data {
- unsigned char flags;
-#define EE_ADDR8 0x01 /* 8 bit addr. cfg */
-#define EE_ADDR16 0x02 /* 16 bit addr. cfg */
-#define EE_READONLY 0x08 /* forbid writing */
-#define EE_SIZE1K 0x10 /* 1 kb of data, that is a 93xx46 */
-#define EE_SIZE2K 0x20 /* 2 kb of data, that is a 93xx56 */
-#define EE_SIZE4K 0x40 /* 4 kb of data, that is a 93xx66 */
-
- unsigned int quirks;
-/* Single word read transfers only; no sequential read. */
-#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0)
-/* Instructions such as EWEN are (addrlen + 2) in length. */
-#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH (1 << 1)
-/* Add extra cycle after address during a read */
-#define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE BIT(2)
-
- struct gpio_desc *select;
-};
-
-#define OP_START 0x4
-#define OP_WRITE (OP_START | 0x1)
-#define OP_READ (OP_START | 0x2)
-/* The following addresses are offset for the 1K EEPROM variant in 16-bit mode */
-#define ADDR_EWDS 0x00
-#define ADDR_ERAL 0x20
-#define ADDR_EWEN 0x30
-
-struct eeprom_93xx46_devtype_data {
- unsigned int quirks;
- unsigned char flags;
-};
-
-static const struct eeprom_93xx46_devtype_data at93c46_data = {
- .flags = EE_SIZE1K,
-};
-
-static const struct eeprom_93xx46_devtype_data at93c56_data = {
- .flags = EE_SIZE2K,
-};
-
-static const struct eeprom_93xx46_devtype_data at93c66_data = {
- .flags = EE_SIZE4K,
-};
-
-static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
- .flags = EE_SIZE1K,
- .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ |
- EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
-};
-
-static const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = {
- .flags = EE_SIZE1K,
- .quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE,
-};
-
-struct eeprom_93xx46_dev {
- struct spi_device *spi;
- struct eeprom_93xx46_platform_data *pdata;
- struct mutex lock;
- struct nvmem_config nvmem_config;
- struct nvmem_device *nvmem;
- int addrlen;
- int size;
-};
-
-static inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev)
-{
- return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ;
-}
-
-static inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev)
-{
- return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
-}
-
-static inline bool has_quirk_extra_read_cycle(struct eeprom_93xx46_dev *edev)
-{
- return edev->pdata->quirks & EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE;
-}
-
-static int eeprom_93xx46_read(void *priv, unsigned int off,
- void *val, size_t count)
-{
- struct eeprom_93xx46_dev *edev = priv;
- char *buf = val;
- int err = 0;
- int bits;
-
- if (unlikely(off >= edev->size))
- return 0;
- if ((off + count) > edev->size)
- count = edev->size - off;
- if (unlikely(!count))
- return count;
-
- mutex_lock(&edev->lock);
-
- gpiod_set_value_cansleep(edev->pdata->select, 1);
-
- /* The opcode in front of the address is three bits. */
- bits = edev->addrlen + 3;
-
- while (count) {
- struct spi_message m;
- struct spi_transfer t[2] = {};
- u16 cmd_addr = OP_READ << edev->addrlen;
- size_t nbytes = count;
-
- if (edev->pdata->flags & EE_ADDR8) {
- cmd_addr |= off;
- if (has_quirk_single_word_read(edev))
- nbytes = 1;
- } else {
- cmd_addr |= (off >> 1);
- if (has_quirk_single_word_read(edev))
- nbytes = 2;
- }
-
- dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
- cmd_addr, edev->spi->max_speed_hz);
-
- if (has_quirk_extra_read_cycle(edev)) {
- cmd_addr <<= 1;
- bits += 1;
- }
-
- t[0].tx_buf = (char *)&cmd_addr;
- t[0].len = 2;
- t[0].bits_per_word = bits;
-
- t[1].rx_buf = buf;
- t[1].len = count;
- t[1].bits_per_word = 8;
-
- spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t));
-
- err = spi_sync(edev->spi, &m);
- /* have to wait at least Tcsl ns */
- ndelay(250);
-
- if (err) {
- dev_err(&edev->spi->dev, "read %zu bytes at %u: err. %d\n",
- nbytes, off, err);
- break;
- }
-
- buf += nbytes;
- off += nbytes;
- count -= nbytes;
- }
-
- gpiod_set_value_cansleep(edev->pdata->select, 0);
-
- mutex_unlock(&edev->lock);
-
- return err;
-}
-
-static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
-{
- struct spi_message m;
- struct spi_transfer t = {};
- int bits, ret;
- u16 cmd_addr;
-
- /* The opcode in front of the address is three bits. */
- bits = edev->addrlen + 3;
-
- cmd_addr = OP_START << edev->addrlen;
- cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << (edev->addrlen - 6);
-
- if (has_quirk_instruction_length(edev)) {
- cmd_addr <<= 2;
- bits += 2;
- }
-
- 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;
-
- spi_message_init_with_transfers(&m, &t, 1);
-
- mutex_lock(&edev->lock);
-
- gpiod_set_value_cansleep(edev->pdata->select, 1);
-
- ret = spi_sync(edev->spi, &m);
- /* have to wait at least Tcsl ns */
- ndelay(250);
- if (ret)
- dev_err(&edev->spi->dev, "erase/write %s error %d\n",
- str_enable_disable(is_on), ret);
-
- gpiod_set_value_cansleep(edev->pdata->select, 0);
-
- mutex_unlock(&edev->lock);
- return ret;
-}
-
-static ssize_t
-eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
- const char *buf, unsigned int off)
-{
- struct spi_message m;
- struct spi_transfer t[2] = {};
- int bits, data_len, ret;
- u16 cmd_addr;
-
- if (unlikely(off >= edev->size))
- return -EINVAL;
-
- /* The opcode in front of the address is three bits. */
- bits = edev->addrlen + 3;
-
- cmd_addr = OP_WRITE << edev->addrlen;
-
- if (edev->pdata->flags & EE_ADDR8) {
- cmd_addr |= off;
- data_len = 1;
- } else {
- cmd_addr |= (off >> 1);
- data_len = 2;
- }
-
- 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;
-
- t[1].tx_buf = buf;
- t[1].len = data_len;
- t[1].bits_per_word = 8;
-
- spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t));
-
- ret = spi_sync(edev->spi, &m);
- /* have to wait program cycle time Twc ms */
- mdelay(6);
- return ret;
-}
-
-static int eeprom_93xx46_write(void *priv, unsigned int off,
- void *val, size_t count)
-{
- struct eeprom_93xx46_dev *edev = priv;
- char *buf = val;
- int ret, step = 1;
- unsigned int i;
-
- if (unlikely(off >= edev->size))
- return -EFBIG;
- if ((off + count) > edev->size)
- count = edev->size - off;
- if (unlikely(!count))
- return count;
-
- /* only write even number of bytes on 16-bit devices */
- if (edev->pdata->flags & EE_ADDR16) {
- step = 2;
- count &= ~1;
- }
-
- /* erase/write enable */
- ret = eeprom_93xx46_ew(edev, 1);
- if (ret)
- return ret;
-
- mutex_lock(&edev->lock);
-
- gpiod_set_value_cansleep(edev->pdata->select, 1);
-
- for (i = 0; i < count; i += step) {
- ret = eeprom_93xx46_write_word(edev, &buf[i], off + i);
- if (ret) {
- dev_err(&edev->spi->dev, "write failed at %u: %d\n", off + i, ret);
- break;
- }
- }
-
- gpiod_set_value_cansleep(edev->pdata->select, 0);
-
- mutex_unlock(&edev->lock);
-
- /* erase/write disable */
- eeprom_93xx46_ew(edev, 0);
- return ret;
-}
-
-static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
-{
- struct spi_message m;
- struct spi_transfer t = {};
- int bits, ret;
- u16 cmd_addr;
-
- /* The opcode in front of the address is three bits. */
- bits = edev->addrlen + 3;
-
- cmd_addr = OP_START << edev->addrlen;
- cmd_addr |= ADDR_ERAL << (edev->addrlen - 6);
-
- if (has_quirk_instruction_length(edev)) {
- cmd_addr <<= 2;
- bits += 2;
- }
-
- 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;
-
- spi_message_init_with_transfers(&m, &t, 1);
-
- mutex_lock(&edev->lock);
-
- gpiod_set_value_cansleep(edev->pdata->select, 1);
-
- ret = spi_sync(edev->spi, &m);
- if (ret)
- dev_err(&edev->spi->dev, "erase error %d\n", ret);
- /* have to wait erase cycle time Tec ms */
- mdelay(6);
-
- gpiod_set_value_cansleep(edev->pdata->select, 0);
-
- mutex_unlock(&edev->lock);
- return ret;
-}
-
-static ssize_t erase_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev);
- bool erase;
- int ret;
-
- ret = kstrtobool(buf, &erase);
- if (ret)
- return ret;
-
- if (erase) {
- ret = eeprom_93xx46_ew(edev, 1);
- if (ret)
- return ret;
- ret = eeprom_93xx46_eral(edev);
- if (ret)
- return ret;
- ret = eeprom_93xx46_ew(edev, 0);
- if (ret)
- return ret;
- }
- return count;
-}
-static DEVICE_ATTR_WO(erase);
-
-static const struct of_device_id eeprom_93xx46_of_table[] = {
- { .compatible = "eeprom-93xx46", .data = &at93c46_data, },
- { .compatible = "atmel,at93c46", .data = &at93c46_data, },
- { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
- { .compatible = "atmel,at93c56", .data = &at93c56_data, },
- { .compatible = "atmel,at93c66", .data = &at93c66_data, },
- { .compatible = "microchip,93lc46b", .data = &microchip_93lc46b_data, },
- {}
-};
-MODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table);
-
-static const struct spi_device_id eeprom_93xx46_spi_ids[] = {
- { .name = "eeprom-93xx46",
- .driver_data = (kernel_ulong_t)&at93c46_data, },
- { .name = "at93c46",
- .driver_data = (kernel_ulong_t)&at93c46_data, },
- { .name = "at93c46d",
- .driver_data = (kernel_ulong_t)&atmel_at93c46d_data, },
- { .name = "at93c56",
- .driver_data = (kernel_ulong_t)&at93c56_data, },
- { .name = "at93c66",
- .driver_data = (kernel_ulong_t)&at93c66_data, },
- { .name = "93lc46b",
- .driver_data = (kernel_ulong_t)&microchip_93lc46b_data, },
- {}
-};
-MODULE_DEVICE_TABLE(spi, eeprom_93xx46_spi_ids);
-
-static int eeprom_93xx46_probe_fw(struct device *dev)
-{
- const struct eeprom_93xx46_devtype_data *data;
- struct eeprom_93xx46_platform_data *pd;
- u32 tmp;
- int ret;
-
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
-
- ret = device_property_read_u32(dev, "data-size", &tmp);
- if (ret < 0) {
- dev_err(dev, "data-size property not found\n");
- return ret;
- }
-
- if (tmp == 8) {
- pd->flags |= EE_ADDR8;
- } else if (tmp == 16) {
- pd->flags |= EE_ADDR16;
- } else {
- dev_err(dev, "invalid data-size (%d)\n", tmp);
- return -EINVAL;
- }
-
- if (device_property_read_bool(dev, "read-only"))
- pd->flags |= EE_READONLY;
-
- pd->select = devm_gpiod_get_optional(dev, "select", GPIOD_OUT_LOW);
- if (IS_ERR(pd->select))
- return PTR_ERR(pd->select);
- gpiod_set_consumer_name(pd->select, "93xx46 EEPROMs OE");
-
- data = spi_get_device_match_data(to_spi_device(dev));
- if (data) {
- pd->quirks = data->quirks;
- pd->flags |= data->flags;
- }
-
- dev->platform_data = pd;
-
- return 0;
-}
-
-static int eeprom_93xx46_probe(struct spi_device *spi)
-{
- struct eeprom_93xx46_platform_data *pd;
- struct eeprom_93xx46_dev *edev;
- struct device *dev = &spi->dev;
- int err;
-
- err = eeprom_93xx46_probe_fw(dev);
- if (err < 0)
- return err;
-
- pd = spi->dev.platform_data;
- if (!pd) {
- dev_err(&spi->dev, "missing platform data\n");
- return -ENODEV;
- }
-
- edev = devm_kzalloc(&spi->dev, sizeof(*edev), GFP_KERNEL);
- if (!edev)
- return -ENOMEM;
-
- if (pd->flags & EE_SIZE1K)
- edev->size = 128;
- else if (pd->flags & EE_SIZE2K)
- edev->size = 256;
- else if (pd->flags & EE_SIZE4K)
- edev->size = 512;
- else {
- dev_err(&spi->dev, "unspecified size\n");
- return -EINVAL;
- }
-
- if (pd->flags & EE_ADDR8)
- edev->addrlen = ilog2(edev->size);
- else if (pd->flags & EE_ADDR16)
- edev->addrlen = ilog2(edev->size) - 1;
- else {
- dev_err(&spi->dev, "unspecified address type\n");
- return -EINVAL;
- }
-
- mutex_init(&edev->lock);
-
- edev->spi = spi;
- edev->pdata = pd;
-
- edev->nvmem_config.type = NVMEM_TYPE_EEPROM;
- edev->nvmem_config.name = dev_name(&spi->dev);
- edev->nvmem_config.dev = &spi->dev;
- edev->nvmem_config.read_only = pd->flags & EE_READONLY;
- edev->nvmem_config.root_only = true;
- edev->nvmem_config.owner = THIS_MODULE;
- edev->nvmem_config.compat = true;
- edev->nvmem_config.base_dev = &spi->dev;
- edev->nvmem_config.reg_read = eeprom_93xx46_read;
- edev->nvmem_config.reg_write = eeprom_93xx46_write;
- edev->nvmem_config.priv = edev;
- edev->nvmem_config.stride = 4;
- edev->nvmem_config.word_size = 1;
- edev->nvmem_config.size = edev->size;
-
- edev->nvmem = devm_nvmem_register(&spi->dev, &edev->nvmem_config);
- if (IS_ERR(edev->nvmem))
- return PTR_ERR(edev->nvmem);
-
- dev_info(&spi->dev, "%d-bit eeprom containing %d bytes %s\n",
- (pd->flags & EE_ADDR8) ? 8 : 16,
- edev->size,
- (pd->flags & EE_READONLY) ? "(readonly)" : "");
-
- if (!(pd->flags & EE_READONLY)) {
- if (device_create_file(&spi->dev, &dev_attr_erase))
- dev_err(&spi->dev, "can't create erase interface\n");
- }
-
- spi_set_drvdata(spi, edev);
- return 0;
-}
-
-static void eeprom_93xx46_remove(struct spi_device *spi)
-{
- struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
-
- if (!(edev->pdata->flags & EE_READONLY))
- device_remove_file(&spi->dev, &dev_attr_erase);
-}
-
-static struct spi_driver eeprom_93xx46_driver = {
- .driver = {
- .name = "93xx46",
- .of_match_table = eeprom_93xx46_of_table,
- },
- .probe = eeprom_93xx46_probe,
- .remove = eeprom_93xx46_remove,
- .id_table = eeprom_93xx46_spi_ids,
-};
-
-module_spi_driver(eeprom_93xx46_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
-MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
-MODULE_ALIAS("spi:93xx46");
diff --git a/drivers/misc/eeprom/m24lr.c b/drivers/misc/eeprom/m24lr.c
deleted file mode 100644
index 7a9fd45a8e46..000000000000
--- a/drivers/misc/eeprom/m24lr.c
+++ /dev/null
@@ -1,606 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * m24lr.c - Sysfs control interface for ST M24LR series RFID/NFC chips
- *
- * Copyright (c) 2025 Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
- *
- * This driver implements both the sysfs-based control interface and EEPROM
- * access for STMicroelectronics M24LR series chips (e.g., M24LR04E-R).
- * It provides access to control registers for features such as password
- * authentication, memory protection, and device configuration. In addition,
- * it manages read and write operations to the EEPROM region of the chip.
- */
-
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/nvmem-provider.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-
-#define M24LR_WRITE_TIMEOUT 25u
-#define M24LR_READ_TIMEOUT (M24LR_WRITE_TIMEOUT)
-
-/**
- * struct m24lr_chip - describes chip-specific sysfs layout
- * @sss_len: the length of the sss region
- * @page_size: chip-specific limit on the maximum number of bytes allowed
- * in a single write operation.
- * @eeprom_size: size of the EEPROM in byte
- *
- * Supports multiple M24LR chip variants (e.g., M24LRxx) by allowing each
- * to define its own set of sysfs attributes, depending on its available
- * registers and features.
- */
-struct m24lr_chip {
- unsigned int sss_len;
- unsigned int page_size;
- unsigned int eeprom_size;
-};
-
-/**
- * struct m24lr - core driver data for M24LR chip control
- * @uid: 64 bits unique identifier stored in the device
- * @sss_len: the length of the sss region
- * @page_size: chip-specific limit on the maximum number of bytes allowed
- * in a single write operation.
- * @eeprom_size: size of the EEPROM in byte
- * @ctl_regmap: regmap interface for accessing the system parameter sector
- * @eeprom_regmap: regmap interface for accessing the EEPROM
- * @lock: mutex to synchronize operations to the device
- *
- * Central data structure holding the state and resources used by the
- * M24LR device driver.
- */
-struct m24lr {
- u64 uid;
- unsigned int sss_len;
- unsigned int page_size;
- unsigned int eeprom_size;
- struct regmap *ctl_regmap;
- struct regmap *eeprom_regmap;
- struct mutex lock; /* synchronize operations to the device */
-};
-
-static const struct regmap_range m24lr_ctl_vo_ranges[] = {
- regmap_reg_range(0, 63),
-};
-
-static const struct regmap_access_table m24lr_ctl_vo_table = {
- .yes_ranges = m24lr_ctl_vo_ranges,
- .n_yes_ranges = ARRAY_SIZE(m24lr_ctl_vo_ranges),
-};
-
-static const struct regmap_config m24lr_ctl_regmap_conf = {
- .name = "m24lr_ctl",
- .reg_stride = 1,
- .reg_bits = 16,
- .val_bits = 8,
- .disable_locking = false,
- .cache_type = REGCACHE_RBTREE,/* Flat can't be used, there's huge gap */
- .volatile_table = &m24lr_ctl_vo_table,
-};
-
-/* Chip descriptor for M24LR04E-R variant */
-static const struct m24lr_chip m24lr04e_r_chip = {
- .page_size = 4,
- .eeprom_size = 512,
- .sss_len = 4,
-};
-
-/* Chip descriptor for M24LR16E-R variant */
-static const struct m24lr_chip m24lr16e_r_chip = {
- .page_size = 4,
- .eeprom_size = 2048,
- .sss_len = 16,
-};
-
-/* Chip descriptor for M24LR64E-R variant */
-static const struct m24lr_chip m24lr64e_r_chip = {
- .page_size = 4,
- .eeprom_size = 8192,
- .sss_len = 64,
-};
-
-static const struct i2c_device_id m24lr_ids[] = {
- { "m24lr04e-r", (kernel_ulong_t)&m24lr04e_r_chip},
- { "m24lr16e-r", (kernel_ulong_t)&m24lr16e_r_chip},
- { "m24lr64e-r", (kernel_ulong_t)&m24lr64e_r_chip},
- { }
-};
-MODULE_DEVICE_TABLE(i2c, m24lr_ids);
-
-static const struct of_device_id m24lr_of_match[] = {
- { .compatible = "st,m24lr04e-r", .data = &m24lr04e_r_chip},
- { .compatible = "st,m24lr16e-r", .data = &m24lr16e_r_chip},
- { .compatible = "st,m24lr64e-r", .data = &m24lr64e_r_chip},
- { }
-};
-MODULE_DEVICE_TABLE(of, m24lr_of_match);
-
-/**
- * m24lr_regmap_read - read data using regmap with retry on failure
- * @regmap: regmap instance for the device
- * @buf: buffer to store the read data
- * @size: number of bytes to read
- * @offset: starting register address
- *
- * Attempts to read a block of data from the device with retries and timeout.
- * Some M24LR chips may transiently NACK reads (e.g., during internal write
- * cycles), so this function retries with a short sleep until the timeout
- * expires.
- *
- * Returns:
- * Number of bytes read on success,
- * -ETIMEDOUT if the read fails within the timeout window.
- */
-static ssize_t m24lr_regmap_read(struct regmap *regmap, u8 *buf,
- size_t size, unsigned int offset)
-{
- int err;
- unsigned long timeout, read_time;
- ssize_t ret = -ETIMEDOUT;
-
- timeout = jiffies + msecs_to_jiffies(M24LR_READ_TIMEOUT);
- do {
- read_time = jiffies;
-
- err = regmap_bulk_read(regmap, offset, buf, size);
- if (!err) {
- ret = size;
- break;
- }
-
- usleep_range(1000, 2000);
- } while (time_before(read_time, timeout));
-
- return ret;
-}
-
-/**
- * m24lr_regmap_write - write data using regmap with retry on failure
- * @regmap: regmap instance for the device
- * @buf: buffer containing the data to write
- * @size: number of bytes to write
- * @offset: starting register address
- *
- * Attempts to write a block of data to the device with retries and a timeout.
- * Some M24LR devices may NACK I2C writes while an internal write operation
- * is in progress. This function retries the write operation with a short delay
- * until it succeeds or the timeout is reached.
- *
- * Returns:
- * Number of bytes written on success,
- * -ETIMEDOUT if the write fails within the timeout window.
- */
-static ssize_t m24lr_regmap_write(struct regmap *regmap, const u8 *buf,
- size_t size, unsigned int offset)
-{
- int err;
- unsigned long timeout, write_time;
- ssize_t ret = -ETIMEDOUT;
-
- timeout = jiffies + msecs_to_jiffies(M24LR_WRITE_TIMEOUT);
-
- do {
- write_time = jiffies;
-
- err = regmap_bulk_write(regmap, offset, buf, size);
- if (!err) {
- ret = size;
- break;
- }
-
- usleep_range(1000, 2000);
- } while (time_before(write_time, timeout));
-
- return ret;
-}
-
-static ssize_t m24lr_read(struct m24lr *m24lr, u8 *buf, size_t size,
- unsigned int offset, bool is_eeprom)
-{
- struct regmap *regmap;
- ssize_t ret;
-
- if (is_eeprom)
- regmap = m24lr->eeprom_regmap;
- else
- regmap = m24lr->ctl_regmap;
-
- mutex_lock(&m24lr->lock);
- ret = m24lr_regmap_read(regmap, buf, size, offset);
- mutex_unlock(&m24lr->lock);
-
- return ret;
-}
-
-/**
- * m24lr_write - write buffer to M24LR device with page alignment handling
- * @m24lr: pointer to driver context
- * @buf: data buffer to write
- * @size: number of bytes to write
- * @offset: target register address in the device
- * @is_eeprom: true if the write should target the EEPROM,
- * false if it should target the system parameters sector.
- *
- * Writes data to the M24LR device using regmap, split into chunks no larger
- * than page_size to respect device-specific write limitations (e.g., page
- * size or I2C hold-time concerns). Each chunk is aligned to the page boundary
- * defined by page_size.
- *
- * Returns:
- * Total number of bytes written on success,
- * A negative error code if any write fails.
- */
-static ssize_t m24lr_write(struct m24lr *m24lr, const u8 *buf, size_t size,
- unsigned int offset, bool is_eeprom)
-{
- unsigned int n, next_sector;
- struct regmap *regmap;
- ssize_t ret = 0;
- ssize_t err;
-
- if (is_eeprom)
- regmap = m24lr->eeprom_regmap;
- else
- regmap = m24lr->ctl_regmap;
-
- n = min_t(unsigned int, size, m24lr->page_size);
- next_sector = roundup(offset + 1, m24lr->page_size);
- if (offset + n > next_sector)
- n = next_sector - offset;
-
- mutex_lock(&m24lr->lock);
- while (n) {
- err = m24lr_regmap_write(regmap, buf + offset, n, offset);
- if (IS_ERR_VALUE(err)) {
- if (!ret)
- ret = err;
-
- break;
- }
-
- offset += n;
- size -= n;
- ret += n;
- n = min_t(unsigned int, size, m24lr->page_size);
- }
- mutex_unlock(&m24lr->lock);
-
- return ret;
-}
-
-/**
- * m24lr_write_pass - Write password to M24LR043-R using secure format
- * @m24lr: Pointer to device control structure
- * @buf: Input buffer containing hex-encoded password
- * @count: Number of bytes in @buf
- * @code: Operation code to embed between password copies
- *
- * This function parses a 4-byte password, encodes it in big-endian format,
- * and constructs a 9-byte sequence of the form:
- *
- * [BE(password), code, BE(password)]
- *
- * The result is written to register 0x0900 (2304), which is the password
- * register in M24LR04E-R chip.
- *
- * Return: Number of bytes written on success, or negative error code on failure
- */
-static ssize_t m24lr_write_pass(struct m24lr *m24lr, const char *buf,
- size_t count, u8 code)
-{
- __be32 be_pass;
- u8 output[9];
- ssize_t ret;
- u32 pass;
- int err;
-
- if (!count)
- return -EINVAL;
-
- if (count > 8)
- return -EINVAL;
-
- err = kstrtou32(buf, 16, &pass);
- if (err)
- return err;
-
- be_pass = cpu_to_be32(pass);
-
- memcpy(output, &be_pass, sizeof(be_pass));
- output[4] = code;
- memcpy(output + 5, &be_pass, sizeof(be_pass));
-
- mutex_lock(&m24lr->lock);
- ret = m24lr_regmap_write(m24lr->ctl_regmap, output, 9, 2304);
- mutex_unlock(&m24lr->lock);
-
- return ret;
-}
-
-static ssize_t m24lr_read_reg_le(struct m24lr *m24lr, u64 *val,
- unsigned int reg_addr,
- unsigned int reg_size)
-{
- ssize_t ret;
- __le64 input = 0;
-
- ret = m24lr_read(m24lr, (u8 *)&input, reg_size, reg_addr, false);
- if (IS_ERR_VALUE(ret))
- return ret;
-
- if (ret != reg_size)
- return -EINVAL;
-
- switch (reg_size) {
- case 1:
- *val = *(u8 *)&input;
- break;
- case 2:
- *val = le16_to_cpu((__le16)input);
- break;
- case 4:
- *val = le32_to_cpu((__le32)input);
- break;
- case 8:
- *val = le64_to_cpu((__le64)input);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int m24lr_nvmem_read(void *priv, unsigned int offset, void *val,
- size_t bytes)
-{
- ssize_t err;
- struct m24lr *m24lr = priv;
-
- if (!bytes)
- return bytes;
-
- if (offset + bytes > m24lr->eeprom_size)
- return -EINVAL;
-
- err = m24lr_read(m24lr, val, bytes, offset, true);
- if (IS_ERR_VALUE(err))
- return err;
-
- return 0;
-}
-
-static int m24lr_nvmem_write(void *priv, unsigned int offset, void *val,
- size_t bytes)
-{
- ssize_t err;
- struct m24lr *m24lr = priv;
-
- if (!bytes)
- return -EINVAL;
-
- if (offset + bytes > m24lr->eeprom_size)
- return -EINVAL;
-
- err = m24lr_write(m24lr, val, bytes, offset, true);
- if (IS_ERR_VALUE(err))
- return err;
-
- return 0;
-}
-
-static ssize_t m24lr_ctl_sss_read(struct file *filep, struct kobject *kobj,
- const struct bin_attribute *attr, char *buf,
- loff_t offset, size_t count)
-{
- struct m24lr *m24lr = attr->private;
-
- if (!count)
- return count;
-
- if (size_add(offset, count) > m24lr->sss_len)
- return -EINVAL;
-
- return m24lr_read(m24lr, buf, count, offset, false);
-}
-
-static ssize_t m24lr_ctl_sss_write(struct file *filep, struct kobject *kobj,
- const struct bin_attribute *attr, char *buf,
- loff_t offset, size_t count)
-{
- struct m24lr *m24lr = attr->private;
-
- if (!count)
- return -EINVAL;
-
- if (size_add(offset, count) > m24lr->sss_len)
- return -EINVAL;
-
- return m24lr_write(m24lr, buf, count, offset, false);
-}
-static BIN_ATTR(sss, 0600, m24lr_ctl_sss_read, m24lr_ctl_sss_write, 0);
-
-static ssize_t new_pass_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
-
- return m24lr_write_pass(m24lr, buf, count, 7);
-}
-static DEVICE_ATTR_WO(new_pass);
-
-static ssize_t unlock_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
-
- return m24lr_write_pass(m24lr, buf, count, 9);
-}
-static DEVICE_ATTR_WO(unlock);
-
-static ssize_t uid_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
-
- return sysfs_emit(buf, "%llx\n", m24lr->uid);
-}
-static DEVICE_ATTR_RO(uid);
-
-static ssize_t total_sectors_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct m24lr *m24lr = i2c_get_clientdata(to_i2c_client(dev));
-
- return sysfs_emit(buf, "%x\n", m24lr->sss_len);
-}
-static DEVICE_ATTR_RO(total_sectors);
-
-static struct attribute *m24lr_ctl_dev_attrs[] = {
- &dev_attr_unlock.attr,
- &dev_attr_new_pass.attr,
- &dev_attr_uid.attr,
- &dev_attr_total_sectors.attr,
- NULL,
-};
-
-static const struct m24lr_chip *m24lr_get_chip(struct device *dev)
-{
- const struct m24lr_chip *ret;
- const struct i2c_device_id *id;
-
- id = i2c_match_id(m24lr_ids, to_i2c_client(dev));
-
- if (dev->of_node && of_match_device(m24lr_of_match, dev))
- ret = of_device_get_match_data(dev);
- else if (id)
- ret = (void *)id->driver_data;
- else
- ret = acpi_device_get_match_data(dev);
-
- return ret;
-}
-
-static int m24lr_probe(struct i2c_client *client)
-{
- struct regmap_config eeprom_regmap_conf = {0};
- struct nvmem_config nvmem_conf = {0};
- struct device *dev = &client->dev;
- struct i2c_client *eeprom_client;
- const struct m24lr_chip *chip;
- struct regmap *eeprom_regmap;
- struct nvmem_device *nvmem;
- struct regmap *ctl_regmap;
- struct m24lr *m24lr;
- u32 regs[2];
- long err;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- return -EOPNOTSUPP;
-
- chip = m24lr_get_chip(dev);
- if (!chip)
- return -ENODEV;
-
- m24lr = devm_kzalloc(dev, sizeof(struct m24lr), GFP_KERNEL);
- if (!m24lr)
- return -ENOMEM;
-
- err = device_property_read_u32_array(dev, "reg", regs, ARRAY_SIZE(regs));
- if (err)
- return dev_err_probe(dev, err, "Failed to read 'reg' property\n");
-
- /* Create a second I2C client for the eeprom interface */
- eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter, regs[1]);
- if (IS_ERR(eeprom_client))
- return dev_err_probe(dev, PTR_ERR(eeprom_client),
- "Failed to create dummy I2C client for the EEPROM\n");
-
- ctl_regmap = devm_regmap_init_i2c(client, &m24lr_ctl_regmap_conf);
- if (IS_ERR(ctl_regmap))
- return dev_err_probe(dev, PTR_ERR(ctl_regmap),
- "Failed to init regmap\n");
-
- eeprom_regmap_conf.name = "m24lr_eeprom";
- eeprom_regmap_conf.reg_bits = 16;
- eeprom_regmap_conf.val_bits = 8;
- eeprom_regmap_conf.disable_locking = true;
- eeprom_regmap_conf.max_register = chip->eeprom_size - 1;
-
- eeprom_regmap = devm_regmap_init_i2c(eeprom_client,
- &eeprom_regmap_conf);
- if (IS_ERR(eeprom_regmap))
- return dev_err_probe(dev, PTR_ERR(eeprom_regmap),
- "Failed to init regmap\n");
-
- mutex_init(&m24lr->lock);
- m24lr->sss_len = chip->sss_len;
- m24lr->page_size = chip->page_size;
- m24lr->eeprom_size = chip->eeprom_size;
- m24lr->eeprom_regmap = eeprom_regmap;
- m24lr->ctl_regmap = ctl_regmap;
-
- nvmem_conf.dev = &eeprom_client->dev;
- nvmem_conf.owner = THIS_MODULE;
- nvmem_conf.type = NVMEM_TYPE_EEPROM;
- nvmem_conf.reg_read = m24lr_nvmem_read;
- nvmem_conf.reg_write = m24lr_nvmem_write;
- nvmem_conf.size = chip->eeprom_size;
- nvmem_conf.word_size = 1;
- nvmem_conf.stride = 1;
- nvmem_conf.priv = m24lr;
-
- nvmem = devm_nvmem_register(dev, &nvmem_conf);
- if (IS_ERR(nvmem))
- return dev_err_probe(dev, PTR_ERR(nvmem),
- "Failed to register nvmem\n");
-
- i2c_set_clientdata(client, m24lr);
- i2c_set_clientdata(eeprom_client, m24lr);
-
- bin_attr_sss.size = chip->sss_len;
- bin_attr_sss.private = m24lr;
- err = sysfs_create_bin_file(&dev->kobj, &bin_attr_sss);
- if (err)
- return dev_err_probe(dev, err,
- "Failed to create sss bin file\n");
-
- /* test by reading the uid, if success store it */
- err = m24lr_read_reg_le(m24lr, &m24lr->uid, 2324, sizeof(m24lr->uid));
- if (IS_ERR_VALUE(err))
- goto remove_bin_file;
-
- return 0;
-
-remove_bin_file:
- sysfs_remove_bin_file(&dev->kobj, &bin_attr_sss);
-
- return err;
-}
-
-static void m24lr_remove(struct i2c_client *client)
-{
- sysfs_remove_bin_file(&client->dev.kobj, &bin_attr_sss);
-}
-
-ATTRIBUTE_GROUPS(m24lr_ctl_dev);
-
-static struct i2c_driver m24lr_driver = {
- .driver = {
- .name = "m24lr",
- .of_match_table = m24lr_of_match,
- .dev_groups = m24lr_ctl_dev_groups,
- },
- .probe = m24lr_probe,
- .remove = m24lr_remove,
- .id_table = m24lr_ids,
-};
-module_i2c_driver(m24lr_driver);
-
-MODULE_AUTHOR("Abd-Alrhman Masalkhi");
-MODULE_DESCRIPTION("st m24lr control driver");
-MODULE_LICENSE("GPL");