[U-Boot] [PATCH v10 02/27] mtd: add mtd device create operations

Jagan Teki
2017-12-28T06:12:08Z

mtd is common device interaction for most of
memory technology flashes like nand, parallel nor,
spi-nor, dataflash etc, these are terminated as
interface types in u-boot driver model.

This patch add common way of creating mtd device for
respective underlying interface type. once the interface
driver bind happen, the receptive uclass will pass an
interface type to mtd layer to create a device for it.

MTD_IF_TYPE_SPI_NOR in an interface type for all spi nor devices.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
drivers/mtd/mtd-uclass.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/mtd.h | 14 ++++++
include/mtd.h | 116 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 251 insertions(+)

diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index d2c587f..c94afe9 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -11,6 +11,9 @@
#include <mtd.h>
#include <linux/log2.h>

+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
int mtd_dread(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf)
{
@@ -70,6 +73,124 @@ int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
return ops->write(dev, to, len, retlen, buf);
}

+int mtd_find_device(int mtd_if_type, int devnum, struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_get(UCLASS_MTD, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+
+ debug("%s: mtd_if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+ mtd_if_type, devnum, dev->name, mtd->mtd_if_type, mtd->devnum);
+ if (mtd->mtd_if_type == mtd_if_type && mtd->devnum == devnum) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int mtd_get_device(int mtd_if_type, int devnum, struct udevice **devp)
+{
+ int ret;
+
+ ret = mtd_find_device(mtd_if_type, devnum, devp);
+ if (ret)
+ return ret;
+
+ return device_probe(*devp);
+}
+
+int mtd_select_devnum(enum mtd_if_type mtd_if_type, int devnum)
+{
+ struct udevice *dev;
+
+ return mtd_get_device(mtd_if_type, devnum, &dev);
+}
+
+int mtd_find_max_devnum(enum mtd_if_type mtd_if_type)
+{
+ struct udevice *dev;
+ int max_devnum = -ENODEV;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_MTD, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct mtd_info *mtd = dev_get_uclass_platdata(dev);
+
+ if (mtd->mtd_if_type == mtd_if_type && mtd->devnum > max_devnum)
+ max_devnum = mtd->devnum;
+ }
+
+ return max_devnum;
+}
+
+static int mtd_next_free_devnum(enum mtd_if_type mtd_if_type)
+{
+ int ret;
+
+ ret = mtd_find_max_devnum(mtd_if_type);
+ if (ret == -ENODEV)
+ return 0;
+ if (ret < 0)
+ return ret;
+
+ return ret + 1;
+}
+
+int mtd_create_device(struct udevice *parent, const char *drv_name,
+ const char *name, int mtd_if_type, struct udevice **devp)
+{
+ struct mtd_info *mtd;
+ struct udevice *dev;
+ int devnum, ret;
+
+ devnum = mtd_next_free_devnum(mtd_if_type);
+ if (devnum < 0)
+ return devnum;
+ ret = device_bind_driver(parent, drv_name, name, &dev);
+ if (ret)
+ return ret;
+ mtd = dev_get_uclass_platdata(dev);
+ mtd->mtd_if_type = mtd_if_type;
+ mtd->dev = dev;
+ mtd->devnum = devnum;
+ *devp = dev;
+
+ return 0;
+}
+
+int mtd_create_devicef(struct udevice *parent, const char *drv_name,
+ const char *name, int mtd_if_type,
+ struct udevice **devp)
+{
+ char dev_name[30], *str;
+ int ret;
+
+ snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
+ str = strdup(dev_name);
+ if (!str)
+ return -ENOMEM;
+
+ ret = mtd_create_device(parent, drv_name, str, mtd_if_type, devp);
+ if (ret) {
+ free(str);
+ return ret;
+ }
+ device_set_name_alloced(*devp);
+
+ return ret;
+}
+
/*
* Implement a MTD uclass which should include most flash drivers.
* The uclass private is pointed to mtd_info.
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ba4cbba..6ec9763 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -149,6 +149,16 @@ struct nand_ecclayout {

struct module; /* only needed for owner field in mtd_info */

+#ifdef CONFIG_MTD
+/* Interface types: */
+enum mtd_if_type {
+ MTD_IF_TYPE_UNKNOWN = 0,
+ MTD_IF_TYPE_SPI_NOR,
+
+ MTD_IF_TYPE_COUNT,
+};
+#endif
+
struct mtd_info {
u_char type;
uint32_t flags;
@@ -309,6 +319,10 @@ struct mtd_info {
struct udevice *dev;
#endif
int usecount;
+#ifdef CONFIG_MTD
+ enum mtd_if_type mtd_if_type; /* type of mtd interface */
+ int devnum; /* device number */
+#endif
};

int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
diff --git a/include/mtd.h b/include/mtd.h
index 32b11c3..273b3a6 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -66,4 +66,120 @@ int mtd_dwrite(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
*/
int mtd_derase(struct mtd_info *mtd, struct erase_info *instr);

+/**
+ * mtd_find_device() - find a mtd device
+ *
+ * This function does not activate the device. The device will be returned
+ * whether or not it is activated.
+ *
+ * @mtd_if_type: interface type (enum mtd_if_type_t)
+ * @devnum: device number (specific to each interface type)
+ * @devp: the device, if found
+ * @return 0 if found, -ENODEV if no device found, or other -ve error value
+ */
+int mtd_find_device(int mtd_if_type, int devnum, struct udevice **devp);
+
+/**
+ * mtd_get_device() - find and probe a mtd device ready for use
+ *
+ * @mtd_if_type: interface type (enum mtd_if_type_t)
+ * @devnum: device number (specific to each interface type)
+ * @devp: the device, if found
+ * @return 0 if found, -ENODEV if no device found, or other -ve error value
+ */
+int mtd_get_device(int mtd_if_type, int devnum, struct udevice **devp);
+
+/**
+ * mtd_first_device() - find the first device for a given interface
+ *
+ * The device is probed ready for use
+ *
+ * @devnum: device number (specific to each interface type)
+ * @devp: the device, if found
+ * @return 0 if found, -ENODEV if no device, or other -ve error value
+ */
+int mtd_first_device(int mtd_if_type, struct udevice **devp);
+
+/**
+ * mtd_next_device() - find the next device for a given interface
+ *
+ * This can be called repeatedly after mtd_first_device() to iterate through
+ * all devices of the given interface type.
+ *
+ * The device is probed ready for use
+ *
+ * @devp: on entry, the previous device returned. On exit, the next
+ * device, if found
+ * @return 0 if found, -ENODEV if no device, or other -ve error value
+ */
+int mtd_next_device(struct udevice **devp);
+
+/**
+ * mtd_create_device() - create a new mtd device
+ *
+ * @parent: parent of the new device
+ * @drv_name: driver name to use for the mtd device
+ * @name: name for the device
+ * @mtd_if_type: Interface type (enum mtd_if_type_t)
+ * @devp: the new device (which has not been probed)
+ */
+int mtd_create_device(struct udevice *parent, const char *drv_name,
+ const char *name, int mtd_if_type,
+ struct udevice **devp);
+
+/**
+ * mtd_create_devicef() - Cceate a new named mtd device
+ *
+ * @parent: parent of the new device
+ * @drv_name: driver name to use for the mtd device
+ * @name: name for the device (parent name is prepended)
+ * @mtd_if_type: interface type (enum mtd_if_type_t)
+ * @devp: the new device (which has not been probed)
+ */
+int mtd_create_devicef(struct udevice *parent, const char *drv_name,
+ const char *name, int mtd_if_type,
+ struct udevice **devp);
+
+/**
+ * mtd_prepare_device() - prepare a mtd device for use
+ *
+ * This reads partition information from the device if supported.
+ *
+ * @dev: device to prepare
+ * @return 0 if ok, -ve on error
+ */
+int mtd_prepare_device(struct udevice *dev);
+
+/**
+ * mtd_unbind_all() - unbind all device of the given interface type
+ *
+ * The devices are removed and then unbound.
+ *
+ * @mtd_if_type: interface type to unbind
+ * @return 0 if OK, -ve on error
+ */
+int mtd_unbind_all(int mtd_if_type);
+
+/**
+ * mtd_find_max_devnum() - find the maximum device number for an interface type
+ *
+ * Finds the last allocated device number for an interface type @mtd_if_type. The
+ * next number is safe to use for a newly allocated device.
+ *
+ * @mtd_if_type: interface type to scan
+ * @return maximum device number found, or -ENODEV if none, or other -ve on
+ * error
+ */
+int mtd_find_max_devnum(enum mtd_if_type mtd_if_type);
+
+/**
+ * mtd_select_devnum() - select the mtd device from device number
+ *
+ * @mtd_if_type: interface type to scan
+ * @devnum: device number, specific to the interface type, or -1 to
+ * @return maximum device number found, or -ENODEV if none, or other -ve on
+ * error
+ */
+int mtd_select_devnum(enum mtd_if_type mtd_if_type, int devnum);
+
#endif /* _MTD_H_ */
--
2.7.4