drm/meson: dw-hdmi: Disable clocks on driver teardown

The HDMI driver request clocks early, but never disable them, leaving
the clocks on even when the driver is removed.

Fix it by slightly refactoring the clock code, and register a devm
action that will eventually disable/unprepare the enabled clocks.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201120094205.525228-2-maz@kernel.org
This commit is contained in:
Marc Zyngier 2020-11-20 09:42:04 +00:00 committed by Neil Armstrong
parent f0aee45ffc
commit 1dfeea9045
1 changed files with 29 additions and 14 deletions

View File

@ -145,8 +145,6 @@ struct meson_dw_hdmi {
struct reset_control *hdmitx_apb; struct reset_control *hdmitx_apb;
struct reset_control *hdmitx_ctrl; struct reset_control *hdmitx_ctrl;
struct reset_control *hdmitx_phy; struct reset_control *hdmitx_phy;
struct clk *hdmi_pclk;
struct clk *venci_clk;
struct regulator *hdmi_supply; struct regulator *hdmi_supply;
u32 irq_stat; u32 irq_stat;
struct dw_hdmi *hdmi; struct dw_hdmi *hdmi;
@ -946,6 +944,29 @@ static void meson_disable_regulator(void *data)
regulator_disable(data); regulator_disable(data);
} }
static void meson_disable_clk(void *data)
{
clk_disable_unprepare(data);
}
static int meson_enable_clk(struct device *dev, char *name)
{
struct clk *clk;
int ret;
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
dev_err(dev, "Unable to get %s pclk\n", name);
return PTR_ERR(clk);
}
ret = clk_prepare_enable(clk);
if (!ret)
ret = devm_add_action_or_reset(dev, meson_disable_clk, clk);
return ret;
}
static int meson_dw_hdmi_bind(struct device *dev, struct device *master, static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
void *data) void *data)
{ {
@ -1026,19 +1047,13 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
if (IS_ERR(meson_dw_hdmi->hdmitx)) if (IS_ERR(meson_dw_hdmi->hdmitx))
return PTR_ERR(meson_dw_hdmi->hdmitx); return PTR_ERR(meson_dw_hdmi->hdmitx);
meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr"); ret = meson_enable_clk(dev, "isfr");
if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) { if (ret)
dev_err(dev, "Unable to get HDMI pclk\n"); return ret;
return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
}
clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci"); ret = meson_enable_clk(dev, "venci");
if (IS_ERR(meson_dw_hdmi->venci_clk)) { if (ret)
dev_err(dev, "Unable to get venci clk\n"); return ret;
return PTR_ERR(meson_dw_hdmi->venci_clk);
}
clk_prepare_enable(meson_dw_hdmi->venci_clk);
dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi, dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
&meson_dw_hdmi_regmap_config); &meson_dw_hdmi_regmap_config);