aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2013-10-21 05:28:02 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2013-10-31 02:38:40 -0400
commit40f075330adfa497cc2894f9c6a32bb99c5cd5b8 (patch)
tree61755f3cb66f0c8133711141d8db989ae89c850b /drivers/media
parentfc5d0f8a8878319f6cb87045fd704360b2bb4e52 (diff)
[media] V4L2: soc-camera: work around unbalanced calls to .s_power()
Some non soc-camera drivers, e.g. em28xx, use subdevice drivers, originally written for soc-camera, which use soc_camera_power_on() and soc_camera_power_off() helpers to implement their .s_power() methods. Those helpers in turn can enable and disable a clock, if it is supplied to them as a parameter. This works well when camera host drivers balance their calls to subdevices' .s_power() methods. However, some such drivers fail to do that, which leads to unbalanced calls to v4l2_clk_enable() / v4l2_clk_disable(), which then in turn produce kernel warnings. Such behaviour is wrong and should be fixed, however, sometimes it is difficult, because some of those drivers are rather old and use lots of subdevices, which all should be tested after such a fix. To support such drivers this patch adds a work-around, allowing host drivers or platforms to set a flag, in which case soc-camera helpers will only enable the clock, if it is disabled, and disable it only once on the first call to .s_power(0). Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index e201d48de70e..4b8c024fc487 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -71,11 +71,21 @@ static int video_dev_create(struct soc_camera_device *icd);
71int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd, 71int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
72 struct v4l2_clk *clk) 72 struct v4l2_clk *clk)
73{ 73{
74 int ret = clk ? v4l2_clk_enable(clk) : 0; 74 int ret;
75 if (ret < 0) { 75 bool clock_toggle;
76 dev_err(dev, "Cannot enable clock: %d\n", ret); 76
77 return ret; 77 if (clk && (!ssdd->unbalanced_power ||
78 !test_and_set_bit(0, &ssdd->clock_state))) {
79 ret = v4l2_clk_enable(clk);
80 if (ret < 0) {
81 dev_err(dev, "Cannot enable clock: %d\n", ret);
82 return ret;
83 }
84 clock_toggle = true;
85 } else {
86 clock_toggle = false;
78 } 87 }
88
79 ret = regulator_bulk_enable(ssdd->sd_pdata.num_regulators, 89 ret = regulator_bulk_enable(ssdd->sd_pdata.num_regulators,
80 ssdd->sd_pdata.regulators); 90 ssdd->sd_pdata.regulators);
81 if (ret < 0) { 91 if (ret < 0) {
@@ -98,7 +108,7 @@ epwron:
98 regulator_bulk_disable(ssdd->sd_pdata.num_regulators, 108 regulator_bulk_disable(ssdd->sd_pdata.num_regulators,
99 ssdd->sd_pdata.regulators); 109 ssdd->sd_pdata.regulators);
100eregenable: 110eregenable:
101 if (clk) 111 if (clock_toggle)
102 v4l2_clk_disable(clk); 112 v4l2_clk_disable(clk);
103 113
104 return ret; 114 return ret;
@@ -127,7 +137,7 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd
127 ret = ret ? : err; 137 ret = ret ? : err;
128 } 138 }
129 139
130 if (clk) 140 if (clk && (!ssdd->unbalanced_power || test_and_clear_bit(0, &ssdd->clock_state)))
131 v4l2_clk_disable(clk); 141 v4l2_clk_disable(clk);
132 142
133 return ret; 143 return ret;