From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 19 Dec 2024 01:47:39 +0000
Subject: [PATCH] add wifi6 8852be driver

---
 kernel/drivers/media/i2c/sc132gs.c |  294 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 252 insertions(+), 42 deletions(-)

diff --git a/kernel/drivers/media/i2c/sc132gs.c b/kernel/drivers/media/i2c/sc132gs.c
index 5576d36..a8f0a50 100644
--- a/kernel/drivers/media/i2c/sc132gs.c
+++ b/kernel/drivers/media/i2c/sc132gs.c
@@ -8,6 +8,8 @@
  * V0.0X01.0X03 add enum_frame_interval function.
  * V0.0X01.0X04 add quick stream on/off
  * V0.0X01.0X05 add function g_mbus_config
+ * V0.0X01.0X06 add function reset gpio control
+ * V0.0X01.0X06 add 2-lane mode as default
  */
 
 #include <linux/clk.h>
@@ -28,12 +30,17 @@
 #include <media/v4l2-subdev.h>
 #include <linux/pinctrl/consumer.h>
 
-#define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x05)
+#define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x07)
 #ifndef V4L2_CID_DIGITAL_GAIN
 #define V4L2_CID_DIGITAL_GAIN		V4L2_CID_GAIN
 #endif
 
-#define SC132GS_PIXEL_RATE		(72 * 1000 * 1000)
+#define MIPI_FREQ_180M			180000000
+#define MIPI_FREQ_360M			360000000
+
+#define PIXEL_RATE_WITH_180M		(MIPI_FREQ_180M * 2 / 10 * 2)
+#define PIXEL_RATE_WITH_360M		(MIPI_FREQ_360M * 2 / 8 * 1)
+
 #define SC132GS_XVCLK_FREQ		24000000
 
 #define CHIP_ID				0x0132
@@ -69,13 +76,8 @@
 
 #define SC132GS_NAME			"sc132gs"
 
-#define PIX_FORMAT MEDIA_BUS_FMT_Y8_1X8
-
 #define OF_CAMERA_PINCTRL_STATE_DEFAULT	"rockchip,camera_default"
 #define OF_CAMERA_PINCTRL_STATE_SLEEP	"rockchip,camera_sleep"
-
-#define SC132GS_LANES			1
-#define SC132GS_BITS_PER_SAMPLE		8
 
 static const char * const sc132gs_supply_names[] = {
 	"avdd",		/* Analog power */
@@ -84,6 +86,11 @@
 };
 
 #define SC132GS_NUM_SUPPLIES ARRAY_SIZE(sc132gs_supply_names)
+
+enum {
+	LINK_FREQ_180M_INDEX,
+	LINK_FREQ_360M_INDEX,
+};
 
 struct regval {
 	u16 addr;
@@ -97,12 +104,17 @@
 	u32 hts_def;
 	u32 vts_def;
 	u32 exp_def;
+	u32 link_freq_index;
+	u64 pixel_rate;
 	const struct regval *reg_list;
+	u32 lanes;
+	u32 bus_fmt;
 };
 
 struct sc132gs {
 	struct i2c_client	*client;
 	struct clk		*xvclk;
+	struct gpio_desc	*reset_gpio;
 	struct gpio_desc	*pwdn_gpio;
 	struct regulator_bulk_data supplies[SC132GS_NUM_SUPPLIES];
 	struct pinctrl		*pinctrl;
@@ -117,7 +129,11 @@
 	struct v4l2_ctrl	*hblank;
 	struct v4l2_ctrl	*vblank;
 	struct v4l2_ctrl	*test_pattern;
+	struct v4l2_ctrl	*pixel_rate;
+	struct v4l2_ctrl	*link_freq;
 	struct mutex		mutex;
+	struct v4l2_fract	cur_fps;
+	u32			cur_vts;
 	bool			streaming;
 	bool			power_on;
 	const struct sc132gs_mode *cur_mode;
@@ -131,7 +147,7 @@
 
 /*
  * Xclk 24Mhz
- * Pclk 72Mhz
+ * Pclk 90Mhz
  * linelength 1696(0x06a0)
  * framelength 2122(0x084a)
  * grabwindow_width 1080
@@ -140,7 +156,7 @@
  * max_framerate 30fps
  * mipi_datarate per lane 720Mbps
  */
-static const struct regval sc132gs_global_regs[] = {
+static const struct regval sc132gs_1lane_8bit_regs[] = {
 	{0x0103, 0x01},
 	{0x0100, 0x00},
 
@@ -247,6 +263,130 @@
 	{REG_NULL, 0x00},
 };
 
+/*
+ * Xclk 24Mhz
+ * Pclk 72Mhz
+ * linelength 1696(0x06a0)
+ * framelength 2122(0x084a)
+ * grabwindow_width 1080
+ * grabwindow_height 1280
+ * mipi 2 lane
+ * max_framerate 30fps
+ * mipi_datarate per lane 360Mbps
+ */
+static const struct regval sc132gs_2lane_10bit_regs[] = {
+	{0x0103, 0x01},
+	{0x0100, 0x00},
+
+	//PLL bypass
+	{0x36e9, 0x80},
+	{0x36f9, 0x80},
+
+	{0x3018, 0x32},
+	{0x3019, 0x0c},
+	{0x301a, 0xb4},
+	{0x3031, 0x0a},
+	{0x3032, 0x60},
+	{0x3038, 0x44},
+	{0x3207, 0x17},
+	{0x320c, 0x05},
+	{0x320d, 0xdc},
+	{0x320e, 0x09},
+	{0x320f, 0x60},
+	{0x3250, 0xcc},
+	{0x3251, 0x02},
+	{0x3252, 0x09},
+	{0x3253, 0x5b},
+	{0x3254, 0x05},
+	{0x3255, 0x3b},
+	{0x3306, 0x78},
+	{0x330a, 0x00},
+	{0x330b, 0xc8},
+	{0x330f, 0x24},
+	{0x3314, 0x80},
+	{0x3315, 0x40},
+	{0x3317, 0xf0},
+	{0x331f, 0x12},
+	{0x3364, 0x00},
+	{0x3385, 0x41},
+	{0x3387, 0x41},
+	{0x3389, 0x09},
+	{0x33ab, 0x00},
+	{0x33ac, 0x00},
+	{0x33b1, 0x03},
+	{0x33b2, 0x12},
+	{0x33f8, 0x02},
+	{0x33fa, 0x01},
+	{0x3409, 0x08},
+	{0x34f0, 0xc0},
+	{0x34f1, 0x20},
+	{0x34f2, 0x03},
+	{0x3622, 0xf5},
+	{0x3630, 0x5c},
+	{0x3631, 0x80},
+	{0x3632, 0xc8},
+	{0x3633, 0x32},
+	{0x3638, 0x2a},
+	{0x3639, 0x07},
+	{0x363b, 0x48},
+	{0x363c, 0x83},
+	{0x363d, 0x10},
+	{0x36ea, 0x38},
+	{0x36fa, 0x25},
+	{0x36fb, 0x05},
+	{0x36fd, 0x04},
+	{0x3900, 0x11},
+	{0x3901, 0x05},
+	{0x3902, 0xc5},
+	{0x3904, 0x04},
+	{0x3908, 0x91},
+	{0x391e, 0x00},
+	{0x3e01, 0x11},
+	{0x3e02, 0x20},
+	{0x3e09, 0x20},
+	{0x3e0e, 0xd2},
+	{0x3e14, 0xb0},
+	{0x3e1e, 0x7c},
+	{0x3e26, 0x20},
+	{0x4418, 0x38},
+	{0x4503, 0x10},
+	{0x4837, 0x21},
+	{0x5000, 0x0e},
+	{0x540c, 0x51},
+	{0x550f, 0x38},
+	{0x5780, 0x67},
+	{0x5784, 0x10},
+	{0x5785, 0x06},
+	{0x5787, 0x02},
+	{0x5788, 0x00},
+	{0x5789, 0x00},
+	{0x578a, 0x02},
+	{0x578b, 0x00},
+	{0x578c, 0x00},
+	{0x5790, 0x00},
+	{0x5791, 0x00},
+	{0x5792, 0x00},
+	{0x5793, 0x00},
+	{0x5794, 0x00},
+	{0x5795, 0x00},
+	{0x5799, 0x04},
+
+	//flip
+	//{0x3221, (0x3 << 5)},
+
+	//mirror
+	{0x3221, (0x3 << 1)},
+
+	//flip & mirror
+	//{0x3221, ((0x3 << 1)|(0x3 << 5))},
+
+	//PLL set
+	{0x36e9, 0x20},
+	{0x36f9, 0x24},
+
+	{REG_NULL, 0x00},
+};
+
 static const struct sc132gs_mode supported_modes[] = {
 	{
 		.width = 1080,
@@ -258,7 +398,28 @@
 		.exp_def = 0x0148,
 		.hts_def = 0x06a0,
 		.vts_def = 0x084a,
-		.reg_list = sc132gs_global_regs,
+		.link_freq_index = LINK_FREQ_180M_INDEX,
+		.pixel_rate      = PIXEL_RATE_WITH_180M,
+		.reg_list = sc132gs_2lane_10bit_regs,
+		.lanes    = 2,
+		.bus_fmt  = MEDIA_BUS_FMT_Y10_1X10,
+	},
+
+	{
+		.width = 1080,
+		.height = 1280,
+		.max_fps = {
+			.numerator = 10000,
+			.denominator = 300000,
+		},
+		.exp_def = 0x0148,
+		.hts_def = 0x06a0,
+		.vts_def = 0x084a,
+		.link_freq_index = LINK_FREQ_360M_INDEX,
+		.pixel_rate      = PIXEL_RATE_WITH_360M,
+		.reg_list = sc132gs_1lane_8bit_regs,
+		.lanes    = 1,
+		.bus_fmt  = MEDIA_BUS_FMT_Y8_1X8,
 	},
 };
 
@@ -270,10 +431,9 @@
 	"Vertical Color Bar Type 4"
 };
 
-#define SC132GS_LINK_FREQ_360MHZ	(360 * 1000 * 1000)
-
 static const s64 link_freq_menu_items[] = {
-	SC132GS_LINK_FREQ_360MHZ
+	MIPI_FREQ_180M,
+	MIPI_FREQ_360M,
 };
 
 /* Write registers up to 4 at a time */
@@ -374,7 +534,8 @@
 
 	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
 		dist = sc132gs_get_reso_dist(&supported_modes[i], framefmt);
-		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
+		if ((cur_best_fit_dist == -1 || dist < cur_best_fit_dist) &&
+		    (supported_modes[i].bus_fmt == framefmt->code)) {
 			cur_best_fit_dist = dist;
 			cur_best_fit = i;
 		}
@@ -393,7 +554,7 @@
 	mutex_lock(&sc132gs->mutex);
 
 	mode = sc132gs_find_best_fit(fmt);
-	fmt->format.code = PIX_FORMAT;
+	fmt->format.code = mode->bus_fmt;
 	fmt->format.width = mode->width;
 	fmt->format.height = mode->height;
 	fmt->format.field = V4L2_FIELD_NONE;
@@ -413,6 +574,10 @@
 		__v4l2_ctrl_modify_range(sc132gs->vblank, vblank_def,
 					 SC132GS_VTS_MAX - mode->height,
 					 1, vblank_def);
+		__v4l2_ctrl_s_ctrl_int64(sc132gs->pixel_rate, mode->pixel_rate);
+		__v4l2_ctrl_s_ctrl(sc132gs->link_freq, mode->link_freq_index);
+		sc132gs->cur_fps = mode->max_fps;
+		sc132gs->cur_vts = mode->vts_def;
 	}
 
 	mutex_unlock(&sc132gs->mutex);
@@ -438,7 +603,7 @@
 	} else {
 		fmt->format.width = mode->width;
 		fmt->format.height = mode->height;
-		fmt->format.code = PIX_FORMAT;
+		fmt->format.code = mode->bus_fmt;
 		fmt->format.field = V4L2_FIELD_NONE;
 	}
 	mutex_unlock(&sc132gs->mutex);
@@ -450,9 +615,11 @@
 				 struct v4l2_subdev_pad_config *cfg,
 				 struct v4l2_subdev_mbus_code_enum *code)
 {
+	struct sc132gs *sc132gs = to_sc132gs(sd);
+
 	if (code->index != 0)
 		return -EINVAL;
-	code->code = PIX_FORMAT;
+	code->code = sc132gs->cur_mode->bus_fmt;
 
 	return 0;
 }
@@ -464,7 +631,7 @@
 	if (fse->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
 
-	if (fse->code != PIX_FORMAT)
+	if (fse->code != supported_modes[fse->index].bus_fmt)
 		return -EINVAL;
 
 	fse->min_width = supported_modes[fse->index].width;
@@ -533,7 +700,7 @@
 {
 	void __user *up = compat_ptr(arg);
 	struct rkmodule_inf *inf;
-	long ret;
+	long ret = 0;
 	u32 stream = 0;
 
 	switch (cmd) {
@@ -545,14 +712,18 @@
 		}
 
 		ret = sc132gs_ioctl(sd, cmd, inf);
-		if (!ret)
+		if (!ret) {
 			ret = copy_to_user(up, inf, sizeof(*inf));
+			if (ret)
+				ret = -EFAULT;
+		}
 		kfree(inf);
 		break;
 	case RKMODULE_SET_QUICK_STREAM:
-		ret = copy_from_user(&stream, up, sizeof(u32));
-		if (!ret)
-			ret = sc132gs_ioctl(sd, cmd, &stream);
+		if (copy_from_user(&stream, up, sizeof(u32)))
+			return -EFAULT;
+
+		ret = sc132gs_ioctl(sd, cmd, &stream);
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -649,12 +820,21 @@
 {
 	struct sc132gs *sc132gs = to_sc132gs(sd);
 	struct i2c_client *client = sc132gs->client;
+	unsigned int fps;
 	int ret = 0;
 
 	mutex_lock(&sc132gs->mutex);
 	on = !!on;
 	if (on == sc132gs->streaming)
 		goto unlock_and_return;
+
+	fps = DIV_ROUND_CLOSEST(sc132gs->cur_mode->max_fps.denominator,
+				sc132gs->cur_mode->max_fps.numerator);
+
+	dev_info(&sc132gs->client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on,
+				sc132gs->cur_mode->width,
+				sc132gs->cur_mode->height,
+				fps);
 
 	if (on) {
 		ret = pm_runtime_get_sync(&client->dev);
@@ -718,9 +898,10 @@
 	struct sc132gs *sc132gs = to_sc132gs(sd);
 	const struct sc132gs_mode *mode = sc132gs->cur_mode;
 
-	mutex_lock(&sc132gs->mutex);
-	fi->interval = mode->max_fps;
-	mutex_unlock(&sc132gs->mutex);
+	if (sc132gs->streaming)
+		fi->interval = sc132gs->cur_fps;
+	else
+		fi->interval = mode->max_fps;
 
 	return 0;
 }
@@ -761,8 +942,16 @@
 		goto disable_clk;
 	}
 
+	if (!IS_ERR(sc132gs->reset_gpio))
+		gpiod_set_value_cansleep(sc132gs->reset_gpio, 1);
+
+	usleep_range(1000, 2000);
+
 	if (!IS_ERR(sc132gs->pwdn_gpio))
 		gpiod_set_value_cansleep(sc132gs->pwdn_gpio, 1);
+
+	if (!IS_ERR(sc132gs->reset_gpio))
+		gpiod_set_value_cansleep(sc132gs->reset_gpio, 0);
 
 	/* 8192 cycles prior to first SCCB transaction */
 	delay_us = sc132gs_cal_delay(8192);
@@ -779,6 +968,9 @@
 static void __sc132gs_power_off(struct sc132gs *sc132gs)
 {
 	int ret;
+
+	if (!IS_ERR(sc132gs->reset_gpio))
+		gpiod_set_value_cansleep(sc132gs->reset_gpio, 1);
 
 	if (!IS_ERR(sc132gs->pwdn_gpio))
 		gpiod_set_value_cansleep(sc132gs->pwdn_gpio, 0);
@@ -824,7 +1016,7 @@
 	/* Initialize try_fmt */
 	try_fmt->width = def_mode->width;
 	try_fmt->height = def_mode->height;
-	try_fmt->code = PIX_FORMAT;
+	try_fmt->code = def_mode->bus_fmt;
 	try_fmt->field = V4L2_FIELD_NONE;
 
 	mutex_unlock(&sc132gs->mutex);
@@ -841,24 +1033,23 @@
 	if (fie->index >= ARRAY_SIZE(supported_modes))
 		return -EINVAL;
 
-	if (fie->code != PIX_FORMAT)
-		return -EINVAL;
-
+	fie->code = supported_modes[fie->index].bus_fmt;
 	fie->width = supported_modes[fie->index].width;
 	fie->height = supported_modes[fie->index].height;
 	fie->interval = supported_modes[fie->index].max_fps;
 	return 0;
 }
 
-static int sc132gs_g_mbus_config(struct v4l2_subdev *sd,
+static int sc132gs_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
 				struct v4l2_mbus_config *config)
 {
 	u32 val = 0;
+	struct sc132gs *sc132gs = to_sc132gs(sd);
 
-	val = 1 << (SC132GS_LANES - 1) |
+	val = 1 << (sc132gs->cur_mode->lanes - 1) |
 	      V4L2_MBUS_CSI2_CHANNEL_0 |
 	      V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
-	config->type = V4L2_MBUS_CSI2;
+	config->type = V4L2_MBUS_CSI2_DPHY;
 	config->flags = val;
 
 	return 0;
@@ -886,7 +1077,6 @@
 static const struct v4l2_subdev_video_ops sc132gs_video_ops = {
 	.s_stream = sc132gs_s_stream,
 	.g_frame_interval = sc132gs_g_frame_interval,
-	.g_mbus_config = sc132gs_g_mbus_config,
 };
 
 static const struct v4l2_subdev_pad_ops sc132gs_pad_ops = {
@@ -895,6 +1085,7 @@
 	.enum_frame_interval = sc132gs_enum_frame_interval,
 	.get_fmt = sc132gs_get_fmt,
 	.set_fmt = sc132gs_set_fmt,
+	.get_mbus_config = sc132gs_g_mbus_config,
 };
 
 static const struct v4l2_subdev_ops sc132gs_subdev_ops = {
@@ -902,6 +1093,14 @@
 	.video	= &sc132gs_video_ops,
 	.pad	= &sc132gs_pad_ops,
 };
+
+static void sc132gs_modify_fps_info(struct sc132gs *sc132gs)
+{
+	const struct sc132gs_mode *mode = sc132gs->cur_mode;
+
+	sc132gs->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def /
+				       sc132gs->cur_vts;
+}
 
 static int sc132gs_set_ctrl(struct v4l2_ctrl *ctrl)
 {
@@ -939,6 +1138,10 @@
 		ret = sc132gs_write_reg(sc132gs->client, SC132GS_REG_VTS,
 					SC132GS_REG_VALUE_16BIT,
 					ctrl->val + sc132gs->cur_mode->height);
+		if (!ret)
+			sc132gs->cur_vts = ctrl->val + sc132gs->cur_mode->height;
+		sc132gs_modify_fps_info(sc132gs);
+		break;
 		break;
 	case V4L2_CID_TEST_PATTERN:
 		ret = sc132gs_enable_test_pattern(sc132gs, ctrl->val);
@@ -962,7 +1165,6 @@
 {
 	const struct sc132gs_mode *mode;
 	struct v4l2_ctrl_handler *handler;
-	struct v4l2_ctrl *ctrl;
 	s64 exposure_max, vblank_def;
 	u32 h_blank;
 	int ret;
@@ -974,13 +1176,16 @@
 		return ret;
 	handler->lock = &sc132gs->mutex;
 
-	ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
-				      0, 0, link_freq_menu_items);
-	if (ctrl)
-		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	sc132gs->link_freq = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
+						    ARRAY_SIZE(link_freq_menu_items) - 1, 0,
+						    link_freq_menu_items);
 
-	v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
-			  0, SC132GS_PIXEL_RATE, 1, SC132GS_PIXEL_RATE);
+	sc132gs->pixel_rate = v4l2_ctrl_new_std(handler, NULL,
+						V4L2_CID_PIXEL_RATE,
+						0, PIXEL_RATE_WITH_360M,
+						1, mode->pixel_rate);
+
+	__v4l2_ctrl_s_ctrl(sc132gs->link_freq, mode->pixel_rate);
 
 	h_blank = mode->hts_def - mode->width;
 	sc132gs->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
@@ -1016,7 +1221,8 @@
 			"Failed to init controls(%d)\n", ret);
 		goto err_free_handler;
 	}
-
+	sc132gs->cur_fps = mode->max_fps;
+	sc132gs->cur_vts = mode->vts_def;
 	sc132gs->subdev.ctrl_handler = handler;
 
 	return 0;
@@ -1098,6 +1304,10 @@
 		return -EINVAL;
 	}
 
+	sc132gs->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(sc132gs->reset_gpio))
+		dev_warn(dev, "Failed to get reset-gpios\n");
+
 	sc132gs->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
 	if (IS_ERR(sc132gs->pwdn_gpio))
 		dev_warn(dev, "Failed to get pwdn-gpios\n");

--
Gitblit v1.6.2