summaryrefslogtreecommitdiff
path: root/drivers/media/i2c
diff options
context:
space:
mode:
authorPetr Cvek <petrcvekcz@gmail.com>2018-12-13 18:39:13 +0300
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2019-01-16 21:17:09 +0300
commit9f7e55d235b62e95043917fcb86a87064678074c (patch)
tree8ad04ed6ab3779cd8c96ac8f5511f3514e97db4f /drivers/media/i2c
parent57b0ad9ebe60366b1243bcf612a93a990a3ceff1 (diff)
downloadlinux-9f7e55d235b62e95043917fcb86a87064678074c.tar.xz
media: i2c: ov9640: drop soc_camera code and switch to v4l2_async
This patch removes the dependency on an obsoleted soc_camera from ov9640 driver and changes the code to be a standalone v4l2 async subdevice. It also adds GPIO allocations for power and reset signals (as they are not handled by soc_camera now). The values for waiting on GPIOs (reset and power) settling down were taken from the datasheet (> 1 ms after HW/SW reset). The upper limit was chosen as an arbitrary value. Also one occurrence of mdelay() was changed to msleep(). The delays were successfully tested on a real hardware. The patch makes ov9640 sensor again compatible with the pxa_camera driver. Signed-off-by: Petr Cvek <petrcvekcz@gmail.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r--drivers/media/i2c/ov9640.c76
-rw-r--r--drivers/media/i2c/ov9640.h2
2 files changed, 55 insertions, 23 deletions
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index eb91b8240083..1f7cf01d037f 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -9,6 +9,7 @@
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
*
* Based on ov7670 and soc_camera_platform driver,
+ * transition from soc_camera to pxa_camera based on mt9m111
*
* Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
* Copyright (C) 2008 Magnus Damm
@@ -27,10 +28,14 @@
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
-#include <media/soc_camera.h>
+#include <media/v4l2-async.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+
+#include <linux/gpio/consumer.h>
#include "ov9640.h"
@@ -323,11 +328,23 @@ static int ov9640_set_register(struct v4l2_subdev *sd,
static int ov9640_s_power(struct v4l2_subdev *sd, int on)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
- return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
+ int ret = 0;
+
+ if (on) {
+ gpiod_set_value(priv->gpio_power, 1);
+ usleep_range(1000, 2000);
+ ret = v4l2_clk_enable(priv->clk);
+ usleep_range(1000, 2000);
+ gpiod_set_value(priv->gpio_reset, 0);
+ } else {
+ gpiod_set_value(priv->gpio_reset, 1);
+ usleep_range(1000, 2000);
+ v4l2_clk_disable(priv->clk);
+ usleep_range(1000, 2000);
+ gpiod_set_value(priv->gpio_power, 0);
+ }
+ return ret;
}
/* select nearest higher resolution for capture */
@@ -475,7 +492,7 @@ static int ov9640_prog_dflt(struct i2c_client *client)
}
/* wait for the changes to actually happen, 140ms are not enough yet */
- mdelay(150);
+ msleep(150);
return 0;
}
@@ -630,14 +647,10 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = {
static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -666,18 +679,27 @@ static int ov9640_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov9640_priv *priv;
- struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!ssdd) {
- dev_err(&client->dev, "Missing platform_data for driver\n");
- return -EINVAL;
- }
-
- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(*priv),
+ GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power",
+ GPIOD_OUT_LOW);
+ if (IS_ERR_OR_NULL(priv->gpio_power)) {
+ ret = PTR_ERR(priv->gpio_power);
+ return ret;
+ }
+
+ priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR_OR_NULL(priv->gpio_reset)) {
+ ret = PTR_ERR(priv->gpio_reset);
+ return ret;
+ }
+
v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
v4l2_ctrl_handler_init(&priv->hdl, 2);
@@ -696,12 +718,20 @@ static int ov9640_probe(struct i2c_client *client,
}
ret = ov9640_video_probe(client);
- if (ret) {
- v4l2_clk_put(priv->clk);
-eclkget:
- v4l2_ctrl_handler_free(&priv->hdl);
- }
+ if (ret)
+ goto eprobe;
+ priv->subdev.dev = &client->dev;
+ ret = v4l2_async_register_subdev(&priv->subdev);
+ if (ret)
+ goto eprobe;
+
+ return 0;
+
+eprobe:
+ v4l2_clk_put(priv->clk);
+eclkget:
+ v4l2_ctrl_handler_free(&priv->hdl);
return ret;
}
@@ -711,7 +741,7 @@ static int ov9640_remove(struct i2c_client *client)
struct ov9640_priv *priv = to_ov9640_sensor(sd);
v4l2_clk_put(priv->clk);
- v4l2_device_unregister_subdev(&priv->subdev);
+ v4l2_async_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
return 0;
}
diff --git a/drivers/media/i2c/ov9640.h b/drivers/media/i2c/ov9640.h
index 65d13ff17536..be5e4b29ac69 100644
--- a/drivers/media/i2c/ov9640.h
+++ b/drivers/media/i2c/ov9640.h
@@ -200,6 +200,8 @@ struct ov9640_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct v4l2_clk *clk;
+ struct gpio_desc *gpio_power;
+ struct gpio_desc *gpio_reset;
int model;
int revision;