Commit f1403802 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

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: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: default avatarJacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent b904512b
Loading
Loading
Loading
Loading
+95 −33
Original line number Diff line number Diff line
@@ -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;
	/* 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