diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2013-05-31 07:40:36 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-06-08 18:53:16 -0400 |
commit | b4155d7d5b2c4e82238d629c451f7c27c9f37d9c (patch) | |
tree | 8ac568ea27b7786ddd68bf408fb2ed6e7b1d6aa2 /drivers/media | |
parent | 3cf138a6393d4ae2aeabce4c4b776d7d15cce69b (diff) |
[media] exynos4-is: Ensure fimc-is clocks are not enabled until properly configured
Use clk_prepare_enable/clk_unprepare_disable instead of preparing the
clocks during the driver initalization and then using just clk_disable/
clk_enable. The clock framework doesn't guarantee a clock will not get
enabled during e.g. clk_set_parent if clk_prepare has been called on it.
So we ensure clk_prepare() is called only when it is safe to enable
the clocks, i.e. the parent clocks and the clocks' frequencies are set.
It must be ensured the FIMC-IS clocks have proper frequencies before they
are enabled, otherwise the whole system will hang.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyunmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/exynos4-is/fimc-is.c | 13 |
1 files changed, 3 insertions, 10 deletions
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 1adf6dfcb39e..89f28fe42709 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c | |||
@@ -71,7 +71,6 @@ static void fimc_is_put_clocks(struct fimc_is *is) | |||
71 | for (i = 0; i < ISS_CLKS_MAX; i++) { | 71 | for (i = 0; i < ISS_CLKS_MAX; i++) { |
72 | if (IS_ERR(is->clocks[i])) | 72 | if (IS_ERR(is->clocks[i])) |
73 | continue; | 73 | continue; |
74 | clk_unprepare(is->clocks[i]); | ||
75 | clk_put(is->clocks[i]); | 74 | clk_put(is->clocks[i]); |
76 | is->clocks[i] = ERR_PTR(-EINVAL); | 75 | is->clocks[i] = ERR_PTR(-EINVAL); |
77 | } | 76 | } |
@@ -90,12 +89,6 @@ static int fimc_is_get_clocks(struct fimc_is *is) | |||
90 | ret = PTR_ERR(is->clocks[i]); | 89 | ret = PTR_ERR(is->clocks[i]); |
91 | goto err; | 90 | goto err; |
92 | } | 91 | } |
93 | ret = clk_prepare(is->clocks[i]); | ||
94 | if (ret < 0) { | ||
95 | clk_put(is->clocks[i]); | ||
96 | is->clocks[i] = ERR_PTR(-EINVAL); | ||
97 | goto err; | ||
98 | } | ||
99 | } | 92 | } |
100 | 93 | ||
101 | return 0; | 94 | return 0; |
@@ -103,7 +96,7 @@ err: | |||
103 | fimc_is_put_clocks(is); | 96 | fimc_is_put_clocks(is); |
104 | dev_err(&is->pdev->dev, "failed to get clock: %s\n", | 97 | dev_err(&is->pdev->dev, "failed to get clock: %s\n", |
105 | fimc_is_clocks[i]); | 98 | fimc_is_clocks[i]); |
106 | return -ENXIO; | 99 | return ret; |
107 | } | 100 | } |
108 | 101 | ||
109 | static int fimc_is_setup_clocks(struct fimc_is *is) | 102 | static int fimc_is_setup_clocks(struct fimc_is *is) |
@@ -144,7 +137,7 @@ int fimc_is_enable_clocks(struct fimc_is *is) | |||
144 | for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { | 137 | for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { |
145 | if (IS_ERR(is->clocks[i])) | 138 | if (IS_ERR(is->clocks[i])) |
146 | continue; | 139 | continue; |
147 | ret = clk_enable(is->clocks[i]); | 140 | ret = clk_prepare_enable(is->clocks[i]); |
148 | if (ret < 0) { | 141 | if (ret < 0) { |
149 | dev_err(&is->pdev->dev, "clock %s enable failed\n", | 142 | dev_err(&is->pdev->dev, "clock %s enable failed\n", |
150 | fimc_is_clocks[i]); | 143 | fimc_is_clocks[i]); |
@@ -163,7 +156,7 @@ void fimc_is_disable_clocks(struct fimc_is *is) | |||
163 | 156 | ||
164 | for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { | 157 | for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { |
165 | if (!IS_ERR(is->clocks[i])) { | 158 | if (!IS_ERR(is->clocks[i])) { |
166 | clk_disable(is->clocks[i]); | 159 | clk_disable_unprepare(is->clocks[i]); |
167 | pr_debug("disabled clock: %s\n", fimc_is_clocks[i]); | 160 | pr_debug("disabled clock: %s\n", fimc_is_clocks[i]); |
168 | } | 161 | } |
169 | } | 162 | } |