mutex_init(&mtd->master.chrdev_lock);
 }
 
+static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user)
+{
+       struct otp_info *info = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t size = 0;
+       unsigned int i;
+       size_t retlen;
+       int ret;
+
+       if (is_user)
+               ret = mtd_get_user_prot_info(mtd, PAGE_SIZE, &retlen, info);
+       else
+               ret = mtd_get_fact_prot_info(mtd, PAGE_SIZE, &retlen, info);
+       if (ret)
+               goto err;
+
+       for (i = 0; i < retlen / sizeof(*info); i++) {
+               size += info->length;
+               info++;
+       }
+
+       kfree(info);
+       return size;
+
+err:
+       kfree(info);
+       return ret;
+}
+
+static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
+                                                  const char *compatible,
+                                                  int size,
+                                                  nvmem_reg_read_t reg_read)
+{
+       struct nvmem_device *nvmem = NULL;
+       struct nvmem_config config = {};
+       struct device_node *np;
+
+       /* DT binding is optional */
+       np = of_get_compatible_child(mtd->dev.of_node, compatible);
+
+       /* OTP nvmem will be registered on the physical device */
+       config.dev = mtd->dev.parent;
+       /* just reuse the compatible as name */
+       config.name = compatible;
+       config.id = NVMEM_DEVID_NONE;
+       config.owner = THIS_MODULE;
+       config.type = NVMEM_TYPE_OTP;
+       config.root_only = true;
+       config.reg_read = reg_read;
+       config.size = size;
+       config.of_node = np;
+       config.priv = mtd;
+
+       nvmem = nvmem_register(&config);
+       /* Just ignore if there is no NVMEM support in the kernel */
+       if (IS_ERR(nvmem) && PTR_ERR(nvmem) == -EOPNOTSUPP)
+               nvmem = NULL;
+
+       of_node_put(np);
+
+       return nvmem;
+}
+
+static int mtd_nvmem_user_otp_reg_read(void *priv, unsigned int offset,
+                                      void *val, size_t bytes)
+{
+       struct mtd_info *mtd = priv;
+       size_t retlen;
+       int ret;
+
+       ret = mtd_read_user_prot_reg(mtd, offset, bytes, &retlen, val);
+       if (ret)
+               return ret;
+
+       return retlen == bytes ? 0 : -EIO;
+}
+
+static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset,
+                                      void *val, size_t bytes)
+{
+       struct mtd_info *mtd = priv;
+       size_t retlen;
+       int ret;
+
+       ret = mtd_read_fact_prot_reg(mtd, offset, bytes, &retlen, val);
+       if (ret)
+               return ret;
+
+       return retlen == bytes ? 0 : -EIO;
+}
+
+static int mtd_otp_nvmem_add(struct mtd_info *mtd)
+{
+       struct nvmem_device *nvmem;
+       ssize_t size;
+       int err;
+
+       if (mtd->_get_user_prot_info && mtd->_read_user_prot_reg) {
+               size = mtd_otp_size(mtd, true);
+               if (size < 0)
+                       return size;
+
+               if (size > 0) {
+                       nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size,
+                                                      mtd_nvmem_user_otp_reg_read);
+                       if (IS_ERR(nvmem)) {
+                               dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
+                               return PTR_ERR(nvmem);
+                       }
+                       mtd->otp_user_nvmem = nvmem;
+               }
+       }
+
+       if (mtd->_get_fact_prot_info && mtd->_read_fact_prot_reg) {
+               size = mtd_otp_size(mtd, false);
+               if (size < 0) {
+                       err = size;
+                       goto err;
+               }
+
+               if (size > 0) {
+                       nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size,
+                                                      mtd_nvmem_fact_otp_reg_read);
+                       if (IS_ERR(nvmem)) {
+                               dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
+                               err = PTR_ERR(nvmem);
+                               goto err;
+                       }
+                       mtd->otp_factory_nvmem = nvmem;
+               }
+       }
+
+       return 0;
+
+err:
+       if (mtd->otp_user_nvmem)
+               nvmem_unregister(mtd->otp_user_nvmem);
+       return err;
+}
+
 /**
  * mtd_device_parse_register - parse partitions and register an MTD device.
  *
                register_reboot_notifier(&mtd->reboot_notifier);
        }
 
+       ret = mtd_otp_nvmem_add(mtd);
+
 out:
        if (ret && device_is_registered(&mtd->dev))
                del_mtd_device(mtd);
        if (master->_reboot)
                unregister_reboot_notifier(&master->reboot_notifier);
 
+       if (master->otp_user_nvmem)
+               nvmem_unregister(master->otp_user_nvmem);
+
+       if (master->otp_factory_nvmem)
+               nvmem_unregister(master->otp_factory_nvmem);
+
        err = del_mtd_partitions(master);
        if (err)
                return err;