summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/nand/raw/nand_base.c32
-rw-r--r--include/linux/mtd/rawnand.h21
2 files changed, 51 insertions, 2 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index dcdf0f373100..dea41fa25be1 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -6718,6 +6718,20 @@ err_free_buf:
}
EXPORT_SYMBOL(nand_scan_tail);
+static int nand_attach(struct nand_chip *chip)
+{
+ if (chip->controller->ops && chip->controller->ops->attach_chip)
+ return chip->controller->ops->attach_chip(chip);
+
+ return 0;
+}
+
+static void nand_detach(struct nand_chip *chip)
+{
+ if (chip->controller->ops && chip->controller->ops->detach_chip)
+ chip->controller->ops->detach_chip(chip);
+}
+
/**
* nand_scan_with_ids - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
@@ -6731,11 +6745,21 @@ EXPORT_SYMBOL(nand_scan_tail);
int nand_scan_with_ids(struct mtd_info *mtd, int maxchips,
struct nand_flash_dev *ids)
{
+ struct nand_chip *chip = mtd_to_nand(mtd);
int ret;
ret = nand_scan_ident(mtd, maxchips, ids);
- if (!ret)
- ret = nand_scan_tail(mtd);
+ if (ret)
+ return ret;
+
+ ret = nand_attach(chip);
+ if (ret)
+ return ret;
+
+ ret = nand_scan_tail(mtd);
+ if (ret)
+ nand_detach(chip);
+
return ret;
}
EXPORT_SYMBOL(nand_scan_with_ids);
@@ -6763,7 +6787,11 @@ void nand_cleanup(struct nand_chip *chip)
/* Free manufacturer priv data. */
nand_manufacturer_cleanup(chip);
+
+ /* Free controller specific allocations after chip identification */
+ nand_detach(chip);
}
+
EXPORT_SYMBOL_GPL(nand_cleanup);
/**
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 93a2678e0f0d..fbd6b29cf22c 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -510,6 +510,25 @@ struct nand_id {
};
/**
+ * struct nand_controller_ops - Controller operations
+ *
+ * @attach_chip: this method is called after the NAND detection phase after
+ * flash ID and MTD fields such as erase size, page size and OOB
+ * size have been set up. ECC requirements are available if
+ * provided by the NAND chip or device tree. Typically used to
+ * choose the appropriate ECC configuration and allocate
+ * associated resources.
+ * This hook is optional.
+ * @detach_chip: free all resources allocated/claimed in
+ * nand_controller_ops->attach_chip().
+ * This hook is optional.
+ */
+struct nand_controller_ops {
+ int (*attach_chip)(struct nand_chip *chip);
+ void (*detach_chip)(struct nand_chip *chip);
+};
+
+/**
* struct nand_controller - Structure used to describe a NAND controller
*
* @lock: protection lock
@@ -517,11 +536,13 @@ struct nand_id {
* @wq: wait queue to sleep on if a NAND operation is in
* progress used instead of the per chip wait queue
* when a hw controller is available.
+ * @ops: NAND controller operations.
*/
struct nand_controller {
spinlock_t lock;
struct nand_chip *active;
wait_queue_head_t wq;
+ const struct nand_controller_ops *ops;
};
static inline void nand_controller_init(struct nand_controller *nfc)