summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/ov5670.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/ov5670.c')
-rw-r--r--drivers/media/i2c/ov5670.c175
1 files changed, 69 insertions, 106 deletions
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index d722348b938b..04b3183b7bcb 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017 Intel Corporation.
-#include <asm/unaligned.h>
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -12,6 +11,8 @@
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/unaligned.h>
+
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
@@ -1854,6 +1855,8 @@ static const struct ov5670_mode supported_modes[] = {
};
struct ov5670 {
+ struct device *dev;
+
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_fwnode_endpoint endpoint;
@@ -1879,11 +1882,9 @@ struct ov5670 {
struct gpio_desc *pwdn_gpio; /* PWDNB pin. */
struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */
- /* To serialize asynchronus callbacks */
+ /* To serialize asynchronous callbacks */
struct mutex mutex;
- /* Streaming on/off */
- bool streaming;
/* True if the device has been identified */
bool identified;
};
@@ -1961,7 +1962,6 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len,
static int ov5670_write_regs(struct ov5670 *ov5670,
const struct ov5670_reg *regs, unsigned int len)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
unsigned int i;
int ret;
@@ -1969,7 +1969,7 @@ static int ov5670_write_regs(struct ov5670 *ov5670,
ret = ov5670_write_reg(ov5670, regs[i].address, 1, regs[i].val);
if (ret) {
dev_err_ratelimited(
- &client->dev,
+ ov5670->dev,
"Failed to write reg 0x%4.4x. error = %d\n",
regs[i].address, ret);
@@ -2034,7 +2034,6 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov5670 *ov5670 = container_of(ctrl->handler,
struct ov5670, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
s64 max;
int ret;
@@ -2050,7 +2049,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
}
/* V4L2 controls values will be applied only when power is already up */
- if (!pm_runtime_get_if_in_use(&client->dev))
+ if (!pm_runtime_get_if_in_use(ov5670->dev))
return 0;
switch (ctrl->id) {
@@ -2082,12 +2081,12 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
break;
default:
ret = -EINVAL;
- dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+ dev_info(ov5670->dev, "%s Unhandled id:0x%x, val:0x%x\n",
__func__, ctrl->id, ctrl->val);
break;
}
- pm_runtime_put(&client->dev);
+ pm_runtime_put(ov5670->dev);
return ret;
}
@@ -2101,7 +2100,6 @@ static int ov5670_init_controls(struct ov5670 *ov5670)
{
struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 =
&ov5670->endpoint.bus.mipi_csi2;
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
unsigned int lanes_count;
@@ -2179,7 +2177,7 @@ static int ov5670_init_controls(struct ov5670 *ov5670)
goto error;
}
- ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ ret = v4l2_fwnode_device_parse(ov5670->dev, &props);
if (ret)
goto error;
@@ -2198,13 +2196,13 @@ error:
return ret;
}
-static int ov5670_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ov5670_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_try_format(sd, state, 0);
+ v4l2_subdev_state_get_format(state, 0);
const struct ov5670_mode *default_mode = &supported_modes[0];
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0);
fmt->width = default_mode->width;
fmt->height = default_mode->height;
@@ -2265,9 +2263,8 @@ static int ov5670_do_get_pad_format(struct ov5670 *ov5670,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
ov5670_update_pad_format(ov5670->cur_mode, fmt);
@@ -2312,7 +2309,7 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov5670_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
ov5670->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index);
@@ -2353,7 +2350,6 @@ static int ov5670_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
/* Verify chip ID */
static int ov5670_identify_module(struct ov5670 *ov5670)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
int ret;
u32 val;
@@ -2366,7 +2362,7 @@ static int ov5670_identify_module(struct ov5670 *ov5670)
return ret;
if (val != OV5670_CHIP_ID) {
- dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ dev_err(ov5670->dev, "chip id mismatch: %x!=%x\n",
OV5670_CHIP_ID, val);
return -ENXIO;
}
@@ -2392,7 +2388,6 @@ static int ov5670_mipi_configure(struct ov5670 *ov5670)
/* Prepare streaming by writing default values and customized values */
static int ov5670_start_streaming(struct ov5670 *ov5670)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
const struct ov5670_reg_list *reg_list;
int link_freq_index;
int ret;
@@ -2405,7 +2400,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
ret = ov5670_write_reg(ov5670, OV5670_REG_SOFTWARE_RST,
OV5670_REG_VALUE_08BIT, OV5670_SOFTWARE_RST);
if (ret) {
- dev_err(&client->dev, "%s failed to set powerup registers\n",
+ dev_err(ov5670->dev, "%s failed to set powerup registers\n",
__func__);
return ret;
}
@@ -2415,7 +2410,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
reg_list = &link_freq_configs[link_freq_index].reg_list;
ret = ov5670_write_reg_list(ov5670, reg_list);
if (ret) {
- dev_err(&client->dev, "%s failed to set plls\n", __func__);
+ dev_err(ov5670->dev, "%s failed to set plls\n", __func__);
return ret;
}
@@ -2423,13 +2418,13 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
reg_list = &ov5670->cur_mode->reg_list;
ret = ov5670_write_reg_list(ov5670, reg_list);
if (ret) {
- dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ dev_err(ov5670->dev, "%s failed to set mode\n", __func__);
return ret;
}
ret = ov5670_mipi_configure(ov5670);
if (ret) {
- dev_err(&client->dev, "%s failed to configure MIPI\n", __func__);
+ dev_err(ov5670->dev, "%s failed to configure MIPI\n", __func__);
return ret;
}
@@ -2441,7 +2436,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT,
OV5670_REG_VALUE_08BIT, OV5670_MODE_STREAMING);
if (ret) {
- dev_err(&client->dev, "%s failed to set stream\n", __func__);
+ dev_err(ov5670->dev, "%s failed to set stream\n", __func__);
return ret;
}
@@ -2450,13 +2445,12 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
static int ov5670_stop_streaming(struct ov5670 *ov5670)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
int ret;
ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT,
OV5670_REG_VALUE_08BIT, OV5670_MODE_STANDBY);
if (ret)
- dev_err(&client->dev, "%s failed to set stream\n", __func__);
+ dev_err(ov5670->dev, "%s failed to set stream\n", __func__);
/* Return success even if it was an error, as there is nothing the
* caller can do about it.
@@ -2467,15 +2461,12 @@ static int ov5670_stop_streaming(struct ov5670 *ov5670)
static int ov5670_set_stream(struct v4l2_subdev *sd, int enable)
{
struct ov5670 *ov5670 = to_ov5670(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
mutex_lock(&ov5670->mutex);
- if (ov5670->streaming == enable)
- goto unlock_and_return;
if (enable) {
- ret = pm_runtime_resume_and_get(&client->dev);
+ ret = pm_runtime_resume_and_get(ov5670->dev);
if (ret < 0)
goto unlock_and_return;
@@ -2484,13 +2475,12 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable)
goto error;
} else {
ret = ov5670_stop_streaming(ov5670);
- pm_runtime_put(&client->dev);
+ pm_runtime_put(ov5670->dev);
}
- ov5670->streaming = enable;
goto unlock_and_return;
error:
- pm_runtime_put(&client->dev);
+ pm_runtime_put(ov5670->dev);
unlock_and_return:
mutex_unlock(&ov5670->mutex);
@@ -2541,34 +2531,6 @@ static int __maybe_unused ov5670_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ov5670_suspend(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct ov5670 *ov5670 = to_ov5670(sd);
-
- if (ov5670->streaming)
- ov5670_stop_streaming(ov5670);
-
- return 0;
-}
-
-static int __maybe_unused ov5670_resume(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct ov5670 *ov5670 = to_ov5670(sd);
- int ret;
-
- if (ov5670->streaming) {
- ret = ov5670_start_streaming(ov5670);
- if (ret) {
- ov5670_stop_streaming(ov5670);
- return ret;
- }
- }
-
- return 0;
-}
-
static const struct v4l2_subdev_core_ops ov5670_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
@@ -2583,7 +2545,7 @@ __ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state,
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&sensor->sd, state, pad);
+ return v4l2_subdev_state_get_crop(state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return mode->analog_crop;
}
@@ -2626,7 +2588,6 @@ static const struct v4l2_subdev_video_ops ov5670_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov5670_pad_ops = {
- .init_cfg = ov5670_init_cfg,
.enum_mbus_code = ov5670_enum_mbus_code,
.get_fmt = ov5670_get_pad_format,
.set_fmt = ov5670_set_pad_format,
@@ -2646,32 +2607,33 @@ static const struct v4l2_subdev_ops ov5670_subdev_ops = {
.sensor = &ov5670_sensor_ops,
};
+static const struct v4l2_subdev_internal_ops ov5670_internal_ops = {
+ .init_state = ov5670_init_state,
+};
+
static const struct media_entity_operations ov5670_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
static int ov5670_regulators_probe(struct ov5670 *ov5670)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
unsigned int i;
for (i = 0; i < OV5670_NUM_SUPPLIES; i++)
ov5670->supplies[i].supply = ov5670_supply_names[i];
- return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES,
+ return devm_regulator_bulk_get(ov5670->dev, OV5670_NUM_SUPPLIES,
ov5670->supplies);
}
static int ov5670_gpio_probe(struct ov5670 *ov5670)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
-
- ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+ ov5670->pwdn_gpio = devm_gpiod_get_optional(ov5670->dev, "powerdown",
GPIOD_OUT_LOW);
if (IS_ERR(ov5670->pwdn_gpio))
return PTR_ERR(ov5670->pwdn_gpio);
- ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ ov5670->reset_gpio = devm_gpiod_get_optional(ov5670->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(ov5670->reset_gpio))
return PTR_ERR(ov5670->reset_gpio);
@@ -2691,37 +2653,41 @@ static int ov5670_probe(struct i2c_client *client)
if (!ov5670)
return -ENOMEM;
- ov5670->xvclk = devm_clk_get_optional(&client->dev, NULL);
- if (!IS_ERR_OR_NULL(ov5670->xvclk))
- input_clk = clk_get_rate(ov5670->xvclk);
- else if (!ov5670->xvclk || PTR_ERR(ov5670->xvclk) == -ENOENT)
- device_property_read_u32(&client->dev, "clock-frequency",
- &input_clk);
- else
- return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk),
+ ov5670->dev = &client->dev;
+
+ ov5670->xvclk = devm_v4l2_sensor_clk_get(ov5670->dev, NULL);
+ if (IS_ERR(ov5670->xvclk))
+ return dev_err_probe(ov5670->dev, PTR_ERR(ov5670->xvclk),
"error getting clock\n");
+ input_clk = clk_get_rate(ov5670->xvclk);
if (input_clk != OV5670_XVCLK_FREQ) {
- dev_err(&client->dev,
+ dev_err(ov5670->dev,
"Unsupported clock frequency %u\n", input_clk);
return -EINVAL;
}
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops);
+ ov5670->sd.internal_ops = &ov5670_internal_ops;
ret = ov5670_regulators_probe(ov5670);
if (ret)
- return dev_err_probe(&client->dev, ret, "Regulators probe failed\n");
+ return dev_err_probe(ov5670->dev, ret, "Regulators probe failed\n");
ret = ov5670_gpio_probe(ov5670);
if (ret)
- return dev_err_probe(&client->dev, ret, "GPIO probe failed\n");
+ return dev_err_probe(ov5670->dev, ret, "GPIO probe failed\n");
- /* Graph Endpoint */
- handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+ /*
+ * Graph Endpoint. If it's missing we defer rather than fail, as this
+ * sensor is known to co-exist on systems with the IPU3 and so it might
+ * be created by the ipu-bridge.
+ */
+ handle = fwnode_graph_get_next_endpoint(dev_fwnode(ov5670->dev), NULL);
if (!handle)
- return dev_err_probe(&client->dev, -ENXIO, "Endpoint for node get failed\n");
+ return dev_err_probe(ov5670->dev, -EPROBE_DEFER,
+ "Endpoint for node get failed\n");
ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY;
ov5670->endpoint.bus.mipi_csi2.num_data_lanes = 2;
@@ -2729,20 +2695,20 @@ static int ov5670_probe(struct i2c_client *client)
ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ov5670->endpoint);
fwnode_handle_put(handle);
if (ret)
- return dev_err_probe(&client->dev, ret, "Endpoint parse failed\n");
+ return dev_err_probe(ov5670->dev, ret, "Endpoint parse failed\n");
- full_power = acpi_dev_state_d0(&client->dev);
+ full_power = acpi_dev_state_d0(ov5670->dev);
if (full_power) {
- ret = ov5670_runtime_resume(&client->dev);
+ ret = ov5670_runtime_resume(ov5670->dev);
if (ret) {
- dev_err_probe(&client->dev, ret, "Power up failed\n");
+ dev_err_probe(ov5670->dev, ret, "Power up failed\n");
goto error_endpoint;
}
/* Check module identity */
ret = ov5670_identify_module(ov5670);
if (ret) {
- dev_err_probe(&client->dev, ret, "ov5670_identify_module() error\n");
+ dev_err_probe(ov5670->dev, ret, "ov5670_identify_module() error\n");
goto error_power_off;
}
}
@@ -2754,7 +2720,7 @@ static int ov5670_probe(struct i2c_client *client)
ret = ov5670_init_controls(ov5670);
if (ret) {
- dev_err_probe(&client->dev, ret, "ov5670_init_controls() error\n");
+ dev_err_probe(ov5670->dev, ret, "ov5670_init_controls() error\n");
goto error_mutex_destroy;
}
@@ -2767,30 +2733,28 @@ static int ov5670_probe(struct i2c_client *client)
ov5670->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&ov5670->sd.entity, 1, &ov5670->pad);
if (ret) {
- dev_err_probe(&client->dev, ret, "media_entity_pads_init() error\n");
+ dev_err_probe(ov5670->dev, ret, "media_entity_pads_init() error\n");
goto error_handler_free;
}
- ov5670->streaming = false;
-
/* Set the device's state to active if it's in D0 state. */
if (full_power)
- pm_runtime_set_active(&client->dev);
- pm_runtime_enable(&client->dev);
+ pm_runtime_set_active(ov5670->dev);
+ pm_runtime_enable(ov5670->dev);
/* Async register for subdev */
ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
if (ret < 0) {
- dev_err_probe(&client->dev, ret, "v4l2_async_register_subdev() error\n");
+ dev_err_probe(ov5670->dev, ret, "v4l2_async_register_subdev() error\n");
goto error_pm_disable;
}
- pm_runtime_idle(&client->dev);
+ pm_runtime_idle(ov5670->dev);
return 0;
error_pm_disable:
- pm_runtime_disable(&client->dev);
+ pm_runtime_disable(ov5670->dev);
media_entity_cleanup(&ov5670->sd.entity);
@@ -2802,7 +2766,7 @@ error_mutex_destroy:
error_power_off:
if (full_power)
- ov5670_runtime_suspend(&client->dev);
+ ov5670_runtime_suspend(ov5670->dev);
error_endpoint:
v4l2_fwnode_endpoint_free(&ov5670->endpoint);
@@ -2820,14 +2784,13 @@ static void ov5670_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(sd->ctrl_handler);
mutex_destroy(&ov5670->mutex);
- pm_runtime_disable(&client->dev);
- ov5670_runtime_suspend(&client->dev);
+ pm_runtime_disable(ov5670->dev);
+ ov5670_runtime_suspend(ov5670->dev);
v4l2_fwnode_endpoint_free(&ov5670->endpoint);
}
static const struct dev_pm_ops ov5670_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume)
SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL)
};
@@ -2860,7 +2823,7 @@ static struct i2c_driver ov5670_i2c_driver = {
module_i2c_driver(ov5670_i2c_driver);
-MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
+MODULE_AUTHOR("Rapolu, Chiranjeevi");
MODULE_AUTHOR("Yang, Hyungwoo");
MODULE_DESCRIPTION("Omnivision ov5670 sensor driver");
MODULE_LICENSE("GPL v2");