From 86e3f6d35527608611176b6591bc6a80bfc0f7cf Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 7 Jul 2020 18:29:10 +0100
Subject: [PATCH] media: i2c: ov9281: Add support for 8 bit readout

The sensor supports 8 bit mode as well as 10bit, so add the
relevant code to allow selection of this.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/media/i2c/ov9281.c | 66 ++++++++++++++++++++++++++++++--------
 1 file changed, 52 insertions(+), 14 deletions(-)

--- a/drivers/media/i2c/ov9281.c
+++ b/drivers/media/i2c/ov9281.c
@@ -29,11 +29,12 @@
 
 #define OV9281_LINK_FREQ_400MHZ		400000000
 #define OV9281_LANES			2
-#define OV9281_BITS_PER_SAMPLE		10
 
 /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
-#define OV9281_PIXEL_RATE		(OV9281_LINK_FREQ_400MHZ * 2 * \
-					 OV9281_LANES / OV9281_BITS_PER_SAMPLE)
+#define OV9281_PIXEL_RATE_10BIT		(OV9281_LINK_FREQ_400MHZ * 2 * \
+					 OV9281_LANES / 10)
+#define OV9281_PIXEL_RATE_8BIT		(OV9281_LINK_FREQ_400MHZ * 2 * \
+					 OV9281_LANES / 8)
 #define OV9281_XVCLK_FREQ		24000000
 
 #define CHIP_ID				0x9281
@@ -122,24 +123,25 @@ struct ov9281 {
 	struct v4l2_ctrl	*digi_gain;
 	struct v4l2_ctrl	*hblank;
 	struct v4l2_ctrl	*vblank;
+	struct v4l2_ctrl	*pixel_rate;
 	struct v4l2_ctrl	*test_pattern;
 	struct mutex		mutex;
 	bool			streaming;
 	bool			power_on;
 	const struct ov9281_mode *cur_mode;
+	u32			code;
 };
 
 #define to_ov9281(sd) container_of(sd, struct ov9281, subdev)
 
 /*
  * Xclk 24Mhz
- * max_framerate 120fps
+ * max_framerate 120fps for 10 bit, 144fps for 8 bit.
  * mipi_datarate per lane 800Mbps
  */
 static const struct regval ov9281_1280x800_regs[] = {
 	{0x0103, 0x01},
 	{0x0302, 0x32},
-	{0x030d, 0x50},
 	{0x030e, 0x02},
 	{0x3001, 0x00},
 	{0x3004, 0x00},
@@ -168,7 +170,6 @@ static const struct regval ov9281_1280x8
 	{0x3620, 0x6f},
 	{0x3632, 0x56},
 	{0x3633, 0x78},
-	{0x3662, 0x05},
 	{0x3666, 0x00},
 	{0x366f, 0x5a},
 	{0x3680, 0x84},
@@ -235,6 +236,18 @@ static const struct regval ov9281_1280x8
 	{REG_NULL, 0x00},
 };
 
+static const struct regval op_10bit[] = {
+	{0x030d, 0x50},
+	{0x3662, 0x05},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval op_8bit[] = {
+	{0x030d, 0x60},
+	{0x3662, 0x07},
+	{REG_NULL, 0x00},
+};
+
 static const struct ov9281_mode supported_modes[] = {
 	{
 		.width = 1280,
@@ -374,12 +387,13 @@ static int ov9281_set_fmt(struct v4l2_su
 {
 	struct ov9281 *ov9281 = to_ov9281(sd);
 	const struct ov9281_mode *mode;
-	s64 h_blank, vblank_def;
+	s64 h_blank, vblank_def, pixel_rate;
 
 	mutex_lock(&ov9281->mutex);
 
 	mode = ov9281_find_best_fit(fmt);
-	fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
+	if (fmt->format.code != MEDIA_BUS_FMT_Y8_1X8)
+		fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
 	fmt->format.width = mode->width;
 	fmt->format.height = mode->height;
 	fmt->format.field = V4L2_FIELD_NONE;
@@ -396,6 +410,7 @@ static int ov9281_set_fmt(struct v4l2_su
 		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
 	} else {
 		ov9281->cur_mode = mode;
+		ov9281->code = fmt->format.code;
 		h_blank = mode->hts_def - mode->width;
 		__v4l2_ctrl_modify_range(ov9281->hblank, h_blank,
 					 h_blank, 1, h_blank);
@@ -405,6 +420,11 @@ static int ov9281_set_fmt(struct v4l2_su
 					 OV9281_VTS_MAX - mode->height,
 					 1, vblank_def);
 		__v4l2_ctrl_s_ctrl(ov9281->vblank, vblank_def);
+
+		pixel_rate = (fmt->format.code == MEDIA_BUS_FMT_Y10_1X10) ?
+			OV9281_PIXEL_RATE_10BIT : OV9281_PIXEL_RATE_8BIT;
+		__v4l2_ctrl_modify_range(ov9281->pixel_rate, pixel_rate,
+					 pixel_rate, 1, pixel_rate);
 	}
 
 	mutex_unlock(&ov9281->mutex);
@@ -425,7 +445,7 @@ static int ov9281_get_fmt(struct v4l2_su
 	} else {
 		fmt->format.width = mode->width;
 		fmt->format.height = mode->height;
-		fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
+		fmt->format.code = ov9281->code;
 		fmt->format.field = V4L2_FIELD_NONE;
 		fmt->format.colorspace = V4L2_COLORSPACE_SRGB;
 		fmt->format.ycbcr_enc =
@@ -446,9 +466,16 @@ static int ov9281_enum_mbus_code(struct
 				 struct v4l2_subdev_pad_config *cfg,
 				 struct v4l2_subdev_mbus_code_enum *code)
 {
-	if (code->index)
+	switch (code->index) {
+	default:
 		return -EINVAL;
-	code->code = MEDIA_BUS_FMT_Y10_1X10;
+	case 0:
+		code->code = MEDIA_BUS_FMT_Y10_1X10;
+		break;
+	case 1:
+		code->code = MEDIA_BUS_FMT_Y8_1X8;
+		break;
+	}
 
 	return 0;
 }
@@ -460,7 +487,8 @@ static int ov9281_enum_frame_sizes(struc
 	if (fse->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
 
-	if (fse->code != MEDIA_BUS_FMT_Y10_1X10)
+	if (fse->code != MEDIA_BUS_FMT_Y10_1X10 &&
+	    fse->code != MEDIA_BUS_FMT_Y8_1X8)
 		return -EINVAL;
 
 	fse->min_width  = supported_modes[fse->index].width;
@@ -543,6 +571,13 @@ static int __ov9281_start_stream(struct
 	if (ret)
 		return ret;
 
+	if (ov9281->code == MEDIA_BUS_FMT_Y10_1X10)
+		ret = ov9281_write_array(ov9281->client, op_10bit);
+	else
+		ret = ov9281_write_array(ov9281->client, op_8bit);
+	if (ret)
+		return ret;
+
 	/* In case these controls are set before streaming */
 	mutex_unlock(&ov9281->mutex);
 	ret = v4l2_ctrl_handler_setup(&ov9281->ctrl_handler);
@@ -849,8 +884,11 @@ static int ov9281_initialize_controls(st
 	if (ctrl)
 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
-	v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
-			  0, OV9281_PIXEL_RATE, 1, OV9281_PIXEL_RATE);
+	ov9281->pixel_rate = v4l2_ctrl_new_std(handler, NULL,
+					       V4L2_CID_PIXEL_RATE,
+					       OV9281_PIXEL_RATE_10BIT,
+					       OV9281_PIXEL_RATE_10BIT, 1,
+					       OV9281_PIXEL_RATE_10BIT);
 
 	h_blank = mode->hts_def - mode->width;
 	ov9281->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
