aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2014-12-05 09:15:34 -0500
committerMichael Turquette <mturquette@linaro.org>2014-12-17 10:31:51 -0500
commitf1e9203e2366164b832d8a6ce10134de8c575178 (patch)
treeb63f8a883579d364856014b7b122fb0fbc581d5f
parent83ccc4670477e7722d4654ca44b4b7004fcaada9 (diff)
clk: samsung: Fix Exynos 5420 pinctrl setup and clock disable failure due to domain being gated
Audio subsystem clocks are located in separate block. On Exynos 5420 if clock for this block (from main clock domain) 'mau_epll' is gated then any read or write to audss registers will block. This kind of boot hang was observed on Arndale Octa and Peach Pi/Pit after introducing runtime PM to pl330 DMA driver. After that commit the 'mau_epll' was gated, because the "amba" clock was disabled and there were no more users of mau_epll. The system hang on one of steps: 1. Disabling unused clocks from audss block. 2. During audss GPIO setup (just before probing i2s0 because samsung_pinmux_setup() tried to access memory from audss block which was gated. Add a workaround for this by enabling the 'mau_epll' clock in probe. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Acked-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Tested-by: Kevin Hilman <khilman@linaro.org> Signed-off-by: Michael Turquette <mturquette@linaro.org>
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index b50469faf70c..f7eff82738ab 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);
29static struct clk **clk_table; 29static struct clk **clk_table;
30static void __iomem *reg_base; 30static void __iomem *reg_base;
31static struct clk_onecell_data clk_data; 31static struct clk_onecell_data clk_data;
32/*
33 * On Exynos5420 this will be a clock which has to be enabled before any
34 * access to audss registers. Typically a child of EPLL.
35 *
36 * On other platforms this will be -ENODEV.
37 */
38static struct clk *epll;
32 39
33#define ASS_CLK_SRC 0x0 40#define ASS_CLK_SRC 0x0
34#define ASS_CLK_DIV 0x4 41#define ASS_CLK_DIV 0x4
@@ -98,6 +105,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
98 dev_err(&pdev->dev, "failed to map audss registers\n"); 105 dev_err(&pdev->dev, "failed to map audss registers\n");
99 return PTR_ERR(reg_base); 106 return PTR_ERR(reg_base);
100 } 107 }
108 /* EPLL don't have to be enabled for boards other than Exynos5420 */
109 epll = ERR_PTR(-ENODEV);
101 110
102 clk_table = devm_kzalloc(&pdev->dev, 111 clk_table = devm_kzalloc(&pdev->dev,
103 sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS, 112 sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS,
@@ -115,8 +124,20 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
115 pll_in = devm_clk_get(&pdev->dev, "pll_in"); 124 pll_in = devm_clk_get(&pdev->dev, "pll_in");
116 if (!IS_ERR(pll_ref)) 125 if (!IS_ERR(pll_ref))
117 mout_audss_p[0] = __clk_get_name(pll_ref); 126 mout_audss_p[0] = __clk_get_name(pll_ref);
118 if (!IS_ERR(pll_in)) 127 if (!IS_ERR(pll_in)) {
119 mout_audss_p[1] = __clk_get_name(pll_in); 128 mout_audss_p[1] = __clk_get_name(pll_in);
129
130 if (variant == TYPE_EXYNOS5420) {
131 epll = pll_in;
132
133 ret = clk_prepare_enable(epll);
134 if (ret) {
135 dev_err(&pdev->dev,
136 "failed to prepare the epll clock\n");
137 return ret;
138 }
139 }
140 }
120 clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss", 141 clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss",
121 mout_audss_p, ARRAY_SIZE(mout_audss_p), 142 mout_audss_p, ARRAY_SIZE(mout_audss_p),
122 CLK_SET_RATE_NO_REPARENT, 143 CLK_SET_RATE_NO_REPARENT,
@@ -203,6 +224,9 @@ unregister:
203 clk_unregister(clk_table[i]); 224 clk_unregister(clk_table[i]);
204 } 225 }
205 226
227 if (!IS_ERR(epll))
228 clk_disable_unprepare(epll);
229
206 return ret; 230 return ret;
207} 231}
208 232
@@ -221,6 +245,9 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
221 clk_unregister(clk_table[i]); 245 clk_unregister(clk_table[i]);
222 } 246 }
223 247
248 if (!IS_ERR(epll))
249 clk_disable_unprepare(epll);
250
224 return 0; 251 return 0;
225} 252}
226 253