mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
media: i2c: ov5670: Add runtime_pm operations
Implement the runtime resume and suspend routines and install them as runtime_pm handlers. While at it rework the probe() sequence in order to enable runtime_pm before registering the async subdevice. Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Tested-by: Luca Weiss <luca@z3ntu.xyz> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
0a844ab77b
commit
62ab1e3259
@ -1,8 +1,10 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (c) 2017 Intel Corporation.
|
// Copyright (c) 2017 Intel Corporation.
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/mod_devicetable.h>
|
#include <linux/mod_devicetable.h>
|
||||||
@ -2429,6 +2431,49 @@ unlock_and_return:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused ov5670_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||||
|
struct ov5670 *ov5670 = to_ov5670(sd);
|
||||||
|
unsigned long delay_us;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(ov5670->xvclk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regulator_bulk_enable(OV5670_NUM_SUPPLIES, ov5670->supplies);
|
||||||
|
if (ret) {
|
||||||
|
clk_disable_unprepare(ov5670->xvclk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpiod_set_value_cansleep(ov5670->pwdn_gpio, 0);
|
||||||
|
gpiod_set_value_cansleep(ov5670->reset_gpio, 0);
|
||||||
|
|
||||||
|
/* 8192 * 2 clock pulses before the first SCCB transaction. */
|
||||||
|
delay_us = DIV_ROUND_UP(8192 * 2 * 1000,
|
||||||
|
DIV_ROUND_UP(OV5670_XVCLK_FREQ, 1000));
|
||||||
|
fsleep(delay_us);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused ov5670_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||||
|
struct ov5670 *ov5670 = to_ov5670(sd);
|
||||||
|
|
||||||
|
gpiod_set_value_cansleep(ov5670->reset_gpio, 1);
|
||||||
|
gpiod_set_value_cansleep(ov5670->pwdn_gpio, 1);
|
||||||
|
regulator_bulk_disable(OV5670_NUM_SUPPLIES, ov5670->supplies);
|
||||||
|
clk_disable_unprepare(ov5670->xvclk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __maybe_unused ov5670_suspend(struct device *dev)
|
static int __maybe_unused ov5670_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||||
@ -2570,11 +2615,17 @@ static int ov5670_probe(struct i2c_client *client)
|
|||||||
|
|
||||||
full_power = acpi_dev_state_d0(&client->dev);
|
full_power = acpi_dev_state_d0(&client->dev);
|
||||||
if (full_power) {
|
if (full_power) {
|
||||||
|
ret = ov5670_runtime_resume(&client->dev);
|
||||||
|
if (ret) {
|
||||||
|
err_msg = "Power up failed";
|
||||||
|
goto error_print;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check module identity */
|
/* Check module identity */
|
||||||
ret = ov5670_identify_module(ov5670);
|
ret = ov5670_identify_module(ov5670);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
err_msg = "ov5670_identify_module() error";
|
err_msg = "ov5670_identify_module() error";
|
||||||
goto error_print;
|
goto error_power_off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2603,24 +2654,27 @@ static int ov5670_probe(struct i2c_client *client)
|
|||||||
goto error_handler_free;
|
goto error_handler_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Async register for subdev */
|
|
||||||
ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
|
|
||||||
if (ret < 0) {
|
|
||||||
err_msg = "v4l2_async_register_subdev() error";
|
|
||||||
goto error_entity_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ov5670->streaming = false;
|
ov5670->streaming = false;
|
||||||
|
|
||||||
/* Set the device's state to active if it's in D0 state. */
|
/* Set the device's state to active if it's in D0 state. */
|
||||||
if (full_power)
|
if (full_power)
|
||||||
pm_runtime_set_active(&client->dev);
|
pm_runtime_set_active(&client->dev);
|
||||||
pm_runtime_enable(&client->dev);
|
pm_runtime_enable(&client->dev);
|
||||||
|
|
||||||
|
/* Async register for subdev */
|
||||||
|
ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
|
||||||
|
if (ret < 0) {
|
||||||
|
err_msg = "v4l2_async_register_subdev() error";
|
||||||
|
goto error_pm_disable;
|
||||||
|
}
|
||||||
|
|
||||||
pm_runtime_idle(&client->dev);
|
pm_runtime_idle(&client->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_entity_cleanup:
|
error_pm_disable:
|
||||||
|
pm_runtime_disable(&client->dev);
|
||||||
|
|
||||||
media_entity_cleanup(&ov5670->sd.entity);
|
media_entity_cleanup(&ov5670->sd.entity);
|
||||||
|
|
||||||
error_handler_free:
|
error_handler_free:
|
||||||
@ -2629,6 +2683,10 @@ error_handler_free:
|
|||||||
error_mutex_destroy:
|
error_mutex_destroy:
|
||||||
mutex_destroy(&ov5670->mutex);
|
mutex_destroy(&ov5670->mutex);
|
||||||
|
|
||||||
|
error_power_off:
|
||||||
|
if (full_power)
|
||||||
|
ov5670_runtime_suspend(&client->dev);
|
||||||
|
|
||||||
error_print:
|
error_print:
|
||||||
dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret);
|
dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret);
|
||||||
|
|
||||||
@ -2646,10 +2704,12 @@ static void ov5670_remove(struct i2c_client *client)
|
|||||||
mutex_destroy(&ov5670->mutex);
|
mutex_destroy(&ov5670->mutex);
|
||||||
|
|
||||||
pm_runtime_disable(&client->dev);
|
pm_runtime_disable(&client->dev);
|
||||||
|
ov5670_runtime_suspend(&client->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops ov5670_pm_ops = {
|
static const struct dev_pm_ops ov5670_pm_ops = {
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume)
|
SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume)
|
||||||
|
SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
|
Loading…
Reference in New Issue
Block a user