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/sc401ai.c | 144 +++++++++++++++++++++++++++++++++++------------ 1 files changed, 107 insertions(+), 37 deletions(-) diff --git a/kernel/drivers/media/i2c/sc401ai.c b/kernel/drivers/media/i2c/sc401ai.c index 1c0bfbe..0eac2d3 100644 --- a/kernel/drivers/media/i2c/sc401ai.c +++ b/kernel/drivers/media/i2c/sc401ai.c @@ -9,6 +9,7 @@ * V0.0X01.0X03 fix gain range. * V0.0X01.0X04 add enum_frame_interval function. * V0.0X01.0X05 add quick stream on/off + * V0.0X01.0X06 support thunder boot function. */ #include <linux/clk.h> @@ -31,8 +32,9 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> #include <linux/pinctrl/consumer.h> +#include "../platform/rockchip/isp/rkisp_tb_helper.h" -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x05) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN @@ -120,14 +122,6 @@ #define SC401AI_NUM_SUPPLIES ARRAY_SIZE(sc401ai_supply_names) -enum sc401ai_max_pad { - PAD0, /* link to isp */ - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ - PAD2, /* link to csi wr1 | hdr x3:L */ - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ - PAD_MAX, -}; - struct regval { u16 addr; u8 val; @@ -170,6 +164,7 @@ struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *link_freq; struct mutex mutex; + struct v4l2_fract cur_fps; bool streaming; bool power_on; unsigned int lane_num; @@ -180,6 +175,8 @@ const char *module_name; const char *len_name; u32 cur_vts; + bool is_thunderboot; + bool is_first_streamoff; struct preisp_hdrae_exp_s init_hdrae_exp; }; @@ -454,6 +451,8 @@ SC401AI_LINK_FREQ_630, }; +static int __sc401ai_power_on(struct sc401ai *sc401ai); + /* Write registers up to 4 at a time */ static int sc401ai_write_reg(struct i2c_client *client, u16 reg, u32 len, u32 val) @@ -631,6 +630,11 @@ DIG_Fine_gain_reg = abs(800 * gain / (Dcg_gainx100 * Coarse_gain * DIG_gain) / ANA_Fine_gainx64); + if (sc401ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { + sc401ai->is_thunderboot = false; + __sc401ai_power_on(sc401ai); + } + ret = sc401ai_write_reg(sc401ai->client, SC401AI_REG_DIG_GAIN, SC401AI_REG_VALUE_08BIT, @@ -709,6 +713,8 @@ __v4l2_ctrl_modify_range(sc401ai->vblank, vblank_def, SC401AI_VTS_MAX - mode->height, 1, vblank_def); + sc401ai->cur_fps = mode->max_fps; + sc401ai->cur_vts = mode->vts_def; } mutex_unlock(&sc401ai->mutex); @@ -800,15 +806,17 @@ struct sc401ai *sc401ai = to_sc401ai(sd); const struct sc401ai_mode *mode = sc401ai->cur_mode; - mutex_lock(&sc401ai->mutex); - fi->interval = mode->max_fps; - mutex_unlock(&sc401ai->mutex); + if (sc401ai->streaming) + fi->interval = sc401ai->cur_fps; + else + fi->interval = mode->max_fps; return 0; } static int sc401ai_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *config) + unsigned int pad_id, + struct v4l2_mbus_config *config) { struct sc401ai *sc401ai = to_sc401ai(sd); const struct sc401ai_mode *mode = sc401ai->cur_mode; @@ -823,7 +831,7 @@ if (mode->hdr_mode == HDR_X3) val |= V4L2_MBUS_CSI2_CHANNEL_2; - config->type = V4L2_MBUS_CSI2; + config->type = V4L2_MBUS_CSI2_DPHY; config->flags = val; return 0; @@ -833,10 +841,10 @@ struct rkmodule_inf *inf) { memset(inf, 0, sizeof(*inf)); - strlcpy(inf->base.sensor, SC401AI_NAME, sizeof(inf->base.sensor)); - strlcpy(inf->base.module, sc401ai->module_name, + strscpy(inf->base.sensor, SC401AI_NAME, sizeof(inf->base.sensor)); + strscpy(inf->base.module, sc401ai->module_name, sizeof(inf->base.module)); - strlcpy(inf->base.lens, sc401ai->len_name, sizeof(inf->base.lens)); + strscpy(inf->base.lens, sc401ai->len_name, sizeof(inf->base.lens)); } static long sc401ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) @@ -992,23 +1000,31 @@ { int ret; - ret = sc401ai_write_array(sc401ai->client, sc401ai->cur_mode->reg_list); - if (ret) - return ret; + if (!sc401ai->is_thunderboot) { + ret = sc401ai_write_array(sc401ai->client, sc401ai->cur_mode->reg_list); + if (ret) + return ret; - /* In case these controls are set before streaming */ - ret = __v4l2_ctrl_handler_setup(&sc401ai->ctrl_handler); - if (ret) - return ret; + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&sc401ai->ctrl_handler); + if (ret) + return ret; + } return sc401ai_write_reg(sc401ai->client, - SC401AI_REG_CTRL_MODE, - SC401AI_REG_VALUE_08BIT, - SC401AI_MODE_STREAMING); + SC401AI_REG_CTRL_MODE, + SC401AI_REG_VALUE_08BIT, + SC401AI_MODE_STREAMING); + } static int __sc401ai_stop_stream(struct sc401ai *sc401ai) { + if (sc401ai->is_thunderboot) { + sc401ai->is_first_streamoff = true; + pm_runtime_put(&sc401ai->client->dev); + } + return sc401ai_write_reg(sc401ai->client, SC401AI_REG_CTRL_MODE, SC401AI_REG_VALUE_08BIT, @@ -1027,6 +1043,10 @@ goto unlock_and_return; if (on) { + if (sc401ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { + sc401ai->is_thunderboot = false; + __sc401ai_power_on(sc401ai); + } ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { pm_runtime_put_noidle(&client->dev); @@ -1118,6 +1138,10 @@ dev_err(dev, "Failed to enable xvclk\n"); return ret; } + + if (sc401ai->is_thunderboot) + return 0; + if (!IS_ERR(sc401ai->reset_gpio)) gpiod_set_value_cansleep(sc401ai->reset_gpio, 0); @@ -1155,6 +1179,15 @@ { int ret; struct device *dev = &sc401ai->client->dev; + + if (sc401ai->is_thunderboot) { + if (sc401ai->is_first_streamoff) { + sc401ai->is_thunderboot = false; + sc401ai->is_first_streamoff = false; + } else { + return; + } + } if (!IS_ERR(sc401ai->pwdn_gpio)) gpiod_set_value_cansleep(sc401ai->pwdn_gpio, 0); @@ -1249,7 +1282,6 @@ static const struct v4l2_subdev_video_ops sc401ai_video_ops = { .s_stream = sc401ai_s_stream, .g_frame_interval = sc401ai_g_frame_interval, - .g_mbus_config = sc401ai_g_mbus_config, }; static const struct v4l2_subdev_pad_ops sc401ai_pad_ops = { @@ -1258,6 +1290,7 @@ .enum_frame_interval = sc401ai_enum_frame_interval, .get_fmt = sc401ai_get_fmt, .set_fmt = sc401ai_set_fmt, + .get_mbus_config = sc401ai_g_mbus_config, }; static const struct v4l2_subdev_ops sc401ai_subdev_ops = { @@ -1265,6 +1298,14 @@ .video = &sc401ai_video_ops, .pad = &sc401ai_pad_ops, }; + +static void sc401ai_modify_fps_info(struct sc401ai *sc401ai) +{ + const struct sc401ai_mode *mode = sc401ai->cur_mode; + + sc401ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc401ai->cur_vts; +} static int sc401ai_set_ctrl(struct v4l2_ctrl *ctrl) { @@ -1324,7 +1365,9 @@ SC401AI_REG_VALUE_08BIT, (ctrl->val + sc401ai->cur_mode->height) & 0xff); - sc401ai->cur_vts = ctrl->val + sc401ai->cur_mode->height; + if (!ret) + sc401ai->cur_vts = ctrl->val + sc401ai->cur_mode->height; + sc401ai_modify_fps_info(sc401ai); break; case V4L2_CID_TEST_PATTERN: ret = sc401ai_enable_test_pattern(sc401ai, ctrl->val); @@ -1466,6 +1509,8 @@ } sc401ai->subdev.ctrl_handler = handler; + sc401ai->cur_fps = mode->max_fps; + sc401ai->cur_vts = mode->vts_def; return 0; @@ -1481,6 +1526,11 @@ struct device *dev = &sc401ai->client->dev; u32 id = 0; int ret; + + if (sc401ai->is_thunderboot) { + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); + return 0; + } ret = sc401ai_read_reg(client, SC401AI_REG_CHIP_ID, SC401AI_REG_VALUE_16BIT, &id); @@ -1540,6 +1590,8 @@ return -EINVAL; } + sc401ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); + sc401ai->client = client; for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { if (hdr_mode == supported_modes[i].hdr_mode) { @@ -1556,13 +1608,23 @@ return -EINVAL; } - sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(sc401ai->reset_gpio)) - dev_warn(dev, "Failed to get reset-gpios\n"); + if (sc401ai->is_thunderboot) { + sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); + if (IS_ERR(sc401ai->reset_gpio)) + dev_warn(dev, "Failed to get reset-gpios\n"); - sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); - if (IS_ERR(sc401ai->pwdn_gpio)) - dev_warn(dev, "Failed to get pwdn-gpios\n"); + sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); + if (IS_ERR(sc401ai->pwdn_gpio)) + dev_warn(dev, "Failed to get pwdn-gpios\n"); + } else { + sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(sc401ai->reset_gpio)) + dev_warn(dev, "Failed to get reset-gpios\n"); + + sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); + if (IS_ERR(sc401ai->pwdn_gpio)) + dev_warn(dev, "Failed to get pwdn-gpios\n"); + } sc401ai->pinctrl = devm_pinctrl_get(dev); if (!IS_ERR(sc401ai->pinctrl)) { @@ -1637,7 +1699,10 @@ pm_runtime_set_active(dev); pm_runtime_enable(dev); - pm_runtime_idle(dev); + if (sc401ai->is_thunderboot) + pm_runtime_get_sync(dev); + else + pm_runtime_idle(dev); return 0; @@ -1709,8 +1774,13 @@ i2c_del_driver(&sc401ai_i2c_driver); } +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) +subsys_initcall(sensor_mod_init); +#else device_initcall_sync(sensor_mod_init); +#endif + module_exit(sensor_mod_exit); MODULE_DESCRIPTION("smartsens sc401ai sensor driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); -- Gitblit v1.6.2