Commit 9f7e55d2 authored by Petr Cvek's avatar Petr Cvek Committed by Mauro Carvalho Chehab

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: default avatarPetr Cvek <petrcvekcz@gmail.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 57b0ad9e
......@@ -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;
}
......
......@@ -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;
......
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