Commit 760697be authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

V4L/DVB (13659): soc-camera: convert to the new mediabus API

Convert soc-camera core and all soc-camera drivers to the new mediabus
API. This also takes soc-camera client drivers one step closer to also be
usable with generic v4l2-subdev host drivers.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 9a74251d
......@@ -316,8 +316,9 @@ static struct soc_camera_platform_info camera_info = {
.format_name = "UYVY",
.format_depth = 16,
.format = {
.pixelformat = V4L2_PIX_FMT_UYVY,
.code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.field = V4L2_FIELD_NONE,
.width = 640,
.height = 480,
},
......
......@@ -48,41 +48,46 @@
#define MT9M001_COLUMN_SKIP 20
#define MT9M001_ROW_SKIP 12
static const struct soc_camera_data_format mt9m001_colour_formats[] = {
/* MT9M001 has only one fixed colorspace per pixelcode */
struct mt9m001_datafmt {
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
};
/* Find a data format by a pixel code in an array */
static const struct mt9m001_datafmt *mt9m001_find_datafmt(
enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt,
int n)
{
int i;
for (i = 0; i < n; i++)
if (fmt[i].code == code)
return fmt + i;
return NULL;
}
static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
/*
* Order important: first natively supported,
* second supported with a GPIO extender
*/
{
.name = "Bayer (sRGB) 10 bit",
.depth = 10,
.fourcc = V4L2_PIX_FMT_SBGGR16,
.colorspace = V4L2_COLORSPACE_SRGB,
}, {
.name = "Bayer (sRGB) 8 bit",
.depth = 8,
.fourcc = V4L2_PIX_FMT_SBGGR8,
.colorspace = V4L2_COLORSPACE_SRGB,
}
{V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
};
static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
/* Order important - see above */
{
.name = "Monochrome 10 bit",
.depth = 10,
.fourcc = V4L2_PIX_FMT_Y16,
}, {
.name = "Monochrome 8 bit",
.depth = 8,
.fourcc = V4L2_PIX_FMT_GREY,
},
{V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
};
struct mt9m001 {
struct v4l2_subdev subdev;
struct v4l2_rect rect; /* Sensor window */
__u32 fourcc;
const struct mt9m001_datafmt *fmt;
const struct mt9m001_datafmt *fmts;
int num_fmts;
int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
unsigned int gain;
unsigned int exposure;
......@@ -209,8 +214,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
const u16 hblank = 9, vblank = 25;
unsigned int total_h;
if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 ||
mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16)
if (mt9m001->fmts == mt9m001_colour_fmts)
/*
* Bayer format - even number of rows for simplicity,
* but let the user play with the top row.
......@@ -290,32 +294,32 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
static int mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9m001_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->width = mt9m001->rect.width;
pix->height = mt9m001->rect.height;
pix->pixelformat = mt9m001->fourcc;
pix->field = V4L2_FIELD_NONE;
pix->colorspace = V4L2_COLORSPACE_SRGB;
mf->width = mt9m001->rect.width;
mf->height = mt9m001->rect.height;
mf->code = mt9m001->fmt->code;
mf->colorspace = mt9m001->fmt->colorspace;
mf->field = V4L2_FIELD_NONE;
return 0;
}
static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9m001_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_crop a = {
.c = {
.left = mt9m001->rect.left,
.top = mt9m001->rect.top,
.width = pix->width,
.height = pix->height,
.width = mf->width,
.height = mf->height,
},
};
int ret;
......@@ -323,28 +327,39 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
/* No support for scaling so far, just crop. TODO: use skipping */
ret = mt9m001_s_crop(sd, &a);
if (!ret) {
pix->width = mt9m001->rect.width;
pix->height = mt9m001->rect.height;
mt9m001->fourcc = pix->pixelformat;
mf->width = mt9m001->rect.width;
mf->height = mt9m001->rect.height;
mt9m001->fmt = mt9m001_find_datafmt(mf->code,
mt9m001->fmts, mt9m001->num_fmts);
mf->colorspace = mt9m001->fmt->colorspace;
}
return ret;
}
static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9m001_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct mt9m001_datafmt *fmt;
v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH,
v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH,
MT9M001_MAX_WIDTH, 1,
&pix->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
&mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0);
if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
pix->pixelformat == V4L2_PIX_FMT_SBGGR16)
pix->height = ALIGN(pix->height - 1, 2);
if (mt9m001->fmts == mt9m001_colour_fmts)
mf->height = ALIGN(mf->height - 1, 2);
fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts,
mt9m001->num_fmts);
if (!fmt) {
fmt = mt9m001->fmt;
mf->code = fmt->code;
}
mf->colorspace = fmt->colorspace;
return 0;
}
......@@ -608,11 +623,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
case 0x8411:
case 0x8421:
mt9m001->model = V4L2_IDENT_MT9M001C12ST;
icd->formats = mt9m001_colour_formats;
mt9m001->fmts = mt9m001_colour_fmts;
break;
case 0x8431:
mt9m001->model = V4L2_IDENT_MT9M001C12STM;
icd->formats = mt9m001_monochrome_formats;
mt9m001->fmts = mt9m001_monochrome_fmts;
break;
default:
dev_err(&client->dev,
......@@ -620,7 +635,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
return -ENODEV;
}
icd->num_formats = 0;
mt9m001->num_fmts = 0;
/*
* This is a 10bit sensor, so by default we only allow 10bit.
......@@ -633,14 +648,14 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
flags = SOCAM_DATAWIDTH_10;
if (flags & SOCAM_DATAWIDTH_10)
icd->num_formats++;
mt9m001->num_fmts++;
else
icd->formats++;
mt9m001->fmts++;
if (flags & SOCAM_DATAWIDTH_8)
icd->num_formats++;
mt9m001->num_fmts++;
mt9m001->fourcc = icd->formats->fourcc;
mt9m001->fmt = &mt9m001->fmts[0];
dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
data == 0x8431 ? "C12STM" : "C12ST");
......@@ -686,14 +701,28 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
#endif
};
static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
struct i2c_client *client = sd->priv;
struct mt9m001 *mt9m001 = to_mt9m001(client);
if ((unsigned int)index >= mt9m001->num_fmts)
return -EINVAL;
*code = mt9m001->fmts[index].code;
return 0;
}
static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
.s_stream = mt9m001_s_stream,
.s_fmt = mt9m001_s_fmt,
.g_fmt = mt9m001_g_fmt,
.try_fmt = mt9m001_try_fmt,
.s_mbus_fmt = mt9m001_s_fmt,
.g_mbus_fmt = mt9m001_g_fmt,
.try_mbus_fmt = mt9m001_try_fmt,
.s_crop = mt9m001_s_crop,
.g_crop = mt9m001_g_crop,
.cropcap = mt9m001_cropcap,
.enum_mbus_fmt = mt9m001_enum_fmt,
};
static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
......
This diff is collapsed.
......@@ -60,15 +60,6 @@
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \
SOCAM_MASTER | SOCAM_DATAWIDTH_10)
static const struct soc_camera_data_format mt9t031_colour_formats[] = {
{
.name = "Bayer (sRGB) 10 bit",
.depth = 10,
.fourcc = V4L2_PIX_FMT_SGRBG10,
.colorspace = V4L2_COLORSPACE_SRGB,
}
};
struct mt9t031 {
struct v4l2_subdev subdev;
struct v4l2_rect rect; /* Sensor window */
......@@ -378,27 +369,27 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9t031_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9t031 *mt9t031 = to_mt9t031(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->width = mt9t031->rect.width / mt9t031->xskip;
pix->height = mt9t031->rect.height / mt9t031->yskip;
pix->pixelformat = V4L2_PIX_FMT_SGRBG10;
pix->field = V4L2_FIELD_NONE;
pix->colorspace = V4L2_COLORSPACE_SRGB;
mf->width = mt9t031->rect.width / mt9t031->xskip;
mf->height = mt9t031->rect.height / mt9t031->yskip;
mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
mf->colorspace = V4L2_COLORSPACE_SRGB;
mf->field = V4L2_FIELD_NONE;
return 0;
}
static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9t031_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9t031 *mt9t031 = to_mt9t031(client);
struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
u16 xskip, yskip;
struct v4l2_rect rect = mt9t031->rect;
......@@ -406,8 +397,11 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
* try_fmt has put width and height within limits.
* S_FMT: use binning and skipping for scaling
*/
xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH);
yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT);
xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH);
yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT);
mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
mf->colorspace = V4L2_COLORSPACE_SRGB;
/* mt9t031_set_params() doesn't change width and height */
return mt9t031_set_params(icd, &rect, xskip, yskip);
......@@ -417,13 +411,15 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
* If a user window larger than sensor window is requested, we'll increase the
* sensor window.
*/
static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9t031_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
v4l_bound_align_image(
&pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
&pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
&mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
&mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
mf->colorspace = V4L2_COLORSPACE_SRGB;
return 0;
}
......@@ -684,7 +680,6 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
*/
static int mt9t031_video_probe(struct i2c_client *client)
{
struct soc_camera_device *icd = client->dev.platform_data;
struct mt9t031 *mt9t031 = to_mt9t031(client);
s32 data;
int ret;
......@@ -699,8 +694,6 @@ static int mt9t031_video_probe(struct i2c_client *client)
switch (data) {
case 0x1621:
mt9t031->model = V4L2_IDENT_MT9T031;
icd->formats = mt9t031_colour_formats;
icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
break;
default:
dev_err(&client->dev,
......@@ -741,14 +734,25 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
#endif
};
static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
return -EINVAL;
*code = V4L2_MBUS_FMT_SBGGR10_1X10;
return 0;
}
static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = {
.s_stream = mt9t031_s_stream,
.s_fmt = mt9t031_s_fmt,
.g_fmt = mt9t031_g_fmt,
.try_fmt = mt9t031_try_fmt,
.s_mbus_fmt = mt9t031_s_fmt,
.g_mbus_fmt = mt9t031_g_fmt,
.try_mbus_fmt = mt9t031_try_fmt,
.s_crop = mt9t031_s_crop,
.g_crop = mt9t031_g_crop,
.cropcap = mt9t031_cropcap,
.enum_mbus_fmt = mt9t031_enum_fmt,
};
static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = {
......
......@@ -64,41 +64,46 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
#define MT9V022_COLUMN_SKIP 1
#define MT9V022_ROW_SKIP 4
static const struct soc_camera_data_format mt9v022_colour_formats[] = {
/* MT9V022 has only one fixed colorspace per pixelcode */
struct mt9v022_datafmt {
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
};
/* Find a data format by a pixel code in an array */
static const struct mt9v022_datafmt *mt9v022_find_datafmt(
enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt,
int n)
{
int i;
for (i = 0; i < n; i++)
if (fmt[i].code == code)
return fmt + i;
return NULL;
}
static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
/*
* Order important: first natively supported,
* second supported with a GPIO extender
*/
{
.name = "Bayer (sRGB) 10 bit",
.depth = 10,
.fourcc = V4L2_PIX_FMT_SBGGR16,
.colorspace = V4L2_COLORSPACE_SRGB,
}, {
.name = "Bayer (sRGB) 8 bit",
.depth = 8,
.fourcc = V4L2_PIX_FMT_SBGGR8,
.colorspace = V4L2_COLORSPACE_SRGB,
}
{V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
};
static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
/* Order important - see above */
{
.name = "Monochrome 10 bit",
.depth = 10,
.fourcc = V4L2_PIX_FMT_Y16,
}, {
.name = "Monochrome 8 bit",
.depth = 8,
.fourcc = V4L2_PIX_FMT_GREY,
},
{V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
};
struct mt9v022 {
struct v4l2_subdev subdev;
struct v4l2_rect rect; /* Sensor window */
__u32 fourcc;
const struct mt9v022_datafmt *fmt;
const struct mt9v022_datafmt *fmts;
int num_fmts;
int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
u16 chip_control;
unsigned short y_skip_top; /* Lines to skip at the top */
......@@ -275,8 +280,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
int ret;
/* Bayer format - even size lengths */
if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 ||
mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) {
if (mt9v022->fmts == mt9v022_colour_fmts) {
rect.width = ALIGN(rect.width, 2);
rect.height = ALIGN(rect.height, 2);
/* Let the user play with the starting pixel */
......@@ -354,32 +358,32 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9v022_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->width = mt9v022->rect.width;
pix->height = mt9v022->rect.height;
pix->pixelformat = mt9v022->fourcc;
pix->field = V4L2_FIELD_NONE;
pix->colorspace = V4L2_COLORSPACE_SRGB;
mf->width = mt9v022->rect.width;
mf->height = mt9v022->rect.height;
mf->code = mt9v022->fmt->code;
mf->colorspace = mt9v022->fmt->colorspace;
mf->field = V4L2_FIELD_NONE;
return 0;
}
static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9v022_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_crop a = {
.c = {
.left = mt9v022->rect.left,
.top = mt9v022->rect.top,
.width = pix->width,
.height = pix->height,
.width = mf->width,
.height = mf->height,
},
};
int ret;
......@@ -388,14 +392,14 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
* The caller provides a supported format, as verified per call to
* icd->try_fmt(), datawidth is from our supported format list
*/
switch (pix->pixelformat) {
case V4L2_PIX_FMT_GREY:
case V4L2_PIX_FMT_Y16:
switch (mf->code) {
case V4L2_MBUS_FMT_GREY8_1X8:
case V4L2_MBUS_FMT_Y10_1X10:
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
return -EINVAL;
break;
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SBGGR16:
case V4L2_MBUS_FMT_SBGGR8_1X8:
case V4L2_MBUS_FMT_SBGGR10_1X10:
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
return -EINVAL;
break;
......@@ -409,27 +413,39 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
/* No support for scaling on this camera, just crop. */
ret = mt9v022_s_crop(sd, &a);
if (!ret) {
pix->width = mt9v022->rect.width;
pix->height = mt9v022->rect.height;
mt9v022->fourcc = pix->pixelformat;
mf->width = mt9v022->rect.width;
mf->height = mt9v022->rect.height;
mt9v022->fmt = mt9v022_find_datafmt(mf->code,
mt9v022->fmts, mt9v022->num_fmts);
mf->colorspace = mt9v022->fmt->colorspace;
}
return ret;
}
static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int mt9v022_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
const struct mt9v022_datafmt *fmt;
int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
mf->code == V4L2_MBUS_FMT_SBGGR10_1X10;
v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH,
v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
MT9V022_MAX_WIDTH, align,
&pix->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
&mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
mt9v022->num_fmts);
if (!fmt) {
fmt = mt9v022->fmt;
mf->code = fmt->code;
}
mf->colorspace = fmt->colorspace;
return 0;
}
......@@ -749,17 +765,17 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
!strcmp("color", sensor_type))) {
ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
icd->formats = mt9v022_colour_formats;
mt9v022->fmts = mt9v022_colour_fmts;
} else {
ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
icd->formats = mt9v022_monochrome_formats;
mt9v022->fmts = mt9v022_monochrome_fmts;
}
if (ret < 0)
goto ei2c;
icd->num_formats = 0;
mt9v022->num_fmts = 0;
/*
* This is a 10bit sensor, so by default we only allow 10bit.
......@@ -772,14 +788,14 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
flags = SOCAM_DATAWIDTH_10;
if (flags & SOCAM_DATAWIDTH_10)
icd->num_formats++;
mt9v022->num_fmts++;
else
icd->formats++;
mt9v022->fmts++;
if (flags & SOCAM_DATAWIDTH_8)
icd->num_formats++;
mt9v022->num_fmts++;
mt9v022->fourcc = icd->formats->fourcc;
mt9v022->fmt = &mt9v022->fmts[0];
dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
......@@ -823,14 +839,28 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
#endif
};
static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
struct i2c_client *client = sd->priv;
struct mt9v022 *mt9v022 = to_mt9v022(client);
if ((unsigned int)index >= mt9v022->num_fmts)
return -EINVAL;
*code = mt9v022->fmts[index].code;
return 0;
}
static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
.s_stream = mt9v022_s_stream,
.s_fmt = mt9v022_s_fmt,
.g_fmt = mt9v022_g_fmt,
.try_fmt = mt9v022_try_fmt,
.s_mbus_fmt = mt9v022_s_fmt,
.g_mbus_fmt = mt9v022_g_fmt,
.try_mbus_fmt = mt9v022_try_fmt,
.s_crop = mt9v022_s_crop,
.g_crop = mt9v022_g_crop,
.cropcap = mt9v022_cropcap,
.enum_mbus_fmt = mt9v022_enum_fmt,
};
static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
......
......@@ -37,6 +37,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/videobuf-dma-contig.h>
#include <media/soc_mediabus.h>
#include <asm/dma.h>
#include <asm/fiq.h>
......@@ -94,9 +95,9 @@
/* buffer for one video frame */
struct mx1_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
const struct soc_camera_data_format *fmt;
int inwork;
struct videobuf_buffer vb;
enum v4l2_mbus_pixelcode code;
int inwork;
};
/*
......@@ -128,9 +129,13 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct soc_camera_device *icd = vq->priv_data;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
*size = icd->user_width * icd->user_height *
((icd->current_fmt->depth + 7) >> 3);
if (bytes_per_line < 0)
return bytes_per_line;
*size = bytes_per_line * icd->user_height;
if (!*count)
*count = 32;
......@@ -169,6 +174,11 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
struct soc_camera_device *icd = vq->priv_data;
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
int ret;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
if (bytes_per_line < 0)
return bytes_per_line;
dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
......@@ -184,18 +194,18 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
*/
buf->inwork = 1;
if (buf->fmt != icd->current_fmt ||
if (buf->code != icd->current_fmt->code ||
vb->width != icd->user_width ||
vb->height != icd->user_height ||
vb->field != field) {
buf->fmt = icd->current_fmt;
buf->code = icd->current_fmt->code;
vb->width = icd->user_width;
vb->height = icd->user_height;
vb->field = field;
vb->state = VIDEOBUF_NEEDS_INIT;
}
vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);
vb->size = bytes_per_line * vb->height;
if (0 != vb->baddr && vb->bsize < vb->size) {
ret = -EINVAL;
goto out;
......@@ -497,12 +507,10 @@ static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
/* MX1 supports only 8bit buswidth */
common_flags = soc_camera_bus_param_compatible(camera_flags,
CSI_BUS_FLAGS);
CSI_BUS_FLAGS);
if (!common_flags)
return -EINVAL;
icd->buswidth = 8;
/* Make choises, based on platform choice */
if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
......@@ -555,7 +563,8 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
struct v4l2_mbus_framefmt mf;
int ret, buswidth;
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
......@@ -564,12 +573,33 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
return -EINVAL;
}
ret = v4l2_subdev_call(sd, video, s_fmt, f);
if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
buswidth = xlate->host_fmt->bits_per_sample;
if (buswidth > 8) {
dev_warn(icd->dev.parent,
"bits-per-sample %d for format %x unsupported\n",
buswidth, pix->pixelformat);
return -EINVAL;
}
mf.width = pix->width;
mf.height = pix->height;
mf.field = pix->field;
mf.colorspace = pix->colorspace;
mf.code = xlate->code;
ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
if (ret < 0)
return ret;
if (mf.code != xlate->code)
return -EINVAL;
pix->width = mf.width;
pix->height = mf.height;
pix->field = mf.field;
pix->colorspace = mf.colorspace;
icd->current_fmt = xlate;
return ret;
}
......@@ -577,10 +607,36 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_mbus_framefmt mf;
int ret;
/* TODO: limit to mx1 hardware capabilities */
xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
if (!xlate) {
dev_warn(icd->dev.parent, "Format %x not found\n",
pix->pixelformat);
return -EINVAL;
}
mf.width = pix->width;
mf.height = pix->height;
mf.field = pix->field;
mf.colorspace = pix->colorspace;
mf.code = xlate->code;
/* limit to sensor capabilities */
return v4l2_subdev_call(sd, video, try_fmt, f);
ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
if (ret < 0)
return ret;
pix->width = mf.width;
pix->height = mf.height;
pix->field = mf.field;
pix->colorspace = mf.colorspace;
return 0;
}
static int mx1_camera_reqbufs(struct soc_camera_file *icf,
......
This diff is collapsed.
......@@ -24,6 +24,7 @@
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/ov772x.h>
/*
......@@ -382,7 +383,8 @@ struct regval_list {
};
struct ov772x_color_format {
const struct soc_camera_data_format *format;
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
u8 dsp3;
u8 com3;
u8 com7;
......@@ -399,7 +401,7 @@ struct ov772x_win_size {
struct ov772x_priv {
struct v4l2_subdev subdev;
struct ov772x_camera_info *info;
const struct ov772x_color_format *fmt;
const struct ov772x_color_format *cfmt;
const struct ov772x_win_size *win;
int model;
unsigned short flag_vflip:1;
......@@ -434,93 +436,57 @@ static const struct regval_list ov772x_vga_regs[] = {
};
/*
* supported format list
*/
#define SETFOURCC(type) .name = (#type), .fourcc = (V4L2_PIX_FMT_ ## type)
static const struct soc_camera_data_format ov772x_fmt_lists[] = {
{
SETFOURCC(YUYV),
.depth = 16,
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
SETFOURCC(YVYU),
.depth = 16,
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
SETFOURCC(UYVY),
.depth = 16,
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
SETFOURCC(RGB555),
.depth = 16,
.colorspace = V4L2_COLORSPACE_SRGB,
},
{
SETFOURCC(RGB555X),
.depth = 16,
.colorspace = V4L2_COLORSPACE_SRGB,
},
{
SETFOURCC(RGB565),
.depth = 16,
.colorspace = V4L2_COLORSPACE_SRGB,
},
{
SETFOURCC(RGB565X),
.depth = 16,
.colorspace = V4L2_COLORSPACE_SRGB,
},
};
/*
* color format list
* supported color format list
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
.format = &ov772x_fmt_lists[0],
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
.code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
.format = &ov772x_fmt_lists[1],
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
.code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
.format = &ov772x_fmt_lists[2],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = OFMT_YUV,
.code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = OFMT_YUV,
},
{
.format = &ov772x_fmt_lists[3],
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB555 | OFMT_RGB,
.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
.format = &ov772x_fmt_lists[4],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB555 | OFMT_RGB,
.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
.format = &ov772x_fmt_lists[5],
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB565 | OFMT_RGB,
.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.com3 = SWAP_RGB,
.com7 = FMT_RGB565 | OFMT_RGB,
},
{
.format = &ov772x_fmt_lists[6],
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB565 | OFMT_RGB,
.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.com3 = 0x0,
.com7 = FMT_RGB565 | OFMT_RGB,
},
};
......@@ -642,15 +608,15 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
if (!priv->win || !priv->fmt) {
if (!priv->win || !priv->cfmt) {
dev_err(&client->dev, "norm or win select error\n");
return -EPERM;
}
ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
dev_dbg(&client->dev, "format %s, win %s\n",
priv->fmt->format->name, priv->win->name);
dev_dbg(&client->dev, "format %d, win %s\n",
priv->cfmt->code, priv->win->name);
return 0;
}
......@@ -806,8 +772,8 @@ static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
return win;
}
static int ov772x_set_params(struct i2c_client *client,
u32 *width, u32 *height, u32 pixfmt)
static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height,
enum v4l2_mbus_pixelcode code)
{
struct ov772x_priv *priv = to_ov772x(client);
int ret = -EINVAL;
......@@ -817,14 +783,14 @@ static int ov772x_set_params(struct i2c_client *client,
/*
* select format
*/
priv->fmt = NULL;
priv->cfmt = NULL;
for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
if (pixfmt == ov772x_cfmts[i].format->fourcc) {
priv->fmt = ov772x_cfmts + i;
if (code == ov772x_cfmts[i].code) {
priv->cfmt = ov772x_cfmts + i;
break;
}
}
if (!priv->fmt)
if (!priv->cfmt)
goto ov772x_set_fmt_error;
/*
......@@ -894,7 +860,7 @@ static int ov772x_set_params(struct i2c_client *client,
/*
* set DSP_CTRL3
*/
val = priv->fmt->dsp3;
val = priv->cfmt->dsp3;
if (val) {
ret = ov772x_mask_set(client,
DSP_CTRL3, UV_MASK, val);
......@@ -905,7 +871,7 @@ static int ov772x_set_params(struct i2c_client *client,
/*
* set COM3
*/
val = priv->fmt->com3;
val = priv->cfmt->com3;
if (priv->info->flags & OV772X_FLAG_VFLIP)
val |= VFLIP_IMG;
if (priv->info->flags & OV772X_FLAG_HFLIP)
......@@ -923,9 +889,9 @@ static int ov772x_set_params(struct i2c_client *client,
/*
* set COM7
*/
val = priv->win->com7_bit | priv->fmt->com7;
val = priv->win->com7_bit | priv->cfmt->com7;
ret = ov772x_mask_set(client,
COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
COM7, SLCT_MASK | FMT_MASK | OFMT_MASK,
val);
if (ret < 0)
goto ov772x_set_fmt_error;
......@@ -951,7 +917,7 @@ static int ov772x_set_params(struct i2c_client *client,
ov772x_reset(client);
priv->win = NULL;
priv->fmt = NULL;
priv->cfmt = NULL;
return ret;
}
......@@ -981,54 +947,79 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int ov772x_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct ov772x_priv *priv = to_ov772x(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
if (!priv->win || !priv->fmt) {
if (!priv->win || !priv->cfmt) {
u32 width = VGA_WIDTH, height = VGA_HEIGHT;
int ret = ov772x_set_params(client, &width, &height,
V4L2_PIX_FMT_YUYV);
V4L2_MBUS_FMT_YUYV8_2X8_LE);
if (ret < 0)
return ret;
}
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pix->width = priv->win->width;
pix->height = priv->win->height;
pix->pixelformat = priv->fmt->format->fourcc;
pix->colorspace = priv->fmt->format->colorspace;
pix->field = V4L2_FIELD_NONE;
mf->width = priv->win->width;
mf->height = priv->win->height;
mf->code = priv->cfmt->code;
mf->colorspace = priv->cfmt->colorspace;
mf->field = V4L2_FIELD_NONE;
return 0;
}
static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int ov772x_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct ov772x_priv *priv = to_ov772x(client);
int ret = ov772x_set_params(client, &mf->width, &mf->height,
mf->code);
if (!ret)
mf->colorspace = priv->cfmt->colorspace;
return ov772x_set_params(client, &pix->width, &pix->height,
pix->pixelformat);
return ret;
}
static int ov772x_try_fmt(struct v4l2_subdev *sd,
struct v4l2_format *f)
struct v4l2_mbus_framefmt *mf)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
struct i2c_client *client = sd->priv;
struct ov772x_priv *priv = to_ov772x(client);
const struct ov772x_win_size *win;
int i;
/*
* select suitable win
*/
win = ov772x_select_win(pix->width, pix->height);
win = ov772x_select_win(mf->width, mf->height);
mf->width = win->width;
mf->height = win->height;
mf->field = V4L2_FIELD_NONE;
pix->width = win->width;
pix->height = win->height;
pix->field = V4L2_FIELD_NONE;
for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++)
if (mf->code == ov772x_cfmts[i].code)
break;
if (i == ARRAY_SIZE(ov772x_cfmts)) {
/* Unsupported format requested. Propose either */
if (priv->cfmt) {
/* the current one or */
mf->colorspace = priv->cfmt->colorspace;
mf->code = priv->cfmt->code;
} else {
/* the default one */
mf->colorspace = ov772x_cfmts[0].colorspace;
mf->code = ov772x_cfmts[0].code;
}
} else {
/* Also return the colorspace */
mf->colorspace = ov772x_cfmts[i].colorspace;
}
return 0;
}
......@@ -1057,9 +1048,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd,
return -ENODEV;
}
icd->formats = ov772x_fmt_lists;
icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
/*
* check and show product ID and manufacturer ID
*/
......@@ -1109,13 +1097,24 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
#endif
};
static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts))
return -EINVAL;
*code = ov772x_cfmts[index].code;
return 0;
}
static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
.s_stream = ov772x_s_stream,
.g_fmt = ov772x_g_fmt,
.s_fmt = ov772x_s_fmt,
.try_fmt = ov772x_try_fmt,
.g_mbus_fmt = ov772x_g_fmt,
.s_mbus_fmt = ov772x_s_fmt,
.try_mbus_fmt = ov772x_try_fmt,
.cropcap = ov772x_cropcap,
.g_crop = ov772x_g_crop,
.enum_mbus_fmt = ov772x_enum_fmt,
};
static struct v4l2_subdev_ops ov772x_subdev_ops = {
......
......@@ -154,19 +154,10 @@ static const struct ov9640_reg ov9640_regs_rgb[] = {
{ OV9640_MTXS, 0x65 },
};
/*
* TODO: this sensor also supports RGB555 and RGB565 formats, but support for
* them has not yet been sufficiently tested and so it is not included with
* this version of the driver. To test and debug these formats add two entries
* to the below array, see ov722x.c for an example.
*/
static const struct soc_camera_data_format ov9640_fmt_lists[] = {
{
.name = "UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
.colorspace = V4L2_COLORSPACE_JPEG,
},
static enum v4l2_mbus_pixelcode ov9640_codes[] = {
V4L2_MBUS_FMT_YUYV8_2X8_BE,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
};
static const struct v4l2_queryctrl ov9640_controls[] = {
......@@ -434,20 +425,22 @@ static void ov9640_res_roundup(u32 *width, u32 *height)
}
/* Prepare necessary register changes depending on color encoding */
static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt)
static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
struct ov9640_reg_alt *alt)
{
switch (pixfmt) {
case V4L2_PIX_FMT_UYVY:
switch (code) {
default:
case V4L2_MBUS_FMT_YUYV8_2X8_BE:
alt->com12 = OV9640_COM12_YUV_AVG;
alt->com13 = OV9640_COM13_Y_DELAY_EN |
OV9640_COM13_YUV_DLY(0x01);
break;
case V4L2_PIX_FMT_RGB555:
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
alt->com7 = OV9640_COM7_RGB;
alt->com13 = OV9640_COM13_RGB_AVG;
alt->com15 = OV9640_COM15_RGB_555;
break;
case V4L2_PIX_FMT_RGB565:
case V4L2_MBUS_FMT_RGB565_2X8_LE:
alt->com7 = OV9640_COM7_RGB;
alt->com13 = OV9640_COM13_RGB_AVG;
alt->com15 = OV9640_COM15_RGB_565;
......@@ -456,8 +449,8 @@ static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt)
}
/* Setup registers according to resolution and color encoding */
static int ov9640_write_regs(struct i2c_client *client,
u32 width, u32 pixfmt, struct ov9640_reg_alt *alts)
static int ov9640_write_regs(struct i2c_client *client, u32 width,
enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts)
{
const struct ov9640_reg *ov9640_regs, *matrix_regs;
int ov9640_regs_len, matrix_regs_len;
......@@ -500,7 +493,7 @@ static int ov9640_write_regs(struct i2c_client *client,
}
/* select color matrix configuration for given color encoding */
if (pixfmt == V4L2_PIX_FMT_UYVY) {
if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) {
matrix_regs = ov9640_regs_yuv;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
} else {
......@@ -562,15 +555,17 @@ static int ov9640_prog_dflt(struct i2c_client *client)
}
/* set the format we will capture in */
static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int ov9640_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct ov9640_reg_alt alts = {0};
enum v4l2_colorspace cspace;
enum v4l2_mbus_pixelcode code = mf->code;
int ret;
ov9640_res_roundup(&pix->width, &pix->height);
ov9640_alter_regs(pix->pixelformat, &alts);
ov9640_res_roundup(&mf->width, &mf->height);
ov9640_alter_regs(mf->code, &alts);
ov9640_reset(client);
......@@ -578,19 +573,57 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
if (ret)
return ret;
return ov9640_write_regs(client, pix->width, pix->pixelformat, &alts);
switch (code) {
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
case V4L2_MBUS_FMT_RGB565_2X8_LE:
cspace = V4L2_COLORSPACE_SRGB;
break;
default:
code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
case V4L2_MBUS_FMT_YUYV8_2X8_BE:
cspace = V4L2_COLORSPACE_JPEG;
}
ret = ov9640_write_regs(client, mf->width, code, &alts);
if (!ret) {
mf->code = code;
mf->colorspace = cspace;
}
return ret;
}
static int ov9640_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int ov9640_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
ov9640_res_roundup(&mf->width, &mf->height);
ov9640_res_roundup(&pix->width, &pix->height);
pix->field = V4L2_FIELD_NONE;
mf->field = V4L2_FIELD_NONE;
switch (mf->code) {
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
case V4L2_MBUS_FMT_RGB565_2X8_LE:
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
case V4L2_MBUS_FMT_YUYV8_2X8_BE:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
return 0;
}
static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes))
return -EINVAL;
*code = ov9640_codes[index];
return 0;
}
static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
a->c.left = 0;
......@@ -637,9 +670,6 @@ static int ov9640_video_probe(struct soc_camera_device *icd,
goto err;
}
icd->formats = ov9640_fmt_lists;
icd->num_formats = ARRAY_SIZE(ov9640_fmt_lists);
/*
* check and show product ID and manufacturer ID
*/
......@@ -702,11 +732,12 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = {
};
static struct v4l2_subdev_video_ops ov9640_video_ops = {
.s_stream = ov9640_s_stream,
.s_fmt = ov9640_s_fmt,
.try_fmt = ov9640_try_fmt,
.cropcap = ov9640_cropcap,
.g_crop = ov9640_g_crop,
.s_stream = ov9640_s_stream,
.s_mbus_fmt = ov9640_s_fmt,
.try_mbus_fmt = ov9640_try_fmt,
.enum_mbus_fmt = ov9640_enum_fmt,
.cropcap = ov9640_cropcap,
.g_crop = ov9640_g_crop,
};
......
This diff is collapsed.
......@@ -16,6 +16,7 @@
#include <media/v4l2-subdev.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#define RJ54N1_DEV_CODE 0x0400
#define RJ54N1_DEV_CODE2 0x0401
......@@ -85,18 +86,35 @@
/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
static const struct soc_camera_data_format rj54n1_colour_formats[] = {
{
.name = "YUYV",
.depth = 16,
.fourcc = V4L2_PIX_FMT_YUYV,
.colorspace = V4L2_COLORSPACE_JPEG,
}, {
.name = "RGB565",
.depth = 16,
.fourcc = V4L2_PIX_FMT_RGB565,
.colorspace = V4L2_COLORSPACE_SRGB,
}
/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
struct rj54n1_datafmt {
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
};
/* Find a data format by a pixel code in an array */
static const struct rj54n1_datafmt *rj54n1_find_datafmt(
enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt,
int n)
{
int i;
for (i = 0; i < n; i++)
if (fmt[i].code == code)
return fmt + i;
return NULL;
}
static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
{V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
};
struct rj54n1_clock_div {
......@@ -109,12 +127,12 @@ struct rj54n1_clock_div {
struct rj54n1 {
struct v4l2_subdev subdev;
const struct rj54n1_datafmt *fmt;
struct v4l2_rect rect; /* Sensor window */
unsigned short width; /* Output window */
unsigned short height;
unsigned short resize; /* Sensor * 1024 / resize = Output */
struct rj54n1_clock_div clk_div;
u32 fourcc;
unsigned short scale;
u8 bank;
};
......@@ -440,6 +458,16 @@ static int reg_write_multiple(struct i2c_client *client,
return 0;
}
static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts))
return -EINVAL;
*code = rj54n1_colour_fmts[index].code;
return 0;
}
static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
{
/* TODO: start / stop streaming */
......@@ -527,16 +555,17 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
static int rj54n1_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int rj54n1_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->pixelformat = rj54n1->fourcc;
pix->field = V4L2_FIELD_NONE;
pix->width = rj54n1->width;
pix->height = rj54n1->height;
mf->code = rj54n1->fmt->code;
mf->colorspace = rj54n1->fmt->colorspace;
mf->field = V4L2_FIELD_NONE;
mf->width = rj54n1->width;
mf->height = rj54n1->height;
return 0;
}
......@@ -787,26 +816,44 @@ static int rj54n1_reg_init(struct i2c_client *client)
}
/* FIXME: streaming output only up to 800x600 is functional */
static int rj54n1_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int rj54n1_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
struct i2c_client *client = sd->priv;
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct rj54n1_datafmt *fmt;
int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE ||
mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE ||
mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE ||
mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE;
dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
__func__, mf->code, mf->width, mf->height);
fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
ARRAY_SIZE(rj54n1_colour_fmts));
if (!fmt) {
fmt = rj54n1->fmt;
mf->code = fmt->code;
}
pix->field = V4L2_FIELD_NONE;
mf->field = V4L2_FIELD_NONE;
mf->colorspace = fmt->colorspace;
if (pix->width > 800)
pix->width = 800;
if (pix->height > 600)
pix->height = 600;
v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
&mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
return 0;
}
static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int rj54n1_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
unsigned int output_w, output_h,
const struct rj54n1_datafmt *fmt;
unsigned int output_w, output_h, max_w, max_h,
input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
int ret;
......@@ -814,7 +861,7 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
* The host driver can call us without .try_fmt(), so, we have to take
* care ourseleves
*/
ret = rj54n1_try_fmt(sd, f);
ret = rj54n1_try_fmt(sd, mf);
/*
* Verify if the sensor has just been powered on. TODO: replace this
......@@ -832,49 +879,101 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
}
/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
switch (pix->pixelformat) {
case V4L2_PIX_FMT_YUYV:
switch (mf->code) {
case V4L2_MBUS_FMT_YUYV8_2X8_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
case V4L2_PIX_FMT_RGB565:
case V4L2_MBUS_FMT_YVYU8_2X8_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
break;
case V4L2_MBUS_FMT_RGB565_2X8_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
case V4L2_MBUS_FMT_RGB565_2X8_BE:
ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
break;
case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
break;
case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
break;
case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
break;
case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
break;
case V4L2_MBUS_FMT_SBGGR10_1X10:
ret = reg_write(client, RJ54N1_OUT_SEL, 5);
break;
default:
ret = -EINVAL;
}
/* Special case: a raw mode with 10 bits of data per clock tick */
if (!ret)
ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
(mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2);
if (ret < 0)
return ret;
/* Supported scales 1:1 - 1:16 */
if (pix->width < input_w / 16)
pix->width = input_w / 16;
if (pix->height < input_h / 16)
pix->height = input_h / 16;
/* Supported scales 1:1 >= scale > 1:16 */
max_w = mf->width * (16 * 1024 - 1) / 1024;
if (input_w > max_w)
input_w = max_w;
max_h = mf->height * (16 * 1024 - 1) / 1024;
if (input_h > max_h)
input_h = max_h;
output_w = pix->width;
output_h = pix->height;
output_w = mf->width;
output_h = mf->height;
ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
if (ret < 0)
return ret;
rj54n1->fourcc = pix->pixelformat;
fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
ARRAY_SIZE(rj54n1_colour_fmts));
rj54n1->fmt = fmt;
rj54n1->resize = ret;
rj54n1->rect.width = input_w;
rj54n1->rect.height = input_h;
rj54n1->width = output_w;
rj54n1->height = output_h;
pix->width = output_w;
pix->height = output_h;
pix->field = V4L2_FIELD_NONE;
mf->width = output_w;
mf->height = output_h;
mf->field = V4L2_FIELD_NONE;
mf->colorspace = fmt->colorspace;
return ret;
return 0;
}
static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
......@@ -1054,9 +1153,10 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
.s_stream = rj54n1_s_stream,
.s_fmt = rj54n1_s_fmt,
.g_fmt = rj54n1_g_fmt,
.try_fmt = rj54n1_try_fmt,
.s_mbus_fmt = rj54n1_s_fmt,
.g_mbus_fmt = rj54n1_g_fmt,
.try_mbus_fmt = rj54n1_try_fmt,
.enum_mbus_fmt = rj54n1_enum_fmt,
.g_crop = rj54n1_g_crop,
.cropcap = rj54n1_cropcap,
};
......@@ -1153,7 +1253,7 @@ static int rj54n1_probe(struct i2c_client *client,
rj54n1->rect.height = RJ54N1_MAX_HEIGHT;
rj54n1->width = RJ54N1_MAX_WIDTH;
rj54n1->height = RJ54N1_MAX_HEIGHT;
rj54n1->fourcc = V4L2_PIX_FMT_YUYV;
rj54n1->fmt = &rj54n1_colour_fmts[0];
rj54n1->resize = 1024;
ret = rj54n1_video_probe(icd, client);
......@@ -1164,9 +1264,6 @@ static int rj54n1_probe(struct i2c_client *client,
return ret;
}
icd->formats = rj54n1_colour_formats;
icd->num_formats = ARRAY_SIZE(rj54n1_colour_formats);
return ret;
}
......
This diff is collapsed.
......@@ -31,6 +31,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-dev.h>
#include <media/videobuf-core.h>
#include <media/soc_mediabus.h>
/* Default to VGA resolution */
#define DEFAULT_WIDTH 640
......@@ -40,18 +41,6 @@ static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
const struct soc_camera_data_format *soc_camera_format_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
{
unsigned int i;
for (i = 0; i < icd->num_formats; i++)
if (icd->formats[i].fourcc == fourcc)
return icd->formats + i;
return NULL;
}
EXPORT_SYMBOL(soc_camera_format_by_fourcc);
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
{
......@@ -207,21 +196,26 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
/* Always entered with .video_lock held */
static int soc_camera_init_user_formats(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int i, fmts = 0, ret;
int i, fmts = 0, raw_fmts = 0, ret;
enum v4l2_mbus_pixelcode code;
while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
raw_fmts++;
if (!ici->ops->get_formats)
/*
* Fallback mode - the host will have to serve all
* sensor-provided formats one-to-one to the user
*/
fmts = icd->num_formats;
fmts = raw_fmts;
else
/*
* First pass - only count formats this host-sensor
* configuration can provide
*/
for (i = 0; i < icd->num_formats; i++) {
for (i = 0; i < raw_fmts; i++) {
ret = ici->ops->get_formats(icd, i, NULL);
if (ret < 0)
return ret;
......@@ -242,11 +236,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
/* Second pass - actually fill data formats */
fmts = 0;
for (i = 0; i < icd->num_formats; i++)
for (i = 0; i < raw_fmts; i++)
if (!ici->ops->get_formats) {
icd->user_formats[i].host_fmt = icd->formats + i;
icd->user_formats[i].cam_fmt = icd->formats + i;
icd->user_formats[i].buswidth = icd->formats[i].depth;
v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
icd->user_formats[i].host_fmt =
soc_mbus_get_fmtdesc(code);
icd->user_formats[i].code = code;
} else {
ret = ici->ops->get_formats(icd, i,
&icd->user_formats[fmts]);
......@@ -255,7 +250,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
fmts += ret;
}
icd->current_fmt = icd->user_formats[0].host_fmt;
icd->current_fmt = &icd->user_formats[0];
return 0;
......@@ -281,7 +276,7 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
((x) >> 24) & 0xff
/* Called with .vb_lock held */
/* Called with .vb_lock held, or from the first open(2), see comment there */
static int soc_camera_set_fmt(struct soc_camera_file *icf,
struct v4l2_format *f)
{
......@@ -302,7 +297,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
if (ret < 0) {
return ret;
} else if (!icd->current_fmt ||
icd->current_fmt->fourcc != pix->pixelformat) {
icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
dev_err(&icd->dev,
"Host driver hasn't set up current format correctly!\n");
return -EINVAL;
......@@ -310,6 +305,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
icd->user_width = pix->width;
icd->user_height = pix->height;
icd->colorspace = pix->colorspace;
icf->vb_vidq.field =
icd->field = pix->field;
......@@ -369,8 +365,9 @@ static int soc_camera_open(struct file *file)
.width = icd->user_width,
.height = icd->user_height,
.field = icd->field,
.pixelformat = icd->current_fmt->fourcc,
.colorspace = icd->current_fmt->colorspace,
.colorspace = icd->colorspace,
.pixelformat =
icd->current_fmt->host_fmt->fourcc,
},
};
......@@ -390,7 +387,12 @@ static int soc_camera_open(struct file *file)
goto eiciadd;
}
/* Try to configure with default parameters */
/*
* Try to configure with default parameters. Notice: this is the
* very first open, so, we cannot race against other calls,
* apart from someone else calling open() simultaneously, but
* .video_lock is protecting us against it.
*/
ret = soc_camera_set_fmt(icf, &f);
if (ret < 0)
goto esfmt;
......@@ -534,7 +536,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
{
struct soc_camera_file *icf = file->private_data;
struct soc_camera_device *icd = icf->icd;
const struct soc_camera_data_format *format;
const struct soc_mbus_pixelfmt *format;
WARN_ON(priv != file->private_data);
......@@ -543,7 +545,8 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
format = icd->user_formats[f->index].host_fmt;
strlcpy(f->description, format->name, sizeof(f->description));
if (format->name)
strlcpy(f->description, format->name, sizeof(f->description));
f->pixelformat = format->fourcc;
return 0;
}
......@@ -560,12 +563,15 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
pix->width = icd->user_width;
pix->height = icd->user_height;
pix->field = icf->vb_vidq.field;
pix->pixelformat = icd->current_fmt->fourcc;
pix->bytesperline = pix->width *
DIV_ROUND_UP(icd->current_fmt->depth, 8);
pix->pixelformat = icd->current_fmt->host_fmt->fourcc;
pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
icd->current_fmt->host_fmt);
pix->colorspace = icd->colorspace;
if (pix->bytesperline < 0)
return pix->bytesperline;
pix->sizeimage = pix->height * pix->bytesperline;
dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
icd->current_fmt->fourcc);
icd->current_fmt->host_fmt->fourcc);
return 0;
}
......@@ -894,7 +900,7 @@ static int soc_camera_probe(struct device *dev)
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct device *control = NULL;
struct v4l2_subdev *sd;
struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
struct v4l2_mbus_framefmt mf;
int ret;
dev_info(dev, "Probing %s\n", dev_name(dev));
......@@ -965,9 +971,11 @@ static int soc_camera_probe(struct device *dev)
/* Try to improve our guess of a reasonable window format */
sd = soc_camera_to_subdev(icd);
if (!v4l2_subdev_call(sd, video, g_fmt, &f)) {
icd->user_width = f.fmt.pix.width;
icd->user_height = f.fmt.pix.height;
if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
icd->user_width = mf.width;
icd->user_height = mf.height;
icd->colorspace = mf.colorspace;
icd->field = mf.field;
}
/* Do we have to sysfs_remove_link() before device_unregister()? */
......
......@@ -22,7 +22,6 @@
struct soc_camera_platform_priv {
struct v4l2_subdev subdev;
struct soc_camera_data_format format;
};
static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev)
......@@ -58,36 +57,36 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
}
static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
struct v4l2_format *f)
struct v4l2_mbus_framefmt *mf)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
struct v4l2_pix_format *pix = &f->fmt.pix;
pix->width = p->format.width;
pix->height = p->format.height;
mf->width = p->format.width;
mf->height = p->format.height;
mf->code = p->format.code;
mf->colorspace = p->format.colorspace;
return 0;
}
static void soc_camera_platform_video_probe(struct soc_camera_device *icd,
struct platform_device *pdev)
static struct v4l2_subdev_core_ops platform_subdev_core_ops;
static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
struct soc_camera_platform_priv *priv = get_priv(pdev);
struct soc_camera_platform_info *p = pdev->dev.platform_data;
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
priv->format.name = p->format_name;
priv->format.depth = p->format_depth;
priv->format.fourcc = p->format.pixelformat;
priv->format.colorspace = p->format.colorspace;
if (index)
return -EINVAL;
icd->formats = &priv->format;
icd->num_formats = 1;
*code = p->format.code;
return 0;
}
static struct v4l2_subdev_core_ops platform_subdev_core_ops;
static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
.s_stream = soc_camera_platform_s_stream,
.try_fmt = soc_camera_platform_try_fmt,
.try_mbus_fmt = soc_camera_platform_try_fmt,
.enum_mbus_fmt = soc_camera_platform_enum_fmt,
};
static struct v4l2_subdev_ops platform_subdev_ops = {
......@@ -128,12 +127,10 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
/* Set the control device reference */
dev_set_drvdata(&icd->dev, &pdev->dev);
icd->ops = &soc_camera_platform_ops;
icd->ops = &soc_camera_platform_ops;
ici = to_soc_camera_host(icd->dev.parent);
soc_camera_platform_video_probe(icd, pdev);
v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
v4l2_set_subdevdata(&priv->subdev, p);
strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);
......
......@@ -251,15 +251,6 @@ static const struct regval_list tw9910_default_regs[] =
ENDMARKER,
};
static const struct soc_camera_data_format tw9910_color_fmt[] = {
{
.name = "VYUY",
.fourcc = V4L2_PIX_FMT_VYUY,
.depth = 16,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
}
};
static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
{
.name = "NTSC SQ",
......@@ -814,11 +805,11 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
return 0;
}
static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int tw9910_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct tw9910_priv *priv = to_tw9910(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
if (!priv->scale) {
int ret;
......@@ -835,74 +826,76 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
return ret;
}
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pix->width = priv->scale->width;
pix->height = priv->scale->height;
pix->pixelformat = V4L2_PIX_FMT_VYUY;
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
pix->field = V4L2_FIELD_INTERLACED;
mf->width = priv->scale->width;
mf->height = priv->scale->height;
mf->code = V4L2_MBUS_FMT_YVYU8_2X8_BE;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mf->field = V4L2_FIELD_INTERLACED;
return 0;
}
static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int tw9910_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct tw9910_priv *priv = to_tw9910(client);
struct v4l2_pix_format *pix = &f->fmt.pix;
/* See tw9910_s_crop() - no proper cropping support */
struct v4l2_crop a = {
.c = {
.left = 0,
.top = 0,
.width = pix->width,
.height = pix->height,
.width = mf->width,
.height = mf->height,
},
};
int i, ret;
int ret;
WARN_ON(mf->field != V4L2_FIELD_ANY &&
mf->field != V4L2_FIELD_INTERLACED);
/*
* check color format
*/
for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++)
if (pix->pixelformat == tw9910_color_fmt[i].fourcc)
break;
if (i == ARRAY_SIZE(tw9910_color_fmt))
if (mf->code != V4L2_MBUS_FMT_YVYU8_2X8_BE)
return -EINVAL;
mf->colorspace = V4L2_COLORSPACE_JPEG;
ret = tw9910_s_crop(sd, &a);
if (!ret) {
pix->width = priv->scale->width;
pix->height = priv->scale->height;
mf->width = priv->scale->width;
mf->height = priv->scale->height;
}
return ret;
}
static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
static int tw9910_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
struct i2c_client *client = sd->priv;
struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
const struct tw9910_scale_ctrl *scale;
if (V4L2_FIELD_ANY == pix->field) {
pix->field = V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != pix->field) {
dev_err(&client->dev, "Field type invalid.\n");
if (V4L2_FIELD_ANY == mf->field) {
mf->field = V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != mf->field) {
dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
return -EINVAL;
}
mf->code = V4L2_MBUS_FMT_YVYU8_2X8_BE;
mf->colorspace = V4L2_COLORSPACE_JPEG;
/*
* select suitable norm
*/
scale = tw9910_select_norm(icd, pix->width, pix->height);
scale = tw9910_select_norm(icd, mf->width, mf->height);
if (!scale)
return -EINVAL;
pix->width = scale->width;
pix->height = scale->height;
mf->width = scale->width;
mf->height = scale->height;
return 0;
}
......@@ -930,9 +923,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
return -ENODEV;
}
icd->formats = tw9910_color_fmt;
icd->num_formats = ARRAY_SIZE(tw9910_color_fmt);
/*
* check and show Product ID
* So far only revisions 0 and 1 have been seen
......@@ -973,14 +963,25 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
#endif
};
static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
return -EINVAL;
*code = V4L2_MBUS_FMT_YVYU8_2X8_BE;
return 0;
}
static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
.s_stream = tw9910_s_stream,
.g_fmt = tw9910_g_fmt,
.s_fmt = tw9910_s_fmt,
.try_fmt = tw9910_try_fmt,
.g_mbus_fmt = tw9910_g_fmt,
.s_mbus_fmt = tw9910_s_fmt,
.try_mbus_fmt = tw9910_try_fmt,
.cropcap = tw9910_cropcap,
.g_crop = tw9910_g_crop,
.s_crop = tw9910_s_crop,
.enum_mbus_fmt = tw9910_enum_fmt,
};
static struct v4l2_subdev_ops tw9910_subdev_ops = {
......
......@@ -24,15 +24,13 @@ struct soc_camera_device {
struct device *pdev; /* Platform device */
s32 user_width;
s32 user_height;
enum v4l2_colorspace colorspace;
unsigned char iface; /* Host number */
unsigned char devnum; /* Device number per host */
unsigned char buswidth; /* See comment in .c */
struct soc_camera_sense *sense; /* See comment in struct definition */
struct soc_camera_ops *ops;
struct video_device *vdev;
const struct soc_camera_data_format *current_fmt;
const struct soc_camera_data_format *formats;
int num_formats;
const struct soc_camera_format_xlate *current_fmt;
struct soc_camera_format_xlate *user_formats;
int num_user_formats;
enum v4l2_field field; /* Preserve field over close() */
......@@ -161,23 +159,13 @@ static inline struct v4l2_subdev *soc_camera_to_subdev(
int soc_camera_host_register(struct soc_camera_host *ici);
void soc_camera_host_unregister(struct soc_camera_host *ici);
const struct soc_camera_data_format *soc_camera_format_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc);
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc);
struct soc_camera_data_format {
const char *name;
unsigned int depth;
__u32 fourcc;
enum v4l2_colorspace colorspace;
};
/**
* struct soc_camera_format_xlate - match between host and sensor formats
* @cam_fmt: sensor format provided by the sensor
* @host_fmt: host format after host translation from cam_fmt
* @buswidth: bus width for this format
* @code: code of a sensor provided format
* @host_fmt: host format after host translation from code
*
* Host and sensor translation structure. Used in table of host and sensor
* formats matchings in soc_camera_device. A host can override the generic list
......@@ -185,9 +173,8 @@ struct soc_camera_data_format {
* format setup.
*/
struct soc_camera_format_xlate {
const struct soc_camera_data_format *cam_fmt;
const struct soc_camera_data_format *host_fmt;
unsigned char buswidth;
enum v4l2_mbus_pixelcode code;
const struct soc_mbus_pixelfmt *host_fmt;
};
struct soc_camera_ops {
......
......@@ -19,7 +19,7 @@ struct device;
struct soc_camera_platform_info {
const char *format_name;
unsigned long format_depth;
struct v4l2_pix_format format;
struct v4l2_mbus_framefmt format;
unsigned long bus_param;
struct device *dev;
int (*set_capture)(struct soc_camera_platform_info *info, int enable);
......
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