diff options
Diffstat (limited to 'drivers/mtd/nand/raw/denali_dt.c')
-rw-r--r-- | drivers/mtd/nand/raw/denali_dt.c | 70 |
1 files changed, 55 insertions, 15 deletions
diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 5869e90cc14b..0faaad032e5f 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -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 { @@ -79,63 +81,99 @@ MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); static int denali_dt_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct resource *res; struct denali_dt *dt; const struct denali_dt_data *data; struct denali_nand_info *denali; int ret; - dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL); + dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL); if (!dt) return -ENOMEM; denali = &dt->denali; - data = of_device_get_match_data(&pdev->dev); + data = of_device_get_match_data(dev); if (data) { denali->revision = data->revision; denali->caps = data->caps; denali->ecc_caps = data->ecc_caps; } - denali->dev = &pdev->dev; + denali->dev = dev; denali->irq = platform_get_irq(pdev, 0); if (denali->irq < 0) { - dev_err(&pdev->dev, "no irq defined\n"); + dev_err(dev, "no irq defined\n"); return denali->irq; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg"); - denali->reg = devm_ioremap_resource(&pdev->dev, res); + denali->reg = devm_ioremap_resource(dev, res); if (IS_ERR(denali->reg)) return PTR_ERR(denali->reg); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); - denali->host = devm_ioremap_resource(&pdev->dev, res); + denali->host = devm_ioremap_resource(dev, res); if (IS_ERR(denali->host)) return PTR_ERR(denali->host); - dt->clk = devm_clk_get(&pdev->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(&pdev->dev, "no clk available\n"); + 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_rate = clk_get_rate(dt->clk); + 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_rate = 50000000; + 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); @@ -147,6 +185,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; |