Commit 2f0babb7 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

[media] V4L: soc-camera: make (almost) all client drivers re-usable outside of the framework

The most important change in this patch is direct linking to struct
soc_camera_link via the client->dev.platform_data pointer. This makes most
of the soc-camera client drivers also usable outside of the soc-camera
framework. After this change all what is needed for these drivers to
function are inclusions of soc-camera headers for some convenience macros,
suitably configured platform data, which is anyway always required, and
loaded soc-camera core module for library functions. If desired, these
library functions can be made generic in the future and moved to a more
neutral location.

The only two client drivers, that still depend on soc-camera are:

mt9t031: it uses struct video_device for its PM. Since no hardware is
available, alternative methods cannot be tested.

ov6650: it uses struct soc_camera_device to pass its sense data back to
the bridge driver. A generic v4l2-subdevice approach should be developed
to perform this.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 1a99b972
...@@ -21,6 +21,13 @@ ...@@ -21,6 +21,13 @@
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
/*
* ATTENTION: this driver still cannot be used outside of the soc-camera
* framework because of its PM implementation, using the video_device node.
* If hardware becomes available for testing, alternative PM approaches shall
* be considered and tested.
*/
/* /*
* mt9t031 i2c address 0x5d * mt9t031 i2c address 0x5d
* The platform has to define i2c_board_info and link to it from * The platform has to define i2c_board_info and link to it from
...@@ -606,6 +613,19 @@ static struct device_type mt9t031_dev_type = { ...@@ -606,6 +613,19 @@ static struct device_type mt9t031_dev_type = {
.pm = &mt9t031_dev_pm_ops, .pm = &mt9t031_dev_pm_ops,
}; };
static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct video_device *vdev = soc_camera_i2c_to_vdev(client);
if (on)
vdev->dev.type = &mt9t031_dev_type;
else
vdev->dev.type = NULL;
return 0;
}
/* /*
* Interface active, can use i2c. If it fails, it can indeed mean, that * Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one * this wasn't our capture interface, so, we wait for the right one
...@@ -613,7 +633,6 @@ static struct device_type mt9t031_dev_type = { ...@@ -613,7 +633,6 @@ static struct device_type mt9t031_dev_type = {
static int mt9t031_video_probe(struct i2c_client *client) static int mt9t031_video_probe(struct i2c_client *client)
{ {
struct mt9t031 *mt9t031 = to_mt9t031(client); struct mt9t031 *mt9t031 = to_mt9t031(client);
struct video_device *vdev = soc_camera_i2c_to_vdev(client);
s32 data; s32 data;
int ret; int ret;
...@@ -637,12 +656,11 @@ static int mt9t031_video_probe(struct i2c_client *client) ...@@ -637,12 +656,11 @@ static int mt9t031_video_probe(struct i2c_client *client)
dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
ret = mt9t031_idle(client); ret = mt9t031_idle(client);
if (ret < 0) { if (ret < 0)
dev_err(&client->dev, "Failed to initialise the camera\n"); dev_err(&client->dev, "Failed to initialise the camera\n");
} else { else
vdev->dev.type = &mt9t031_dev_type;
v4l2_ctrl_handler_setup(&mt9t031->hdl); v4l2_ctrl_handler_setup(&mt9t031->hdl);
}
return ret; return ret;
} }
...@@ -663,6 +681,7 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { ...@@ -663,6 +681,7 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
.g_chip_ident = mt9t031_g_chip_ident, .g_chip_ident = mt9t031_g_chip_ident,
.s_power = mt9t031_s_power,
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9t031_g_register, .g_register = mt9t031_g_register,
.s_register = mt9t031_s_register, .s_register = mt9t031_s_register,
......
...@@ -541,7 +541,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, ...@@ -541,7 +541,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe,
static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_device *icd = client->dev.platform_data; struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id;
struct soc_camera_sense *sense = icd->sense; struct soc_camera_sense *sense = icd->sense;
struct ov6650 *priv = to_ov6650(client); struct ov6650 *priv = to_ov6650(client);
bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
......
...@@ -249,6 +249,14 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) ...@@ -249,6 +249,14 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
return v4l2_subdev_call(sd, core, s_std, *a); return v4l2_subdev_call(sd, core, s_std, *a);
} }
static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
{
struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, g_std, a);
}
static int soc_camera_enum_fsizes(struct file *file, void *fh, static int soc_camera_enum_fsizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize) struct v4l2_frmsizeenum *fsize)
{ {
...@@ -977,7 +985,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, ...@@ -977,7 +985,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
goto ei2cga; goto ei2cga;
} }
icl->board_info->platform_data = icd; icl->board_info->platform_data = icl;
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
icl->board_info, NULL); icl->board_info, NULL);
...@@ -1376,6 +1384,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { ...@@ -1376,6 +1384,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_g_input = soc_camera_g_input, .vidioc_g_input = soc_camera_g_input,
.vidioc_s_input = soc_camera_s_input, .vidioc_s_input = soc_camera_s_input,
.vidioc_s_std = soc_camera_s_std, .vidioc_s_std = soc_camera_s_std,
.vidioc_g_std = soc_camera_g_std,
.vidioc_enum_framesizes = soc_camera_enum_fsizes, .vidioc_enum_framesizes = soc_camera_enum_fsizes,
.vidioc_reqbufs = soc_camera_reqbufs, .vidioc_reqbufs = soc_camera_reqbufs,
.vidioc_querybuf = soc_camera_querybuf, .vidioc_querybuf = soc_camera_querybuf,
......
...@@ -230,6 +230,7 @@ struct tw9910_priv { ...@@ -230,6 +230,7 @@ struct tw9910_priv {
struct v4l2_subdev subdev; struct v4l2_subdev subdev;
struct tw9910_video_info *info; struct tw9910_video_info *info;
const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *scale;
v4l2_std_id norm;
u32 revision; u32 revision;
}; };
...@@ -421,12 +422,11 @@ static int tw9910_power(struct i2c_client *client, int enable) ...@@ -421,12 +422,11 @@ static int tw9910_power(struct i2c_client *client, int enable)
return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
} }
static const struct tw9910_scale_ctrl *tw9910_select_norm(struct soc_camera_device *icd, static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
u32 width, u32 height) u32 width, u32 height)
{ {
const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *scale;
const struct tw9910_scale_ctrl *ret = NULL; const struct tw9910_scale_ctrl *ret = NULL;
v4l2_std_id norm = icd->vdev->current_norm;
__u32 diff = 0xffffffff, tmp; __u32 diff = 0xffffffff, tmp;
int size, i; int size, i;
...@@ -495,14 +495,27 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -495,14 +495,27 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
return tw9910_power(client, enable); return tw9910_power(client, enable);
} }
static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
*norm = priv->norm;
return 0;
}
static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
{ {
int ret = -EINVAL; struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
ret = 0; return -EINVAL;
return ret; priv->norm = norm;
return 0;
} }
static int tw9910_g_chip_ident(struct v4l2_subdev *sd, static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
...@@ -557,14 +570,13 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) ...@@ -557,14 +570,13 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client); struct tw9910_priv *priv = to_tw9910(client);
struct soc_camera_device *icd = client->dev.platform_data;
int ret = -EINVAL; int ret = -EINVAL;
u8 val; u8 val;
/* /*
* select suitable norm * select suitable norm
*/ */
priv->scale = tw9910_select_norm(icd, *width, *height); priv->scale = tw9910_select_norm(priv->norm, *width, *height);
if (!priv->scale) if (!priv->scale)
goto tw9910_set_fmt_error; goto tw9910_set_fmt_error;
...@@ -642,11 +654,11 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) ...@@ -642,11 +654,11 @@ static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_device *icd = client->dev.platform_data; struct tw9910_priv *priv = to_tw9910(client);
a->c.left = 0; a->c.left = 0;
a->c.top = 0; a->c.top = 0;
if (icd->vdev->current_norm & V4L2_STD_NTSC) { if (priv->norm & V4L2_STD_NTSC) {
a->c.width = 640; a->c.width = 640;
a->c.height = 480; a->c.height = 480;
} else { } else {
...@@ -661,11 +673,11 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ...@@ -661,11 +673,11 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_device *icd = client->dev.platform_data; struct tw9910_priv *priv = to_tw9910(client);
a->bounds.left = 0; a->bounds.left = 0;
a->bounds.top = 0; a->bounds.top = 0;
if (icd->vdev->current_norm & V4L2_STD_NTSC) { if (priv->norm & V4L2_STD_NTSC) {
a->bounds.width = 640; a->bounds.width = 640;
a->bounds.height = 480; a->bounds.height = 480;
} else { } else {
...@@ -732,7 +744,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, ...@@ -732,7 +744,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf) struct v4l2_mbus_framefmt *mf)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd); struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_device *icd = client->dev.platform_data; struct tw9910_priv *priv = to_tw9910(client);
const struct tw9910_scale_ctrl *scale; const struct tw9910_scale_ctrl *scale;
if (V4L2_FIELD_ANY == mf->field) { if (V4L2_FIELD_ANY == mf->field) {
...@@ -748,7 +760,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, ...@@ -748,7 +760,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
/* /*
* select suitable norm * select suitable norm
*/ */
scale = tw9910_select_norm(icd, mf->width, mf->height); scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
if (!scale) if (!scale)
return -EINVAL; return -EINVAL;
...@@ -758,8 +770,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, ...@@ -758,8 +770,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
return 0; return 0;
} }
static int tw9910_video_probe(struct soc_camera_device *icd, static int tw9910_video_probe(struct i2c_client *client)
struct i2c_client *client)
{ {
struct tw9910_priv *priv = to_tw9910(client); struct tw9910_priv *priv = to_tw9910(client);
s32 id; s32 id;
...@@ -792,8 +803,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, ...@@ -792,8 +803,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
dev_info(&client->dev, dev_info(&client->dev,
"tw9910 Product ID %0x:%0x\n", id, priv->revision); "tw9910 Product ID %0x:%0x\n", id, priv->revision);
icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; priv->norm = V4L2_STD_NTSC;
icd->vdev->current_norm = V4L2_STD_NTSC;
return 0; return 0;
} }
...@@ -801,6 +811,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, ...@@ -801,6 +811,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
.g_chip_ident = tw9910_g_chip_ident, .g_chip_ident = tw9910_g_chip_ident,
.s_std = tw9910_s_std, .s_std = tw9910_s_std,
.g_std = tw9910_g_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = tw9910_g_register, .g_register = tw9910_g_register,
.s_register = tw9910_s_register, .s_register = tw9910_s_register,
...@@ -883,7 +894,6 @@ static int tw9910_probe(struct i2c_client *client, ...@@ -883,7 +894,6 @@ static int tw9910_probe(struct i2c_client *client,
{ {
struct tw9910_priv *priv; struct tw9910_priv *priv;
struct tw9910_video_info *info; struct tw9910_video_info *info;
struct soc_camera_device *icd = client->dev.platform_data;
struct i2c_adapter *adapter = struct i2c_adapter *adapter =
to_i2c_adapter(client->dev.parent); to_i2c_adapter(client->dev.parent);
struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
...@@ -911,7 +921,7 @@ static int tw9910_probe(struct i2c_client *client, ...@@ -911,7 +921,7 @@ static int tw9910_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
ret = tw9910_video_probe(icd, client); ret = tw9910_video_probe(client);
if (ret) if (ret)
kfree(priv); kfree(priv);
......
...@@ -253,14 +253,14 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, ...@@ -253,14 +253,14 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl,
#include <linux/i2c.h> #include <linux/i2c.h>
static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client)
{ {
struct soc_camera_device *icd = client->dev.platform_data; struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id;
return icd ? icd->vdev : NULL; return icd ? icd->vdev : NULL;
} }
static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client) static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client)
{ {
struct soc_camera_device *icd = client->dev.platform_data; return client->dev.platform_data;
return icd ? to_soc_camera_link(icd) : NULL;
} }
static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev) static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev)
......
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