The X1000 and X1830 have a TCU clock gate, so pass it to the driver. Without this the TCU can be gated automatically, which prevents timers from running. Add a workaround to allow the driver to probe even if the TCU clock is missing on the affected SoCs; in this case the TCU clock is ignored, as it was before. With workarounds like "clk_ignore_unused" on the kernel command line, this allows users who upgrade the kernel but use the old device tree to boot successfully. They will now get a warning encouraging them to update the device tree. Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@xxxxxxxxx> --- drivers/clk/ingenic/tcu.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c index 77acfbeb4830..03e9553bcac4 100644 --- a/drivers/clk/ingenic/tcu.c +++ b/drivers/clk/ingenic/tcu.c @@ -31,6 +31,7 @@ struct ingenic_soc_info { unsigned int num_channels; bool has_ost; bool has_tcu_clk; + bool allow_missing_tcu_clk; }; struct ingenic_tcu_clk_info { @@ -320,7 +321,8 @@ static const struct ingenic_soc_info jz4770_soc_info = { static const struct ingenic_soc_info x1000_soc_info = { .num_channels = 8, .has_ost = false, /* X1000 has OST, but it not belong TCU */ - .has_tcu_clk = false, + .has_tcu_clk = true, + .allow_missing_tcu_clk = true, }; static const struct of_device_id __maybe_unused ingenic_tcu_of_match[] __initconst = { @@ -355,14 +357,29 @@ static int __init ingenic_tcu_probe(struct device_node *np) tcu->clk = of_clk_get_by_name(np, "tcu"); if (IS_ERR(tcu->clk)) { ret = PTR_ERR(tcu->clk); - pr_crit("Cannot get TCU clock\n"); - goto err_free_tcu; - } - ret = clk_prepare_enable(tcu->clk); - if (ret) { - pr_crit("Unable to enable TCU clock\n"); - goto err_put_clk; + /* + * Old versions of this driver incorrectly specified + * some SoCs as not having a TCU clock, so old device + * trees didn't define one. We try to allow the kernel + * to boot with an old device tree by just continuing + * on without the clock and hoping it won't get turned + * off (eg. with "clk_ignore_unused" kernel argument). + */ + if (ret == -EINVAL && + tcu->soc_info->allow_missing_tcu_clk) { + pr_warn("TCU clock missing from device tree, please update your device tree\n"); + tcu->clk = NULL; + } else { + pr_crit("Cannot get TCU clock\n"); + goto err_free_tcu; + } + } else { + ret = clk_prepare_enable(tcu->clk); + if (ret) { + pr_crit("Unable to enable TCU clock\n"); + goto err_put_clk; + } } } @@ -432,10 +449,10 @@ static int __init ingenic_tcu_probe(struct device_node *np) clk_hw_unregister(tcu->clocks->hws[i]); kfree(tcu->clocks); err_clk_disable: - if (tcu->soc_info->has_tcu_clk) + if (tcu->clk) clk_disable_unprepare(tcu->clk); err_put_clk: - if (tcu->soc_info->has_tcu_clk) + if (tcu->clk) clk_put(tcu->clk); err_free_tcu: kfree(tcu); -- 2.34.1