summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/ov13858.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/ov13858.c')
-rw-r--r--drivers/media/i2c/ov13858.c149
1 files changed, 58 insertions, 91 deletions
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index 7fc70af53e45..162b49046990 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -2,11 +2,13 @@
// Copyright (c) 2017 Intel Corporation.
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#define OV13858_REG_VALUE_08BIT 1
@@ -1027,6 +1029,9 @@ static const struct ov13858_mode supported_modes[] = {
};
struct ov13858 {
+ struct device *dev;
+ struct clk *clk;
+
struct v4l2_subdev sd;
struct media_pad pad;
@@ -1043,9 +1048,6 @@ struct ov13858 {
/* Mutex for serialized access */
struct mutex mutex;
-
- /* Streaming on/off */
- bool streaming;
};
#define to_ov13858(_sd) container_of(_sd, struct ov13858, sd)
@@ -1119,7 +1121,6 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len,
static int ov13858_write_regs(struct ov13858 *ov13858,
const struct ov13858_reg *regs, u32 len)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
int ret;
u32 i;
@@ -1128,7 +1129,7 @@ static int ov13858_write_regs(struct ov13858 *ov13858,
regs[i].val);
if (ret) {
dev_err_ratelimited(
- &client->dev,
+ ov13858->dev,
"Failed to write reg 0x%4.4x. error = %d\n",
regs[i].address, ret);
@@ -1149,9 +1150,8 @@ static int ov13858_write_reg_list(struct ov13858 *ov13858,
static int ov13858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov13858 *ov13858 = to_ov13858(sd);
- struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
+ struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state,
+ 0);
mutex_lock(&ov13858->mutex);
@@ -1212,7 +1212,6 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov13858 *ov13858 = container_of(ctrl->handler,
struct ov13858, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
s64 max;
int ret;
@@ -1231,7 +1230,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl)
* Applying V4L2 control value only happens
* when power is up for streaming
*/
- if (!pm_runtime_get_if_in_use(&client->dev))
+ if (!pm_runtime_get_if_in_use(ov13858->dev))
return 0;
ret = 0;
@@ -1259,13 +1258,13 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl)
ret = ov13858_enable_test_pattern(ov13858, ctrl->val);
break;
default:
- dev_info(&client->dev,
+ dev_info(ov13858->dev,
"ctrl(id:0x%x,val:0x%x) is not handled\n",
ctrl->id, ctrl->val);
break;
}
- pm_runtime_put(&client->dev);
+ pm_runtime_put(ov13858->dev);
return ret;
}
@@ -1319,10 +1318,9 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
- struct v4l2_subdev *sd = &ov13858->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
ov13858_update_pad_format(ov13858->cur_mode, fmt);
@@ -1371,7 +1369,7 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov13858_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ov13858->cur_mode = mode;
@@ -1412,7 +1410,6 @@ static int ov13858_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
/* Start streaming */
static int ov13858_start_streaming(struct ov13858 *ov13858)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
const struct ov13858_reg_list *reg_list;
int ret, link_freq_index;
@@ -1420,7 +1417,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858)
ret = ov13858_write_reg(ov13858, OV13858_REG_SOFTWARE_RST,
OV13858_REG_VALUE_08BIT, OV13858_SOFTWARE_RST);
if (ret) {
- dev_err(&client->dev, "%s failed to set powerup registers\n",
+ dev_err(ov13858->dev, "%s failed to set powerup registers\n",
__func__);
return ret;
}
@@ -1430,7 +1427,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858)
reg_list = &link_freq_configs[link_freq_index].reg_list;
ret = ov13858_write_reg_list(ov13858, reg_list);
if (ret) {
- dev_err(&client->dev, "%s failed to set plls\n", __func__);
+ dev_err(ov13858->dev, "%s failed to set plls\n", __func__);
return ret;
}
@@ -1438,7 +1435,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858)
reg_list = &ov13858->cur_mode->reg_list;
ret = ov13858_write_reg_list(ov13858, reg_list);
if (ret) {
- dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ dev_err(ov13858->dev, "%s failed to set mode\n", __func__);
return ret;
}
@@ -1462,17 +1459,12 @@ static int ov13858_stop_streaming(struct ov13858 *ov13858)
static int ov13858_set_stream(struct v4l2_subdev *sd, int enable)
{
struct ov13858 *ov13858 = to_ov13858(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
mutex_lock(&ov13858->mutex);
- if (ov13858->streaming == enable) {
- mutex_unlock(&ov13858->mutex);
- return 0;
- }
if (enable) {
- ret = pm_runtime_resume_and_get(&client->dev);
+ ret = pm_runtime_resume_and_get(ov13858->dev);
if (ret < 0)
goto err_unlock;
@@ -1485,57 +1477,24 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable)
goto err_rpm_put;
} else {
ov13858_stop_streaming(ov13858);
- pm_runtime_put(&client->dev);
+ pm_runtime_put(ov13858->dev);
}
- ov13858->streaming = enable;
mutex_unlock(&ov13858->mutex);
return ret;
err_rpm_put:
- pm_runtime_put(&client->dev);
+ pm_runtime_put(ov13858->dev);
err_unlock:
mutex_unlock(&ov13858->mutex);
return ret;
}
-static int __maybe_unused ov13858_suspend(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct ov13858 *ov13858 = to_ov13858(sd);
-
- if (ov13858->streaming)
- ov13858_stop_streaming(ov13858);
-
- return 0;
-}
-
-static int __maybe_unused ov13858_resume(struct device *dev)
-{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct ov13858 *ov13858 = to_ov13858(sd);
- int ret;
-
- if (ov13858->streaming) {
- ret = ov13858_start_streaming(ov13858);
- if (ret)
- goto error;
- }
-
- return 0;
-
-error:
- ov13858_stop_streaming(ov13858);
- ov13858->streaming = false;
- return ret;
-}
-
/* Verify chip ID */
static int ov13858_identify_module(struct ov13858 *ov13858)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
int ret;
u32 val;
@@ -1545,7 +1504,7 @@ static int ov13858_identify_module(struct ov13858 *ov13858)
return ret;
if (val != OV13858_CHIP_ID) {
- dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ dev_err(ov13858->dev, "chip id mismatch: %x!=%x\n",
OV13858_CHIP_ID, val);
return -EIO;
}
@@ -1553,6 +1512,12 @@ static int ov13858_identify_module(struct ov13858 *ov13858)
return 0;
}
+static const struct v4l2_subdev_core_ops ov13858_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
static const struct v4l2_subdev_video_ops ov13858_video_ops = {
.s_stream = ov13858_set_stream,
};
@@ -1569,6 +1534,7 @@ static const struct v4l2_subdev_sensor_ops ov13858_sensor_ops = {
};
static const struct v4l2_subdev_ops ov13858_subdev_ops = {
+ .core = &ov13858_core_ops,
.video = &ov13858_video_ops,
.pad = &ov13858_pad_ops,
.sensor = &ov13858_sensor_ops,
@@ -1585,7 +1551,6 @@ static const struct v4l2_subdev_internal_ops ov13858_internal_ops = {
/* Initialize control handlers */
static int ov13858_init_controls(struct ov13858 *ov13858)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
s64 exposure_max;
@@ -1659,12 +1624,12 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
0, 0, ov13858_test_pattern_menu);
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
- dev_err(&client->dev, "%s control init failed (%d)\n",
+ dev_err(ov13858->dev, "%s control init failed (%d)\n",
__func__, ret);
goto error;
}
- ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ ret = v4l2_fwnode_device_parse(ov13858->dev, &props);
if (ret)
goto error;
@@ -1690,28 +1655,36 @@ static void ov13858_free_controls(struct ov13858 *ov13858)
mutex_destroy(&ov13858->mutex);
}
-static int ov13858_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int ov13858_probe(struct i2c_client *client)
{
struct ov13858 *ov13858;
+ unsigned long freq;
int ret;
- u32 val = 0;
-
- device_property_read_u32(&client->dev, "clock-frequency", &val);
- if (val != 19200000)
- return -EINVAL;
ov13858 = devm_kzalloc(&client->dev, sizeof(*ov13858), GFP_KERNEL);
if (!ov13858)
return -ENOMEM;
+ ov13858->dev = &client->dev;
+
+ ov13858->clk = devm_v4l2_sensor_clk_get(ov13858->dev, NULL);
+ if (IS_ERR(ov13858->clk))
+ return dev_err_probe(ov13858->dev, PTR_ERR(ov13858->clk),
+ "failed to get clock\n");
+
+ freq = clk_get_rate(ov13858->clk);
+ if (freq != 19200000)
+ return dev_err_probe(ov13858->dev, -EINVAL,
+ "external clock %lu is not supported\n",
+ freq);
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops);
/* Check module identity */
ret = ov13858_identify_module(ov13858);
if (ret) {
- dev_err(&client->dev, "failed to find sensor: %d\n", ret);
+ dev_err(ov13858->dev, "failed to find sensor: %d\n", ret);
return ret;
}
@@ -1724,7 +1697,8 @@ static int ov13858_probe(struct i2c_client *client,
/* Initialize subdev */
ov13858->sd.internal_ops = &ov13858_internal_ops;
- ov13858->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ ov13858->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
ov13858->sd.entity.ops = &ov13858_subdev_entity_ops;
ov13858->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
@@ -1732,7 +1706,7 @@ static int ov13858_probe(struct i2c_client *client,
ov13858->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&ov13858->sd.entity, 1, &ov13858->pad);
if (ret) {
- dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
+ dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret);
goto error_handler_free;
}
@@ -1744,9 +1718,9 @@ static int ov13858_probe(struct i2c_client *client,
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
*/
- pm_runtime_set_active(&client->dev);
- pm_runtime_enable(&client->dev);
- pm_runtime_idle(&client->dev);
+ pm_runtime_set_active(ov13858->dev);
+ pm_runtime_enable(ov13858->dev);
+ pm_runtime_idle(ov13858->dev);
return 0;
@@ -1755,12 +1729,12 @@ error_media_entity:
error_handler_free:
ov13858_free_controls(ov13858);
- dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
+ dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret);
return ret;
}
-static int ov13858_remove(struct i2c_client *client)
+static void ov13858_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov13858 *ov13858 = to_ov13858(sd);
@@ -1769,22 +1743,16 @@ static int ov13858_remove(struct i2c_client *client)
media_entity_cleanup(&sd->entity);
ov13858_free_controls(ov13858);
- pm_runtime_disable(&client->dev);
-
- return 0;
+ pm_runtime_disable(ov13858->dev);
}
static const struct i2c_device_id ov13858_id_table[] = {
- {"ov13858", 0},
- {},
+ { "ov13858" },
+ {}
};
MODULE_DEVICE_TABLE(i2c, ov13858_id_table);
-static const struct dev_pm_ops ov13858_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ov13858_suspend, ov13858_resume)
-};
-
#ifdef CONFIG_ACPI
static const struct acpi_device_id ov13858_acpi_ids[] = {
{"OVTID858"},
@@ -1797,7 +1765,6 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids);
static struct i2c_driver ov13858_i2c_driver = {
.driver = {
.name = "ov13858",
- .pm = &ov13858_pm_ops,
.acpi_match_table = ACPI_PTR(ov13858_acpi_ids),
},
.probe = ov13858_probe,
@@ -1808,7 +1775,7 @@ static struct i2c_driver ov13858_i2c_driver = {
module_i2c_driver(ov13858_i2c_driver);
MODULE_AUTHOR("Kan, Chris <chris.kan@intel.com>");
-MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>");
-MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>");
+MODULE_AUTHOR("Rapolu, Chiranjeevi");
+MODULE_AUTHOR("Yang, Hyungwoo");
MODULE_DESCRIPTION("Omnivision ov13858 sensor driver");
MODULE_LICENSE("GPL v2");