mtd: rawnand: denali_dt: add more clocks based on IP datasheet
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Fri, 22 Jun 2018 16:06:37 +0000 (01:06 +0900)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Wed, 18 Jul 2018 07:24:14 +0000 (09:24 +0200)
Currently, denali_dt.c requires a single anonymous clock, but
the Denali User's Guide requires three clocks for this IP:

 - clk: controller core clock

 - clk_x: bus interface clock

 - ecc_clk: clock at which ECC circuitry is run

This commit supports these named clocks to represent the real hardware.

For the backward compatibility, the driver still accepts a single clock
just as before.  The clk_x_rate is taken from the clock driver again if
the named clock "clk_x" is available.  This will happen only for future
DT, hence the existing DT files are not affected.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Richard Weinberger <richard@nod.at>
Tested-by: Richard Weinberger <richard@nod.at>
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nand/raw/denali_dt.c

index 6b4bd16e8bee18196fdafc0174c7b623df1f2dfc..afaae378c624a709e7c4f268b1197af805574e77 100644 (file)
@@ -27,7 +27,9 @@
 
 struct denali_dt {
        struct denali_nand_info denali;
-       struct clk              *clk;
+       struct clk *clk;        /* core clock */
+       struct clk *clk_x;      /* bus interface clock */
+       struct clk *clk_ecc;    /* ECC circuit clock */
 };
 
 struct denali_dt_data {
@@ -115,28 +117,61 @@ static int denali_dt_probe(struct platform_device *pdev)
        if (IS_ERR(denali->host))
                return PTR_ERR(denali->host);
 
-       dt->clk = devm_clk_get(dev, NULL);
+       /*
+        * A single anonymous clock is supported for the backward compatibility.
+        * New platforms should support all the named clocks.
+        */
+       dt->clk = devm_clk_get(dev, "nand");
+       if (IS_ERR(dt->clk))
+               dt->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(dt->clk)) {
                dev_err(dev, "no clk available\n");
                return PTR_ERR(dt->clk);
        }
+
+       dt->clk_x = devm_clk_get(dev, "nand_x");
+       if (IS_ERR(dt->clk_x))
+               dt->clk_x = NULL;
+
+       dt->clk_ecc = devm_clk_get(dev, "ecc");
+       if (IS_ERR(dt->clk_ecc))
+               dt->clk_ecc = NULL;
+
        ret = clk_prepare_enable(dt->clk);
        if (ret)
                return ret;
 
-       /*
-        * Hardcode the clock rate for the backward compatibility.
-        * This works for both SOCFPGA and UniPhier.
-        */
-       denali->clk_x_rate = 200000000;
+       ret = clk_prepare_enable(dt->clk_x);
+       if (ret)
+               goto out_disable_clk;
+
+       ret = clk_prepare_enable(dt->clk_ecc);
+       if (ret)
+               goto out_disable_clk_x;
+
+       if (dt->clk_x) {
+               denali->clk_x_rate = clk_get_rate(dt->clk_x);
+       } else {
+               /*
+                * Hardcode the clock rates for the backward compatibility.
+                * This works for both SOCFPGA and UniPhier.
+                */
+               dev_notice(dev,
+                          "necessary clock is missing. default clock rates are used.\n");
+               denali->clk_x_rate = 200000000;
+       }
 
        ret = denali_init(denali);
        if (ret)
-               goto out_disable_clk;
+               goto out_disable_clk_ecc;
 
        platform_set_drvdata(pdev, dt);
        return 0;
 
+out_disable_clk_ecc:
+       clk_disable_unprepare(dt->clk_ecc);
+out_disable_clk_x:
+       clk_disable_unprepare(dt->clk_x);
 out_disable_clk:
        clk_disable_unprepare(dt->clk);
 
@@ -148,6 +183,8 @@ static int denali_dt_remove(struct platform_device *pdev)
        struct denali_dt *dt = platform_get_drvdata(pdev);
 
        denali_remove(&dt->denali);
+       clk_disable_unprepare(dt->clk_ecc);
+       clk_disable_unprepare(dt->clk_x);
        clk_disable_unprepare(dt->clk);
 
        return 0;