diff options
author | Tomasz Figa <t.figa@samsung.com> | 2013-06-26 09:37:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-08-24 03:51:12 -0400 |
commit | d334ab08e8e1f6907d44c716f852f49076e957ca (patch) | |
tree | 50600b3b71d4a618b052c15d3713743c5fca8513 /drivers/media | |
parent | b82180dba53e71fbc1b08bc8beca75d1dea5e993 (diff) |
[media] exynos4-is: Handle suspend/resume of fimc-is-i2c correctly
If the same callbacks are used for runtime and system suspend/resume,
clocks can get disabled twice, which can lead to negative reference
counts and kernel warnings.
This patch splits suspend/resume callbacks into separate runtime and
system-wide functions, so clock gating is done correctly.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/exynos4-is/fimc-is-i2c.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c index 617a798d9235..6bc481a9e93f 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c | |||
@@ -83,21 +83,46 @@ static int fimc_is_i2c_remove(struct platform_device *pdev) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static int fimc_is_i2c_suspend(struct device *dev) | 86 | #if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP) |
87 | static int fimc_is_i2c_runtime_suspend(struct device *dev) | ||
87 | { | 88 | { |
88 | struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev); | 89 | struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev); |
90 | |||
89 | clk_disable_unprepare(isp_i2c->clock); | 91 | clk_disable_unprepare(isp_i2c->clock); |
90 | return 0; | 92 | return 0; |
91 | } | 93 | } |
92 | 94 | ||
93 | static int fimc_is_i2c_resume(struct device *dev) | 95 | static int fimc_is_i2c_runtime_resume(struct device *dev) |
94 | { | 96 | { |
95 | struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev); | 97 | struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev); |
98 | |||
96 | return clk_prepare_enable(isp_i2c->clock); | 99 | return clk_prepare_enable(isp_i2c->clock); |
97 | } | 100 | } |
101 | #endif | ||
98 | 102 | ||
99 | static UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend, | 103 | #ifdef CONFIG_PM_SLEEP |
100 | fimc_is_i2c_resume, NULL); | 104 | static int fimc_is_i2c_suspend(struct device *dev) |
105 | { | ||
106 | if (pm_runtime_suspended(dev)) | ||
107 | return 0; | ||
108 | |||
109 | return fimc_is_i2c_runtime_suspend(dev); | ||
110 | } | ||
111 | |||
112 | static int fimc_is_i2c_resume(struct device *dev) | ||
113 | { | ||
114 | if (pm_runtime_suspended(dev)) | ||
115 | return 0; | ||
116 | |||
117 | return fimc_is_i2c_runtime_resume(dev); | ||
118 | } | ||
119 | #endif | ||
120 | |||
121 | static struct dev_pm_ops fimc_is_i2c_pm_ops = { | ||
122 | SET_RUNTIME_PM_OPS(fimc_is_i2c_runtime_suspend, | ||
123 | fimc_is_i2c_runtime_resume, NULL) | ||
124 | SET_SYSTEM_SLEEP_PM_OPS(fimc_is_i2c_suspend, fimc_is_i2c_resume) | ||
125 | }; | ||
101 | 126 | ||
102 | static const struct of_device_id fimc_is_i2c_of_match[] = { | 127 | static const struct of_device_id fimc_is_i2c_of_match[] = { |
103 | { .compatible = FIMC_IS_I2C_COMPATIBLE }, | 128 | { .compatible = FIMC_IS_I2C_COMPATIBLE }, |