summaryrefslogtreecommitdiff
path: root/drivers/nvmem
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-05-27 15:22:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-05-27 15:22:01 -0700
commitaacc73ceeb8bf664426f0e53db2778a59325bd9f (patch)
treec34e850094c178bc2e81676c652463f54402f030 /drivers/nvmem
parenta9e6060bb2a6cae6d43a98ec0794844ad01273d3 (diff)
parent8b8ef309093ff196967a21ee51a9cdb404a13bf6 (diff)
Merge tag 'gpio-updates-for-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "We have three new drivers, some refactoring in the GPIO core, lots of various changes across many drivers, new configfs interface for the virtual gpio-aggregator module and DT-bindings updates. The treewide conversion of GPIO drivers to using the new value setter callbacks is ongoing with another round of GPIO drivers updated. You will also see these commits coming in from other subsystems as with the relevant changes merged into mainline last cycle, I've started converting GPIO providers located elsewhere than drivers/gpio/. GPIO core: - use more lock guards where applicable - refactor GPIO ACPI code and shrink it in the process by 8% - move GPIO ACPI quirks into a separate file - remove unneeded #ifdef - convert GPIO devres helpers to using devm_add_action() where applicable which shrinks and simplifies the code - refactor GPIO descriptor validation in GPIO consumer interfaces - don't allow setting values on input lines in the GPIO core which will take off the burden from GPIO drivers of checking this down the line - provide gpiod_is_equal() as a way of safely comparing two GPIO descriptors (the only current user is in regulator core) New drivers: - add the GPIO module for the max77759 multifunction device - add the GPIO driver for the VeriSilicon BLZP1600 GPIO controller - add the GPIO driver for the Spacemit K1 SoC Driver improvements: - convert more drivers to using the new GPIO line value setter callbacks - convert more drivers to making the irq_chip immutable as is recommended by the interrupt subsystem - extend build testing coverage by enabling more modules to be built with COMPILE_TEST=y - extend the gpio-aggregator module with a configfs interface that makes the setup easier for user-space than the existing driver-level sysfs attributes and also adds more advanced configuration features (such as referring to aggregated lines by their original names or modifying their names as exposed by the aggregated chip) - add a missing mutex_destroy() in gpio-imx-scu - add an OF polarity quirk for s5m8767 - allow building gpio-vf610 as a loadable module - make gpio-mxc not hardcode its GPIO base number with GPIO SYSFS interface disabled (another small step towards getting rid of the global GPIO numberspace) - add support for level-triggered interrupts to gpio-pca953x - don't double-check the ngpios property in gpio-ds4520 as GPIO core already does it - don't double-check the number of GPIOs in gpio-imx-scu as GPIO core already does it - remove unused callbacks from gpio-max3191x DT bindings: - add device-tree bindings for max77759, spacemit,k1 and blzp1600 (new drivers added this cycle) - document more properties for gpio-vf610 and gpio-tegra186 - document a new pca95xx variant - fix style of examples in several GPIO DT-binding documents Misc: - TODO list updates" * tag 'gpio-updates-for-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (123 commits) gpio: timberdale: select GPIOLIB_IRQCHIP gpio: lpc18xx: select GPIOLIB_IRQCHIP gpio: grgpio: select GPIOLIB_IRQCHIP gpio: bcm-kona: select GPIOLIB_IRQCHIP dt-bindings: gpio: vf610: add ngpios and gpio-reserved-ranges gpio: davinci: select GPIOLIB_IRQCHIP gpiolib-acpi: Update file references in the Documentation and MAINTAINERS gpiolib: acpi: Move quirks to a separate file gpiolib: acpi: Add acpi_gpio_need_run_edge_events_on_boot() getter gpiolib: acpi: Handle deferred list via new API gpiolib: acpi: Make sure we fill struct acpi_gpio_info gpiolib: acpi: Switch to use enum in acpi_gpio_in_ignore_list() gpiolib: acpi: Use temporary variable for struct acpi_gpio_info gpiolib: remove unneeded #ifdef gpio: mpc8xxx: select GPIOLIB_IRQCHIP gpio: pxa: select GPIOLIB_IRQCHIP gpio: pxa: Make irq_chip immutable gpio: timberdale: Make irq_chip immutable gpio: xgene-sb: Make irq_chip immutable gpio: davinci: Make irq_chip immutable ...
Diffstat (limited to 'drivers/nvmem')
-rw-r--r--drivers/nvmem/Kconfig12
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/max77759-nvmem.c145
3 files changed, 159 insertions, 0 deletions
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 8671b7c974b9..3de07ef52490 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -154,6 +154,18 @@ config NVMEM_LPC18XX_OTP
To compile this driver as a module, choose M here: the module
will be called nvmem_lpc18xx_otp.
+config NVMEM_MAX77759
+ tristate "Maxim Integrated MAX77759 NVMEM Support"
+ depends on MFD_MAX77759
+ default MFD_MAX77759
+ help
+ Say Y here to include support for the user-accessible storage found
+ in Maxim Integrated MAX77759 PMICs. This IC provides space for 30
+ bytes of storage.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem-max77759.
+
config NVMEM_MESON_EFUSE
tristate "Amlogic Meson GX eFuse Support"
depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 5b77bbb6488b..a9d03cfbbd27 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -34,6 +34,8 @@ obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o
nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o
obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o
nvmem_lpc18xx_otp-y := lpc18xx_otp.o
+obj-$(CONFIG_NVMEM_MAX77759) += nvmem-max77759.o
+nvmem-max77759-y := max77759-nvmem.o
obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o
nvmem_meson_efuse-y := meson-efuse.o
obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o
diff --git a/drivers/nvmem/max77759-nvmem.c b/drivers/nvmem/max77759-nvmem.c
new file mode 100644
index 000000000000..c9961ad0e232
--- /dev/null
+++ b/drivers/nvmem/max77759-nvmem.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright 2020 Google Inc
+// Copyright 2025 Linaro Ltd.
+//
+// NVMEM driver for Maxim MAX77759
+
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/device/driver.h>
+#include <linux/err.h>
+#include <linux/mfd/max77759.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+
+#define MAX77759_NVMEM_OPCODE_HEADER_LEN 3
+/*
+ * NVMEM commands have a three byte header (which becomes part of the command),
+ * so we need to subtract that.
+ */
+#define MAX77759_NVMEM_SIZE (MAX77759_MAXQ_OPCODE_MAXLENGTH \
+ - MAX77759_NVMEM_OPCODE_HEADER_LEN)
+
+struct max77759_nvmem {
+ struct device *dev;
+ struct max77759 *max77759;
+};
+
+static int max77759_nvmem_reg_read(void *priv, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct max77759_nvmem *nvmem = priv;
+ DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length,
+ MAX77759_NVMEM_OPCODE_HEADER_LEN);
+ DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length,
+ MAX77759_MAXQ_OPCODE_MAXLENGTH);
+ int ret;
+
+ cmd->cmd[0] = MAX77759_MAXQ_OPCODE_USER_SPACE_READ;
+ cmd->cmd[1] = offset;
+ cmd->cmd[2] = bytes;
+ rsp->length = bytes + MAX77759_NVMEM_OPCODE_HEADER_LEN;
+
+ ret = max77759_maxq_command(nvmem->max77759, cmd, rsp);
+ if (ret < 0)
+ return ret;
+
+ if (memcmp(cmd->cmd, rsp->rsp, MAX77759_NVMEM_OPCODE_HEADER_LEN)) {
+ dev_warn(nvmem->dev, "protocol error (read)\n");
+ return -EIO;
+ }
+
+ memcpy(val, &rsp->rsp[MAX77759_NVMEM_OPCODE_HEADER_LEN], bytes);
+
+ return 0;
+}
+
+static int max77759_nvmem_reg_write(void *priv, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct max77759_nvmem *nvmem = priv;
+ DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length,
+ MAX77759_MAXQ_OPCODE_MAXLENGTH);
+ DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length,
+ MAX77759_MAXQ_OPCODE_MAXLENGTH);
+ int ret;
+
+ cmd->cmd[0] = MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE;
+ cmd->cmd[1] = offset;
+ cmd->cmd[2] = bytes;
+ memcpy(&cmd->cmd[MAX77759_NVMEM_OPCODE_HEADER_LEN], val, bytes);
+ cmd->length = bytes + MAX77759_NVMEM_OPCODE_HEADER_LEN;
+ rsp->length = cmd->length;
+
+ ret = max77759_maxq_command(nvmem->max77759, cmd, rsp);
+ if (ret < 0)
+ return ret;
+
+ if (memcmp(cmd->cmd, rsp->rsp, cmd->length)) {
+ dev_warn(nvmem->dev, "protocol error (write)\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int max77759_nvmem_probe(struct platform_device *pdev)
+{
+ struct nvmem_config config = {
+ .dev = &pdev->dev,
+ .name = dev_name(&pdev->dev),
+ .id = NVMEM_DEVID_NONE,
+ .type = NVMEM_TYPE_EEPROM,
+ .ignore_wp = true,
+ .size = MAX77759_NVMEM_SIZE,
+ .word_size = sizeof(u8),
+ .stride = sizeof(u8),
+ .reg_read = max77759_nvmem_reg_read,
+ .reg_write = max77759_nvmem_reg_write,
+ };
+ struct max77759_nvmem *nvmem;
+
+ nvmem = devm_kzalloc(&pdev->dev, sizeof(*nvmem), GFP_KERNEL);
+ if (!nvmem)
+ return -ENOMEM;
+
+ nvmem->dev = &pdev->dev;
+ nvmem->max77759 = dev_get_drvdata(pdev->dev.parent);
+
+ config.priv = nvmem;
+
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
+}
+
+static const struct of_device_id max77759_nvmem_of_id[] = {
+ { .compatible = "maxim,max77759-nvmem", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max77759_nvmem_of_id);
+
+static const struct platform_device_id max77759_nvmem_platform_id[] = {
+ { "max77759-nvmem", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max77759_nvmem_platform_id);
+
+static struct platform_driver max77759_nvmem_driver = {
+ .driver = {
+ .name = "max77759-nvmem",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = max77759_nvmem_of_id,
+ },
+ .probe = max77759_nvmem_probe,
+ .id_table = max77759_nvmem_platform_id,
+};
+
+module_platform_driver(max77759_nvmem_driver);
+
+MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>");
+MODULE_DESCRIPTION("NVMEM driver for Maxim MAX77759");
+MODULE_LICENSE("GPL");