summaryrefslogtreecommitdiffstats
path: root/drivers/nvmem/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-07-20 00:55:08 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2024-07-20 00:55:08 +0200
commitacc5965b9ff8a1889f5b51466562896d59c6e1b9 (patch)
tree8cd651e6594a9133f216d59a4fa1f18d8c63fb26 /drivers/nvmem/core.c
parentMerge tag 'staging-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git... (diff)
parentmisc: Kconfig: exclude mrvl-cn10k-dpi compilation for 32-bit systems (diff)
downloadlinux-acc5965b9ff8a1889f5b51466562896d59c6e1b9.tar.xz
linux-acc5965b9ff8a1889f5b51466562896d59c6e1b9.zip
Merge tag 'char-misc-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc and other driver updates from Greg KH: "Here is the "big" set of char/misc and other driver subsystem changes for 6.11-rc1. Nothing major in here, just loads of new drivers and updates. Included in here are: - IIO api updates and new drivers added - wait_interruptable_timeout() api cleanups for some drivers - MODULE_DESCRIPTION() additions for loads of drivers - parport out-of-bounds fix - interconnect driver updates and additions - mhi driver updates and additions - w1 driver fixes - binder speedups and fixes - eeprom driver updates - coresight driver updates - counter driver update - new misc driver additions - other minor api updates All of these, EXCEPT for the final Kconfig build fix for 32bit systems, have been in linux-next for a while with no reported issues. The Kconfig fixup went in 29 hours ago, so might have missed the latest linux-next, but was acked by everyone involved" * tag 'char-misc-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (330 commits) misc: Kconfig: exclude mrvl-cn10k-dpi compilation for 32-bit systems misc: delete Makefile.rej binder: fix hang of unregistered readers misc: Kconfig: add a new dependency for MARVELL_CN10K_DPI virtio: add missing MODULE_DESCRIPTION() macro agp: uninorth: add missing MODULE_DESCRIPTION() macro spmi: add missing MODULE_DESCRIPTION() macros dev/parport: fix the array out-of-bounds risk samples: configfs: add missing MODULE_DESCRIPTION() macro misc: mrvl-cn10k-dpi: add Octeon CN10K DPI administrative driver misc: keba: Fix missing AUXILIARY_BUS dependency slimbus: Fix struct and documentation alignment in stream.c MAINTAINERS: CC dri-devel list on Qualcomm FastRPC patches misc: fastrpc: use coherent pool for untranslated Compute Banks misc: fastrpc: support complete DMA pool access to the DSP misc: fastrpc: add missing MODULE_DESCRIPTION() macro misc: fastrpc: Add missing dev_err newlines misc: fastrpc: Use memdup_user() nvmem: core: Implement force_ro sysfs attribute nvmem: Use sysfs_emit() for type attribute ...
Diffstat (limited to 'drivers/nvmem/core.c')
-rw-r--r--drivers/nvmem/core.c90
1 files changed, 54 insertions, 36 deletions
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index f8dd7eb40fbe..516dfd861b9f 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -179,12 +179,35 @@ static ssize_t type_show(struct device *dev,
{
struct nvmem_device *nvmem = to_nvmem_device(dev);
- return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
+ return sysfs_emit(buf, "%s\n", nvmem_type_str[nvmem->type]);
}
static DEVICE_ATTR_RO(type);
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+
+ return sysfs_emit(buf, "%d\n", nvmem->read_only);
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+ int ret = kstrtobool(buf, &nvmem->read_only);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(force_ro);
+
static struct attribute *nvmem_attrs[] = {
+ &dev_attr_force_ro.attr,
&dev_attr_type.attr,
NULL,
};
@@ -203,19 +226,12 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
dev = kobj_to_dev(kobj);
nvmem = to_nvmem_device(dev);
- /* Stop the user from reading */
- if (pos >= nvmem->size)
- return 0;
-
if (!IS_ALIGNED(pos, nvmem->stride))
return -EINVAL;
if (count < nvmem->word_size)
return -EINVAL;
- if (pos + count > nvmem->size)
- count = nvmem->size - pos;
-
count = round_down(count, nvmem->word_size);
if (!nvmem->reg_read)
@@ -243,19 +259,12 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
dev = kobj_to_dev(kobj);
nvmem = to_nvmem_device(dev);
- /* Stop the user from writing */
- if (pos >= nvmem->size)
- return -EFBIG;
-
if (!IS_ALIGNED(pos, nvmem->stride))
return -EINVAL;
if (count < nvmem->word_size)
return -EINVAL;
- if (pos + count > nvmem->size)
- count = nvmem->size - pos;
-
count = round_down(count, nvmem->word_size);
if (!nvmem->reg_write)
@@ -299,6 +308,25 @@ static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj,
return nvmem_bin_attr_get_umode(nvmem);
}
+static umode_t nvmem_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+
+ /*
+ * If the device has no .reg_write operation, do not allow
+ * configuration as read-write.
+ * If the device is set as read-only by configuration, it
+ * can be forced into read-write mode using the 'force_ro'
+ * attribute.
+ */
+ if (attr == &dev_attr_force_ro.attr && !nvmem->reg_write)
+ return 0; /* Attribute not visible */
+
+ return attr->mode;
+}
+
static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
const char *id, int index);
@@ -355,11 +383,7 @@ static const struct attribute_group nvmem_bin_group = {
.bin_attrs = nvmem_bin_attributes,
.attrs = nvmem_attrs,
.is_bin_visible = nvmem_bin_attr_is_visible,
-};
-
-/* Cell attributes will be dynamically allocated */
-static struct attribute_group nvmem_cells_group = {
- .name = "cells",
+ .is_visible = nvmem_attr_is_visible,
};
static const struct attribute_group *nvmem_dev_groups[] = {
@@ -367,11 +391,6 @@ static const struct attribute_group *nvmem_dev_groups[] = {
NULL,
};
-static const struct attribute_group *nvmem_cells_groups[] = {
- &nvmem_cells_group,
- NULL,
-};
-
static struct bin_attribute bin_attr_nvmem_eeprom_compat = {
.attr = {
.name = "eeprom",
@@ -428,23 +447,24 @@ static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
{
- struct bin_attribute **cells_attrs, *attrs;
+ struct attribute_group group = {
+ .name = "cells",
+ };
struct nvmem_cell_entry *entry;
+ struct bin_attribute *attrs;
unsigned int ncells = 0, i = 0;
int ret = 0;
mutex_lock(&nvmem_mutex);
- if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated) {
- nvmem_cells_group.bin_attrs = NULL;
+ if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated)
goto unlock_mutex;
- }
/* Allocate an array of attributes with a sentinel */
ncells = list_count_nodes(&nvmem->cells);
- cells_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
- sizeof(struct bin_attribute *), GFP_KERNEL);
- if (!cells_attrs) {
+ group.bin_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
+ sizeof(struct bin_attribute *), GFP_KERNEL);
+ if (!group.bin_attrs) {
ret = -ENOMEM;
goto unlock_mutex;
}
@@ -471,13 +491,11 @@ static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
goto unlock_mutex;
}
- cells_attrs[i] = &attrs[i];
+ group.bin_attrs[i] = &attrs[i];
i++;
}
- nvmem_cells_group.bin_attrs = cells_attrs;
-
- ret = device_add_groups(&nvmem->dev, nvmem_cells_groups);
+ ret = device_add_group(&nvmem->dev, &group);
if (ret)
goto unlock_mutex;