|
@@ -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;
|