aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk/samsung/clk-exynos-audss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/samsung/clk-exynos-audss.c')
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index acce708ace18..f2c2ccce49bb 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -29,6 +29,13 @@ static DEFINE_SPINLOCK(lock);
static struct clk **clk_table;
static void __iomem *reg_base;
static struct clk_onecell_data clk_data;
+/*
+ * On Exynos5420 this will be a clock which has to be enabled before any
+ * access to audss registers. Typically a child of EPLL.
+ *
+ * On other platforms this will be -ENODEV.
+ */
+static struct clk *epll;
#define ASS_CLK_SRC 0x0
#define ASS_CLK_DIV 0x4
@@ -98,6 +105,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to map audss registers\n");
return PTR_ERR(reg_base);
}
+ /* EPLL don't have to be enabled for boards other than Exynos5420 */
+ epll = ERR_PTR(-ENODEV);
clk_table = devm_kzalloc(&pdev->dev,
sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS,
@@ -115,8 +124,20 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
pll_in = devm_clk_get(&pdev->dev, "pll_in");
if (!IS_ERR(pll_ref))
mout_audss_p[0] = __clk_get_name(pll_ref);
- if (!IS_ERR(pll_in))
+ if (!IS_ERR(pll_in)) {
mout_audss_p[1] = __clk_get_name(pll_in);
+
+ if (variant == TYPE_EXYNOS5420) {
+ epll = pll_in;
+
+ ret = clk_prepare_enable(epll);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to prepare the epll clock\n");
+ return ret;
+ }
+ }
+ }
clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss",
mout_audss_p, ARRAY_SIZE(mout_audss_p),
CLK_SET_RATE_NO_REPARENT,
@@ -203,6 +224,9 @@ unregister:
clk_unregister(clk_table[i]);
}
+ if (!IS_ERR(epll))
+ clk_disable_unprepare(epll);
+
return ret;
}
@@ -210,6 +234,10 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
{
int i;
+#ifdef CONFIG_PM_SLEEP
+ unregister_syscore_ops(&exynos_audss_clk_syscore_ops);
+#endif
+
of_clk_del_provider(pdev->dev.of_node);
for (i = 0; i < clk_data.clk_num; i++) {
@@ -217,6 +245,9 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
clk_unregister(clk_table[i]);
}
+ if (!IS_ERR(epll))
+ clk_disable_unprepare(epll);
+
return 0;
}