Commit 089b7c70 authored by Jacopo Mondi's avatar Jacopo Mondi Committed by Mauro Carvalho Chehab

media: ov5647: Use pm_runtime infrastructure

Use the pm_runtime framework to replace the legacy s_power() operation.
Signed-off-by: default avatarJacopo Mondi <jacopo@jmondi.org>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 646a0249
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
...@@ -881,86 +882,75 @@ static int ov5647_stream_off(struct v4l2_subdev *sd) ...@@ -881,86 +882,75 @@ static int ov5647_stream_off(struct v4l2_subdev *sd)
return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01); return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
} }
static int set_sw_standby(struct v4l2_subdev *sd, bool standby) static int ov5647_power_on(struct device *dev)
{ {
struct ov5647 *sensor = dev_get_drvdata(dev);
int ret; int ret;
u8 rdval;
ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval); dev_dbg(dev, "OV5647 power on\n");
if (ret < 0)
return ret;
if (standby) if (sensor->pwdn) {
rdval &= ~0x01; gpiod_set_value_cansleep(sensor->pwdn, 0);
else msleep(PWDN_ACTIVE_DELAY_MS);
rdval |= 0x01; }
return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
}
static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) ret = clk_prepare_enable(sensor->xclk);
{ if (ret < 0) {
struct i2c_client *client = v4l2_get_subdevdata(sd); dev_err(dev, "clk prepare enable failed\n");
struct ov5647 *sensor = to_sensor(sd); goto error_pwdn;
int ret = 0; }
mutex_lock(&sensor->lock); ret = ov5647_write_array(&sensor->sd, sensor_oe_enable_regs,
ARRAY_SIZE(sensor_oe_enable_regs));
if (ret < 0) {
dev_err(dev, "write sensor_oe_enable_regs error\n");
goto error_clk_disable;
}
if (on && !sensor->power_count) { /* Stream off to coax lanes into LP-11 state. */
dev_dbg(&client->dev, "OV5647 power on\n"); ret = ov5647_stream_off(&sensor->sd);
if (ret < 0) {
dev_err(dev, "camera not available, check power\n");
goto error_clk_disable;
}
if (sensor->pwdn) { return 0;
gpiod_set_value_cansleep(sensor->pwdn, 0);
msleep(PWDN_ACTIVE_DELAY_MS);
}
ret = clk_prepare_enable(sensor->xclk); error_clk_disable:
if (ret < 0) { clk_disable_unprepare(sensor->xclk);
dev_err(&client->dev, "clk prepare enable failed\n"); error_pwdn:
goto out; gpiod_set_value_cansleep(sensor->pwdn, 1);
}
ret = ov5647_write_array(sd, sensor_oe_enable_regs, return ret;
ARRAY_SIZE(sensor_oe_enable_regs)); }
if (ret < 0) {
clk_disable_unprepare(sensor->xclk);
dev_err(&client->dev,
"write sensor_oe_enable_regs error\n");
goto out;
}
/* Stream off to coax lanes into LP-11 state. */ static int ov5647_power_off(struct device *dev)
ret = ov5647_stream_off(sd); {
if (ret < 0) { struct ov5647 *sensor = dev_get_drvdata(dev);
clk_disable_unprepare(sensor->xclk); u8 rdval;
dev_err(&client->dev, int ret;
"Camera not available, check Power\n");
goto out;
}
} else if (!on && sensor->power_count == 1) {
dev_dbg(&client->dev, "OV5647 power off\n");
ret = ov5647_write_array(sd, sensor_oe_disable_regs, dev_dbg(dev, "OV5647 power off\n");
ARRAY_SIZE(sensor_oe_disable_regs));
if (ret < 0)
dev_dbg(&client->dev, "disable oe failed\n");
ret = set_sw_standby(sd, true); ret = ov5647_write_array(&sensor->sd, sensor_oe_disable_regs,
if (ret < 0) ARRAY_SIZE(sensor_oe_disable_regs));
dev_dbg(&client->dev, "soft stby failed\n"); if (ret < 0)
dev_dbg(dev, "disable oe failed\n");
clk_disable_unprepare(sensor->xclk); /* Enter software standby */
gpiod_set_value_cansleep(sensor->pwdn, 1); ret = ov5647_read(&sensor->sd, OV5647_SW_STANDBY, &rdval);
} if (ret < 0)
dev_dbg(dev, "software standby failed\n");
/* Update the power count. */ rdval &= ~0x01;
sensor->power_count += on ? 1 : -1; ret = ov5647_write(&sensor->sd, OV5647_SW_STANDBY, rdval);
WARN_ON(sensor->power_count < 0); if (ret < 0)
dev_dbg(dev, "software standby failed\n");
out: clk_disable_unprepare(sensor->xclk);
mutex_unlock(&sensor->lock); gpiod_set_value_cansleep(sensor->pwdn, 1);
return ret; return 0;
} }
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
...@@ -989,7 +979,6 @@ static int ov5647_sensor_set_register(struct v4l2_subdev *sd, ...@@ -989,7 +979,6 @@ static int ov5647_sensor_set_register(struct v4l2_subdev *sd,
/* Subdev core operations registration */ /* Subdev core operations registration */
static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
.s_power = ov5647_sensor_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov5647_sensor_get_register, .g_register = ov5647_sensor_get_register,
.s_register = ov5647_sensor_set_register, .s_register = ov5647_sensor_set_register,
...@@ -1543,24 +1532,29 @@ static int ov5647_probe(struct i2c_client *client) ...@@ -1543,24 +1532,29 @@ static int ov5647_probe(struct i2c_client *client)
if (ret < 0) if (ret < 0)
goto ctrl_handler_free; goto ctrl_handler_free;
if (sensor->pwdn) { ret = ov5647_power_on(dev);
gpiod_set_value_cansleep(sensor->pwdn, 0); if (ret)
msleep(PWDN_ACTIVE_DELAY_MS); goto entity_cleanup;
}
ret = ov5647_detect(sd); ret = ov5647_detect(sd);
gpiod_set_value_cansleep(sensor->pwdn, 1);
if (ret < 0) if (ret < 0)
goto entity_cleanup; goto power_off;
ret = v4l2_async_register_subdev(sd); ret = v4l2_async_register_subdev(sd);
if (ret < 0) if (ret < 0)
goto entity_cleanup; goto power_off;
/* Enable runtime PM and turn off the device */
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_idle(dev);
dev_dbg(dev, "OmniVision OV5647 camera driver probed\n"); dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
return 0; return 0;
power_off:
ov5647_power_off(dev);
entity_cleanup: entity_cleanup:
media_entity_cleanup(&sd->entity); media_entity_cleanup(&sd->entity);
ctrl_handler_free: ctrl_handler_free:
...@@ -1580,11 +1574,16 @@ static int ov5647_remove(struct i2c_client *client) ...@@ -1580,11 +1574,16 @@ static int ov5647_remove(struct i2c_client *client)
media_entity_cleanup(&sensor->sd.entity); media_entity_cleanup(&sensor->sd.entity);
v4l2_ctrl_handler_free(&sensor->ctrls); v4l2_ctrl_handler_free(&sensor->ctrls);
v4l2_device_unregister_subdev(sd); v4l2_device_unregister_subdev(sd);
pm_runtime_disable(&client->dev);
mutex_destroy(&sensor->lock); mutex_destroy(&sensor->lock);
return 0; return 0;
} }
static const struct dev_pm_ops ov5647_pm_ops = {
SET_RUNTIME_PM_OPS(ov5647_power_off, ov5647_power_on, NULL)
};
static const struct i2c_device_id ov5647_id[] = { static const struct i2c_device_id ov5647_id[] = {
{ "ov5647", 0 }, { "ov5647", 0 },
{ /* sentinel */ } { /* sentinel */ }
...@@ -1603,6 +1602,7 @@ static struct i2c_driver ov5647_driver = { ...@@ -1603,6 +1602,7 @@ static struct i2c_driver ov5647_driver = {
.driver = { .driver = {
.of_match_table = of_match_ptr(ov5647_of_match), .of_match_table = of_match_ptr(ov5647_of_match),
.name = "ov5647", .name = "ov5647",
.pm = &ov5647_pm_ops,
}, },
.probe_new = ov5647_probe, .probe_new = ov5647_probe,
.remove = ov5647_remove, .remove = ov5647_remove,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment