{"id":807250,"url":"http://patchwork.ozlabs.org/api/patches/807250/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-mtd/patch/1504036047-38848-1-git-send-email-matthew.weber@rockwellcollins.com/","project":{"id":3,"url":"http://patchwork.ozlabs.org/api/projects/3/?format=json","name":"Linux MTD development","link_name":"linux-mtd","list_id":"linux-mtd.lists.infradead.org","list_email":"linux-mtd@lists.infradead.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<1504036047-38848-1-git-send-email-matthew.weber@rockwellcollins.com>","list_archive_url":null,"date":"2017-08-29T19:47:27","name":"[v2] mtd: map: new driver for NXP IFC","commit_ref":null,"pull_url":null,"state":"changes-requested","archived":false,"hash":"341408df4c09b53c0a8b6facc271c611dd72b066","submitter":{"id":64259,"url":"http://patchwork.ozlabs.org/api/people/64259/?format=json","name":"Matt Weber","email":"matthew.weber@rockwellcollins.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-mtd/patch/1504036047-38848-1-git-send-email-matthew.weber@rockwellcollins.com/mbox/","series":[{"id":452,"url":"http://patchwork.ozlabs.org/api/series/452/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-mtd/list/?series=452","date":"2017-08-29T19:47:27","name":"[v2] mtd: map: new driver for NXP IFC","version":2,"mbox":"http://patchwork.ozlabs.org/series/452/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/807250/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/807250/checks/","tags":{},"related":[],"headers":{"Return-Path":"<linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org; spf=none (mailfrom)\n\tsmtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133;\n\thelo=bombadil.infradead.org;\n\tenvelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)","ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org header.b=\"Z37mNPRY\"; \n\tdkim-atps=neutral"],"Received":["from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xhfLy0379z9sNc\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 30 Aug 2017 05:48:10 +1000 (AEST)","from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmmUN-0004Ae-69; Tue, 29 Aug 2017 19:47:55 +0000","from ch3vs04.rockwellcollins.com ([205.175.226.52])\n\tby bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dmmUI-00049P-DX\n\tfor linux-mtd@lists.infradead.org; Tue, 29 Aug 2017 19:47:53 +0000","from ofwch3n02.rockwellcollins.com (HELO\n\tcrulimr01.rockwellcollins.com) ([205.175.226.14])\n\tby ch3vs04.rockwellcollins.com with ESMTP; 29 Aug 2017 14:47:29 -0500"],"DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe:\n\tList-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date:\n\tSubject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:\n\tResent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:\n\tReferences:List-Owner; bh=bYAa31T9VMd7RNgODsu2MCx5dOW5W1NXPeYaWhowU6Q=;\n\tb=Z37\n\tmNPRY8rJwhVpS7b6l5itAvCAJ6wjb/rU3GFE1F0QjkNv9LBNPgPu7lGQ1fLhCcja5osNxnqPw5c+v\n\tNQvxCjaIDfgyRqc20Ip9+AjiLVHqvw9NLhHVu/jQ4Po9UwZHwib53Zru05wBXRBMnrt6q/6WosxCu\n\tJCQJG2hpfp1Z3qdK6sh2Dh1y/gDyIOW0ArTQ7zAOTu1I/xiX8KOqN+QKgoXD0u1ZJE/gpKqnEmva7\n\tf4Tvsc1R7T3Zx1m5UjuOYV6s2orax3wU7OzZ9f8rGNqOFtuOlcYnvSgZvfnz5+lh8jLNFvLloQGgv\n\tSf1pzcXVizd9iMTwa/Yemdo/XRazaxQ==;","X-Received":"from largo.rockwellcollins.com (unknown [192.168.140.76])\n\tby crulimr01.rockwellcollins.com (Postfix) with ESMTP id DB9766032C; \n\tTue, 29 Aug 2017 14:47:28 -0500 (CDT)","From":"Matt Weber <matthew.weber@rockwellcollins.com>","To":"linux-mtd@lists.infradead.org","Subject":"[PATCH v2] mtd: map: new driver for NXP IFC","Date":"Tue, 29 Aug 2017 14:47:27 -0500","Message-Id":"<1504036047-38848-1-git-send-email-matthew.weber@rockwellcollins.com>","X-Mailer":"git-send-email 1.9.1","X-CRM114-Version":"20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ","X-CRM114-CacheID":"sfid-20170829_124750_582057_CDC6E86E ","X-CRM114-Status":"GOOD (  23.39  )","X-Spam-Score":"-1.9 (-)","X-Spam-Report":"SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details:   (-1.9 points)\n\tpts rule name              description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-0.0 SPF_PASS               SPF: sender matches SPF record\n\t-0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay\n\tdomain\n\t-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]","X-BeenThere":"linux-mtd@lists.infradead.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"Linux MTD discussion mailing list <linux-mtd.lists.infradead.org>","List-Unsubscribe":"<http://lists.infradead.org/mailman/options/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=unsubscribe>","List-Archive":"<http://lists.infradead.org/pipermail/linux-mtd/>","List-Post":"<mailto:linux-mtd@lists.infradead.org>","List-Help":"<mailto:linux-mtd-request@lists.infradead.org?subject=help>","List-Subscribe":"<http://lists.infradead.org/mailman/listinfo/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>","Cc":"Matt Weber <matthew.weber@rockwellcollins.com>,\n\tboris.brezillon@free-electrons.com,\n\tSanjay Tandel <sanjay.tandel@rockwellcollins.com>, arnd@arndb.de","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"\"linux-mtd\" <linux-mtd-bounces@lists.infradead.org>","Errors-To":"linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"},"content":"From: Sanjay Tandel <sanjay.tandel@rockwellcollins.com>\n\nThis patch adds map driver for parallel flash chips interfaced over\na NXP Integrated Flash Controller (IFC). This driver allows either\n8-bit or 16-bit accesses, depending on bank-width, to parallel flash\nchips(like Everspin MR0A16A), which are physically mapped to CPU's\nmemory space. For unaligned accesses, it performs read-modify-write\noperations to keep access size same as bank-width.\n\nSigned-off-by: Sanjay Tandel <sanjay.tandel@rockwellcollins.com>\nSigned-off-by: Matt Weber <matthew.weber@rockwellcollins.com>\n---\n\nChanges\nv1 -> v2\n - Refactored driver to be custom for the IFC bus controllder\n  (Suggested by Boris)\n - Updated patch name\n - Cleaned up description to be specific about issue and behavior\n - Version 1 - https://patchwork.ozlabs.org/patch/797787/\n---\n Documentation/devicetree/bindings/mtd/ifc-mram.txt |  34 ++\n drivers/mtd/maps/Kconfig                           |  13 +\n drivers/mtd/maps/Makefile                          |   1 +\n drivers/mtd/maps/ifc_mram.c                        | 343 +++++++++++++++++++++\n 4 files changed, 391 insertions(+)\n create mode 100644 Documentation/devicetree/bindings/mtd/ifc-mram.txt\n create mode 100644 drivers/mtd/maps/ifc_mram.c","diff":"diff --git a/Documentation/devicetree/bindings/mtd/ifc-mram.txt b/Documentation/devicetree/bindings/mtd/ifc-mram.txt\nnew file mode 100644\nindex 0000000..c5c3210\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/mtd/ifc-mram.txt\n@@ -0,0 +1,34 @@\n+Integrated Flash Controller based physically-mapped parallel MRAM,\n+NOR flash, MTD-RAM (NVRAM...)\n+\n+ - compatible : should contain the specific model of mtd chip(s)\n+   used, if known, followed by \"ifc-mram\".\n+ - reg : Address range(s) of the mtd chip(s)\n+   It's possible to (optionally) define multiple \"reg\" tuples so that\n+   non-identical chips can be described in one node.\n+ - bank-width : Width (in bytes) of the bank.  Equal to the\n+   device width times the number of interleaved chips.\n+ - device-width : (optional) Width of a single mtd chip.  If\n+   omitted, assumed to be equal to 'bank-width'.\n+ - #address-cells, #size-cells : Must be present if the device has\n+   sub-nodes representing partitions (see below).  In this case\n+   both #address-cells and #size-cells must be equal to 1.\n+ - linux,mtd-name: allow to specify the mtd name.\n+\n+The device tree may optionally contain sub-nodes describing partitions of the\n+address space. See partition.txt for more detail.\n+\n+Example:\n+\n+        mram@1,0 {\n+                #address-cells = <1>;\n+                #size-cells = <1>;\n+                compatible = \"everspin,mram\", \"ifc-mram\";\n+                reg = <0x1 0x0 0x10000 0x1 0x10000 0x10000>;\n+                bank-width = <2>;\n+\n+                partition@0 {\n+                        reg = <0 0x00020000>;\n+                        label = \"MRAM Data 0\";\n+                };\n+        };\ndiff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig\nindex 542fdf8..95bd44e 100644\n--- a/drivers/mtd/maps/Kconfig\n+++ b/drivers/mtd/maps/Kconfig\n@@ -419,4 +419,17 @@ config MTD_LATCH_ADDR\n \n           If compiled as a module, it will be called latch-addr-flash.\n \n+config MTD_IFC_MRAM\n+\ttristate \"Map driver for Integrated Flash Controller\"\n+\tdepends on MTD_COMPLEX_MAPPINGS\n+\thelp\n+\t  Map driver for chips connected parallely to Integrated Flash\n+\t  Controller. This driver allows either 8-bit or 16-bit accesses,\n+\t  depending on bank-width, to parallel flash chips, which are\n+\t  physically mapped to CPU's memory space. For unaligned accesses,\n+\t  it does read-modify-write.\n+\t  Example: Everspin MR0A16A.\n+\n+\t  If compiled as a module, it will be called ifc-mram.\n+\n endmenu\ndiff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile\nindex 5a09a72..0ab793e 100644\n--- a/drivers/mtd/maps/Makefile\n+++ b/drivers/mtd/maps/Makefile\n@@ -47,3 +47,4 @@ obj-$(CONFIG_MTD_VMU)\t\t+= vmu-flash.o\n obj-$(CONFIG_MTD_GPIO_ADDR)\t+= gpio-addr-flash.o\n obj-$(CONFIG_MTD_LATCH_ADDR)\t+= latch-addr-flash.o\n obj-$(CONFIG_MTD_LANTIQ)\t+= lantiq-flash.o\n+obj-$(CONFIG_MTD_IFC_MRAM)\t+= ifc_mram.o\ndiff --git a/drivers/mtd/maps/ifc_mram.c b/drivers/mtd/maps/ifc_mram.c\nnew file mode 100644\nindex 0000000..1341e0a\n--- /dev/null\n+++ b/drivers/mtd/maps/ifc_mram.c\n@@ -0,0 +1,343 @@\n+/*\n+ * Integrated Flash Controlller Map Driver\n+ *\n+ * Copyright 2017 Rockwell Collins\n+ *\n+ * Aug 18 2017  Sanjay Tandel <sanjay.tandel@rockwellcollins.com>\n+ *\n+ * Based on:\n+ * Flash mappings described by the OF (or flattened) device tree\n+ *\n+ * Copyright (C) 2006 MontaVista Software Inc.\n+ * Author: Vitaly Wool <vwool@ru.mvista.com>\n+ *\n+ * Revised to handle newer style flash binding by:\n+ *   Copyright (C) 2007 David Gibson, IBM Corporation.\n+ *\n+ */\n+\n+#include <linux/module.h>\n+#include <linux/types.h>\n+#include <linux/device.h>\n+#include <linux/mtd/mtd.h>\n+#include <linux/mtd/map.h>\n+#include <linux/mtd/partitions.h>\n+#include <linux/mtd/concat.h>\n+#include <linux/of.h>\n+#include <linux/of_address.h>\n+#include <linux/of_platform.h>\n+#include <linux/slab.h>\n+\n+static const struct of_device_id ifc_mram_match[] = {\n+\t{\n+\t\t.compatible\t= \"ifc-mram\",\n+\t},\n+\t{}\n+};\n+MODULE_DEVICE_TABLE(of, ifc_mram_match);\n+struct ifc_mram_list {\n+\tstruct mtd_info *mtd;\n+\tstruct map_info map;\n+\tstruct resource *res;\n+};\n+\n+struct ifc_mram {\n+\tstruct mtd_info\t\t*cmtd;\n+\tint list_size; /* number of elements in ifc_mram_list */\n+\tstruct ifc_mram_list\tlist[0];\n+};\n+\n+\n+static void ifc_mram_copy_from8(void *to, void __iomem *from, size_t count)\n+{\n+\tu8 *t = to;\n+\n+\twhile (count > 0) {\n+\t\t*t = (u8)readb_relaxed(from);\n+\t\tt++;\n+\t\tfrom++;\n+\t\tcount--;\n+\t}\n+}\n+\n+static void ifc_mram_copy_from16(void *to, void __iomem *from, size_t count)\n+{\n+\tu8 *t = to;\n+\n+\tif (!(IS_ALIGNED((unsigned long)from, 2))) {\n+\t\tfrom = (void __iomem *)ALIGN((unsigned long)from, 2) - 2;\n+\t\t*(u8 *)t = (u8)((cpu_to_le16(readw_relaxed(from)) & 0xff00)\n+\t\t\t\t\t\t\t\t\t>> 8);\n+\t\tcount--;\n+\t\tt++;\n+\t\tfrom += 2;\n+\t}\n+\twhile (count >= 2) {\n+\t\t*(u16 *)t = cpu_to_le16(readw_relaxed(from));\n+\t\tcount -= 2;\n+\t\tt += 2;\n+\t\tfrom += 2;\n+\t};\n+\twhile (count > 0) {\n+\t\t*(u8 *)t = (u8)(cpu_to_le16(readw_relaxed(from)) & 0x00ff);\n+\t\tcount--;\n+\t\tt++;\n+\t\tfrom++;\n+\t}\n+}\n+\n+static void ifc_mram_copy_from(struct map_info *map, void *to,\n+\t\t\t\t\tunsigned long from, ssize_t len)\n+{\n+\tif (map->cached)\n+\t\tmemcpy(to, (char *)map->cached + from, len);\n+\telse if (map_bankwidth_is_1(map))\n+\t\tifc_mram_copy_from8(to, map->virt + from, len);\n+\telse if (map_bankwidth_is_2(map))\n+\t\tifc_mram_copy_from16(to, map->virt + from, len);\n+\telse\n+\t\tmemcpy_fromio(to, map->virt + from, len);\n+}\n+\n+static void ifc_mram_copy_to8(void __iomem *to, const void *from, size_t count)\n+{\n+\tconst unsigned char *f = from;\n+\n+\twhile (count > 0) {\n+\t\twriteb_relaxed(*f, to);\n+\t\tcount--;\n+\t\tto++;\n+\t\tf++;\n+\t}\n+}\n+\n+static void ifc_mram_copy_to16(void __iomem *to, const void *from, size_t count)\n+{\n+\tconst unsigned char *f = from;\n+\tu16 d;\n+\n+\tif (!(IS_ALIGNED((unsigned long)to, 2))) {\n+\t\tto = (void __iomem *)ALIGN((unsigned long)to, 2) - 2;\n+\t\td = (cpu_to_le16(readw_relaxed(to)) & 0x00ff)\n+\t\t\t\t\t| ((u16)(*(const u8 *)f) << 8);\n+\t\twritew_relaxed(le16_to_cpu(d), to);\n+\t\tcount--;\n+\t\tto += 2;\n+\t\tf++;\n+\t}\n+\twhile (count >= 2) {\n+\t\twritew_relaxed(le16_to_cpu(*(const u16 *)f), to);\n+\t\tcount -= 2;\n+\t\tto += 2;\n+\t\tf += 2;\n+\t};\n+\twhile (count > 0) {\n+\t\td = (cpu_to_le16(readw_relaxed(to)) & 0xff00)\n+\t\t\t\t\t| (u16)(*(const u8 *)f);\n+\t\twritew_relaxed(le16_to_cpu(d), to);\n+\t\tcount--;\n+\t\tto++;\n+\t\tf++;\n+\t}\n+}\n+\n+static void ifc_mram_copy_to(struct map_info *map, unsigned long to,\n+\t\t\t\t\tconst void *from, ssize_t len)\n+{\n+\tif (map_bankwidth_is_1(map))\n+\t\tifc_mram_copy_to8(map->virt + to, from, len);\n+\telse if (map_bankwidth_is_2(map))\n+\t\tifc_mram_copy_to16(map->virt + to, from, len);\n+\telse\n+\t\tmemcpy_toio(map->virt + to, from, len);\n+}\n+static int ifc_mram_remove(struct platform_device *dev)\n+{\n+\tstruct ifc_mram *info;\n+\tint i;\n+\n+\tinfo = dev_get_drvdata(&dev->dev);\n+\tif (!info)\n+\t\treturn 0;\n+\tdev_set_drvdata(&dev->dev, NULL);\n+\n+\tif (info->cmtd) {\n+\t\tmtd_device_unregister(info->cmtd);\n+\t\tif (info->cmtd != info->list[0].mtd)\n+\t\t\tmtd_concat_destroy(info->cmtd);\n+\t}\n+\n+\tfor (i = 0; i < info->list_size; i++) {\n+\t\tif (info->list[i].mtd)\n+\t\t\tmap_destroy(info->list[i].mtd);\n+\n+\t\tif (info->list[i].map.virt)\n+\t\t\tiounmap(info->list[i].map.virt);\n+\n+\t\tif (info->list[i].res) {\n+\t\t\trelease_resource(info->list[i].res);\n+\t\t\tkfree(info->list[i].res);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int ifc_mram_probe(struct platform_device *dev)\n+{\n+\tconst struct of_device_id *match;\n+\tstruct device_node *dp = dev->dev.of_node;\n+\tstruct resource res;\n+\tstruct ifc_mram *info;\n+\tconst __be32 *width;\n+\tint err;\n+\tint i;\n+\tint count;\n+\tconst __be32 *p;\n+\tint reg_tuple_size;\n+\tstruct mtd_info **mtd_list = NULL;\n+\tresource_size_t res_size;\n+\tstruct mtd_part_parser_data ppdata;\n+\tbool map_indirect;\n+\tconst char *mtd_name = NULL;\n+\n+\tmatch = of_match_device(ifc_mram_match, &dev->dev);\n+\tif (!match) {\n+\t\tpr_info(\"%s: compatible string not matched\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\treg_tuple_size =\n+\t\t(of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);\n+\n+\tof_property_read_string(dp, \"linux,mtd-name\", &mtd_name);\n+\n+\tp = of_get_property(dp, \"reg\", &count);\n+\tif (count % reg_tuple_size != 0) {\n+\t\tdev_err(&dev->dev, \"Malformed reg property on %s\\n\",\n+\t\t\t\tdev->dev.of_node->full_name);\n+\t\terr = -EINVAL;\n+\t\tgoto err_flash_remove;\n+\t}\n+\tcount /= reg_tuple_size;\n+\n+\terr = -ENOMEM;\n+\tinfo = devm_kzalloc(&dev->dev,\n+\t\t\t    sizeof(struct ifc_mram) +\n+\t\t\t    sizeof(struct ifc_mram_list) * count, GFP_KERNEL);\n+\tif (!info)\n+\t\tgoto err_flash_remove;\n+\n+\tdev_set_drvdata(&dev->dev, info);\n+\n+\tmtd_list = kcalloc(count, sizeof(*mtd_list), GFP_KERNEL);\n+\tif (!mtd_list)\n+\t\tgoto err_flash_remove;\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\terr = -ENXIO;\n+\t\tif (of_address_to_resource(dp, i, &res)) {\n+\t\t\t/*\n+\t\t\t * Continue with next register tuple if this\n+\t\t\t * one is not mappable\n+\t\t\t */\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tdev_dbg(&dev->dev, \"ifc_mram device: %pR\\n\", &res);\n+\n+\t\terr = -EBUSY;\n+\t\tres_size = resource_size(&res);\n+\t\tinfo->list[i].res = request_mem_region(res.start, res_size,\n+\t\t\t\t\t\t       dev_name(&dev->dev));\n+\t\tif (!info->list[i].res)\n+\t\t\tgoto err_out;\n+\n+\t\terr = -ENXIO;\n+\t\twidth = of_get_property(dp, \"bank-width\", NULL);\n+\t\tif (!width) {\n+\t\t\tdev_err(&dev->dev,\n+\t\t\t\t\"Can't get bank width from device tree\\n\");\n+\t\t\tgoto err_out;\n+\t\t}\n+\n+\t\tinfo->list[i].map.name = mtd_name ?: dev_name(&dev->dev);\n+\t\tinfo->list[i].map.phys = res.start;\n+\t\tinfo->list[i].map.size = res_size;\n+\t\tinfo->list[i].map.bankwidth = be32_to_cpup(width);\n+\t\tinfo->list[i].map.device_node = dp;\n+\n+\t\terr = -ENOMEM;\n+\t\tinfo->list[i].map.virt = ioremap(info->list[i].map.phys,\n+\t\t\t\t\t\t info->list[i].map.size);\n+\t\tif (!info->list[i].map.virt) {\n+\t\t\tdev_err(&dev->dev,\n+\t\t\t\t\"Failed to ioremap() flash region\\n\");\n+\t\t\tgoto err_out;\n+\t\t}\n+\n+\t\tsimple_map_init(&info->list[i].map);\n+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS\n+\t\tinfo->list[i].map.copy_from = ifc_mram_copy_from;\n+\t\tinfo->list[i].map.copy_to = ifc_mram_copy_to;\n+#endif\n+\n+\n+\t\tinfo->list[i].mtd = do_map_probe(\"map_ram\",\n+\t\t\t\t\t\t\t &info->list[i].map);\n+\t\tmtd_list[i] = info->list[i].mtd;\n+\n+\t\terr = -ENXIO;\n+\t\tif (!info->list[i].mtd) {\n+\t\t\tdev_err(&dev->dev, \"do_map_probe() failed\\n\");\n+\t\t\tgoto err_out;\n+\t\t} else {\n+\t\t\tinfo->list_size++;\n+\t\t}\n+\t\tinfo->list[i].mtd->owner = THIS_MODULE;\n+\t\tinfo->list[i].mtd->dev.parent = &dev->dev;\n+\t}\n+\n+\terr = 0;\n+\tinfo->cmtd = NULL;\n+\tif (info->list_size == 1) {\n+\t\tinfo->cmtd = info->list[0].mtd;\n+\t} else if (info->list_size > 1) {\n+\t\t/*\n+\t\t * We detected multiple devices. Concatenate them together.\n+\t\t */\n+\t\tinfo->cmtd = mtd_concat_create(mtd_list, info->list_size,\n+\t\t\t\t\t       dev_name(&dev->dev));\n+\t}\n+\tif (info->cmtd == NULL)\n+\t\terr = -ENXIO;\n+\n+\tif (err)\n+\t\tgoto err_out;\n+\n+\tppdata.of_node = dp;\n+\tmtd_device_parse_register(info->cmtd, NULL, &ppdata, NULL, 0);\n+\tkfree(mtd_list);\n+\treturn 0;\n+\n+err_out:\n+\tkfree(mtd_list);\n+err_flash_remove:\n+\tifc_mram_remove(dev);\n+\n+\treturn err;\n+}\n+\n+\n+static struct platform_driver ifc_mram_driver = {\n+\t.driver = {\n+\t\t.name = \"ifc-mram\",\n+\t\t.of_match_table = ifc_mram_match,\n+\t},\n+\t.probe\t\t= ifc_mram_probe,\n+\t.remove\t\t= ifc_mram_remove,\n+};\n+\n+module_platform_driver(ifc_mram_driver);\n+\n+MODULE_LICENSE(\"GPL v2\");\n+MODULE_AUTHOR(\"Sanjay Tandel\");\n+MODULE_DESCRIPTION(\"IFC MRAM Map Driver\");\n","prefixes":["v2"]}