From 15d33a027ddeb8d8b54fa877c20b1b2195b17b83 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Mon, 11 Mar 2019 11:45:39 +0530 Subject: [PATCH] nvmem: core: Export nvmem cell info to userspace Existing nvmem framework export full register space as nvmem binary, but not exporting child node of nvmem which is nvmem cell. Kernel can read the specific cell by using nvmem_cell_read but userspace don't have such provision. Add framework to export nvmem cell as well, So userspace can use it directly. Change-Id: I3b41a91820f6d2a4536933e7bab4ac1b94f1541a Signed-off-by: Shiraz Hashim Signed-off-by: Gaurav Kohli --- drivers/nvmem/Kconfig | 7 +++++++ drivers/nvmem/core.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index dcaafaee68e4..90fa702867ad 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -97,6 +97,13 @@ config MTK_EFUSE This driver can also be built as a module. If so, the module will be called efuse-mtk. +config QCOM_QFPROM_SYSFS + tristate "QCOM QFPROM SYSFS" + depends on QCOM_QFPROM + help + Say y here to enable QFPROM SYSFS support. The QFPROM SYSFS + create each child node of QFPROM as sysfs entries as well. + config QCOM_QFPROM tristate "QCOM QFPROM Support" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 960542dea5ad..64cffe141075 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -27,6 +27,9 @@ struct nvmem_cell { int nbits; struct device_node *np; struct nvmem_device *nvmem; +#ifdef CONFIG_QCOM_QFPROM_SYSFS + struct bin_attribute attr; +#endif struct list_head node; }; @@ -60,6 +63,28 @@ static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, return -EINVAL; } +#ifdef CONFIG_QCOM_QFPROM_SYSFS +static ssize_t bin_attr_nvmem_cell_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t pos, size_t count) +{ + struct nvmem_cell *cell; + size_t len; + u8 *data; + + cell = attr->private; + + data = nvmem_cell_read(cell, &len); + if (IS_ERR(data)) + return -EINVAL; + + len = min(len, count); + memcpy(buf, data, len); + kfree(data); + return len; +} +#endif + static void nvmem_release(struct device *dev) { struct nvmem_device *nvmem = to_nvmem_device(dev); @@ -107,6 +132,9 @@ static void nvmem_cell_drop(struct nvmem_cell *cell) { blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); mutex_lock(&nvmem_mutex); +#ifdef CONFIG_QCOM_QFPROM_SYSFS + device_remove_bin_file(&cell->nvmem->dev, &cell->attr); +#endif list_del(&cell->node); mutex_unlock(&nvmem_mutex); of_node_put(cell->np); @@ -124,8 +152,25 @@ static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) static void nvmem_cell_add(struct nvmem_cell *cell) { +#ifdef CONFIG_QCOM_QFPROM_SYSFS + int rval; + struct bin_attribute *nvmem_cell_attr = &cell->attr; +#endif mutex_lock(&nvmem_mutex); list_add_tail(&cell->node, &cell->nvmem->cells); + +#ifdef CONFIG_QCOM_QFPROM_SYSFS + /* add attr for this cell */ + nvmem_cell_attr->attr.name = cell->name; + nvmem_cell_attr->attr.mode = 0444; + nvmem_cell_attr->private = cell; + nvmem_cell_attr->size = cell->bytes; + nvmem_cell_attr->read = bin_attr_nvmem_cell_read; + rval = device_create_bin_file(&cell->nvmem->dev, nvmem_cell_attr); + if (rval) + dev_err(&cell->nvmem->dev, + "Failed to create cell binary file %d\n", rval); +#endif mutex_unlock(&nvmem_mutex); blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); }