[PATCH v2 31/58] mtd: rawnand: mxc: retain open-handle state on removal

From: James Hilliard

Date: Tue Nov 10 2026 - 02:51:17 EST


Keep chip metadata and controller storage alive until the final MTD
reference is released. Unregister and disconnect each published chip
before releasing the resources used by its hardware operations.

Retain the embedded legacy controller and drain I/O before clock
disable.

Cc: Fabio Estevam <festevam@xxxxxxxxx>
Cc: Frank Li <Frank.Li@xxxxxxx>
Cc: imx@xxxxxxxxxxxxxxx
Cc: Pengutronix Kernel Team <kernel@xxxxxxxxxxxxxx>
Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
Cc: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
drivers/mtd/nand/raw/mxc_nand.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c
index 4d8b92e7e672..d9f1e57c1ebf 100644
--- a/drivers/mtd/nand/raw/mxc_nand.c
+++ b/drivers/mtd/nand/raw/mxc_nand.c
@@ -1686,6 +1686,11 @@ static const struct nand_controller_ops mxcnd_controller_ops = {
.exec_op = mxcnd_exec_op,
};

+static void mxcnd_release(struct nand_controller *controller)
+{
+ kfree(container_of(controller, struct mxc_nand_host, nand.legacy.dummy_controller));
+}
+
static int mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
@@ -1694,10 +1699,14 @@ static int mxcnd_probe(struct platform_device *pdev)
int err = 0;

/* Allocate memory for MTD device structure and private data */
- host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
- GFP_KERNEL);
+ host = kzalloc_obj(*host);
if (!host)
return -ENOMEM;
+ this = &host->nand;
+ this->controller = &this->legacy.dummy_controller;
+ err = devm_nand_controller_init(&pdev->dev, this->controller, mxcnd_release);
+ if (err)
+ return err;

/* allocate a temporary buffer for the nand_scan_ident() */
host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
@@ -1796,9 +1805,15 @@ static int mxcnd_probe(struct platform_device *pdev)
goto escan;

/* Register the partitions */
- err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+ err = nand_set_release(this, NULL);
if (err)
goto cleanup_nand;
+ err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
+ if (err) {
+ nand_disconnect(this);
+ mtd_put_master(mtd);
+ goto escan;
+ }

platform_set_drvdata(pdev, host);

@@ -1821,9 +1836,10 @@ static void mxcnd_remove(struct platform_device *pdev)

ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
- nand_cleanup(chip);
+ nand_disconnect(chip);
if (host->clk_act)
clk_disable_unprepare(host->clk);
+ mtd_put_master(nand_to_mtd(chip));
}

static struct platform_driver mxcnd_driver = {

--
2.53.0