123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001
- From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
- Date: Sat, 25 Aug 2018 12:35:22 +0200
- Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices
- Some mtd drivers like physmap variants have support for concatenating
- multiple mtd devices, but there is no generic way to define such a
- concat device from within the device tree.
- This is useful for some SoC boards that use multiple flash chips as
- memory banks of a single mtd device, with partitions spanning chip
- borders.
- This commit adds a driver for creating virtual mtd-concat devices. They
- must have a compatible = "mtd-concat" line, and define a list of devices
- to concat in the 'devices' property, for example:
- flash {
- compatible = "mtd-concat";
- devices = <&flash0 &flash1>;
- partitions {
- ...
- };
- };
- The driver is added to the very end of the mtd Makefile to increase the
- likelyhood of all child devices already being loaded at the time of
- probing, preventing unnecessary deferred probes.
- Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
- ---
- drivers/mtd/Kconfig | 2 +
- drivers/mtd/Makefile | 3 +
- drivers/mtd/composite/Kconfig | 12 +++
- drivers/mtd/composite/Makefile | 6 ++
- drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++
- 5 files changed, 151 insertions(+)
- create mode 100644 drivers/mtd/composite/Kconfig
- create mode 100644 drivers/mtd/composite/Makefile
- create mode 100644 drivers/mtd/composite/virt_concat.c
- --- a/drivers/mtd/Kconfig
- +++ b/drivers/mtd/Kconfig
- @@ -377,4 +377,6 @@ source "drivers/mtd/spi-nor/Kconfig"
-
- source "drivers/mtd/ubi/Kconfig"
-
- +source "drivers/mtd/composite/Kconfig"
- +
- endif # MTD
- --- a/drivers/mtd/Makefile
- +++ b/drivers/mtd/Makefile
- @@ -39,3 +39,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n
-
- obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
- obj-$(CONFIG_MTD_UBI) += ubi/
- +
- +# Composite drivers must be loaded last
- +obj-y += composite/
- --- /dev/null
- +++ b/drivers/mtd/composite/Kconfig
- @@ -0,0 +1,12 @@
- +menu "Composite MTD device drivers"
- + depends on MTD!=n
- +
- +config MTD_VIRT_CONCAT
- + tristate "Virtual concat MTD device"
- + help
- + This driver allows creation of a virtual MTD concat device, which
- + concatenates multiple underlying MTD devices to a single device.
- + This is required by some SoC boards where multiple memory banks are
- + used as one device with partitions spanning across device boundaries.
- +
- +endmenu
- --- /dev/null
- +++ b/drivers/mtd/composite/Makefile
- @@ -0,0 +1,6 @@
- +# SPDX-License-Identifier: GPL-2.0
- +#
- +# linux/drivers/mtd/composite/Makefile
- +#
- +
- +obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o
- --- /dev/null
- +++ b/drivers/mtd/composite/virt_concat.c
- @@ -0,0 +1,128 @@
- +// SPDX-License-Identifier: GPL-2.0+
- +/*
- + * Virtual concat MTD device driver
- + *
- + * Copyright (C) 2018 Bernhard Frauendienst
- + * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de
- + */
- +
- +#include <linux/module.h>
- +#include <linux/device.h>
- +#include <linux/mtd/concat.h>
- +#include <linux/mtd/mtd.h>
- +#include <linux/mtd/partitions.h>
- +#include <linux/of.h>
- +#include <linux/of_platform.h>
- +#include <linux/slab.h>
- +
- +/*
- + * struct of_virt_concat - platform device driver data.
- + * @cmtd the final mtd_concat device
- + * @num_devices the number of devices in @devices
- + * @devices points to an array of devices already loaded
- + */
- +struct of_virt_concat {
- + struct mtd_info *cmtd;
- + int num_devices;
- + struct mtd_info **devices;
- +};
- +
- +static int virt_concat_remove(struct platform_device *pdev)
- +{
- + struct of_virt_concat *info;
- + int i;
- +
- + info = platform_get_drvdata(pdev);
- + if (!info)
- + return 0;
- +
- + // unset data for when this is called after a probe error
- + platform_set_drvdata(pdev, NULL);
- +
- + if (info->cmtd) {
- + mtd_device_unregister(info->cmtd);
- + mtd_concat_destroy(info->cmtd);
- + }
- +
- + if (info->devices) {
- + for (i = 0; i < info->num_devices; i++)
- + put_mtd_device(info->devices[i]);
- + }
- +
- + return 0;
- +}
- +
- +static int virt_concat_probe(struct platform_device *pdev)
- +{
- + struct device_node *node = pdev->dev.of_node;
- + struct of_phandle_iterator it;
- + struct of_virt_concat *info;
- + struct mtd_info *mtd;
- + int err = 0, count;
- +
- + count = of_count_phandle_with_args(node, "devices", NULL);
- + if (count <= 0)
- + return -EINVAL;
- +
- + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
- + if (!info)
- + return -ENOMEM;
- + info->devices = devm_kcalloc(&pdev->dev, count,
- + sizeof(*(info->devices)), GFP_KERNEL);
- + if (!info->devices) {
- + err = -ENOMEM;
- + goto err_remove;
- + }
- +
- + platform_set_drvdata(pdev, info);
- +
- + of_for_each_phandle(&it, err, node, "devices", NULL, 0) {
- + mtd = get_mtd_device_by_node(it.node);
- + if (IS_ERR(mtd)) {
- + of_node_put(it.node);
- + err = -EPROBE_DEFER;
- + goto err_remove;
- + }
- +
- + info->devices[info->num_devices++] = mtd;
- + }
- +
- + info->cmtd = mtd_concat_create(info->devices, info->num_devices,
- + dev_name(&pdev->dev));
- + if (!info->cmtd) {
- + err = -ENXIO;
- + goto err_remove;
- + }
- +
- + info->cmtd->dev.parent = &pdev->dev;
- + mtd_set_of_node(info->cmtd, node);
- + mtd_device_register(info->cmtd, NULL, 0);
- +
- + return 0;
- +
- +err_remove:
- + virt_concat_remove(pdev);
- +
- + return err;
- +}
- +
- +static const struct of_device_id virt_concat_of_match[] = {
- + { .compatible = "mtd-concat", },
- + { /* sentinel */ }
- +};
- +MODULE_DEVICE_TABLE(of, virt_concat_of_match);
- +
- +static struct platform_driver virt_concat_driver = {
- + .probe = virt_concat_probe,
- + .remove = virt_concat_remove,
- + .driver = {
- + .name = "virt-mtdconcat",
- + .of_match_table = virt_concat_of_match,
- + },
- +};
- +
- +module_platform_driver(virt_concat_driver);
- +
- +MODULE_LICENSE("GPL v2");
- +MODULE_AUTHOR("Bernhard Frauendienst <kernel@nospam.obeliks.de>");
- +MODULE_DESCRIPTION("Virtual concat MTD device driver");
|