Loading Documentation/ABI/stable/sysfs-bus-nvmem +0 −2 Original line number Diff line number Diff line Loading @@ -6,8 +6,6 @@ Description: This file allows user to read/write the raw NVMEM contents. Permissions for write to this file depends on the nvmem provider configuration. Note: This file is only present if CONFIG_NVMEM_SYSFS is enabled ex: hexdump /sys/bus/nvmem/devices/qfprom0/nvmem Loading drivers/nvmem/Kconfig +0 −10 Original line number Diff line number Diff line Loading @@ -13,16 +13,6 @@ menuconfig NVMEM if NVMEM config NVMEM_SYSFS bool "/sys/bus/nvmem/devices/*/nvmem (sysfs interface)" depends on SYSFS default y help Say Y here to add a sysfs interface for NVMEM. This interface is mostly used by userspace applications to read/write directly into nvmem. config NVMEM_IMX_IIM tristate "i.MX IC Identification Module support" depends on ARCH_MXC || COMPILE_TEST Loading drivers/nvmem/Makefile +0 −3 Original line number Diff line number Diff line Loading @@ -6,9 +6,6 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o nvmem_core-y := core.o obj-$(CONFIG_NVMEM_SYSFS) += nvmem_sysfs.o nvmem_sysfs-y := nvmem-sysfs.o # Devices obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o nvmem-bcm-ocotp-y := bcm-ocotp.o Loading drivers/nvmem/core.c +282 −77 Original line number Diff line number Diff line Loading @@ -19,13 +19,33 @@ #include <linux/fs.h> #include <linux/idr.h> #include <linux/init.h> #include <linux/kref.h> #include <linux/module.h> #include <linux/nvmem-consumer.h> #include <linux/nvmem-provider.h> #include <linux/of.h> #include <linux/slab.h> #include "nvmem.h" struct nvmem_device { const char *name; struct module *owner; struct device dev; int stride; int word_size; int id; struct kref refcnt; size_t size; bool read_only; int flags; struct bin_attribute eeprom; struct device *base_dev; struct list_head cells; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; void *priv; }; #define FLAG_COMPAT BIT(0) struct nvmem_cell { const char *name; Loading @@ -40,9 +60,11 @@ struct nvmem_cell { static DEFINE_MUTEX(nvmem_mutex); static DEFINE_IDA(nvmem_ida); static LIST_HEAD(nvmem_cells); static DEFINE_MUTEX(nvmem_cells_mutex); #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, void *val, size_t bytes) { Loading @@ -61,6 +83,168 @@ static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, return -EINVAL; } static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from reading */ if (pos >= nvmem->size) return 0; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem_reg_read(nvmem, pos, buf, count); if (rc) return rc; return count; } static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from writing */ if (pos >= nvmem->size) return -EFBIG; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem_reg_write(nvmem, pos, buf, count); if (rc) return rc; return count; } /* default read/write permissions */ static struct bin_attribute bin_attr_rw_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUGO, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_attributes[] = { &bin_attr_rw_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_group = { .bin_attrs = nvmem_bin_rw_attributes, }; static const struct attribute_group *nvmem_rw_dev_groups[] = { &nvmem_bin_rw_group, NULL, }; /* read only permission */ static struct bin_attribute bin_attr_ro_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUGO, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_attributes[] = { &bin_attr_ro_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_group = { .bin_attrs = nvmem_bin_ro_attributes, }; static const struct attribute_group *nvmem_ro_dev_groups[] = { &nvmem_bin_ro_group, NULL, }; /* default read/write permissions, root only */ static struct bin_attribute bin_attr_rw_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUSR, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { &bin_attr_rw_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_root_group = { .bin_attrs = nvmem_bin_rw_root_attributes, }; static const struct attribute_group *nvmem_rw_root_dev_groups[] = { &nvmem_bin_rw_root_group, NULL, }; /* read only permission, root only */ static struct bin_attribute bin_attr_ro_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUSR, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { &bin_attr_ro_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_root_group = { .bin_attrs = nvmem_bin_ro_root_attributes, }; static const struct attribute_group *nvmem_ro_root_dev_groups[] = { &nvmem_bin_ro_root_group, NULL, }; static void nvmem_release(struct device *dev) { struct nvmem_device *nvmem = to_nvmem_device(dev); Loading Loading @@ -97,48 +281,27 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) return to_nvmem_device(d); } static struct nvmem_cell *nvmem_find_cell(const char *cell_id) { struct nvmem_cell *p; mutex_lock(&nvmem_cells_mutex); list_for_each_entry(p, &nvmem_cells, node) if (!strcmp(p->name, cell_id)) { mutex_unlock(&nvmem_cells_mutex); return p; } mutex_unlock(&nvmem_cells_mutex); return NULL; } static void nvmem_cell_drop(struct nvmem_cell *cell) { mutex_lock(&nvmem_cells_mutex); mutex_lock(&nvmem_mutex); list_del(&cell->node); mutex_unlock(&nvmem_cells_mutex); mutex_unlock(&nvmem_mutex); kfree(cell); } static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) { struct nvmem_cell *cell; struct list_head *p, *n; struct nvmem_cell *cell, *p; list_for_each_safe(p, n, &nvmem_cells) { cell = list_entry(p, struct nvmem_cell, node); if (cell->nvmem == nvmem) list_for_each_entry_safe(cell, p, &nvmem->cells, node) nvmem_cell_drop(cell); } } static void nvmem_cell_add(struct nvmem_cell *cell) { mutex_lock(&nvmem_cells_mutex); list_add_tail(&cell->node, &nvmem_cells); mutex_unlock(&nvmem_cells_mutex); mutex_lock(&nvmem_mutex); list_add_tail(&cell->node, &cell->nvmem->cells); mutex_unlock(&nvmem_mutex); } static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, Loading Loading @@ -217,6 +380,43 @@ int nvmem_add_cells(struct nvmem_device *nvmem, } EXPORT_SYMBOL_GPL(nvmem_add_cells); /* * nvmem_setup_compat() - Create an additional binary entry in * drivers sys directory, to be backwards compatible with the older * drivers/misc/eeprom drivers. */ static int nvmem_setup_compat(struct nvmem_device *nvmem, const struct nvmem_config *config) { int rval; if (!config->base_dev) return -EINVAL; if (nvmem->read_only) nvmem->eeprom = bin_attr_ro_root_nvmem; else nvmem->eeprom = bin_attr_rw_root_nvmem; nvmem->eeprom.attr.name = "eeprom"; nvmem->eeprom.size = nvmem->size; #ifdef CONFIG_DEBUG_LOCK_ALLOC nvmem->eeprom.attr.key = &eeprom_lock_key; #endif nvmem->eeprom.private = &nvmem->dev; nvmem->base_dev = config->base_dev; rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); if (rval) { dev_err(&nvmem->dev, "Failed to create eeprom binary file %d\n", rval); return rval; } nvmem->flags |= FLAG_COMPAT; return 0; } /** * nvmem_register() - Register a nvmem device for given nvmem_config. * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem Loading Loading @@ -245,6 +445,9 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) return ERR_PTR(rval); } kref_init(&nvmem->refcnt); INIT_LIST_HEAD(&nvmem->cells); nvmem->id = rval; nvmem->owner = config->owner; if (!nvmem->owner && config->dev->driver) Loading @@ -271,7 +474,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->read_only = device_property_present(config->dev, "read-only") | config->read_only; nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); if (config->root_only) nvmem->dev.groups = nvmem->read_only ? nvmem_ro_root_dev_groups : nvmem_rw_root_dev_groups; else nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; device_initialize(&nvmem->dev); Loading @@ -282,7 +492,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_put_device; if (config->compat) { rval = nvmem_sysfs_setup_compat(nvmem, config); rval = nvmem_setup_compat(nvmem, config); if (rval) goto err_device_del; } Loading @@ -297,7 +507,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) err_teardown_compat: if (config->compat) nvmem_sysfs_remove_compat(nvmem, config); device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); err_device_del: device_del(&nvmem->dev); err_put_device: Loading @@ -307,6 +517,20 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) } EXPORT_SYMBOL_GPL(nvmem_register); static void nvmem_device_release(struct kref *kref) { struct nvmem_device *nvmem; nvmem = container_of(kref, struct nvmem_device, refcnt); if (nvmem->flags & FLAG_COMPAT) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_device_remove_all_cells(nvmem); device_del(&nvmem->dev); put_device(&nvmem->dev); } /** * nvmem_unregister() - Unregister previously registered nvmem device * Loading @@ -316,19 +540,7 @@ EXPORT_SYMBOL_GPL(nvmem_register); */ int nvmem_unregister(struct nvmem_device *nvmem) { mutex_lock(&nvmem_mutex); if (nvmem->users) { mutex_unlock(&nvmem_mutex); return -EBUSY; } mutex_unlock(&nvmem_mutex); if (nvmem->flags & FLAG_COMPAT) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_device_remove_all_cells(nvmem); device_del(&nvmem->dev); put_device(&nvmem->dev); kref_put(&nvmem->refcnt, nvmem_device_release); return 0; } Loading Loading @@ -401,52 +613,32 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np, { struct nvmem_device *nvmem = NULL; mutex_lock(&nvmem_mutex); if (!np) return ERR_PTR(-ENOENT); if (np) { mutex_lock(&nvmem_mutex); nvmem = of_nvmem_find(np); if (!nvmem) { mutex_unlock(&nvmem_mutex); if (!nvmem) return ERR_PTR(-EPROBE_DEFER); } } else { struct nvmem_cell *cell = nvmem_find_cell(cell_id); if (cell) { nvmem = cell->nvmem; *cellp = cell; } if (!nvmem) { mutex_unlock(&nvmem_mutex); return ERR_PTR(-ENOENT); } } nvmem->users++; mutex_unlock(&nvmem_mutex); if (!try_module_get(nvmem->owner)) { dev_err(&nvmem->dev, "could not increase module refcount for cell %s\n", nvmem->name); mutex_lock(&nvmem_mutex); nvmem->users--; mutex_unlock(&nvmem_mutex); return ERR_PTR(-EINVAL); } kref_get(&nvmem->refcnt); return nvmem; } static void __nvmem_device_put(struct nvmem_device *nvmem) { module_put(nvmem->owner); mutex_lock(&nvmem_mutex); nvmem->users--; mutex_unlock(&nvmem_mutex); kref_put(&nvmem->refcnt, nvmem_device_release); } static struct nvmem_device *nvmem_find(const char *name) Loading Loading @@ -1120,6 +1312,19 @@ int nvmem_device_write(struct nvmem_device *nvmem, } EXPORT_SYMBOL_GPL(nvmem_device_write); /** * nvmem_dev_name() - Get the name of a given nvmem device. * * @nvmem: nvmem device. * * Return: name of the nvmem device. */ const char *nvmem_dev_name(struct nvmem_device *nvmem) { return dev_name(&nvmem->dev); } EXPORT_SYMBOL_GPL(nvmem_dev_name); static int __init nvmem_init(void) { return bus_register(&nvmem_bus_type); Loading drivers/nvmem/nvmem-sysfs.cdeleted 100644 → 0 +0 −230 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019, Linaro Limited */ #include "nvmem.h" #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from reading */ if (pos >= nvmem->size) return 0; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem->reg_read(nvmem->priv, pos, buf, count); if (rc) return rc; return count; } static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from writing */ if (pos >= nvmem->size) return -EFBIG; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem->reg_write(nvmem->priv, pos, buf, count); if (rc) return rc; return count; } /* default read/write permissions */ static struct bin_attribute bin_attr_rw_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUGO, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_attributes[] = { &bin_attr_rw_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_group = { .bin_attrs = nvmem_bin_rw_attributes, }; static const struct attribute_group *nvmem_rw_dev_groups[] = { &nvmem_bin_rw_group, NULL, }; /* read only permission */ static struct bin_attribute bin_attr_ro_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUGO, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_attributes[] = { &bin_attr_ro_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_group = { .bin_attrs = nvmem_bin_ro_attributes, }; static const struct attribute_group *nvmem_ro_dev_groups[] = { &nvmem_bin_ro_group, NULL, }; /* default read/write permissions, root only */ static struct bin_attribute bin_attr_rw_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUSR, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { &bin_attr_rw_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_root_group = { .bin_attrs = nvmem_bin_rw_root_attributes, }; static const struct attribute_group *nvmem_rw_root_dev_groups[] = { &nvmem_bin_rw_root_group, NULL, }; /* read only permission, root only */ static struct bin_attribute bin_attr_ro_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUSR, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { &bin_attr_ro_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_root_group = { .bin_attrs = nvmem_bin_ro_root_attributes, }; static const struct attribute_group *nvmem_ro_root_dev_groups[] = { &nvmem_bin_ro_root_group, NULL, }; const struct attribute_group **nvmem_sysfs_get_groups( struct nvmem_device *nvmem, const struct nvmem_config *config) { if (config->root_only) return nvmem->read_only ? nvmem_ro_root_dev_groups : nvmem_rw_root_dev_groups; return nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; } /* * nvmem_setup_compat() - Create an additional binary entry in * drivers sys directory, to be backwards compatible with the older * drivers/misc/eeprom drivers. */ int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, const struct nvmem_config *config) { int rval; if (!config->compat) return 0; if (!config->base_dev) return -EINVAL; if (nvmem->read_only) nvmem->eeprom = bin_attr_ro_root_nvmem; else nvmem->eeprom = bin_attr_rw_root_nvmem; nvmem->eeprom.attr.name = "eeprom"; nvmem->eeprom.size = nvmem->size; #ifdef CONFIG_DEBUG_LOCK_ALLOC nvmem->eeprom.attr.key = &eeprom_lock_key; #endif nvmem->eeprom.private = &nvmem->dev; nvmem->base_dev = config->base_dev; rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); if (rval) { dev_err(&nvmem->dev, "Failed to create eeprom binary file %d\n", rval); return rval; } nvmem->flags |= FLAG_COMPAT; return 0; } void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, const struct nvmem_config *config) { if (config->compat) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); } Loading
Documentation/ABI/stable/sysfs-bus-nvmem +0 −2 Original line number Diff line number Diff line Loading @@ -6,8 +6,6 @@ Description: This file allows user to read/write the raw NVMEM contents. Permissions for write to this file depends on the nvmem provider configuration. Note: This file is only present if CONFIG_NVMEM_SYSFS is enabled ex: hexdump /sys/bus/nvmem/devices/qfprom0/nvmem Loading
drivers/nvmem/Kconfig +0 −10 Original line number Diff line number Diff line Loading @@ -13,16 +13,6 @@ menuconfig NVMEM if NVMEM config NVMEM_SYSFS bool "/sys/bus/nvmem/devices/*/nvmem (sysfs interface)" depends on SYSFS default y help Say Y here to add a sysfs interface for NVMEM. This interface is mostly used by userspace applications to read/write directly into nvmem. config NVMEM_IMX_IIM tristate "i.MX IC Identification Module support" depends on ARCH_MXC || COMPILE_TEST Loading
drivers/nvmem/Makefile +0 −3 Original line number Diff line number Diff line Loading @@ -6,9 +6,6 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o nvmem_core-y := core.o obj-$(CONFIG_NVMEM_SYSFS) += nvmem_sysfs.o nvmem_sysfs-y := nvmem-sysfs.o # Devices obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o nvmem-bcm-ocotp-y := bcm-ocotp.o Loading
drivers/nvmem/core.c +282 −77 Original line number Diff line number Diff line Loading @@ -19,13 +19,33 @@ #include <linux/fs.h> #include <linux/idr.h> #include <linux/init.h> #include <linux/kref.h> #include <linux/module.h> #include <linux/nvmem-consumer.h> #include <linux/nvmem-provider.h> #include <linux/of.h> #include <linux/slab.h> #include "nvmem.h" struct nvmem_device { const char *name; struct module *owner; struct device dev; int stride; int word_size; int id; struct kref refcnt; size_t size; bool read_only; int flags; struct bin_attribute eeprom; struct device *base_dev; struct list_head cells; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; void *priv; }; #define FLAG_COMPAT BIT(0) struct nvmem_cell { const char *name; Loading @@ -40,9 +60,11 @@ struct nvmem_cell { static DEFINE_MUTEX(nvmem_mutex); static DEFINE_IDA(nvmem_ida); static LIST_HEAD(nvmem_cells); static DEFINE_MUTEX(nvmem_cells_mutex); #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, void *val, size_t bytes) { Loading @@ -61,6 +83,168 @@ static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, return -EINVAL; } static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from reading */ if (pos >= nvmem->size) return 0; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem_reg_read(nvmem, pos, buf, count); if (rc) return rc; return count; } static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from writing */ if (pos >= nvmem->size) return -EFBIG; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem_reg_write(nvmem, pos, buf, count); if (rc) return rc; return count; } /* default read/write permissions */ static struct bin_attribute bin_attr_rw_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUGO, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_attributes[] = { &bin_attr_rw_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_group = { .bin_attrs = nvmem_bin_rw_attributes, }; static const struct attribute_group *nvmem_rw_dev_groups[] = { &nvmem_bin_rw_group, NULL, }; /* read only permission */ static struct bin_attribute bin_attr_ro_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUGO, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_attributes[] = { &bin_attr_ro_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_group = { .bin_attrs = nvmem_bin_ro_attributes, }; static const struct attribute_group *nvmem_ro_dev_groups[] = { &nvmem_bin_ro_group, NULL, }; /* default read/write permissions, root only */ static struct bin_attribute bin_attr_rw_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUSR, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { &bin_attr_rw_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_root_group = { .bin_attrs = nvmem_bin_rw_root_attributes, }; static const struct attribute_group *nvmem_rw_root_dev_groups[] = { &nvmem_bin_rw_root_group, NULL, }; /* read only permission, root only */ static struct bin_attribute bin_attr_ro_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUSR, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { &bin_attr_ro_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_root_group = { .bin_attrs = nvmem_bin_ro_root_attributes, }; static const struct attribute_group *nvmem_ro_root_dev_groups[] = { &nvmem_bin_ro_root_group, NULL, }; static void nvmem_release(struct device *dev) { struct nvmem_device *nvmem = to_nvmem_device(dev); Loading Loading @@ -97,48 +281,27 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) return to_nvmem_device(d); } static struct nvmem_cell *nvmem_find_cell(const char *cell_id) { struct nvmem_cell *p; mutex_lock(&nvmem_cells_mutex); list_for_each_entry(p, &nvmem_cells, node) if (!strcmp(p->name, cell_id)) { mutex_unlock(&nvmem_cells_mutex); return p; } mutex_unlock(&nvmem_cells_mutex); return NULL; } static void nvmem_cell_drop(struct nvmem_cell *cell) { mutex_lock(&nvmem_cells_mutex); mutex_lock(&nvmem_mutex); list_del(&cell->node); mutex_unlock(&nvmem_cells_mutex); mutex_unlock(&nvmem_mutex); kfree(cell); } static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) { struct nvmem_cell *cell; struct list_head *p, *n; struct nvmem_cell *cell, *p; list_for_each_safe(p, n, &nvmem_cells) { cell = list_entry(p, struct nvmem_cell, node); if (cell->nvmem == nvmem) list_for_each_entry_safe(cell, p, &nvmem->cells, node) nvmem_cell_drop(cell); } } static void nvmem_cell_add(struct nvmem_cell *cell) { mutex_lock(&nvmem_cells_mutex); list_add_tail(&cell->node, &nvmem_cells); mutex_unlock(&nvmem_cells_mutex); mutex_lock(&nvmem_mutex); list_add_tail(&cell->node, &cell->nvmem->cells); mutex_unlock(&nvmem_mutex); } static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, Loading Loading @@ -217,6 +380,43 @@ int nvmem_add_cells(struct nvmem_device *nvmem, } EXPORT_SYMBOL_GPL(nvmem_add_cells); /* * nvmem_setup_compat() - Create an additional binary entry in * drivers sys directory, to be backwards compatible with the older * drivers/misc/eeprom drivers. */ static int nvmem_setup_compat(struct nvmem_device *nvmem, const struct nvmem_config *config) { int rval; if (!config->base_dev) return -EINVAL; if (nvmem->read_only) nvmem->eeprom = bin_attr_ro_root_nvmem; else nvmem->eeprom = bin_attr_rw_root_nvmem; nvmem->eeprom.attr.name = "eeprom"; nvmem->eeprom.size = nvmem->size; #ifdef CONFIG_DEBUG_LOCK_ALLOC nvmem->eeprom.attr.key = &eeprom_lock_key; #endif nvmem->eeprom.private = &nvmem->dev; nvmem->base_dev = config->base_dev; rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); if (rval) { dev_err(&nvmem->dev, "Failed to create eeprom binary file %d\n", rval); return rval; } nvmem->flags |= FLAG_COMPAT; return 0; } /** * nvmem_register() - Register a nvmem device for given nvmem_config. * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem Loading Loading @@ -245,6 +445,9 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) return ERR_PTR(rval); } kref_init(&nvmem->refcnt); INIT_LIST_HEAD(&nvmem->cells); nvmem->id = rval; nvmem->owner = config->owner; if (!nvmem->owner && config->dev->driver) Loading @@ -271,7 +474,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->read_only = device_property_present(config->dev, "read-only") | config->read_only; nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); if (config->root_only) nvmem->dev.groups = nvmem->read_only ? nvmem_ro_root_dev_groups : nvmem_rw_root_dev_groups; else nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; device_initialize(&nvmem->dev); Loading @@ -282,7 +492,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_put_device; if (config->compat) { rval = nvmem_sysfs_setup_compat(nvmem, config); rval = nvmem_setup_compat(nvmem, config); if (rval) goto err_device_del; } Loading @@ -297,7 +507,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) err_teardown_compat: if (config->compat) nvmem_sysfs_remove_compat(nvmem, config); device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); err_device_del: device_del(&nvmem->dev); err_put_device: Loading @@ -307,6 +517,20 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) } EXPORT_SYMBOL_GPL(nvmem_register); static void nvmem_device_release(struct kref *kref) { struct nvmem_device *nvmem; nvmem = container_of(kref, struct nvmem_device, refcnt); if (nvmem->flags & FLAG_COMPAT) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_device_remove_all_cells(nvmem); device_del(&nvmem->dev); put_device(&nvmem->dev); } /** * nvmem_unregister() - Unregister previously registered nvmem device * Loading @@ -316,19 +540,7 @@ EXPORT_SYMBOL_GPL(nvmem_register); */ int nvmem_unregister(struct nvmem_device *nvmem) { mutex_lock(&nvmem_mutex); if (nvmem->users) { mutex_unlock(&nvmem_mutex); return -EBUSY; } mutex_unlock(&nvmem_mutex); if (nvmem->flags & FLAG_COMPAT) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_device_remove_all_cells(nvmem); device_del(&nvmem->dev); put_device(&nvmem->dev); kref_put(&nvmem->refcnt, nvmem_device_release); return 0; } Loading Loading @@ -401,52 +613,32 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np, { struct nvmem_device *nvmem = NULL; mutex_lock(&nvmem_mutex); if (!np) return ERR_PTR(-ENOENT); if (np) { mutex_lock(&nvmem_mutex); nvmem = of_nvmem_find(np); if (!nvmem) { mutex_unlock(&nvmem_mutex); if (!nvmem) return ERR_PTR(-EPROBE_DEFER); } } else { struct nvmem_cell *cell = nvmem_find_cell(cell_id); if (cell) { nvmem = cell->nvmem; *cellp = cell; } if (!nvmem) { mutex_unlock(&nvmem_mutex); return ERR_PTR(-ENOENT); } } nvmem->users++; mutex_unlock(&nvmem_mutex); if (!try_module_get(nvmem->owner)) { dev_err(&nvmem->dev, "could not increase module refcount for cell %s\n", nvmem->name); mutex_lock(&nvmem_mutex); nvmem->users--; mutex_unlock(&nvmem_mutex); return ERR_PTR(-EINVAL); } kref_get(&nvmem->refcnt); return nvmem; } static void __nvmem_device_put(struct nvmem_device *nvmem) { module_put(nvmem->owner); mutex_lock(&nvmem_mutex); nvmem->users--; mutex_unlock(&nvmem_mutex); kref_put(&nvmem->refcnt, nvmem_device_release); } static struct nvmem_device *nvmem_find(const char *name) Loading Loading @@ -1120,6 +1312,19 @@ int nvmem_device_write(struct nvmem_device *nvmem, } EXPORT_SYMBOL_GPL(nvmem_device_write); /** * nvmem_dev_name() - Get the name of a given nvmem device. * * @nvmem: nvmem device. * * Return: name of the nvmem device. */ const char *nvmem_dev_name(struct nvmem_device *nvmem) { return dev_name(&nvmem->dev); } EXPORT_SYMBOL_GPL(nvmem_dev_name); static int __init nvmem_init(void) { return bus_register(&nvmem_bus_type); Loading
drivers/nvmem/nvmem-sysfs.cdeleted 100644 → 0 +0 −230 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019, Linaro Limited */ #include "nvmem.h" #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key eeprom_lock_key; #endif static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from reading */ if (pos >= nvmem->size) return 0; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem->reg_read(nvmem->priv, pos, buf, count); if (rc) return rc; return count; } static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { struct device *dev; struct nvmem_device *nvmem; int rc; if (attr->private) dev = attr->private; else dev = container_of(kobj, struct device, kobj); nvmem = to_nvmem_device(dev); /* Stop the user from writing */ if (pos >= nvmem->size) return -EFBIG; if (count < nvmem->word_size) return -EINVAL; if (pos + count > nvmem->size) count = nvmem->size - pos; count = round_down(count, nvmem->word_size); rc = nvmem->reg_write(nvmem->priv, pos, buf, count); if (rc) return rc; return count; } /* default read/write permissions */ static struct bin_attribute bin_attr_rw_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUGO, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_attributes[] = { &bin_attr_rw_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_group = { .bin_attrs = nvmem_bin_rw_attributes, }; static const struct attribute_group *nvmem_rw_dev_groups[] = { &nvmem_bin_rw_group, NULL, }; /* read only permission */ static struct bin_attribute bin_attr_ro_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUGO, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_attributes[] = { &bin_attr_ro_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_group = { .bin_attrs = nvmem_bin_ro_attributes, }; static const struct attribute_group *nvmem_ro_dev_groups[] = { &nvmem_bin_ro_group, NULL, }; /* default read/write permissions, root only */ static struct bin_attribute bin_attr_rw_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IWUSR | S_IRUSR, }, .read = bin_attr_nvmem_read, .write = bin_attr_nvmem_write, }; static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { &bin_attr_rw_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_rw_root_group = { .bin_attrs = nvmem_bin_rw_root_attributes, }; static const struct attribute_group *nvmem_rw_root_dev_groups[] = { &nvmem_bin_rw_root_group, NULL, }; /* read only permission, root only */ static struct bin_attribute bin_attr_ro_root_nvmem = { .attr = { .name = "nvmem", .mode = S_IRUSR, }, .read = bin_attr_nvmem_read, }; static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { &bin_attr_ro_root_nvmem, NULL, }; static const struct attribute_group nvmem_bin_ro_root_group = { .bin_attrs = nvmem_bin_ro_root_attributes, }; static const struct attribute_group *nvmem_ro_root_dev_groups[] = { &nvmem_bin_ro_root_group, NULL, }; const struct attribute_group **nvmem_sysfs_get_groups( struct nvmem_device *nvmem, const struct nvmem_config *config) { if (config->root_only) return nvmem->read_only ? nvmem_ro_root_dev_groups : nvmem_rw_root_dev_groups; return nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; } /* * nvmem_setup_compat() - Create an additional binary entry in * drivers sys directory, to be backwards compatible with the older * drivers/misc/eeprom drivers. */ int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, const struct nvmem_config *config) { int rval; if (!config->compat) return 0; if (!config->base_dev) return -EINVAL; if (nvmem->read_only) nvmem->eeprom = bin_attr_ro_root_nvmem; else nvmem->eeprom = bin_attr_rw_root_nvmem; nvmem->eeprom.attr.name = "eeprom"; nvmem->eeprom.size = nvmem->size; #ifdef CONFIG_DEBUG_LOCK_ALLOC nvmem->eeprom.attr.key = &eeprom_lock_key; #endif nvmem->eeprom.private = &nvmem->dev; nvmem->base_dev = config->base_dev; rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); if (rval) { dev_err(&nvmem->dev, "Failed to create eeprom binary file %d\n", rval); return rval; } nvmem->flags |= FLAG_COMPAT; return 0; } void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, const struct nvmem_config *config) { if (config->compat) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); }