From 93e191ebba6f2f6ac1a669f5601697a6e32bf336 Mon Sep 17 00:00:00 2001 From: Lin Jinhan Date: Fri, 20 May 2022 16:57:27 +0800 Subject: [PATCH] media: i2c: add SC132GS driver add reset gpio control Signed-off-by: Lin Jinhan Change-Id: I3b39752bddb2035bbd61828c8c86427901c973db --- drivers/media/i2c/Kconfig | 11 +++++++++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/sc132gs.c | 48 ++++++++++++++++++++++++++++++------- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4b61c430da1c..49c5854568a2 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1713,6 +1713,17 @@ config VIDEO_MT9V111 To compile this driver as a module, choose M here: the module will be called mt9v111. +config VIDEO_SC132GS + tristate "SmartSens SC132GS sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE + help + Support for the SmartSens SC132GS sensor. + + To compile this driver as a module, choose M here: the + module will be called sc132gs. + config VIDEO_SC230AI tristate "SmartSens SC230AI sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index cfbfa04dfdd7..84dafb3ed813 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o +obj-$(CONFIG_VIDEO_SC132GS) += sc132gs.o obj-$(CONFIG_VIDEO_SC230AI) += sc230ai.o obj-$(CONFIG_VIDEO_SC301IOT) += sc301iot.o obj-$(CONFIG_VIDEO_SC3336) += sc3336.o diff --git a/drivers/media/i2c/sc132gs.c b/drivers/media/i2c/sc132gs.c index 5576d36302a6..e1e9d49c16b5 100644 --- a/drivers/media/i2c/sc132gs.c +++ b/drivers/media/i2c/sc132gs.c @@ -8,6 +8,7 @@ * 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 */ #include @@ -28,7 +29,7 @@ #include #include -#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 #endif @@ -103,6 +104,7 @@ struct sc132gs_mode { 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; @@ -533,7 +535,7 @@ static long sc132gs_compat_ioctl32(struct v4l2_subdev *sd, { void __user *up = compat_ptr(arg); struct rkmodule_inf *inf; - long ret; + long ret = 0; u32 stream = 0; switch (cmd) { @@ -545,14 +547,18 @@ static long sc132gs_compat_ioctl32(struct v4l2_subdev *sd, } 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,6 +655,7 @@ static int sc132gs_s_stream(struct v4l2_subdev *sd, int on) { struct sc132gs *sc132gs = to_sc132gs(sd); struct i2c_client *client = sc132gs->client; + unsigned int fps; int ret = 0; mutex_lock(&sc132gs->mutex); @@ -656,6 +663,14 @@ static int sc132gs_s_stream(struct v4l2_subdev *sd, int 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); if (ret < 0) { @@ -761,9 +776,17 @@ static int __sc132gs_power_on(struct sc132gs *sc132gs) 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); usleep_range(delay_us, delay_us * 2); @@ -780,6 +803,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); clk_disable_unprepare(sc132gs->xvclk); @@ -850,7 +876,7 @@ static int sc132gs_enum_frame_interval(struct v4l2_subdev *sd, 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; @@ -858,7 +884,7 @@ static int sc132gs_g_mbus_config(struct v4l2_subdev *sd, val = 1 << (SC132GS_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 +912,6 @@ static const struct v4l2_subdev_core_ops sc132gs_core_ops = { 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 +920,7 @@ static const struct v4l2_subdev_pad_ops sc132gs_pad_ops = { .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 = { @@ -1098,6 +1124,10 @@ static int sc132gs_probe(struct i2c_client *client, 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");