Loading Documentation/ABI/stable/sysfs-bus-nvmem +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ 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 +10 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,16 @@ 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 +3 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,9 @@ 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 +4 −233 Original line number Diff line number Diff line Loading @@ -25,25 +25,7 @@ #include <linux/of.h> #include <linux/slab.h> struct nvmem_device { const char *name; struct module *owner; struct device dev; int stride; int word_size; int id; int users; size_t size; bool read_only; int flags; struct bin_attribute eeprom; struct device *base_dev; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; void *priv; }; #define FLAG_COMPAT BIT(0) #include "nvmem.h" struct nvmem_cell { const char *name; Loading @@ -61,11 +43,6 @@ 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 @@ -84,168 +61,6 @@ 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 @@ -402,43 +217,6 @@ 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 @@ -493,14 +271,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->read_only = device_property_present(config->dev, "read-only") | config->read_only; 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; nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); device_initialize(&nvmem->dev); Loading @@ -511,7 +282,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_put_device; if (config->compat) { rval = nvmem_setup_compat(nvmem, config); rval = nvmem_sysfs_setup_compat(nvmem, config); if (rval) goto err_device_del; } Loading @@ -526,7 +297,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) err_teardown_compat: if (config->compat) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_sysfs_remove_compat(nvmem, config); err_device_del: device_del(&nvmem->dev); err_put_device: Loading drivers/nvmem/nvmem-sysfs.c 0 → 100644 +230 −0 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 +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ 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 +10 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,16 @@ 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 +3 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,9 @@ 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 +4 −233 Original line number Diff line number Diff line Loading @@ -25,25 +25,7 @@ #include <linux/of.h> #include <linux/slab.h> struct nvmem_device { const char *name; struct module *owner; struct device dev; int stride; int word_size; int id; int users; size_t size; bool read_only; int flags; struct bin_attribute eeprom; struct device *base_dev; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; void *priv; }; #define FLAG_COMPAT BIT(0) #include "nvmem.h" struct nvmem_cell { const char *name; Loading @@ -61,11 +43,6 @@ 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 @@ -84,168 +61,6 @@ 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 @@ -402,43 +217,6 @@ 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 @@ -493,14 +271,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->read_only = device_property_present(config->dev, "read-only") | config->read_only; 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; nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); device_initialize(&nvmem->dev); Loading @@ -511,7 +282,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_put_device; if (config->compat) { rval = nvmem_setup_compat(nvmem, config); rval = nvmem_sysfs_setup_compat(nvmem, config); if (rval) goto err_device_del; } Loading @@ -526,7 +297,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) err_teardown_compat: if (config->compat) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_sysfs_remove_compat(nvmem, config); err_device_del: device_del(&nvmem->dev); err_put_device: Loading
drivers/nvmem/nvmem-sysfs.c 0 → 100644 +230 −0 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); }