media: i2c: max9286: Support 12-bit raw bayer formats

Add support for 12-bit raw bayer formats to the driver, configuring the
GMSL format accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
Laurent Pinchart 2022-01-01 19:28:02 +01:00 committed by Mauro Carvalho Chehab
parent b904512bf6
commit f1403802d5

View file

@ -136,6 +136,11 @@
#define MAX9286_N_PADS 5
#define MAX9286_SRC_PAD 4
struct max9286_format_info {
u32 code;
u8 datatype;
};
struct max9286_source {
struct v4l2_subdev *sd;
struct fwnode_handle *fwnode;
@ -218,6 +223,34 @@ static inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd)
return container_of(sd, struct max9286_priv, sd);
}
static const struct max9286_format_info max9286_formats[] = {
{
.code = MEDIA_BUS_FMT_UYVY8_1X16,
.datatype = MAX9286_DATATYPE_YUV422_8BIT,
}, {
.code = MEDIA_BUS_FMT_VYUY8_1X16,
.datatype = MAX9286_DATATYPE_YUV422_8BIT,
}, {
.code = MEDIA_BUS_FMT_YUYV8_1X16,
.datatype = MAX9286_DATATYPE_YUV422_8BIT,
}, {
.code = MEDIA_BUS_FMT_YVYU8_1X16,
.datatype = MAX9286_DATATYPE_YUV422_8BIT,
}, {
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
.datatype = MAX9286_DATATYPE_RAW12,
}, {
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
.datatype = MAX9286_DATATYPE_RAW12,
}, {
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
.datatype = MAX9286_DATATYPE_RAW12,
}, {
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
.datatype = MAX9286_DATATYPE_RAW12,
},
};
/* -----------------------------------------------------------------------------
* I2C IO
*/
@ -479,6 +512,38 @@ static int max9286_check_config_link(struct max9286_priv *priv,
return 0;
}
static void max9286_set_video_format(struct max9286_priv *priv,
const struct v4l2_mbus_framefmt *format)
{
const struct max9286_format_info *info = NULL;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
if (max9286_formats[i].code == format->code) {
info = &max9286_formats[i];
break;
}
}
if (WARN_ON(!info))
return;
/*
* Video format setup:
* Disable CSI output, VC is set according to Link number.
*/
max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV);
/* Enable CSI-2 Lane D0-D3 only, DBL mode. */
max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL |
MAX9286_CSILANECNT(priv->csi2_data_lanes) |
info->datatype);
/* Enable HS/VS encoding, use D14/15 for HS/VS, invert VS. */
max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_INVVS |
MAX9286_HVSRC_D14);
}
static void max9286_set_fsync_period(struct max9286_priv *priv)
{
u32 fsync;
@ -697,6 +762,15 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
int ret;
if (enable) {
const struct v4l2_mbus_framefmt *format;
/*
* Get the format from the first used sink pad, as all sink
* formats must be identical.
*/
format = &priv->fmt[__ffs(priv->bound_sources)];
max9286_set_video_format(priv, format);
max9286_set_fsync_period(priv);
/*
@ -817,22 +891,20 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
{
struct max9286_priv *priv = sd_to_max9286(sd);
struct v4l2_mbus_framefmt *cfg_fmt;
unsigned int i;
if (format->pad == MAX9286_SRC_PAD)
return -EINVAL;
/* Refuse non YUV422 formats as we hardcode DT to 8 bit YUV422 */
switch (format->format.code) {
case MEDIA_BUS_FMT_UYVY8_1X16:
case MEDIA_BUS_FMT_VYUY8_1X16:
case MEDIA_BUS_FMT_YUYV8_1X16:
case MEDIA_BUS_FMT_YVYU8_1X16:
break;
default:
format->format.code = MEDIA_BUS_FMT_UYVY8_1X16;
break;
/* Validate the format. */
for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
if (max9286_formats[i].code == format->format.code)
break;
}
if (i == ARRAY_SIZE(max9286_formats))
format->format.code = max9286_formats[0].code;
cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
format->which);
if (!cfg_fmt)
@ -890,16 +962,20 @@ static const struct v4l2_subdev_ops max9286_subdev_ops = {
.pad = &max9286_pad_ops,
};
static const struct v4l2_mbus_framefmt max9286_default_format = {
.width = 1280,
.height = 800,
.code = MEDIA_BUS_FMT_UYVY8_1X16,
.colorspace = V4L2_COLORSPACE_SRGB,
.field = V4L2_FIELD_NONE,
.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
.quantization = V4L2_QUANTIZATION_DEFAULT,
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
};
static void max9286_init_format(struct v4l2_mbus_framefmt *fmt)
{
fmt->width = 1280;
fmt->height = 800;
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
fmt->field = V4L2_FIELD_NONE;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
*fmt = max9286_default_format;
}
static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
@ -1063,23 +1139,9 @@ static int max9286_setup(struct max9286_priv *priv)
max9286_write(priv, 0x0b, link_order[priv->route_mask]);
max9286_write(priv, 0x69, (0xf & ~priv->route_mask));
/*
* Video format setup:
* Disable CSI output, VC is set according to Link number.
*/
max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV);
/* Enable CSI-2 Lane D0-D3 only, DBL mode, YUV422 8-bit. */
max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL |
MAX9286_CSILANECNT(priv->csi2_data_lanes) |
MAX9286_DATATYPE_YUV422_8BIT);
max9286_set_video_format(priv, &max9286_default_format);
max9286_set_fsync_period(priv);
/* Enable HS/VS encoding, use D14/15 for HS/VS, invert VS. */
max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_INVVS |
MAX9286_HVSRC_D14);
/*
* The overlap window seems to provide additional validation by tracking
* the delay between vsync and frame sync, generating an error if the