1 From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001
2 From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
3 Date: Sat, 25 Aug 2018 12:35:22 +0200
4 Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices
6 Some mtd drivers like physmap variants have support for concatenating
7 multiple mtd devices, but there is no generic way to define such a
8 concat device from within the device tree.
10 This is useful for some SoC boards that use multiple flash chips as
11 memory banks of a single mtd device, with partitions spanning chip
14 This commit adds a driver for creating virtual mtd-concat devices. They
15 must have a compatible = "mtd-concat" line, and define a list of devices
16 to concat in the 'devices' property, for example:
19 compatible = "mtd-concat";
21 devices = <&flash0 &flash1>;
28 The driver is added to the very end of the mtd Makefile to increase the
29 likelyhood of all child devices already being loaded at the time of
30 probing, preventing unnecessary deferred probes.
32 Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
34 drivers/mtd/Kconfig | 2 +
35 drivers/mtd/Makefile | 3 +
36 drivers/mtd/composite/Kconfig | 12 +++
37 drivers/mtd/composite/Makefile | 6 ++
38 drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++
39 5 files changed, 151 insertions(+)
40 create mode 100644 drivers/mtd/composite/Kconfig
41 create mode 100644 drivers/mtd/composite/Makefile
42 create mode 100644 drivers/mtd/composite/virt_concat.c
44 --- a/drivers/mtd/Kconfig
45 +++ b/drivers/mtd/Kconfig
46 @@ -374,4 +374,6 @@ source "drivers/mtd/spi-nor/Kconfig"
48 source "drivers/mtd/ubi/Kconfig"
50 +source "drivers/mtd/composite/Kconfig"
53 --- a/drivers/mtd/Makefile
54 +++ b/drivers/mtd/Makefile
55 @@ -39,3 +39,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n
57 obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
58 obj-$(CONFIG_MTD_UBI) += ubi/
60 +# Composite drivers must be loaded last
63 +++ b/drivers/mtd/composite/Kconfig
65 +menu "Composite MTD device drivers"
68 +config MTD_VIRT_CONCAT
69 + tristate "Virtual concat MTD device"
71 + This driver allows creation of a virtual MTD concat device, which
72 + concatenates multiple underlying MTD devices to a single device.
73 + This is required by some SoC boards where multiple memory banks are
74 + used as one device with partitions spanning across device boundaries.
78 +++ b/drivers/mtd/composite/Makefile
80 +# SPDX-License-Identifier: GPL-2.0
82 +# linux/drivers/mtd/composite/Makefile
85 +obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o
87 +++ b/drivers/mtd/composite/virt_concat.c
89 +// SPDX-License-Identifier: GPL-2.0+
91 + * Virtual concat MTD device driver
93 + * Copyright (C) 2018 Bernhard Frauendienst
94 + * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de
97 +#include <linux/module.h>
98 +#include <linux/device.h>
99 +#include <linux/mtd/concat.h>
100 +#include <linux/mtd/mtd.h>
101 +#include <linux/mtd/partitions.h>
102 +#include <linux/of.h>
103 +#include <linux/of_platform.h>
104 +#include <linux/slab.h>
107 + * struct of_virt_concat - platform device driver data.
108 + * @cmtd the final mtd_concat device
109 + * @num_devices the number of devices in @devices
110 + * @devices points to an array of devices already loaded
112 +struct of_virt_concat {
113 + struct mtd_info *cmtd;
115 + struct mtd_info **devices;
118 +static int virt_concat_remove(struct platform_device *pdev)
120 + struct of_virt_concat *info;
123 + info = platform_get_drvdata(pdev);
127 + // unset data for when this is called after a probe error
128 + platform_set_drvdata(pdev, NULL);
131 + mtd_device_unregister(info->cmtd);
132 + mtd_concat_destroy(info->cmtd);
135 + if (info->devices) {
136 + for (i = 0; i < info->num_devices; i++)
137 + put_mtd_device(info->devices[i]);
143 +static int virt_concat_probe(struct platform_device *pdev)
145 + struct device_node *node = pdev->dev.of_node;
146 + struct of_phandle_iterator it;
147 + struct of_virt_concat *info;
148 + struct mtd_info *mtd;
149 + int err = 0, count;
151 + count = of_count_phandle_with_args(node, "devices", NULL);
155 + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
158 + info->devices = devm_kcalloc(&pdev->dev, count,
159 + sizeof(*(info->devices)), GFP_KERNEL);
160 + if (!info->devices) {
165 + platform_set_drvdata(pdev, info);
167 + of_for_each_phandle(&it, err, node, "devices", NULL, 0) {
168 + mtd = get_mtd_device_by_node(it.node);
170 + of_node_put(it.node);
171 + err = -EPROBE_DEFER;
175 + info->devices[info->num_devices++] = mtd;
178 + info->cmtd = mtd_concat_create(info->devices, info->num_devices,
179 + dev_name(&pdev->dev));
185 + info->cmtd->dev.parent = &pdev->dev;
186 + mtd_set_of_node(info->cmtd, node);
187 + mtd_device_register(info->cmtd, NULL, 0);
192 + virt_concat_remove(pdev);
197 +static const struct of_device_id virt_concat_of_match[] = {
198 + { .compatible = "mtd-concat", },
201 +MODULE_DEVICE_TABLE(of, virt_concat_of_match);
203 +static struct platform_driver virt_concat_driver = {
204 + .probe = virt_concat_probe,
205 + .remove = virt_concat_remove,
207 + .name = "virt-mtdconcat",
208 + .of_match_table = virt_concat_of_match,
212 +module_platform_driver(virt_concat_driver);
214 +MODULE_LICENSE("GPL v2");
215 +MODULE_AUTHOR("Bernhard Frauendienst <kernel@nospam.obeliks.de>");
216 +MODULE_DESCRIPTION("Virtual concat MTD device driver");