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

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
Loading
Loading
Loading
Loading
+53 −23
Original line number Diff line number Diff line
@@ -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) {
	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;
}
+2 −0
Original line number Diff line number Diff line
@@ -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;