media: i2c: max9286: Support 12-bit raw bayer formats
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Sat, 1 Jan 2022 18:28:02 +0000 (19:28 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Sun, 22 Jan 2023 08:10:10 +0000 (09:10 +0100)
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>
drivers/media/i2c/max9286.c

index 22c945c98aa799ed573503db003814f63f43cba1..4ed994d485345b20f37c59f83b3350418007b274 100644 (file)
 #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