@@ -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
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> --- Changes since v1: - Fix incorrect array index when media bus code isn't found --- drivers/media/i2c/max9286.c | 128 ++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 33 deletions(-)