mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
media: i2c: add SC132GS driver
add reset gpio control Signed-off-by: Lin Jinhan <troy.lin@rock-chips.com> Change-Id: I3b39752bddb2035bbd61828c8c86427901c973db
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <linux/clk.h>
|
||||
@@ -28,7 +29,7 @@
|
||||
#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, 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");
|
||||
|
||||
Reference in New Issue
Block a user