Commit cbba45d4 authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab

[media] smiapp: Use runtime PM

Switch to runtime PM in sensor power management. The internal power count
is thus removed.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 4ecc2d75
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smiapp.h> #include <linux/smiapp.h>
...@@ -1202,9 +1203,17 @@ static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) ...@@ -1202,9 +1203,17 @@ static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
* Power management * Power management
*/ */
static int smiapp_power_on(struct smiapp_sensor *sensor) static int smiapp_power_on(struct device *dev)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
/*
* The sub-device related to the I2C device is always the
* source one, i.e. ssds[0].
*/
struct smiapp_sensor *sensor =
container_of(ssd, struct smiapp_sensor, ssds[0]);
unsigned int sleep; unsigned int sleep;
int rval; int rval;
...@@ -1330,16 +1339,24 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) ...@@ -1330,16 +1339,24 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
return 0; return 0;
out_cci_addr_fail: out_cci_addr_fail:
gpiod_set_value(sensor->xshutdown, 0); gpiod_set_value(sensor->xshutdown, 0);
clk_disable_unprepare(sensor->ext_clk); clk_disable_unprepare(sensor->ext_clk);
out_xclk_fail: out_xclk_fail:
regulator_disable(sensor->vana); regulator_disable(sensor->vana);
return rval; return rval;
} }
static void smiapp_power_off(struct smiapp_sensor *sensor) static int smiapp_power_off(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
struct smiapp_sensor *sensor =
container_of(ssd, struct smiapp_sensor, ssds[0]);
/* /*
* Currently power/clock to lens are enable/disabled separately * Currently power/clock to lens are enable/disabled separately
* but they are essentially the same signals. So if the sensor is * but they are essentially the same signals. So if the sensor is
...@@ -1357,31 +1374,26 @@ static void smiapp_power_off(struct smiapp_sensor *sensor) ...@@ -1357,31 +1374,26 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
usleep_range(5000, 5000); usleep_range(5000, 5000);
regulator_disable(sensor->vana); regulator_disable(sensor->vana);
sensor->streaming = false; sensor->streaming = false;
return 0;
} }
static int smiapp_set_power(struct v4l2_subdev *subdev, int on) static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
{ {
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); int rval = 0;
int ret = 0;
mutex_lock(&sensor->power_mutex); if (on) {
rval = pm_runtime_get_sync(subdev->dev);
if (rval >= 0)
return 0;
if (on && !sensor->power_count) { if (rval != -EBUSY && rval != -EAGAIN)
/* Power on and perform initialisation. */ pm_runtime_set_active(subdev->dev);
ret = smiapp_power_on(sensor);
if (ret < 0)
goto out;
} else if (!on && sensor->power_count == 1) {
smiapp_power_off(sensor);
} }
/* Update the power count. */ pm_runtime_put(subdev->dev);
sensor->power_count += on ? 1 : -1;
WARN_ON(sensor->power_count < 0);
out: return rval;
mutex_unlock(&sensor->power_mutex);
return ret;
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -2310,15 +2322,25 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, ...@@ -2310,15 +2322,25 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
return -EBUSY; return -EBUSY;
if (!sensor->nvm_size) { if (!sensor->nvm_size) {
int rval;
/* NVM not read yet - read it now */ /* NVM not read yet - read it now */
sensor->nvm_size = sensor->hwcfg->nvm_size; sensor->nvm_size = sensor->hwcfg->nvm_size;
if (smiapp_set_power(subdev, 1) < 0)
rval = pm_runtime_get_sync(&client->dev);
if (rval < 0) {
if (rval != -EBUSY && rval != -EAGAIN)
pm_runtime_set_active(&client->dev);
pm_runtime_put(&client->dev);
return -ENODEV; return -ENODEV;
}
if (smiapp_read_nvm(sensor, sensor->nvm)) { if (smiapp_read_nvm(sensor, sensor->nvm)) {
dev_err(&client->dev, "nvm read failed\n"); dev_err(&client->dev, "nvm read failed\n");
return -ENODEV; return -ENODEV;
} }
smiapp_set_power(subdev, 0);
pm_runtime_put(&client->dev);
} }
/* /*
* NVM is still way below a PAGE_SIZE, so we can safely * NVM is still way below a PAGE_SIZE, so we can safely
...@@ -2619,6 +2641,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ...@@ -2619,6 +2641,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
struct smiapp_subdev *ssd = to_smiapp_subdev(sd); struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
struct smiapp_sensor *sensor = ssd->sensor; struct smiapp_sensor *sensor = ssd->sensor;
unsigned int i; unsigned int i;
int rval;
mutex_lock(&sensor->mutex); mutex_lock(&sensor->mutex);
...@@ -2645,12 +2668,22 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ...@@ -2645,12 +2668,22 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_unlock(&sensor->mutex); mutex_unlock(&sensor->mutex);
return smiapp_set_power(sd, 1); rval = pm_runtime_get_sync(sd->dev);
if (rval >= 0)
return 0;
if (rval != -EBUSY && rval != -EAGAIN)
pm_runtime_set_active(sd->dev);
pm_runtime_put(sd->dev);
return rval;
} }
static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{ {
return smiapp_set_power(sd, 0); pm_runtime_put(sd->dev);
return 0;
} }
static const struct v4l2_subdev_video_ops smiapp_video_ops = { static const struct v4l2_subdev_video_ops smiapp_video_ops = {
...@@ -2708,18 +2741,20 @@ static int smiapp_suspend(struct device *dev) ...@@ -2708,18 +2741,20 @@ static int smiapp_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
bool streaming; bool streaming = sensor->streaming;
int rval;
if (sensor->power_count == 0) rval = pm_runtime_get_sync(dev);
return 0; if (rval < 0) {
if (rval != -EBUSY && rval != -EAGAIN)
pm_runtime_set_active(&client->dev);
pm_runtime_put(dev);
return -EAGAIN;
}
if (sensor->streaming) if (sensor->streaming)
smiapp_stop_streaming(sensor); smiapp_stop_streaming(sensor);
streaming = sensor->streaming;
smiapp_power_off(sensor);
/* save state for resume */ /* save state for resume */
sensor->streaming = streaming; sensor->streaming = streaming;
...@@ -2731,14 +2766,9 @@ static int smiapp_resume(struct device *dev) ...@@ -2731,14 +2766,9 @@ static int smiapp_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
int rval; int rval = 0;
if (sensor->power_count == 0)
return 0;
rval = smiapp_power_on(sensor); pm_runtime_put(dev);
if (rval)
return rval;
if (sensor->streaming) if (sensor->streaming)
rval = smiapp_start_streaming(sensor); rval = smiapp_start_streaming(sensor);
...@@ -2845,7 +2875,6 @@ static int smiapp_probe(struct i2c_client *client, ...@@ -2845,7 +2875,6 @@ static int smiapp_probe(struct i2c_client *client,
sensor->hwcfg = hwcfg; sensor->hwcfg = hwcfg;
mutex_init(&sensor->mutex); mutex_init(&sensor->mutex);
mutex_init(&sensor->power_mutex);
sensor->src = &sensor->ssds[sensor->ssds_used]; sensor->src = &sensor->ssds[sensor->ssds_used];
v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops); v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
...@@ -2877,9 +2906,13 @@ static int smiapp_probe(struct i2c_client *client, ...@@ -2877,9 +2906,13 @@ static int smiapp_probe(struct i2c_client *client,
if (IS_ERR(sensor->xshutdown)) if (IS_ERR(sensor->xshutdown))
return PTR_ERR(sensor->xshutdown); return PTR_ERR(sensor->xshutdown);
rval = smiapp_power_on(sensor); pm_runtime_enable(&client->dev);
if (rval)
return -ENODEV; rval = pm_runtime_get_sync(&client->dev);
if (rval < 0) {
rval = -ENODEV;
goto out_power_off;
}
rval = smiapp_identify_module(sensor); rval = smiapp_identify_module(sensor);
if (rval) { if (rval) {
...@@ -3051,8 +3084,6 @@ static int smiapp_probe(struct i2c_client *client, ...@@ -3051,8 +3084,6 @@ static int smiapp_probe(struct i2c_client *client,
sensor->streaming = false; sensor->streaming = false;
sensor->dev_init_done = true; sensor->dev_init_done = true;
smiapp_power_off(sensor);
rval = media_entity_pads_init(&sensor->src->sd.entity, 2, rval = media_entity_pads_init(&sensor->src->sd.entity, 2,
sensor->src->pads); sensor->src->pads);
if (rval < 0) if (rval < 0)
...@@ -3062,6 +3093,8 @@ static int smiapp_probe(struct i2c_client *client, ...@@ -3062,6 +3093,8 @@ static int smiapp_probe(struct i2c_client *client,
if (rval < 0) if (rval < 0)
goto out_media_entity_cleanup; goto out_media_entity_cleanup;
pm_runtime_put(&client->dev);
return 0; return 0;
out_media_entity_cleanup: out_media_entity_cleanup:
...@@ -3071,7 +3104,9 @@ static int smiapp_probe(struct i2c_client *client, ...@@ -3071,7 +3104,9 @@ static int smiapp_probe(struct i2c_client *client,
smiapp_cleanup(sensor); smiapp_cleanup(sensor);
out_power_off: out_power_off:
smiapp_power_off(sensor); pm_runtime_put(&client->dev);
pm_runtime_disable(&client->dev);
return rval; return rval;
} }
...@@ -3083,11 +3118,8 @@ static int smiapp_remove(struct i2c_client *client) ...@@ -3083,11 +3118,8 @@ static int smiapp_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(subdev); v4l2_async_unregister_subdev(subdev);
if (sensor->power_count) { pm_runtime_suspend(&client->dev);
gpiod_set_value(sensor->xshutdown, 0); pm_runtime_disable(&client->dev);
clk_disable_unprepare(sensor->ext_clk);
sensor->power_count = 0;
}
for (i = 0; i < sensor->ssds_used; i++) { for (i = 0; i < sensor->ssds_used; i++) {
v4l2_device_unregister_subdev(&sensor->ssds[i].sd); v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
...@@ -3112,6 +3144,7 @@ MODULE_DEVICE_TABLE(i2c, smiapp_id_table); ...@@ -3112,6 +3144,7 @@ MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
static const struct dev_pm_ops smiapp_pm_ops = { static const struct dev_pm_ops smiapp_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(smiapp_suspend, smiapp_resume) SET_SYSTEM_SLEEP_PM_OPS(smiapp_suspend, smiapp_resume)
SET_RUNTIME_PM_OPS(smiapp_power_off, smiapp_power_on, NULL)
}; };
static struct i2c_driver smiapp_i2c_driver = { static struct i2c_driver smiapp_i2c_driver = {
......
...@@ -176,16 +176,9 @@ struct smiapp_sensor { ...@@ -176,16 +176,9 @@ struct smiapp_sensor {
* "mutex" is used to serialise access to all fields here * "mutex" is used to serialise access to all fields here
* except v4l2_ctrls at the end of the struct. "mutex" is also * except v4l2_ctrls at the end of the struct. "mutex" is also
* used to serialise access to file handle specific * used to serialise access to file handle specific
* information. The exception to this rule is the power_mutex * information.
* below.
*/ */
struct mutex mutex; struct mutex mutex;
/*
* power_mutex is used to serialise power management related
* activities. Acquiring "mutex" at that time isn't necessary
* since there are no other users anyway.
*/
struct mutex power_mutex;
struct smiapp_subdev ssds[SMIAPP_SUBDEVS]; struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
u32 ssds_used; u32 ssds_used;
struct smiapp_subdev *src; struct smiapp_subdev *src;
...@@ -218,8 +211,6 @@ struct smiapp_sensor { ...@@ -218,8 +211,6 @@ struct smiapp_sensor {
u16 image_start; /* image data start line */ u16 image_start; /* image data start line */
u16 visible_pixel_start; /* start pixel of the visible image */ u16 visible_pixel_start; /* start pixel of the visible image */
int power_count;
bool streaming; bool streaming;
bool dev_init_done; bool dev_init_done;
u8 compressed_min_bpp; u8 compressed_min_bpp;
......
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