@@ -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.
@@ -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,
@@ -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_ */