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/spi/rk1608_dphy.c |  387 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 373 insertions(+), 14 deletions(-)

diff --git a/kernel/drivers/media/spi/rk1608_dphy.c b/kernel/drivers/media/spi/rk1608_dphy.c
index 0740bd9..378ba55 100644
--- a/kernel/drivers/media/spi/rk1608_dphy.c
+++ b/kernel/drivers/media/spi/rk1608_dphy.c
@@ -24,9 +24,10 @@
 #include <linux/of_platform.h>
 #include <linux/types.h>
 #include <linux/rk-preisp.h>
-#include <linux/rkisp1-config.h>
+#include <linux/rk-isp1-config.h>
 #include <linux/rk-camera-module.h>
 #include "rk1608_dphy.h"
+#include <linux/compat.h>
 
 #define RK1608_DPHY_NAME	"RK1608-dphy"
 
@@ -109,9 +110,114 @@
 	return ret;
 }
 
+#define RK1608_MAX_BITRATE (1500000000)
+static int rk1608_get_link_sensor_timing(struct rk1608_dphy *pdata)
+{
+	int ret = 0;
+	u32 i;
+	u32 idx = pdata->fmt_inf_idx;
+	struct rk1608_fmt_inf *fmt_inf = &pdata->fmt_inf[idx];
+	int sub_sensor_num = pdata->sub_sensor_num;
+	u32 width = 0, height = 0, out_width, out_height;
+	struct v4l2_subdev *link_sensor;
+	u32 id = pdata->sd.grp_id;
+	struct v4l2_subdev_frame_interval fi;
+	int max_fps = 30;
+	u64 bps;
+
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+		.pad = 0,
+	};
+
+	if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+
+		link_sensor = i2c_get_clientdata(
+				pdata->link_sensor_client);
+		if (IS_ERR_OR_NULL(link_sensor)) {
+			dev_err(pdata->dev, "can not get link sensor i2c client\n");
+			return -EINVAL;
+		}
+
+		ret = v4l2_subdev_call(link_sensor, pad, get_fmt, NULL, &fmt);
+		if (ret) {
+			dev_info(pdata->dev, "get link fmt fail\n");
+			return -EINVAL;
+		}
+
+		width = fmt.format.width;
+		height = fmt.format.height;
+		dev_info(pdata->dev, "phy[%d] get fmt w:%d h:%d\n",
+				id, width, height);
+
+		memset(&fi, 0, sizeof(fi));
+		ret = v4l2_subdev_call(link_sensor, video, g_frame_interval, &fi);
+		if (ret) {
+			dev_info(pdata->dev, "get link interval fail\n");
+			return -EINVAL;
+		}
+
+		max_fps = fi.interval.denominator / fi.interval.numerator;
+		dev_info(pdata->dev, "phy[%d] get fps:%d (%d/%d)\n",
+				id, max_fps, fi.interval.denominator, fi.interval.numerator);
+
+	} else {
+		width = fmt_inf->mf.width;
+		height = fmt_inf->mf.height;
+		dev_info(pdata->dev, "phy[%d] no link sensor\n", id);
+	}
+
+	if (!width || !height) {
+		dev_err(pdata->dev, "phy[%d] get fmt error!\n", id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (fmt_inf->in_ch[i].width == 0)
+			break;
+
+		fmt_inf->in_ch[i].width = width;
+		fmt_inf->in_ch[i].height = height;
+	}
+
+	out_width = width;
+	out_height = height * (sub_sensor_num + 1); /* sub add main */
+	for (i = 0; i < 4; i++) {
+		if (fmt_inf->out_ch[i].width == 0)
+			break;
+
+		fmt_inf->out_ch[i].width = out_width;
+		fmt_inf->out_ch[i].height = out_height;
+	}
+
+	fmt_inf->hactive = out_width;
+	fmt_inf->vactive = out_height;
+	fmt_inf->htotal = out_width + (width * 1 / 3); //1.33
+	fmt_inf->vtotal = out_height + (height >> 4);
+
+	/* max 30 fps, raw 10 */
+	bps = fmt_inf->htotal * fmt_inf->vtotal
+		/ fmt_inf->mipi_lane_out * 10 * max_fps;
+
+	/* add extra timing */
+	bps = bps * 105;
+	do_div(bps, 100);
+
+	if (bps > RK1608_MAX_BITRATE)
+		bps = RK1608_MAX_BITRATE;
+
+	pdata->link_freqs = (u32)(bps/2);
+	dev_info(pdata->dev, "target mipi bps:%lld\n", bps);
+
+	return 0;
+}
+
 static int rk1608_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct rk1608_dphy *pdata = to_state(sd);
+
+	if (enable && pdata->sub_sensor_num)
+		rk1608_get_link_sensor_timing(pdata);
 
 	pdata->rk1608_sd->grp_id = sd->grp_id;
 	v4l2_subdev_call(pdata->rk1608_sd, video, s_stream, enable);
@@ -159,12 +265,43 @@
 	struct v4l2_mbus_framefmt *mf = &fmt->format;
 	struct rk1608_dphy *pdata = to_state(sd);
 	u32 idx = pdata->fmt_inf_idx;
+	struct v4l2_subdev *link_sensor;
+	int ret = -1;
 
-	mf->code = pdata->fmt_inf[idx].mf.code;
-	mf->width = pdata->fmt_inf[idx].mf.width;
-	mf->height = pdata->fmt_inf[idx].mf.height;
-	mf->field = pdata->fmt_inf[idx].mf.field;
-	mf->colorspace = pdata->fmt_inf[idx].mf.colorspace;
+	if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+		link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+		if (IS_ERR_OR_NULL(link_sensor)) {
+			dev_err(pdata->dev, "can not get link sensor i2c client\n");
+			goto exit;
+		}
+
+		ret = v4l2_subdev_call(link_sensor, pad, get_fmt, NULL, fmt);
+		if (ret) {
+			dev_info(pdata->dev, "get link fmt fail\n");
+			goto exit;
+		}
+
+		dev_info(pdata->dev, "use link sensor fmt w:%d h:%d code:%d\n",
+				mf->width, mf->height, mf->code);
+	}
+
+exit:
+	if (ret || !mf->width || !mf->height) {
+		mf->code = pdata->fmt_inf[idx].mf.code;
+		mf->width = pdata->fmt_inf[idx].mf.width;
+		mf->height = pdata->fmt_inf[idx].mf.height;
+		mf->field = pdata->fmt_inf[idx].mf.field;
+		mf->colorspace = pdata->fmt_inf[idx].mf.colorspace;
+	} else {
+		pdata->fmt_inf[idx].mf.code   = mf->code;
+		pdata->fmt_inf[idx].mf.width  = mf->width;
+		pdata->fmt_inf[idx].mf.height = mf->height;
+		pdata->fmt_inf[idx].mf.field  = mf->field;
+		pdata->fmt_inf[idx].mf.colorspace = mf->colorspace;
+	}
+
+	if (pdata->sub_sensor_num)
+		rk1608_get_link_sensor_timing(pdata);
 
 	return 0;
 }
@@ -201,9 +338,9 @@
 
 	pdata->fmt_inf_idx = idx;
 
+	pdata->rk1608_sd->grp_id = pdata->sd.grp_id;
 	v4l2_subdev_call(pdata->rk1608_sd, pad, set_fmt, cfg, fmt);
 
-	pdata->rk1608_sd->grp_id = pdata->sd.grp_id;
 	remote_ctrl = v4l2_ctrl_find(pdata->rk1608_sd->ctrl_handler,
 						 V4L2_CID_HBLANK);
 	if (remote_ctrl) {
@@ -233,7 +370,30 @@
 				   struct v4l2_subdev_frame_interval *fi)
 {
 	struct rk1608_dphy *pdata = to_state(sd);
+	struct v4l2_subdev *link_sensor;
+	int ret = 0;
 
+	if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+		link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+		if (IS_ERR_OR_NULL(link_sensor)) {
+			dev_err(pdata->dev, "can not get link sensor i2c client\n");
+			return -EINVAL;
+		}
+
+		ret = v4l2_subdev_call(link_sensor,
+				video,
+				g_frame_interval,
+				fi);
+		if (ret)
+			dev_info(pdata->dev, "get link interval fail\n");
+		else
+			return ret;
+	}
+
+	if (!(pdata->rk1608_sd)) {
+		dev_info(pdata->dev, "pdata->rk1608_sd NULL\n");
+		return -EFAULT;
+	}
 	pdata->rk1608_sd->grp_id = sd->grp_id;
 	v4l2_subdev_call(pdata->rk1608_sd,
 			 video,
@@ -249,18 +409,18 @@
 	return 0;
 }
 
-static int rk1608_g_mbus_config(struct v4l2_subdev *sd,
+static int rk1608_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id,
 				struct v4l2_mbus_config *config)
 {
 
 	struct rk1608_dphy *pdata = to_state(sd);
 	u32 val = 0;
 
-	val = 1 << (pdata->fmt_inf[pdata->fmt_inf_idx].mipi_lane - 1) |
+	val = 1 << (pdata->fmt_inf[pdata->fmt_inf_idx].mipi_lane_out - 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;
@@ -269,6 +429,7 @@
 static long rk1608_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	struct rk1608_dphy *pdata = to_state(sd);
+	struct v4l2_subdev *link_sensor;
 	long ret = 0;
 
 	switch (cmd) {
@@ -289,11 +450,22 @@
 	case PREISP_DISP_WRITE_EEPROM:
 	case PREISP_DISP_READ_EEPROM:
 	case PREISP_DISP_SET_LED_ON_OFF:
+	case RKMODULE_SET_QUICK_STREAM:
 		mutex_lock(&rk1608_dphy_mutex);
 		pdata->rk1608_sd->grp_id = pdata->sd.grp_id;
 		ret = v4l2_subdev_call(pdata->rk1608_sd, core, ioctl,
 				       cmd, arg);
 		mutex_unlock(&rk1608_dphy_mutex);
+		break;
+	case RKMODULE_GET_CSI_DPHY_PARAM:
+		if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+			link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+			if (IS_ERR_OR_NULL(link_sensor)) {
+				dev_err(pdata->dev, "can not get link sensor i2c client\n");
+				return -EINVAL;
+			}
+			ret = v4l2_subdev_call(link_sensor, core, ioctl, cmd, arg);
+		}
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -310,7 +482,9 @@
 	struct preisp_hdrae_exp_s hdrae_exp;
 	struct rkmodule_inf *inf;
 	struct rkmodule_awb_cfg *cfg;
-	long ret;
+	struct rkmodule_csi_dphy_param *dphy_param;
+	u32  stream;
+	long ret = -EFAULT;
 
 	switch (cmd) {
 	case PREISP_CMD_SET_HDRAE_EXP:
@@ -327,7 +501,10 @@
 
 		ret = rk1608_ioctl(sd, cmd, inf);
 		if (!ret)
-			ret = copy_to_user(up, inf, sizeof(*inf));
+			if (copy_to_user(up, inf, sizeof(*inf))) {
+				kfree(inf);
+				return -EFAULT;
+			}
 		kfree(inf);
 		break;
 	case RKMODULE_AWB_CFG:
@@ -336,10 +513,29 @@
 			ret = -ENOMEM;
 			return ret;
 		}
-		if (copy_from_user(cfg, up, sizeof(cfg)))
+		if (copy_from_user(cfg, up, sizeof(*cfg)))
 			return -EFAULT;
 		ret = rk1608_ioctl(sd, cmd, cfg);
 		kfree(cfg);
+		break;
+	case RKMODULE_SET_QUICK_STREAM:
+		ret = copy_from_user(&stream, up, sizeof(u32));
+		if (!ret)
+			ret = rk1608_ioctl(sd, cmd, &stream);
+		else
+			ret = -EFAULT;
+
+		break;
+	case RKMODULE_GET_CSI_DPHY_PARAM:
+		dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL);
+		if (!dphy_param) {
+			ret = -ENOMEM;
+			return ret;
+		}
+		if (copy_from_user(dphy_param, up, sizeof(*dphy_param)))
+			return -EFAULT;
+		ret = rk1608_ioctl(sd, cmd, dphy_param);
+		kfree(dphy_param);
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -385,6 +581,87 @@
 				     ctrl->id);
 	if (remote_ctrl)
 		ret = v4l2_ctrl_s_ctrl(remote_ctrl, ctrl->val);
+
+	return ret;
+}
+
+#define CROP_START(SRC, DST) (((SRC) - (DST)) / 2 / 4 * 4)
+static int rk1608_get_selection(struct v4l2_subdev *sd,
+		struct v4l2_subdev_pad_config *cfg,
+		struct v4l2_subdev_selection *sel)
+{
+	struct rk1608_dphy *pdata = to_state(sd);
+	u32 idx = pdata->fmt_inf_idx;
+	u32 width = pdata->fmt_inf[idx].mf.width;
+	u32 height = pdata->fmt_inf[idx].mf.height;
+	struct v4l2_subdev *link_sensor;
+	int ret = -EINVAL;
+
+	if (sel->target != V4L2_SEL_TGT_CROP_BOUNDS)
+		return -EINVAL;
+
+	if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+		link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+		if (IS_ERR_OR_NULL(link_sensor)) {
+			dev_err(pdata->dev, "can not get link sensor i2c client\n");
+			goto err;
+		}
+
+		ret = v4l2_subdev_call(link_sensor, pad, get_selection, NULL, sel);
+		if (!ret)
+			return 0;
+	}
+
+err:
+	if (pdata->fmt_inf[idx].hcrop && pdata->fmt_inf[idx].vcrop) {
+		width = pdata->fmt_inf[idx].hcrop;
+		height = pdata->fmt_inf[idx].vcrop;
+	}
+
+	sel->r.left = CROP_START(pdata->fmt_inf[idx].mf.width, width);
+	sel->r.top = CROP_START(pdata->fmt_inf[idx].mf.height, height);
+	sel->r.width = width;
+	sel->r.height = height;
+
+	return 0;
+}
+
+static int rk1608_enum_frame_interval(struct v4l2_subdev *sd,
+	struct v4l2_subdev_pad_config *cfg,
+	struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct rk1608_dphy *pdata = to_state(sd);
+	u32 idx = pdata->fmt_inf_idx;
+	int ret = 0;
+	struct v4l2_fract max_fps = {
+		.numerator = 10000,
+		.denominator = 300000,
+	};
+	struct v4l2_subdev *link_sensor;
+
+	if (!IS_ERR_OR_NULL(pdata->link_sensor_client)) {
+		link_sensor = i2c_get_clientdata(pdata->link_sensor_client);
+		if (IS_ERR_OR_NULL(link_sensor)) {
+			dev_err(pdata->dev, "can not get link sensor i2c client\n");
+			goto err;
+		}
+
+		ret = v4l2_subdev_call(link_sensor,
+				pad,
+				enum_frame_interval,
+				NULL,
+				fie);
+		return ret;
+	}
+
+err:
+	if (fie->index >= pdata->fmt_inf_num)
+		return -EINVAL;
+
+	fie->code = pdata->fmt_inf[idx].mf.code;
+	fie->width = pdata->fmt_inf[idx].mf.width;
+	fie->height = pdata->fmt_inf[idx].mf.height;
+	fie->interval = max_fps;
 
 	return ret;
 }
@@ -511,7 +788,6 @@
 	.s_stream	= rk1608_s_stream,
 	.g_frame_interval = rk1608_g_frame_interval,
 	.s_frame_interval = rk1608_s_frame_interval,
-	.g_mbus_config = rk1608_g_mbus_config,
 };
 
 static const struct v4l2_subdev_pad_ops rk1608_subdev_pad_ops = {
@@ -519,6 +795,9 @@
 	.enum_frame_size = rk1608_enum_frame_sizes,
 	.get_fmt	= rk1608_get_fmt,
 	.set_fmt	= rk1608_set_fmt,
+	.get_mbus_config = rk1608_g_mbus_config,
+	.get_selection = rk1608_get_selection,
+	.enum_frame_interval = rk1608_enum_frame_interval,
 };
 
 static const struct v4l2_subdev_core_ops rk1608_core_ops = {
@@ -541,7 +820,9 @@
 	struct device_node *node = dphy->dev->of_node;
 	struct device_node *parent_node = of_node_get(node);
 	struct device_node *prev_node = NULL;
+	struct i2c_client *link_sensor_client;
 	u32 idx = 0;
+	u32 sub_idx = 0;
 
 	ret = of_property_read_u32(node, "id", &dphy->sd.grp_id);
 	if (ret)
@@ -590,6 +871,11 @@
 				&dphy->fmt_inf[idx].mipi_lane);
 			if (ret)
 				dev_warn(dphy->dev, "Can not get mipi_lane!");
+
+			ret = of_property_read_u32(node, "mipi_lane_out",
+				&dphy->fmt_inf[idx].mipi_lane_out);
+			if (ret)
+				dev_warn(dphy->dev, "Can not get mipi_lane_out!");
 
 			ret = of_property_read_u32(node, "field",
 				&dphy->fmt_inf[idx].mf.field);
@@ -676,6 +962,16 @@
 			if (ret)
 				dev_info(dphy->dev, "Can not get outch3-info!");
 
+			ret = of_property_read_u32(node, "hcrop",
+				&dphy->fmt_inf[idx].hcrop);
+			if (ret)
+				dev_warn(dphy->dev, "Can not get hcrop!");
+
+			ret = of_property_read_u32(node, "vcrop",
+				&dphy->fmt_inf[idx].vcrop);
+			if (ret)
+				dev_warn(dphy->dev, "Can not get vcrop!");
+
 			idx++;
 		}
 
@@ -684,6 +980,69 @@
 	}
 	dphy->fmt_inf_num = idx;
 
+	prev_node = NULL;
+	/* get virtual sub sensor */
+	node = NULL;
+	while (!IS_ERR_OR_NULL(node =
+				of_get_next_child(parent_node, prev_node))) {
+		if (!strncasecmp(node->name,
+				 "virtual-sub-sensor-config",
+				 strlen("virtual-sub-sensor-config"))) {
+
+			if (sub_idx >= 4) {
+				dev_err(dphy->dev, "get too mach sub_sensor node, max 4.\n");
+				break;
+			}
+
+			ret = of_property_read_u32(node, "id",
+				&dphy->sub_sensor[sub_idx].id);
+			if (ret)
+				dev_warn(dphy->dev, "Can not get sub sensor id!");
+			else
+				dev_info(dphy->dev, "get sub sensor id:%d",
+						dphy->sub_sensor[sub_idx].id);
+
+			ret = of_property_read_u32(node, "in_mipi",
+				&dphy->sub_sensor[sub_idx].in_mipi);
+			if (ret)
+				dev_warn(dphy->dev, "Can not get sub sensor in_mipi!");
+			else
+				dev_info(dphy->dev, "get sub sensor in_mipi:%d",
+						dphy->sub_sensor[sub_idx].in_mipi);
+
+			ret = of_property_read_u32(node, "out_mipi",
+				&dphy->sub_sensor[sub_idx].out_mipi);
+			if (ret)
+				dev_warn(dphy->dev, "Can not get sub sensor out_mipi!");
+			else
+				dev_info(dphy->dev, "get sub sensor out_mipi:%d",
+						dphy->sub_sensor[sub_idx].out_mipi);
+
+			sub_idx++;
+		}
+
+		of_node_put(prev_node);
+		prev_node = node;
+	}
+	dphy->sub_sensor_num = sub_idx;
+
+	node = of_parse_phandle(parent_node, "link-sensor", 0);
+	if (node) {
+		dev_info(dphy->dev, "get link sensor node:%s\n", node->full_name);
+		link_sensor_client =
+			of_find_i2c_device_by_node(node);
+		of_node_put(node);
+		if (IS_ERR_OR_NULL(link_sensor_client)) {
+			dev_err(dphy->dev, "can not get link sensor node\n");
+		} else {
+			dphy->link_sensor_client = link_sensor_client;
+			dev_info(dphy->dev, "get link sensor client\n");
+		}
+	} else {
+		dev_err(dphy->dev, "can not get link-sensor node\n");
+	}
+	/* get virtual sub sensor end */
+
 	of_node_put(prev_node);
 	of_node_put(parent_node);
 

--
Gitblit v1.6.2