mirror of
https://github.com/adulau/aha.git
synced 2025-02-15 11:27:26 +00:00
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: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
9a74251d8b
commit
760697beca
17 changed files with 1389 additions and 986 deletions
|
@ -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 = {
|
||||
|
|
|
@ -123,23 +123,34 @@
|
|||
#define MT9M111_MAX_HEIGHT 1024
|
||||
#define MT9M111_MAX_WIDTH 1280
|
||||
|
||||
#define COL_FMT(_name, _depth, _fourcc, _colorspace) \
|
||||
{ .name = _name, .depth = _depth, .fourcc = _fourcc, \
|
||||
.colorspace = _colorspace }
|
||||
#define RGB_FMT(_name, _depth, _fourcc) \
|
||||
COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB)
|
||||
#define JPG_FMT(_name, _depth, _fourcc) \
|
||||
COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG)
|
||||
/* MT9M111 has only one fixed colorspace per pixelcode */
|
||||
struct mt9m111_datafmt {
|
||||
enum v4l2_mbus_pixelcode code;
|
||||
enum v4l2_colorspace colorspace;
|
||||
};
|
||||
|
||||
static const struct soc_camera_data_format mt9m111_colour_formats[] = {
|
||||
JPG_FMT("CbYCrY 16 bit", 16, V4L2_PIX_FMT_UYVY),
|
||||
JPG_FMT("CrYCbY 16 bit", 16, V4L2_PIX_FMT_VYUY),
|
||||
JPG_FMT("YCbYCr 16 bit", 16, V4L2_PIX_FMT_YUYV),
|
||||
JPG_FMT("YCrYCb 16 bit", 16, V4L2_PIX_FMT_YVYU),
|
||||
RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565),
|
||||
RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555),
|
||||
RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16),
|
||||
RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8),
|
||||
/* Find a data format by a pixel code in an array */
|
||||
static const struct mt9m111_datafmt *mt9m111_find_datafmt(
|
||||
enum v4l2_mbus_pixelcode code, const struct mt9m111_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 mt9m111_datafmt mt9m111_colour_fmts[] = {
|
||||
{V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
|
||||
{V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
|
||||
{V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG},
|
||||
{V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG},
|
||||
{V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
|
||||
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
|
||||
{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
|
||||
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
|
||||
};
|
||||
|
||||
enum mt9m111_context {
|
||||
|
@ -152,7 +163,7 @@ struct mt9m111 {
|
|||
int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
|
||||
enum mt9m111_context context;
|
||||
struct v4l2_rect rect;
|
||||
u32 pixfmt;
|
||||
const struct mt9m111_datafmt *fmt;
|
||||
unsigned int gain;
|
||||
unsigned char autoexposure;
|
||||
unsigned char datawidth;
|
||||
|
@ -258,8 +269,8 @@ static int mt9m111_setup_rect(struct i2c_client *client,
|
|||
int width = rect->width;
|
||||
int height = rect->height;
|
||||
|
||||
if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
|
||||
mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)
|
||||
if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
|
||||
mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE)
|
||||
is_raw_format = 1;
|
||||
else
|
||||
is_raw_format = 0;
|
||||
|
@ -307,7 +318,8 @@ static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
|
|||
|
||||
static int mt9m111_setfmt_bayer8(struct i2c_client *client)
|
||||
{
|
||||
return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER);
|
||||
return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER |
|
||||
MT9M111_OUTFMT_RGB);
|
||||
}
|
||||
|
||||
static int mt9m111_setfmt_bayer10(struct i2c_client *client)
|
||||
|
@ -401,8 +413,8 @@ static int mt9m111_make_rect(struct i2c_client *client,
|
|||
{
|
||||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
|
||||
if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
|
||||
mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) {
|
||||
if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
|
||||
mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
|
||||
/* Bayer format - even size lengths */
|
||||
rect->width = ALIGN(rect->width, 2);
|
||||
rect->height = ALIGN(rect->height, 2);
|
||||
|
@ -460,120 +472,139 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
|
||||
static int mt9m111_g_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
struct i2c_client *client = sd->priv;
|
||||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
|
||||
pix->width = mt9m111->rect.width;
|
||||
pix->height = mt9m111->rect.height;
|
||||
pix->pixelformat = mt9m111->pixfmt;
|
||||
pix->field = V4L2_FIELD_NONE;
|
||||
pix->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
mf->width = mt9m111->rect.width;
|
||||
mf->height = mt9m111->rect.height;
|
||||
mf->code = mt9m111->fmt->code;
|
||||
mf->field = V4L2_FIELD_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt)
|
||||
static int mt9m111_set_pixfmt(struct i2c_client *client,
|
||||
enum v4l2_mbus_pixelcode code)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
int ret;
|
||||
|
||||
switch (pixfmt) {
|
||||
case V4L2_PIX_FMT_SBGGR8:
|
||||
switch (code) {
|
||||
case V4L2_MBUS_FMT_SBGGR8_1X8:
|
||||
ret = mt9m111_setfmt_bayer8(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR16:
|
||||
case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
|
||||
ret = mt9m111_setfmt_bayer10(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB555:
|
||||
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
|
||||
ret = mt9m111_setfmt_rgb555(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
case V4L2_MBUS_FMT_RGB565_2X8_LE:
|
||||
ret = mt9m111_setfmt_rgb565(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_UYVY:
|
||||
case V4L2_MBUS_FMT_YUYV8_2X8_BE:
|
||||
mt9m111->swap_yuv_y_chromas = 0;
|
||||
mt9m111->swap_yuv_cb_cr = 0;
|
||||
ret = mt9m111_setfmt_yuv(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_VYUY:
|
||||
case V4L2_MBUS_FMT_YVYU8_2X8_BE:
|
||||
mt9m111->swap_yuv_y_chromas = 0;
|
||||
mt9m111->swap_yuv_cb_cr = 1;
|
||||
ret = mt9m111_setfmt_yuv(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
case V4L2_MBUS_FMT_YUYV8_2X8_LE:
|
||||
mt9m111->swap_yuv_y_chromas = 1;
|
||||
mt9m111->swap_yuv_cb_cr = 0;
|
||||
ret = mt9m111_setfmt_yuv(client);
|
||||
break;
|
||||
case V4L2_PIX_FMT_YVYU:
|
||||
case V4L2_MBUS_FMT_YVYU8_2X8_LE:
|
||||
mt9m111->swap_yuv_y_chromas = 1;
|
||||
mt9m111->swap_yuv_cb_cr = 1;
|
||||
ret = mt9m111_setfmt_yuv(client);
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "Pixel format not handled : %x\n",
|
||||
pixfmt);
|
||||
code);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
mt9m111->pixfmt = pixfmt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
|
||||
static int mt9m111_s_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
struct i2c_client *client = sd->priv;
|
||||
const struct mt9m111_datafmt *fmt;
|
||||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
struct v4l2_rect rect = {
|
||||
.left = mt9m111->rect.left,
|
||||
.top = mt9m111->rect.top,
|
||||
.width = pix->width,
|
||||
.height = pix->height,
|
||||
.width = mf->width,
|
||||
.height = mf->height,
|
||||
};
|
||||
int ret;
|
||||
|
||||
fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
|
||||
ARRAY_SIZE(mt9m111_colour_fmts));
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
|
||||
pix->pixelformat, rect.left, rect.top, rect.width, rect.height);
|
||||
"%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
|
||||
mf->code, rect.left, rect.top, rect.width, rect.height);
|
||||
|
||||
ret = mt9m111_make_rect(client, &rect);
|
||||
if (!ret)
|
||||
ret = mt9m111_set_pixfmt(client, pix->pixelformat);
|
||||
if (!ret)
|
||||
mt9m111->rect = rect;
|
||||
ret = mt9m111_set_pixfmt(client, mf->code);
|
||||
if (!ret) {
|
||||
mt9m111->rect = rect;
|
||||
mt9m111->fmt = fmt;
|
||||
mf->colorspace = fmt->colorspace;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
|
||||
static int mt9m111_try_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
|
||||
pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
|
||||
struct i2c_client *client = sd->priv;
|
||||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
const struct mt9m111_datafmt *fmt;
|
||||
bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
|
||||
mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
|
||||
|
||||
fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
|
||||
ARRAY_SIZE(mt9m111_colour_fmts));
|
||||
if (!fmt) {
|
||||
fmt = mt9m111->fmt;
|
||||
mf->code = fmt->code;
|
||||
}
|
||||
|
||||
/*
|
||||
* With Bayer format enforce even side lengths, but let the user play
|
||||
* with the starting pixel
|
||||
*/
|
||||
|
||||
if (pix->height > MT9M111_MAX_HEIGHT)
|
||||
pix->height = MT9M111_MAX_HEIGHT;
|
||||
else if (pix->height < 2)
|
||||
pix->height = 2;
|
||||
if (mf->height > MT9M111_MAX_HEIGHT)
|
||||
mf->height = MT9M111_MAX_HEIGHT;
|
||||
else if (mf->height < 2)
|
||||
mf->height = 2;
|
||||
else if (bayer)
|
||||
pix->height = ALIGN(pix->height, 2);
|
||||
mf->height = ALIGN(mf->height, 2);
|
||||
|
||||
if (pix->width > MT9M111_MAX_WIDTH)
|
||||
pix->width = MT9M111_MAX_WIDTH;
|
||||
else if (pix->width < 2)
|
||||
pix->width = 2;
|
||||
if (mf->width > MT9M111_MAX_WIDTH)
|
||||
mf->width = MT9M111_MAX_WIDTH;
|
||||
else if (mf->width < 2)
|
||||
mf->width = 2;
|
||||
else if (bayer)
|
||||
pix->width = ALIGN(pix->width, 2);
|
||||
mf->width = ALIGN(mf->width, 2);
|
||||
|
||||
mf->colorspace = fmt->colorspace;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -863,7 +894,7 @@ static int mt9m111_restore_state(struct i2c_client *client)
|
|||
struct mt9m111 *mt9m111 = to_mt9m111(client);
|
||||
|
||||
mt9m111_set_context(client, mt9m111->context);
|
||||
mt9m111_set_pixfmt(client, mt9m111->pixfmt);
|
||||
mt9m111_set_pixfmt(client, mt9m111->fmt->code);
|
||||
mt9m111_setup_rect(client, &mt9m111->rect);
|
||||
mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
|
||||
mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
|
||||
|
@ -952,9 +983,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
|
|||
goto ei2c;
|
||||
}
|
||||
|
||||
icd->formats = mt9m111_colour_formats;
|
||||
icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
|
||||
|
||||
dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data);
|
||||
|
||||
ei2c:
|
||||
|
@ -971,13 +999,24 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index,
|
||||
enum v4l2_mbus_pixelcode *code)
|
||||
{
|
||||
if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts))
|
||||
return -EINVAL;
|
||||
|
||||
*code = mt9m111_colour_fmts[index].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
|
||||
.s_fmt = mt9m111_s_fmt,
|
||||
.g_fmt = mt9m111_g_fmt,
|
||||
.try_fmt = mt9m111_try_fmt,
|
||||
.s_mbus_fmt = mt9m111_s_fmt,
|
||||
.g_mbus_fmt = mt9m111_g_fmt,
|
||||
.try_mbus_fmt = mt9m111_try_fmt,
|
||||
.s_crop = mt9m111_s_crop,
|
||||
.g_crop = mt9m111_g_crop,
|
||||
.cropcap = mt9m111_cropcap,
|
||||
.enum_mbus_fmt = mt9m111_enum_fmt,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops mt9m111_subdev_ops = {
|
||||
|
@ -1024,6 +1063,7 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
|
||||
mt9m111->rect.width = MT9M111_MAX_WIDTH;
|
||||
mt9m111->rect.height = MT9M111_MAX_HEIGHT;
|
||||
mt9m111->fmt = &mt9m111_colour_fmts[0];
|
||||
|
||||
ret = mt9m111_video_probe(icd, client);
|
||||
if (ret) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <media/v4l2-dev.h>
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
#include <media/soc_camera.h>
|
||||
#include <media/soc_mediabus.h>
|
||||
|
||||
#include <mach/ipu.h>
|
||||
#include <mach/mx3_camera.h>
|
||||
|
@ -63,7 +64,7 @@
|
|||
struct mx3_camera_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
const struct soc_camera_data_format *fmt;
|
||||
enum v4l2_mbus_pixelcode code;
|
||||
|
||||
/* One descriptot per scatterlist (per frame) */
|
||||
struct dma_async_tx_descriptor *txd;
|
||||
|
@ -118,8 +119,6 @@ struct dma_chan_request {
|
|||
enum ipu_channel id;
|
||||
};
|
||||
|
||||
static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt);
|
||||
|
||||
static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
|
||||
{
|
||||
return __raw_readl(mx3->base + reg);
|
||||
|
@ -211,17 +210,16 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
|
|||
struct soc_camera_device *icd = vq->priv_data;
|
||||
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
|
||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||
/*
|
||||
* bits-per-pixel (depth) as specified in camera's pixel format does
|
||||
* not necessarily match what the camera interface writes to RAM, but
|
||||
* it should be good enough for now.
|
||||
*/
|
||||
unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8);
|
||||
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;
|
||||
|
||||
if (!mx3_cam->idmac_channel[0])
|
||||
return -EINVAL;
|
||||
|
||||
*size = icd->user_width * icd->user_height * bpp;
|
||||
*size = bytes_per_line * icd->user_height;
|
||||
|
||||
if (!*count)
|
||||
*count = 32;
|
||||
|
@ -241,21 +239,26 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
|
|||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||
struct mx3_camera_buffer *buf =
|
||||
container_of(vb, struct mx3_camera_buffer, vb);
|
||||
/* current_fmt _must_ always be set */
|
||||
size_t new_size = icd->user_width * icd->user_height *
|
||||
((icd->current_fmt->depth + 7) >> 3);
|
||||
size_t new_size;
|
||||
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;
|
||||
|
||||
new_size = bytes_per_line * icd->user_height;
|
||||
|
||||
/*
|
||||
* I think, in buf_prepare you only have to protect global data,
|
||||
* the actual buffer is yours
|
||||
*/
|
||||
|
||||
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;
|
||||
|
@ -348,13 +351,13 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
|
|||
struct dma_async_tx_descriptor *txd = buf->txd;
|
||||
struct idmac_channel *ichan = to_idmac_chan(txd->chan);
|
||||
struct idmac_video_param *video = &ichan->params.video;
|
||||
const struct soc_camera_data_format *data_fmt = icd->current_fmt;
|
||||
dma_cookie_t cookie;
|
||||
u32 fourcc = icd->current_fmt->host_fmt->fourcc;
|
||||
|
||||
BUG_ON(!irqs_disabled());
|
||||
|
||||
/* This is the configuration of one sg-element */
|
||||
video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc);
|
||||
video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc);
|
||||
video->out_width = icd->user_width;
|
||||
video->out_height = icd->user_height;
|
||||
video->out_stride = icd->user_width;
|
||||
|
@ -568,28 +571,33 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
|
|||
* If requested data width is supported by the platform, use it or any
|
||||
* possible lower value - i.MX31 is smart enough to schift bits
|
||||
*/
|
||||
switch (buswidth) {
|
||||
case 15:
|
||||
if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15))
|
||||
return -EINVAL;
|
||||
if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
|
||||
*flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 |
|
||||
SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
|
||||
break;
|
||||
case 10:
|
||||
if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10))
|
||||
return -EINVAL;
|
||||
else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
|
||||
*flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 |
|
||||
SOCAM_DATAWIDTH_4;
|
||||
else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
|
||||
*flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
|
||||
else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)
|
||||
*flags |= SOCAM_DATAWIDTH_4;
|
||||
|
||||
switch (buswidth) {
|
||||
case 15:
|
||||
if (!(*flags & SOCAM_DATAWIDTH_15))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case 10:
|
||||
if (!(*flags & SOCAM_DATAWIDTH_10))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case 8:
|
||||
if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8))
|
||||
if (!(*flags & SOCAM_DATAWIDTH_8))
|
||||
return -EINVAL;
|
||||
*flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
|
||||
break;
|
||||
case 4:
|
||||
if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4))
|
||||
if (!(*flags & SOCAM_DATAWIDTH_4))
|
||||
return -EINVAL;
|
||||
*flags |= SOCAM_DATAWIDTH_4;
|
||||
break;
|
||||
default:
|
||||
dev_warn(mx3_cam->soc_host.v4l2_dev.dev,
|
||||
|