]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
mtd: add support for reading MTD devices via the nvmem API
authorAlban Bedel <albeu@free.fr>
Tue, 13 Nov 2018 14:01:10 +0000 (15:01 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Dec 2018 14:48:54 +0000 (15:48 +0100)
Allow drivers that use the nvmem API to read data stored on MTD devices.
For this the mtd devices are registered as read-only NVMEM providers.

We don't support device tree systems for now.

Signed-off-by: Alban Bedel <albeu@free.fr>
[Bartosz:
  - include linux/nvmem-provider.h
  - set the name of the nvmem provider
  - set no_of_node to true in nvmem_config
  - don't check the return value of nvmem_unregister() - it cannot fail
  - tweaked the commit message]
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Acked-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mtd/Kconfig
drivers/mtd/mtdcore.c
include/linux/mtd/mtd.h

index c77f537323ecb371d1be527df650bf6fb8ca4713..efbe7a6f1d8ff3e5c5f98b86003da69234d0f44a 100644 (file)
@@ -1,5 +1,6 @@
 menuconfig MTD
        tristate "Memory Technology Device (MTD) support"
+       imply NVMEM
        help
          Memory Technology Devices are flash, RAM and similar chips, often
          used for solid state file systems on embedded devices. This option
index 97ac219c082e7ef78993084ffcc8c9e98abaaac4..5f1053d995b083f43e203efd691c5011a286c27d 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/reboot.h>
 #include <linux/leds.h>
 #include <linux/debugfs.h>
+#include <linux/nvmem-provider.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -488,6 +489,50 @@ int mtd_pairing_groups(struct mtd_info *mtd)
 }
 EXPORT_SYMBOL_GPL(mtd_pairing_groups);
 
+static int mtd_nvmem_reg_read(void *priv, unsigned int offset,
+                             void *val, size_t bytes)
+{
+       struct mtd_info *mtd = priv;
+       size_t retlen;
+       int err;
+
+       err = mtd_read(mtd, offset, bytes, &retlen, val);
+       if (err && err != -EUCLEAN)
+               return err;
+
+       return retlen == bytes ? 0 : -EIO;
+}
+
+static int mtd_nvmem_add(struct mtd_info *mtd)
+{
+       struct nvmem_config config = {};
+
+       config.dev = &mtd->dev;
+       config.name = mtd->name;
+       config.owner = THIS_MODULE;
+       config.reg_read = mtd_nvmem_reg_read;
+       config.size = mtd->size;
+       config.word_size = 1;
+       config.stride = 1;
+       config.read_only = true;
+       config.root_only = true;
+       config.no_of_node = true;
+       config.priv = mtd;
+
+       mtd->nvmem = nvmem_register(&config);
+       if (IS_ERR(mtd->nvmem)) {
+               /* Just ignore if there is no NVMEM support in the kernel */
+               if (PTR_ERR(mtd->nvmem) == -ENOSYS) {
+                       mtd->nvmem = NULL;
+               } else {
+                       dev_err(&mtd->dev, "Failed to register NVMEM device\n");
+                       return PTR_ERR(mtd->nvmem);
+               }
+       }
+
+       return 0;
+}
+
 static struct dentry *dfs_dir_mtd;
 
 /**
@@ -570,6 +615,11 @@ int add_mtd_device(struct mtd_info *mtd)
        if (error)
                goto fail_added;
 
+       /* Add the nvmem provider */
+       error = mtd_nvmem_add(mtd);
+       if (error)
+               goto fail_nvmem_add;
+
        if (!IS_ERR_OR_NULL(dfs_dir_mtd)) {
                mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd);
                if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) {
@@ -595,6 +645,8 @@ int add_mtd_device(struct mtd_info *mtd)
        __module_get(THIS_MODULE);
        return 0;
 
+fail_nvmem_add:
+       device_unregister(&mtd->dev);
 fail_added:
        of_node_put(mtd_get_of_node(mtd));
        idr_remove(&mtd_idr, i);
@@ -637,6 +689,10 @@ int del_mtd_device(struct mtd_info *mtd)
                       mtd->index, mtd->name, mtd->usecount);
                ret = -EBUSY;
        } else {
+               /* Try to remove the NVMEM provider */
+               if (mtd->nvmem)
+                       nvmem_unregister(mtd->nvmem);
+
                device_unregister(&mtd->dev);
 
                idr_remove(&mtd_idr, mtd->index);
index cd0be91bdefa55f568253904c7d374751fffac52..545070c2ee6473b2d395c69716df0198b6b0d4f1 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/notifier.h>
 #include <linux/device.h>
 #include <linux/of.h>
+#include <linux/nvmem-provider.h>
 
 #include <mtd/mtd-abi.h>
 
@@ -341,6 +342,7 @@ struct mtd_info {
        struct device dev;
        int usecount;
        struct mtd_debug_info dbg;
+       struct nvmem_device *nvmem;
 };
 
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,