mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-27 22:53:55 +08:00
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>
This commit is contained in:
parent
57b0ad9ebe
commit
9f7e55d235
@ -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);
|
||||
int ret = 0;
|
||||
|
||||
return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user