OSDN Git Service

Merge tag 'clk-for-linus-3.19' of git://git.linaro.org/people/mike.turquette/linux
[android-x86/kernel.git] / drivers / clk / samsung / clk-exynos-audss.c
index acce708..f2c2ccc 100644 (file)
@@ -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;
 }