Allow creating gpio-addr-flash via device-tree and not just via platform
data.

Mimic what physmap_of_versatile and physmap_of_gemini does to reduce
code duplicity.

Signed-off-by: Ricardo Ribalda Delgado <ricardo.riba...@gmail.com>
---
 drivers/mtd/maps/Kconfig           |  8 +++
 drivers/mtd/maps/Makefile          |  3 +-
 drivers/mtd/maps/gpio-addr-flash.c | 95 +++++++++++++++++++-----------
 drivers/mtd/maps/gpio-addr-flash.h | 34 +++++++++++
 drivers/mtd/maps/physmap_of_core.c |  5 ++
 drivers/mtd/maps/physmap_of_gpio.c | 21 +++++++
 6 files changed, 129 insertions(+), 37 deletions(-)
 create mode 100644 drivers/mtd/maps/gpio-addr-flash.h
 create mode 100644 drivers/mtd/maps/physmap_of_gpio.c

diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index afb36bff13a7..427143d42168 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -94,6 +94,14 @@ config MTD_PHYSMAP_OF_GEMINI
          platforms, some detection and setting up parallel mode on the
          external interface.
 
+config MTD_PHYSMAP_OF_GPIO
+       bool "GPIO-assisted OF-based physical memory map handling"
+       depends on MTD_PHYSMAP_OF
+       depends on MTD_GPIO_ADDR
+       help
+         This provides some extra DT physmap parsing for flashes that are
+         partially physically addressed and assisted by GPIOs.
+
 config MTD_PMC_MSP_EVM
        tristate "CFI Flash device mapped on PMC-Sierra MSP"
        depends on PMC_MSP && MTD_CFI
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 51acf1fec19b..c232ccf05bee 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_MTD_PHYSMAP)     += physmap.o
 physmap_of-objs-y              += physmap_of_core.o
 physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_VERSATILE) += physmap_of_versatile.o
 physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_GEMINI) += physmap_of_gemini.o
+physmap_of-objs-$(CONFIG_MTD_PHYSMAP_OF_GPIO) += physmap_of_gpio.o
 physmap_of-objs                        := $(physmap_of-objs-y)
 obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
 obj-$(CONFIG_MTD_PISMO)                += pismo.o
@@ -44,6 +45,6 @@ obj-$(CONFIG_MTD_PLATRAM)     += plat-ram.o
 obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
 obj-$(CONFIG_MTD_RBTX4939)     += rbtx4939-flash.o
 obj-$(CONFIG_MTD_VMU)          += vmu-flash.o
-obj-$(CONFIG_MTD_GPIO_ADDR)    += gpio-addr-flash.o
+obj-$(CONFIG_MTD_GPIO_ADDR)    += gpio-addr-flash.o
 obj-$(CONFIG_MTD_LATCH_ADDR)   += latch-addr-flash.o
 obj-$(CONFIG_MTD_LANTIQ)       += lantiq-flash.o
diff --git a/drivers/mtd/maps/gpio-addr-flash.c 
b/drivers/mtd/maps/gpio-addr-flash.c
index a20e85aa770e..0d1f66aedf77 100644
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ b/drivers/mtd/maps/gpio-addr-flash.c
@@ -25,25 +25,25 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include "gpio-addr-flash.h"
 
 #define win_mask(x) ((BIT(x)) - 1)
 
 #define DRIVER_NAME "gpio-addr-flash"
 
+#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
+
 /**
- * struct async_state - keep GPIO flash state
+ * struct async_state_pdev - Async state platform device
  *     @mtd:         MTD state for this mapping
  *     @map:         MTD map state for this flash
  *     @gpios:       Struct containing the array of GPIO descriptors
- *     @gpio_values: cached GPIO values
- *     @win_order:   dedicated memory size (if no GPIOs)
+ *     @state:       GPIO flash state
  */
-struct async_state {
+struct async_state_pdev {
        struct mtd_info *mtd;
        struct map_info map;
-       struct gpio_descs *gpios;
-       unsigned int gpio_values;
-       unsigned int win_order;
+       struct async_state state;
 };
 #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
 
@@ -174,6 +174,35 @@ static void gf_copy_to(struct map_info *map, unsigned long 
to,
 static const char * const part_probe_types[] = {
        "cmdlinepart", "RedBoot", NULL };
 
+int gpio_flash_probe_common(struct device *dev, struct async_state *state,
+                           struct map_info *map)
+{
+       if (!is_power_of_2(map->size)) {
+               dev_err(dev, "Window size must be aligned\n");
+               return -EIO;
+       }
+
+       state->gpios = devm_gpiod_get_array_optional(dev, "addr",
+                                                    GPIOD_OUT_LOW);
+       if (!state->gpios)
+               return 0;
+
+       if (IS_ERR(state->gpios))
+               return PTR_ERR(state->gpios);
+
+       state->win_order  = get_bitmask_order(map->size) - 1;
+       map->read       = gf_read;
+       map->copy_from  = gf_copy_from;
+       map->write      = gf_write;
+       map->copy_to    = gf_copy_to;
+       map->size       = BIT(state->win_order + state->gpios->ndescs);
+       map->phys       = NO_XIP;
+       map->map_priv_1 = (unsigned long)state;
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_flash_probe_common);
+
 /**
  * gpio_flash_probe() - setup a mapping for a GPIO assisted flash
  *     @pdev: platform device
@@ -210,7 +239,8 @@ static int gpio_flash_probe(struct platform_device *pdev)
 {
        struct physmap_flash_data *pdata;
        struct resource *memory;
-       struct async_state *state;
+       struct async_state_pdev *state_pdev;
+       int ret;
 
        pdata = dev_get_platdata(&pdev->dev);
        memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -218,40 +248,33 @@ static int gpio_flash_probe(struct platform_device *pdev)
        if (!memory)
                return -EINVAL;
 
-       state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
-       if (!state)
+       state_pdev = devm_kzalloc(&pdev->dev, sizeof(*state_pdev), GFP_KERNEL);
+       if (!state_pdev)
                return -ENOMEM;
 
-       state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
-       if (IS_ERR(state->gpios))
-               return PTR_ERR(state->gpios);
-
-       state->win_order      = get_bitmask_order(resource_size(memory)) - 1;
+       state_pdev->map.virt = devm_ioremap_resource(&pdev->dev, memory);
+       if (IS_ERR(state_pdev->map.virt))
+               return PTR_ERR(state_pdev->map.virt);
 
-       state->map.name       = DRIVER_NAME;
-       state->map.read       = gf_read;
-       state->map.copy_from  = gf_copy_from;
-       state->map.write      = gf_write;
-       state->map.copy_to    = gf_copy_to;
-       state->map.bankwidth  = pdata->width;
-       state->map.size       = BIT(state->win_order + state->gpios->ndescs);
-       state->map.virt       = devm_ioremap_resource(&pdev->dev, memory);
-       if (IS_ERR(state->map.virt))
-               return PTR_ERR(state->map.virt);
+       state_pdev->map.name       = DRIVER_NAME;
+       state_pdev->map.bankwidth  = pdata->width;
+       state_pdev->map.size       = resource_size(memory);
 
-       state->map.phys       = NO_XIP;
-       state->map.map_priv_1 = (unsigned long)state;
+       ret = gpio_flash_probe_common(&pdev->dev, &state_pdev->state,
+                                     &state_pdev->map);
+       if (ret)
+               return ret;
 
-       platform_set_drvdata(pdev, state);
+       platform_set_drvdata(pdev, state_pdev);
 
        dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
-                  state->map.bankwidth * 8);
-       state->mtd = do_map_probe(memory->name, &state->map);
-       if (!state->mtd)
+                  state_pdev->map.bankwidth * 8);
+       state_pdev->mtd = do_map_probe(memory->name, &state_pdev->map);
+       if (!state_pdev->mtd)
                return -ENXIO;
-       state->mtd->dev.parent = &pdev->dev;
+       state_pdev->mtd->dev.parent = &pdev->dev;
 
-       mtd_device_parse_register(state->mtd, part_probe_types, NULL,
+       mtd_device_parse_register(state_pdev->mtd, part_probe_types, NULL,
                                  pdata->parts, pdata->nr_parts);
 
        return 0;
@@ -259,10 +282,10 @@ static int gpio_flash_probe(struct platform_device *pdev)
 
 static int gpio_flash_remove(struct platform_device *pdev)
 {
-       struct async_state *state = platform_get_drvdata(pdev);
+       struct async_state_pdev *state_pdev = platform_get_drvdata(pdev);
 
-       mtd_device_unregister(state->mtd);
-       map_destroy(state->mtd);
+       mtd_device_unregister(state_pdev->mtd);
+       map_destroy(state_pdev->mtd);
        return 0;
 }
 
diff --git a/drivers/mtd/maps/gpio-addr-flash.h 
b/drivers/mtd/maps/gpio-addr-flash.h
new file mode 100644
index 000000000000..443577f7fdfd
--- /dev/null
+++ b/drivers/mtd/maps/gpio-addr-flash.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/of.h>
+#include <linux/mtd/map.h>
+
+/**
+ * struct async_state - keep GPIO flash state
+ *     @gpios:       Struct containing the array of GPIO descriptors
+ *     @gpio_values: cached GPIO values
+ *     @win_order:   dedicated memory size (if no GPIOs)
+ */
+struct async_state {
+       struct gpio_descs *gpios;
+       unsigned int gpio_values;
+       unsigned int win_order;
+};
+
+int gpio_flash_probe_common(struct device *dev,
+                                  struct async_state *state,
+                                  struct map_info *map);
+
+#ifdef CONFIG_MTD_PHYSMAP_OF_GPIO
+int of_flash_probe_gpio(struct platform_device *pdev, struct device_node *np,
+                       struct map_info *map);
+#else
+static inline
+int of_flash_probe_gpio(struct platform_device *pdev, struct device_node *np,
+                       struct map_info *map)
+{
+       if (of_find_property(np, "addr-gpios", NULL))
+               return -EINVAL;
+
+       return 0;
+}
+#endif
diff --git a/drivers/mtd/maps/physmap_of_core.c 
b/drivers/mtd/maps/physmap_of_core.c
index ece605d78c21..c187b6ff873d 100644
--- a/drivers/mtd/maps/physmap_of_core.c
+++ b/drivers/mtd/maps/physmap_of_core.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include "physmap_of_gemini.h"
 #include "physmap_of_versatile.h"
+#include "gpio-addr-flash.h"
 
 struct of_flash_list {
        struct mtd_info *mtd;
@@ -240,6 +241,10 @@ static int of_flash_probe(struct platform_device *dev)
 
                simple_map_init(&info->list[i].map);
 
+               err = of_flash_probe_gpio(dev, dp, &info->list[i].map);
+               if (err)
+                       goto err_out;
+
                /*
                 * On some platforms (e.g. MPC5200) a direct 1:1 mapping
                 * may cause problems with JFFS2 usage, as the local bus (LPB)
diff --git a/drivers/mtd/maps/physmap_of_gpio.c 
b/drivers/mtd/maps/physmap_of_gpio.c
new file mode 100644
index 000000000000..c84c5e96e592
--- /dev/null
+++ b/drivers/mtd/maps/physmap_of_gpio.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Qtechnology A/S
+ *
+ * Ricardo Ribalda <ricardo.riba...@gmail.com>
+ *
+ */
+#include <linux/platform_device.h>
+#include "gpio-addr-flash.h"
+
+int of_flash_probe_gpio(struct platform_device *pdev, struct device_node *np,
+                       struct map_info *map)
+{
+       struct async_state *state;
+
+       state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       return gpio_flash_probe_common(&pdev->dev, state, map);
+}
-- 
2.19.0

Reply via email to