mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
media: atomisp: gc0310: Add runtime-pm support
Add runtime-pm support. This is a preparation patch for letting ACPI deal with the regulators and clocks instead of the DIY code in atomisp_gmin_platform.c. Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
b6763b2247
commit
2726c899fb
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <linux/io.h>
|
||||
#include "../include/linux/atomisp_gmin_platform.h"
|
||||
|
|
@ -96,7 +97,8 @@ static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
container_of(ctrl->handler, struct gc0310_device, ctrls.handler);
|
||||
int ret;
|
||||
|
||||
if (!dev->power_on)
|
||||
/* Only apply changes to the controls if the device is powered up */
|
||||
if (!pm_runtime_get_if_in_use(dev->sd.dev))
|
||||
return 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
|
|
@ -111,6 +113,7 @@ static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
break;
|
||||
}
|
||||
|
||||
pm_runtime_put(dev->sd.dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -184,9 +187,6 @@ static int power_up(struct v4l2_subdev *sd)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (dev->power_on)
|
||||
return 0; /* Already on */
|
||||
|
||||
/* power control */
|
||||
ret = power_ctrl(sd, 1);
|
||||
if (ret)
|
||||
|
|
@ -207,7 +207,6 @@ static int power_up(struct v4l2_subdev *sd)
|
|||
|
||||
msleep(100);
|
||||
|
||||
dev->power_on = true;
|
||||
return 0;
|
||||
|
||||
fail_gpio:
|
||||
|
|
@ -232,9 +231,6 @@ static int power_down(struct v4l2_subdev *sd)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!dev->power_on)
|
||||
return 0; /* Already off */
|
||||
|
||||
/* gpio ctrl */
|
||||
ret = gpio_ctrl(sd, 0);
|
||||
if (ret) {
|
||||
|
|
@ -252,7 +248,6 @@ static int power_down(struct v4l2_subdev *sd)
|
|||
if (ret)
|
||||
dev_err(&client->dev, "vprog failed.\n");
|
||||
|
||||
dev->power_on = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -334,15 +329,20 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
{
|
||||
struct gc0310_device *dev = to_gc0310_sensor(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable);
|
||||
mutex_lock(&dev->input_lock);
|
||||
|
||||
if (dev->is_streaming == enable) {
|
||||
dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped");
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ret = power_up(sd);
|
||||
if (ret)
|
||||
goto error_unlock;
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
if (ret < 0)
|
||||
goto error_power_down;
|
||||
|
||||
ret = gc0310_write_reg_array(client, gc0310_reset_register,
|
||||
ARRAY_SIZE(gc0310_reset_register));
|
||||
|
|
@ -379,13 +379,15 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
goto error_power_down;
|
||||
|
||||
if (!enable)
|
||||
power_down(sd);
|
||||
pm_runtime_put(&client->dev);
|
||||
|
||||
dev->is_streaming = enable;
|
||||
mutex_unlock(&dev->input_lock);
|
||||
return 0;
|
||||
|
||||
error_power_down:
|
||||
power_down(sd);
|
||||
pm_runtime_put(&client->dev);
|
||||
dev->is_streaming = false;
|
||||
error_unlock:
|
||||
mutex_unlock(&dev->input_lock);
|
||||
return ret;
|
||||
|
|
@ -405,19 +407,9 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
|
|||
(struct camera_sensor_platform_data *)platform_data;
|
||||
|
||||
mutex_lock(&dev->input_lock);
|
||||
/* power off the module, then power on it in future
|
||||
* as first power on by board may not fulfill the
|
||||
* power on sequqence needed by the module
|
||||
*/
|
||||
dev->power_on = true; /* force power_down() to run */
|
||||
ret = power_down(sd);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "gc0310 power-off err.\n");
|
||||
goto fail_power_off;
|
||||
}
|
||||
|
||||
ret = power_up(sd);
|
||||
if (ret) {
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "gc0310 power-up err.\n");
|
||||
goto fail_power_on;
|
||||
}
|
||||
|
|
@ -434,11 +426,7 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
|
|||
}
|
||||
|
||||
/* turn off sensor, after probed */
|
||||
ret = power_down(sd);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "gc0310 power-off err.\n");
|
||||
goto fail_csi_cfg;
|
||||
}
|
||||
pm_runtime_put(&client->dev);
|
||||
mutex_unlock(&dev->input_lock);
|
||||
|
||||
return 0;
|
||||
|
|
@ -446,9 +434,7 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
|
|||
fail_csi_cfg:
|
||||
dev->platform_data->csi_cfg(sd, 0);
|
||||
fail_power_on:
|
||||
power_down(sd);
|
||||
dev_err(&client->dev, "sensor power-gating failed\n");
|
||||
fail_power_off:
|
||||
pm_runtime_put(&client->dev);
|
||||
mutex_unlock(&dev->input_lock);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -550,6 +536,7 @@ static void gc0310_remove(struct i2c_client *client)
|
|||
v4l2_device_unregister_subdev(sd);
|
||||
media_entity_cleanup(&dev->sd.entity);
|
||||
v4l2_ctrl_handler_free(&dev->ctrls.handler);
|
||||
pm_runtime_disable(&client->dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
|
|
@ -575,13 +562,22 @@ static int gc0310_probe(struct i2c_client *client)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
|
||||
ret = gc0310_s_config(&dev->sd, client->irq, pdata);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
if (ret) {
|
||||
gc0310_remove(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
if (ret) {
|
||||
gc0310_remove(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
|
@ -604,6 +600,22 @@ static int gc0310_probe(struct i2c_client *client)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int gc0310_suspend(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
|
||||
return power_down(sd);
|
||||
}
|
||||
|
||||
static int gc0310_resume(struct device *dev)
|
||||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
|
||||
return power_up(sd);
|
||||
}
|
||||
|
||||
static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, gc0310_suspend, gc0310_resume, NULL);
|
||||
|
||||
static const struct acpi_device_id gc0310_acpi_match[] = {
|
||||
{"XXGC0310"},
|
||||
{"INT0310"},
|
||||
|
|
@ -614,6 +626,7 @@ MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match);
|
|||
static struct i2c_driver gc0310_driver = {
|
||||
.driver = {
|
||||
.name = "gc0310",
|
||||
.pm = pm_sleep_ptr(&gc0310_pm_ops),
|
||||
.acpi_match_table = gc0310_acpi_match,
|
||||
},
|
||||
.probe_new = gc0310_probe,
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ struct gc0310_device {
|
|||
struct mutex input_lock;
|
||||
|
||||
struct camera_sensor_platform_data *platform_data;
|
||||
bool power_on;
|
||||
bool is_streaming;
|
||||
|
||||
struct gc0310_mode {
|
||||
struct v4l2_mbus_framefmt fmt;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user