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