media: i2c: sensor drivers synchronize with kernel 4.4

kernel 4.4 commit ends f3e1785b1893c4a7bdf543ae048b92f9696daf53

Change-Id: I666049f58cb9939e76cbe889d3f85be012ea0fc1
Signed-off-by: Zefa Chen <zefa.chen@rock-chips.com>
This commit is contained in:
Zefa Chen
2019-10-09 20:38:05 +08:00
committed by Tao Huang
parent ac42acf166
commit 7973ba63f2
36 changed files with 31893 additions and 6110 deletions

View File

@@ -596,6 +596,17 @@ config VIDEO_APTINA_PLL
config VIDEO_SMIAPP_PLL
tristate
config VIDEO_IMX219
tristate "Sony IMX219 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the Sony
IMX219 camera.
To compile this driver as a module, choose M here: the
module will be called imx219.
config VIDEO_IMX258
tristate "Sony IMX258 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -607,6 +618,14 @@ config VIDEO_IMX258
To compile this driver as a module, choose M here: the
module will be called imx258.
config VIDEO_IMX258_EEPROM
tristate "Sony imx258 sensor otp from eeprom support"
depends on VIDEO_V4L2 && I2C
depends on VIDEO_IMX258
select V4L2_FWNODE
help
This driver supports IMX258 OTP load from eeprom.
config VIDEO_IMX274
tristate "Sony IMX274 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -616,6 +635,39 @@ config VIDEO_IMX274
This is a V4L2 sensor driver for the Sony IMX274
CMOS image sensor.
config VIDEO_IMX317
tristate "Sony IMX317 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the Sony
IMX317 camera.
To compile this driver as a module, choose M here: the
module will be called imx317.
config VIDEO_IMX323
tristate "Sony IMX323 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the Sony
IMX323 camera.
To compile this driver as a module, choose M here: the
module will be called imx323.
config VIDEO_IMX327
tristate "Sony IMX327 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the Sony
IMX327 camera.
To compile this driver as a module, choose M here: the
module will be called imx327.
config VIDEO_OV2640
tristate "OmniVision OV2640 sensor support"
depends on VIDEO_V4L2 && I2C
@@ -663,6 +715,42 @@ config VIDEO_OV2685
To compile this driver as a module, choose M here: the
module will be called ov2685.
config VIDEO_OV2718
tristate "OmniVision OV2718 sensor support"
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
OV2718 camera.
To compile this driver as a module, choose M here: the
module will be called ov2718.
config VIDEO_OV2735
tristate "OmniVision OV2735 sensor support"
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
OV2735 camera.
To compile this driver as a module, choose M here: the
module will be called ov2735.
config VIDEO_OV4689
tristate "OmniVision OV4689 sensor support"
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
OV4689 camera.
To compile this driver as a module, choose M here: the
module will be called ov4689.
config VIDEO_OV5640
tristate "OmniVision OV5640 sensor support"
depends on OF
@@ -698,24 +786,24 @@ config VIDEO_OV5647
To compile this driver as a module, choose M here: the
module will be called ov5647.
config VIDEO_OV6650
tristate "OmniVision OV6650 sensor support"
depends on I2C && VIDEO_V4L2
config VIDEO_OV5648
tristate "OmniVision OV5648 sensor support"
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on MEDIA_CAMERA_SUPPORT
---help---
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
OV6650 camera.
OV5648 camera.
To compile this driver as a module, choose M here: the
module will be called ov6650.
module will be called ov5648.
config VIDEO_OV5670
tristate "OmniVision OV5670 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on MEDIA_CAMERA_SUPPORT
depends on MEDIA_CONTROLLER
select V4L2_FWNODE
---help---
help
This is a Video4Linux2 sensor driver for the OmniVision
OV5670 camera.
@@ -724,15 +812,27 @@ config VIDEO_OV5670
config VIDEO_OV5695
tristate "OmniVision OV5695 sensor support"
depends on I2C && VIDEO_V4L2
depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
depends on MEDIA_CAMERA_SUPPORT
---help---
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
OV5695 camera.
To compile this driver as a module, choose M here: the
module will be called ov5695.
config VIDEO_OV6650
tristate "OmniVision OV6650 sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the OmniVision
OV6650 camera.
To compile this driver as a module, choose M here: the
module will be called ov6650.
config VIDEO_OV7251
tristate "OmniVision OV7251 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -785,12 +885,62 @@ config VIDEO_OV7740
This is a Video4Linux2 sensor driver for the OmniVision
OV7740 VGA camera sensor.
config VIDEO_OV9650
tristate "OmniVision OV9650/OV9652 sensor support"
config VIDEO_OV7750
tristate "OmniVision OV7750 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---help---
This is a V4L2 sensor driver for the Omnivision
OV9650 and OV9652 camera sensors.
depends on MEDIA_CAMERA_SUPPORT
depends on MEDIA_CONTROLLER
select V4L2_FWNODE
help
This is a Video4Linux2 sensor driver for the OmniVision
OV7750 camera.
To compile this driver as a module, choose M here: the
module will be called ov7750.
config VIDEO_OV8858
tristate "OmniVision OV8858 sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the OmniVision
OV8858 camera.
To compile this driver as a module, choose M here: the
module will be called ov8858.
config VIDEO_OV9281
tristate "OmniVision OV9281 sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the OmniVision
OV9281 camera.
To compile this driver as a module, choose M here: the
module will be called ov9281.
config VIDEO_OV9650
tristate "OmniVision OV9650 sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the OmniVision
OV9650 camera.
To compile this driver as a module, choose M here: the
module will be called ov9650.
config VIDEO_OV9750
tristate "OmniVision OV9750 sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
help
This is a Video4Linux2 sensor driver for the OmniVision
OV9750 camera.
To compile this driver as a module, choose M here: the
module will be called ov9750.
config VIDEO_OV13850
tristate "OmniVision OV13850 sensor support"
@@ -895,6 +1045,17 @@ config VIDEO_MT9V111
To compile this driver as a module, choose M here: the
module will be called mt9v111.
config VIDEO_AR0230
tristate "Aptina AR0230 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the Aptina AR0230 sensor.
To compile this driver as a module, choose M here: the
module will be called ar0230.
config VIDEO_SR030PC30
tristate "Siliconfile SR030PC30 sensor support"
depends on I2C && VIDEO_V4L2
@@ -976,6 +1137,39 @@ config VIDEO_GC0312
To compile this driver as a module, choose M here: the
module will be called gc0312.
config VIDEO_GC0329
tristate "GalaxyCore GC0329 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC0329 sensor.
To compile this driver as a module, choose M here: the
module will be called gc0329.
config VIDEO_GC0403
tristate "GalaxyCore GC0403 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC0403 sensor.
To compile this driver as a module, choose M here: the
module will be called gc0403.
config VIDEO_GC2035
tristate "GalaxyCore GC2035 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC2035 sensor.
To compile this driver as a module, choose M here: the
module will be called gc2035.
config VIDEO_GC2145
tristate "GalaxyCore GC2145 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -987,6 +1181,116 @@ config VIDEO_GC2145
To compile this driver as a module, choose M here: the
module will be called gc2145.
config VIDEO_GC2155
tristate "GalaxyCore GC2155 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC2155 sensor.
To compile this driver as a module, choose M here: the
module will be called gc2155.
config VIDEO_GC2355
tristate "GalaxyCore GC2355 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC2355 sensor.
To compile this driver as a module, choose M here: the
module will be called gc2355.
config VIDEO_GC2385
tristate "GalaxyCore GC2385 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC2385 sensor.
To compile this driver as a module, choose M here: the
module will be called gc2385.
config VIDEO_GC5025
tristate "GalaxyCore GC5025 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC5025 sensor.
To compile this driver as a module, choose M here: the
module will be called gc5025.
config VIDEO_GC5035
tristate "GalaxyCore GC5035 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC5035 sensor.
To compile this driver as a module, choose M here: the
module will be called gc5035.
config VIDEO_GC8034
tristate "GalaxyCore GC8034 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the GalaxyCore GC8034 sensor.
To compile this driver as a module, choose M here: the
module will be called gc8034.
config VIDEO_BF3925
tristate "BYD BF3925 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the BYD BF3925 sensor.
To compile this driver as a module, choose M here: the
module will be called bf3925.
config VIDEO_JX_H65
tristate "SOI JX_H65 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the SOI JX_H65 sensor.
To compile this driver as a module, choose M here: the
module will be called jx_h65.
config VIDEO_SC031GS
tristate "SmartSens SC031GS sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
Support for the SmartSens SC031GS sensor.
To compile this driver as a module, choose M here: the
module will be called sc031gs.
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.
comment "Flash devices"
config VIDEO_ADP1653

View File

@@ -67,9 +67,13 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_OV2640) += ov2640.o
obj-$(CONFIG_VIDEO_OV2680) += ov2680.o
obj-$(CONFIG_VIDEO_OV2685) += ov2685.o
obj-$(CONFIG_VIDEO_OV2718) += ov2718.o
obj-$(CONFIG_VIDEO_OV2735) += ov2735.o
obj-$(CONFIG_VIDEO_OV4689) += ov4689.o
obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
obj-$(CONFIG_VIDEO_OV5648) += ov5648.o
obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
obj-$(CONFIG_VIDEO_OV5695) += ov5695.o
obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
@@ -78,7 +82,10 @@ obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
obj-$(CONFIG_VIDEO_OV8858) += ov8858.o
obj-$(CONFIG_VIDEO_OV9281) += ov9281.o
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
obj-$(CONFIG_VIDEO_OV9750) += ov9750.o
obj-$(CONFIG_VIDEO_OV13850) += ov13850.o
obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
@@ -89,6 +96,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_AR0230) += ar0230.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o
@@ -107,9 +115,27 @@ obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
obj-$(CONFIG_VIDEO_IMX219) += imx219.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX258_EEPROM) += imx258_eeprom.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_VIDEO_IMX317) += imx317.o
obj-$(CONFIG_VIDEO_IMX323) += imx323.o
obj-$(CONFIG_VIDEO_IMX327) += imx327.o
obj-$(CONFIG_VIDEO_GC0312) += gc0312.o
obj-$(CONFIG_VIDEO_GC0329) += gc0329.o
obj-$(CONFIG_VIDEO_GC0403) += gc0403.o
obj-$(CONFIG_VIDEO_GC2035) += gc2035.o
obj-$(CONFIG_VIDEO_GC2145) += gc2145.o
obj-$(CONFIG_VIDEO_GC2155) += gc2155.o
obj-$(CONFIG_VIDEO_GC2355) += gc2355.o
obj-$(CONFIG_VIDEO_GC2385) += gc2385.o
obj-$(CONFIG_VIDEO_GC5025) += gc5025.o
obj-$(CONFIG_VIDEO_GC5035) += gc5035.o
obj-$(CONFIG_VIDEO_GC8034) += gc8034.o
obj-$(CONFIG_VIDEO_BF3925) += bf3925.o
obj-$(CONFIG_VIDEO_JX_H65) += jx_h65.o
obj-$(CONFIG_VIDEO_SC031GS) += sc031gs.o
obj-$(CONFIG_VIDEO_SC132GS) += sc132gs.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o

1688
drivers/media/i2c/ar0230.c Normal file

File diff suppressed because it is too large Load Diff

1498
drivers/media/i2c/bf3925.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,8 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
@@ -33,6 +34,7 @@
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0)
#define DRIVER_NAME "gc0329"
#define GC0329_PIXEL_RATE (24 * 1000 * 1000)
@@ -96,6 +98,10 @@ struct gc0329 {
struct v4l2_ctrl *link_frequency;
const struct gc0329_framesize *frame_size;
int streaming;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
static const struct sensor_register gc0329_vga_regs[] = {
@@ -652,6 +658,76 @@ static int gc0329_set_fmt(struct v4l2_subdev *sd,
return ret;
}
static void gc0329_get_module_inf(struct gc0329 *gc0329,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, DRIVER_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, gc0329->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, gc0329->len_name, sizeof(inf->base.lens));
}
static long gc0329_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct gc0329 *gc0329 = to_gc0329(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
gc0329_get_module_inf(gc0329, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long gc0329_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = gc0329_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = gc0329_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int gc0329_s_stream(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -803,6 +879,10 @@ static const struct v4l2_subdev_core_ops gc0329_subdev_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
.ioctl = gc0329_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = gc0329_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops gc0329_subdev_video_ops = {
@@ -942,14 +1022,35 @@ static int gc0329_parse_of(struct gc0329 *gc0329)
static int gc0329_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct v4l2_subdev *sd;
struct gc0329 *gc0329;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
gc0329 = devm_kzalloc(&client->dev, sizeof(*gc0329), GFP_KERNEL);
if (!gc0329)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&gc0329->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&gc0329->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&gc0329->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&gc0329->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
gc0329->client = client;
gc0329->xvclk = devm_clk_get(&client->dev, "xvclk");
if (IS_ERR(gc0329->xvclk)) {
@@ -995,8 +1096,8 @@ static int gc0329_probe(struct i2c_client *client,
#if defined(CONFIG_MEDIA_CONTROLLER)
gc0329->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &gc0329->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &gc0329->pad);
if (ret < 0) {
v4l2_ctrl_handler_free(&gc0329->ctrls);
return ret;
@@ -1015,7 +1116,16 @@ static int gc0329_probe(struct i2c_client *client,
if (ret < 0)
goto error;
ret = v4l2_async_register_subdev(&gc0329->sd);
memset(facing, 0, sizeof(facing));
if (strcmp(gc0329->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
gc0329->module_index, facing,
DRIVER_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret)
goto error;

1289
drivers/media/i2c/gc0403.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,8 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
@@ -33,6 +34,7 @@
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0)
#define DRIVER_NAME "gc2035"
#define GC2035_PIXEL_RATE (70 * 1000 * 1000)
@@ -98,6 +100,10 @@ struct gc2035 {
struct v4l2_ctrl *link_frequency;
const struct gc2035_framesize *frame_size;
int streaming;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
static const struct sensor_register gc2035_init_regs[] = {
@@ -1190,10 +1196,84 @@ unlock:
return ret;
}
static void gc2035_get_module_inf(struct gc2035 *gc2035,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, DRIVER_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, gc2035->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, gc2035->len_name, sizeof(inf->base.lens));
}
static long gc2035_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct gc2035 *gc2035 = to_gc2035(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
gc2035_get_module_inf(gc2035, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long gc2035_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = gc2035_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = gc2035_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static const struct v4l2_subdev_core_ops gc2035_subdev_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
.ioctl = gc2035_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = gc2035_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops gc2035_subdev_video_ops = {
@@ -1334,14 +1414,35 @@ static int gc2035_parse_of(struct gc2035 *gc2035)
static int gc2035_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct v4l2_subdev *sd;
struct gc2035 *gc2035;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
gc2035 = devm_kzalloc(&client->dev, sizeof(*gc2035), GFP_KERNEL);
if (!gc2035)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&gc2035->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&gc2035->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&gc2035->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&gc2035->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
gc2035->client = client;
gc2035->xvclk = devm_clk_get(&client->dev, "xvclk");
if (IS_ERR(gc2035->xvclk)) {
@@ -1387,8 +1488,8 @@ static int gc2035_probe(struct i2c_client *client,
#if defined(CONFIG_MEDIA_CONTROLLER)
gc2035->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &gc2035->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &gc2035->pad);
if (ret < 0) {
v4l2_ctrl_handler_free(&gc2035->ctrls);
return ret;
@@ -1407,7 +1508,16 @@ static int gc2035_probe(struct i2c_client *client,
if (ret < 0)
goto error;
ret = v4l2_async_register_subdev(&gc2035->sd);
memset(facing, 0, sizeof(facing));
if (strcmp(gc2035->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
gc2035->module_index, facing,
DRIVER_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret)
goto error;

View File

@@ -3,6 +3,9 @@
* gc2155 driver
*
* Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
*/
#include <linux/clk.h>
@@ -13,11 +16,16 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
#define REG_CHIP_ID_H 0xf0
#define REG_CHIP_ID_L 0xf1
#define CHIP_ID_H 0x21
@@ -27,6 +35,8 @@
#define GC2155_XVCLK_FREQ 24000000
#define GC2155_NAME "gc2155"
static const char * const gc2155_supply_names[] = {
"avdd",
"dovdd",
@@ -54,11 +64,16 @@ struct gc2155 {
struct regulator_bulk_data supplies[GC2155_NUM_SUPPLIES];
bool streaming;
bool power_on;
struct mutex mutex; /* lock to serialize v4l2 callback */
struct v4l2_subdev subdev;
struct media_pad pad;
const struct gc2155_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_gc2155(sd) container_of(sd, struct gc2155, subdev)
@@ -1056,12 +1071,15 @@ static int __gc2155_power_on(struct gc2155 *gc2155)
return ret;
}
if (!IS_ERR(gc2155->xvclk)) {
ret = clk_prepare_enable(gc2155->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
ret = clk_set_rate(gc2155->xvclk, GC2155_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(gc2155->xvclk) != GC2155_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(gc2155->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
if (!IS_ERR(gc2155->pwdn_gpio))
@@ -1086,6 +1104,76 @@ static void __gc2155_power_off(struct gc2155 *gc2155)
regulator_bulk_disable(GC2155_NUM_SUPPLIES, gc2155->supplies);
}
static void gc2155_get_module_inf(struct gc2155 *gc2155,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, GC2155_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, gc2155->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, gc2155->len_name, sizeof(inf->base.lens));
}
static long gc2155_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct gc2155 *gc2155 = to_gc2155(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
gc2155_get_module_inf(gc2155, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long gc2155_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = gc2155_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = gc2155_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int gc2155_s_stream(struct v4l2_subdev *sd, int on)
{
struct gc2155 *gc2155 = to_gc2155(sd);
@@ -1105,12 +1193,6 @@ static int gc2155_s_stream(struct v4l2_subdev *sd, int on)
goto unlock_and_return;
}
ret = gc2155_write_array(gc2155->client, gc2155_global_regs);
if (ret) {
pm_runtime_put(&client->dev);
goto unlock_and_return;
}
ret = gc2155_write_array(gc2155->client,
gc2155->cur_mode->reg_list);
if (ret) {
@@ -1130,6 +1212,44 @@ unlock_and_return:
return ret;
}
static int gc2155_s_power(struct v4l2_subdev *sd, int on)
{
struct gc2155 *gc2155 = to_gc2155(sd);
struct i2c_client *client = gc2155->client;
int ret = 0;
mutex_lock(&gc2155->mutex);
/* If the power state is not modified - no work to do. */
if (gc2155->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ret = gc2155_write_array(gc2155->client, gc2155_global_regs);
if (ret) {
v4l2_err(sd, "could not set init registers\n");
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
gc2155->power_on = true;
} else {
pm_runtime_put(&client->dev);
gc2155->power_on = false;
}
unlock_and_return:
mutex_unlock(&gc2155->mutex);
return ret;
}
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static int gc2155_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
@@ -1177,6 +1297,14 @@ static const struct dev_pm_ops gc2155_pm_ops = {
gc2155_runtime_resume, NULL)
};
static const struct v4l2_subdev_core_ops gc2155_core_ops = {
.s_power = gc2155_s_power,
.ioctl = gc2155_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = gc2155_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops gc2155_video_ops = {
.s_stream = gc2155_s_stream,
};
@@ -1189,6 +1317,7 @@ static const struct v4l2_subdev_pad_ops gc2155_pad_ops = {
};
static const struct v4l2_subdev_ops gc2155_subdev_ops = {
.core = &gc2155_core_ops,
.video = &gc2155_video_ops,
.pad = &gc2155_pad_ops,
};
@@ -1235,13 +1364,34 @@ static int gc2155_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct gc2155 *gc2155;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
gc2155 = devm_kzalloc(dev, sizeof(*gc2155), GFP_KERNEL);
if (!gc2155)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&gc2155->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&gc2155->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&gc2155->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&gc2155->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
gc2155->client = client;
gc2155->cur_mode = &supported_modes[0];
@@ -1250,13 +1400,6 @@ static int gc2155_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(gc2155->xvclk, GC2155_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(gc2155->xvclk) != GC2155_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
gc2155->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gc2155->reset_gpio))
@@ -1289,13 +1432,23 @@ static int gc2155_probe(struct i2c_client *client,
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
gc2155->pad.flags = MEDIA_PAD_FL_SOURCE;
gc2155->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&gc2155->subdev.entity, 1, &gc2155->pad, 0);
gc2155->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&gc2155->subdev.entity, 1, &gc2155->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(&gc2155->subdev);
sd = &gc2155->subdev;
memset(facing, 0, sizeof(facing));
if (strcmp(gc2155->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
gc2155->module_index, facing,
GC2155_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1353,7 +1506,7 @@ static const struct i2c_device_id gc2155_match_id[] = {
static struct i2c_driver gc2155_i2c_driver = {
.driver = {
.name = "gc2155",
.name = GC2155_NAME,
.pm = &gc2155_pm_ops,
.of_match_table = of_match_ptr(gc2155_of_match),
},

View File

@@ -3,6 +3,7 @@
* gc2355 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
*/
#define DEBUG 1
#include <linux/clk.h>
@@ -14,12 +15,17 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <linux/pinctrl/consumer.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x2)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -73,6 +79,8 @@
#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
#define GC2355_NAME "gc2355"
static const char * const gc2355_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
@@ -119,6 +127,10 @@ struct gc2355 {
struct mutex mutex;
bool streaming;
const struct gc2355_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_gc2355(sd) container_of(sd, struct gc2355, subdev)
@@ -509,6 +521,76 @@ static int gc2355_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
static void gc2355_get_module_inf(struct gc2355 *gc2355,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, GC2355_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, gc2355->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, gc2355->len_name, sizeof(inf->base.lens));
}
static long gc2355_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct gc2355 *gc2355 = to_gc2355(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
gc2355_get_module_inf(gc2355, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long gc2355_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = gc2355_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = gc2355_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int __gc2355_start_stream(struct gc2355 *gc2355)
{
int ret;
@@ -601,13 +683,16 @@ static int __gc2355_power_on(struct gc2355 *gc2355)
if (ret < 0)
dev_err(dev, "could not set pins\n");
}
ret = clk_set_rate(gc2355->xvclk, GC2355_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(gc2355->xvclk) != GC2355_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(gc2355->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
if (!IS_ERR(gc2355->reset_gpio))
gpiod_set_value_cansleep(gc2355->reset_gpio, 0);
@@ -708,6 +793,13 @@ static const struct v4l2_subdev_internal_ops gc2355_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops gc2355_core_ops = {
.ioctl = gc2355_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = gc2355_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops gc2355_video_ops = {
.s_stream = gc2355_s_stream,
.g_frame_interval = gc2355_g_frame_interval,
@@ -721,6 +813,7 @@ static const struct v4l2_subdev_pad_ops gc2355_pad_ops = {
};
static const struct v4l2_subdev_ops gc2355_subdev_ops = {
.core = &gc2355_core_ops,
.video = &gc2355_video_ops,
.pad = &gc2355_pad_ops,
};
@@ -956,14 +1049,34 @@ static int gc2355_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct gc2355 *gc2355;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
gc2355 = devm_kzalloc(dev, sizeof(*gc2355), GFP_KERNEL);
if (!gc2355)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&gc2355->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&gc2355->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&gc2355->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&gc2355->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
gc2355->client = client;
gc2355->cur_mode = &supported_modes[0];
@@ -972,13 +1085,6 @@ static int gc2355_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(gc2355->xvclk, GC2355_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(gc2355->xvclk) != GC2355_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
gc2355->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gc2355->reset_gpio))
@@ -1029,17 +1135,27 @@ static int gc2355_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &gc2355_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
gc2355->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &gc2355->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &gc2355->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(gc2355->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
gc2355->module_index, facing,
GC2355_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1100,7 +1216,7 @@ static const struct i2c_device_id gc2355_match_id[] = {
static struct i2c_driver gc2355_i2c_driver = {
.driver = {
.name = "gc2355",
.name = GC2355_NAME,
.pm = &gc2355_pm_ops,
.of_match_table = of_match_ptr(gc2355_of_match),
},

1254
drivers/media/i2c/gc2385.c Normal file

File diff suppressed because it is too large Load Diff

1922
drivers/media/i2c/gc5025.c Normal file

File diff suppressed because it is too large Load Diff

1598
drivers/media/i2c/gc5035.c Normal file

File diff suppressed because it is too large Load Diff

2165
drivers/media/i2c/gc8034.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -16,12 +16,16 @@
#include <linux/of_graph.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-mediabus.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0)
/* IMX219 supported geometry */
#define IMX219_TABLE_END 0xffff
#define IMX219_ANALOGUE_GAIN_MULTIPLIER 256
@@ -40,6 +44,8 @@
#define IMX219_EXP_LINES_MARGIN 4
#define IMX219_NAME "imx219"
static const s64 link_freq_menu_items[] = {
456000000,
};
@@ -231,6 +237,10 @@ struct imx219 {
struct v4l2_ctrl *pixel_rate;
const struct imx219_mode *cur_mode;
u16 cur_vts;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
static const struct imx219_mode supported_modes[] = {
@@ -711,6 +721,77 @@ static int imx219_get_fmt(struct v4l2_subdev *sd,
return 0;
}
static void imx219_get_module_inf(struct imx219 *imx219,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, IMX219_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, imx219->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, imx219->len_name, sizeof(inf->base.lens));
}
static long imx219_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct imx219 *imx219 = to_imx219(client);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
imx219_get_module_inf(imx219, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long imx219_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = imx219_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = imx219_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
/* Various V4L2 operations tables */
static struct v4l2_subdev_video_ops imx219_subdev_video_ops = {
.s_stream = imx219_s_stream,
@@ -719,6 +800,10 @@ static struct v4l2_subdev_video_ops imx219_subdev_video_ops = {
static struct v4l2_subdev_core_ops imx219_subdev_core_ops = {
.s_power = imx219_s_power,
.ioctl = imx219_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = imx219_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_pad_ops imx219_subdev_pad_ops = {
@@ -889,8 +974,17 @@ static int imx219_probe(struct i2c_client *client,
{
struct imx219 *priv;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_warn(&adapter->dev,
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
@@ -900,6 +994,19 @@ static int imx219_probe(struct i2c_client *client,
if (!priv)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&priv->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&priv->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&priv->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&priv->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
priv->clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_info(&client->dev, "Error %ld getting clock\n",
@@ -923,14 +1030,26 @@ static int imx219_probe(struct i2c_client *client,
if (ret < 0)
return ret;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
priv->pad.flags = MEDIA_PAD_FL_SOURCE;
priv->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&priv->subdev.entity, 1, &priv->pad, 0);
priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad);
if (ret < 0)
return ret;
ret = v4l2_async_register_subdev(&priv->subdev);
sd = &priv->subdev;
memset(facing, 0, sizeof(facing));
if (strcmp(priv->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
priv->module_index, facing,
IMX219_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret < 0)
return ret;
@@ -963,7 +1082,7 @@ MODULE_DEVICE_TABLE(i2c, imx219_id);
static struct i2c_driver imx219_i2c_driver = {
.driver = {
.of_match_table = of_match_ptr(imx219_of_match),
.name = "imx219",
.name = IMX219_NAME,
},
.probe = imx219_probe,
.remove = imx219_remove,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,377 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd.
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include "imx258_eeprom_head.h"
#define DEVICE_NAME "imx258_eeprom"
static inline struct imx258_eeprom_device
*sd_to_imx258_eeprom(struct v4l2_subdev *subdev)
{
return container_of(subdev, struct imx258_eeprom_device, sd);
}
/* Read registers up to 4 at a time */
static int imx258_read_reg_otp(struct i2c_client *client, u16 reg,
unsigned int len, u32 *val)
{
struct i2c_msg msgs[2];
u8 *data_be_p;
__be32 data_be = 0;
__be16 reg_addr_be = cpu_to_be16(reg);
int ret;
if (len > 4 || !len)
return -EINVAL;
data_be_p = (u8 *)&data_be;
/* Write register address */
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
msgs[0].buf = (u8 *)&reg_addr_be;
/* Read data from register */
msgs[1].addr = client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = len;
msgs[1].buf = &data_be_p[4 - len];
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs))
return -EIO;
*val = be32_to_cpu(data_be);
return 0;
}
static u8 get_vendor_flag(struct i2c_client *client)
{
u8 vendor_flag = 0;
if (client->addr == SLAVE_ADDRESS_GZ)
vendor_flag |= 0x80;
return vendor_flag;
}
static int imx258_otp_read_gz(struct imx258_eeprom_device *imx258_eeprom_dev)
{
struct i2c_client *client = imx258_eeprom_dev->client;
int otp_flag, i;
struct imx258_otp_info *otp_ptr;
struct device *dev = &imx258_eeprom_dev->client->dev;
int ret = 0;
u32 r_value, gr_value, gb_value, b_value;
u32 temp = 0;
u32 checksum = 0;
otp_ptr = kzalloc(sizeof(*otp_ptr), GFP_KERNEL);
if (!otp_ptr)
return -ENOMEM;
otp_flag = 0;
/* OTP base information*/
ret = imx258_read_reg_otp(client, GZ_INFO_FLAG_REG,
1, &otp_flag);
if (otp_flag == 0x01) {
otp_ptr->flag = 0x80; /* valid INFO in OTP */
ret |= imx258_read_reg_otp(client, GZ_ID_REG,
1, &otp_ptr->module_id);
ret |= imx258_read_reg_otp(client, GZ_LENS_ID_REG,
1, &otp_ptr->lens_id);
ret |= imx258_read_reg_otp(client, GZ_PRODUCT_YEAR_REG,
1, &otp_ptr->year);
ret |= imx258_read_reg_otp(client, GZ_PRODUCT_MONTH_REG,
1, &otp_ptr->month);
ret |= imx258_read_reg_otp(client, GZ_PRODUCT_DAY_REG,
1, &otp_ptr->day);
dev_dbg(dev, "fac info: module(0x%x) lens(0x%x) time(%d_%d_%d)!\n",
otp_ptr->module_id,
otp_ptr->lens_id,
otp_ptr->year,
otp_ptr->month,
otp_ptr->day);
if (ret)
goto err;
}
/* OTP WB calibration data */
ret = imx258_read_reg_otp(client, GZ_AWB_FLAG_REG,
1, &otp_flag);
if (otp_flag == 0x01) {
otp_ptr->flag |= 0x40; /* valid AWB in OTP */
ret |= imx258_read_reg_otp(client, GZ_CUR_R_REG,
1, &r_value);
checksum += r_value;
ret |= imx258_read_reg_otp(client, GZ_CUR_GR_REG,
1, &gr_value);
checksum += gr_value;
ret |= imx258_read_reg_otp(client, GZ_CUR_GB_REG,
1, &gb_value);
checksum += gb_value;
ret |= imx258_read_reg_otp(client, GZ_CUR_B_REG,
1, &b_value);
checksum += b_value;
otp_ptr->rg_ratio =
r_value * 1024 / ((gr_value + gb_value) / 2);
otp_ptr->bg_ratio =
b_value * 1024 / ((gr_value + gb_value) / 2);
ret |= imx258_read_reg_otp(client, GZ_GOLDEN_R_REG,
1, &r_value);
checksum += r_value;
ret |= imx258_read_reg_otp(client, GZ_GOLDEN_GR_REG,
1, &gr_value);
checksum += gr_value;
ret |= imx258_read_reg_otp(client, GZ_GOLDEN_GB_REG,
1, &gb_value);
checksum += gb_value;
ret |= imx258_read_reg_otp(client, GZ_GOLDEN_B_REG,
1, &b_value);
checksum += b_value;
otp_ptr->rg_golden =
r_value * 1024 / ((gr_value + gb_value) / 2);
otp_ptr->bg_golden =
b_value * 1024 / ((gr_value + gb_value) / 2);
ret |= imx258_read_reg_otp(client, GZ_AWB_CHECKSUM_REG,
1, &temp);
if (ret != 0 || (checksum % 0xff) != temp) {
dev_err(dev, "otp awb info: check sum (%d,%d),ret = %d !\n",
checksum,
temp,
ret);
goto err;
}
dev_dbg(dev, "awb cur:(rg 0x%x, bg 0x%x,)\n",
otp_ptr->rg_ratio, otp_ptr->bg_ratio);
dev_dbg(dev, "awb gol:(rg 0x%x, bg 0x%x)\n",
otp_ptr->rg_golden, otp_ptr->bg_golden);
}
checksum = 0;
/* OTP LSC calibration data */
ret = imx258_read_reg_otp(client, GZ_LSC_FLAG_REG,
1, &otp_flag);
if (otp_flag == 0x01) {
otp_ptr->flag |= 0x10; /* valid LSC in OTP */
for (i = 0; i < 504; i++) {
ret |= imx258_read_reg_otp(client,
GZ_LSC_DATA_START_REG + i,
1, &temp);
otp_ptr->lenc[i] = temp;
checksum += temp;
dev_dbg(dev,
"otp read lsc addr = 0x%04x, lenc[%d] = %d\n",
GZ_LSC_DATA_START_REG + i, i, temp);
}
ret |= imx258_read_reg_otp(client, GZ_LSC_CHECKSUM_REG,
1, &temp);
if (ret != 0 || (checksum % 0xff) != temp) {
dev_err(dev,
"otp lsc info: check sum (%d,%d),ret = %d !\n",
checksum, temp, ret);
goto err;
}
}
checksum = 0;
/* OTP VCM calibration data */
ret = imx258_read_reg_otp(client, GZ_VCM_FLAG_REG,
1, &otp_flag);
if (otp_flag == 0x01) {
otp_ptr->flag |= 0x20; /* valid VCM in OTP */
ret |= imx258_read_reg_otp(client, GZ_VCM_DIR_REG,
1, &otp_ptr->vcm_dir);
checksum += otp_ptr->vcm_dir;
ret |= imx258_read_reg_otp(client, GZ_VCM_START_REG,
1, &temp);
checksum += temp;
ret |= imx258_read_reg_otp(client, GZ_VCM_START_REG + 1,
1, &otp_ptr->vcm_start);
checksum += otp_ptr->vcm_start;
otp_ptr->vcm_start |= (temp << 8);
ret |= imx258_read_reg_otp(client, GZ_VCM_END_REG,
1, &temp);
checksum += temp;
ret |= imx258_read_reg_otp(client, GZ_VCM_END_REG + 1,
1, &otp_ptr->vcm_end);
checksum += otp_ptr->vcm_end;
otp_ptr->vcm_end |= (temp << 8);
ret |= imx258_read_reg_otp(client, GZ_VCM_CHECKSUM_REG,
1, &temp);
if (ret != 0 || (checksum % 0xff) != temp) {
dev_err(dev,
"otp VCM info: check sum (%d,%d),ret = %d !\n",
checksum, temp, ret);
goto err;
}
dev_dbg(dev, "vcm_info: 0x%x, 0x%x, 0x%x!\n",
otp_ptr->vcm_start,
otp_ptr->vcm_end,
otp_ptr->vcm_dir);
}
checksum = 0;
/* OTP SPC calibration data */
ret = imx258_read_reg_otp(client, GZ_SPC_FLAG_REG,
1, &otp_flag);
if (otp_flag == 0x01) {
otp_ptr->flag |= 0x08; /* valid LSC in OTP */
for (i = 0; i < 126; i++) {
ret |= imx258_read_reg_otp(client,
GZ_SPC_DATA_START_REG + i,
1, &temp);
otp_ptr->spc[i] = (uint8_t)temp;
checksum += temp;
dev_dbg(dev,
"otp read spc addr = 0x%04x, spc[%d] = %d\n",
GZ_SPC_DATA_START_REG + i, i, temp);
}
ret |= imx258_read_reg_otp(client, GZ_SPC_CHECKSUM_REG,
1, &temp);
if (ret != 0 || (checksum % 0xff) != temp) {
dev_err(dev,
"otp spc info: check sum (%d,%d),ret = %d !\n",
checksum, temp, ret);
goto err;
}
}
if (otp_ptr->flag) {
imx258_eeprom_dev->otp = otp_ptr;
} else {
imx258_eeprom_dev->otp = NULL;
kfree(otp_ptr);
}
return 0;
err:
imx258_eeprom_dev->otp = NULL;
kfree(otp_ptr);
return -EINVAL;
}
static int imx258_otp_read(struct imx258_eeprom_device *imx258_eeprom_dev)
{
u8 vendor_flag = 0;
struct i2c_client *client = imx258_eeprom_dev->client;
vendor_flag = get_vendor_flag(client);
if (vendor_flag == 0x80)
imx258_otp_read_gz(imx258_eeprom_dev);
return 0;
}
static long imx258_eeprom_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
struct imx258_eeprom_device *imx258_eeprom_dev =
sd_to_imx258_eeprom(sd);
imx258_otp_read(imx258_eeprom_dev);
if (arg && imx258_eeprom_dev->otp)
memcpy(arg, imx258_eeprom_dev->otp,
sizeof(struct imx258_otp_info));
return 0;
}
static const struct v4l2_subdev_core_ops imx258_eeprom_core_ops = {
.ioctl = imx258_eeprom_ioctl,
};
static const struct v4l2_subdev_ops imx258_eeprom_ops = {
.core = &imx258_eeprom_core_ops,
};
static void imx258_eeprom_subdev_cleanup(struct imx258_eeprom_device *dev)
{
v4l2_device_unregister_subdev(&dev->sd);
media_entity_cleanup(&dev->sd.entity);
}
static int imx258_eeprom_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct imx258_eeprom_device *imx258_eeprom_dev;
dev_info(&client->dev, "probing...\n");
imx258_eeprom_dev = devm_kzalloc(&client->dev,
sizeof(*imx258_eeprom_dev),
GFP_KERNEL);
if (imx258_eeprom_dev == NULL) {
dev_err(&client->dev, "Probe failed\n");
return -ENOMEM;
}
v4l2_i2c_subdev_init(&imx258_eeprom_dev->sd,
client, &imx258_eeprom_ops);
imx258_eeprom_dev->client = client;
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
dev_info(&client->dev, "probing successful\n");
return 0;
}
static int imx258_eeprom_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct imx258_eeprom_device *imx258_eeprom_dev =
sd_to_imx258_eeprom(sd);
kfree(imx258_eeprom_dev->otp);
pm_runtime_disable(&client->dev);
imx258_eeprom_subdev_cleanup(imx258_eeprom_dev);
return 0;
}
static int __maybe_unused imx258_eeprom_suspend(struct device *dev)
{
return 0;
}
static int __maybe_unused imx258_eeprom_resume(struct device *dev)
{
return 0;
}
static const struct i2c_device_id imx258_eeprom_id_table[] = {
{ DEVICE_NAME, 0 },
{ { 0 } }
};
MODULE_DEVICE_TABLE(i2c, imx258_eeprom_id_table);
static const struct of_device_id imx258_eeprom_of_table[] = {
{ .compatible = "sony,imx258_eeprom" },
{ { 0 } }
};
MODULE_DEVICE_TABLE(of, imx258_eeprom_of_table);
static const struct dev_pm_ops imx258_eeprom_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(imx258_eeprom_suspend, imx258_eeprom_resume)
SET_RUNTIME_PM_OPS(imx258_eeprom_suspend, imx258_eeprom_resume, NULL)
};
static struct i2c_driver imx258_eeprom_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.pm = &imx258_eeprom_pm_ops,
.of_match_table = imx258_eeprom_of_table,
},
.probe = &imx258_eeprom_probe,
.remove = &imx258_eeprom_remove,
.id_table = imx258_eeprom_id_table,
};
module_i2c_driver(imx258_eeprom_i2c_driver);
MODULE_DESCRIPTION("IMX258 OTP driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd. */
#ifndef IMX258_EEPROM_HEAD_H
#define IMX258_EEPROM_HEAD_H
#define SLAVE_ADDRESS_GZ 0x50
#define GZ_INFO_FLAG_REG 0X0000
#define GZ_ID_REG 0X0005
#define GZ_LENS_ID_REG 0X0006
#define GZ_PRODUCT_YEAR_REG 0X000A
#define GZ_PRODUCT_MONTH_REG 0X000B
#define GZ_PRODUCT_DAY_REG 0X000C
#define GZ_AWB_FLAG_REG 0x001c
#define GZ_CUR_R_REG 0x001d
#define GZ_CUR_GR_REG 0x001e
#define GZ_CUR_GB_REG 0x001f
#define GZ_CUR_B_REG 0x0020
#define GZ_GOLDEN_R_REG 0x0021
#define GZ_GOLDEN_GR_REG 0x0022
#define GZ_GOLDEN_GB_REG 0x0023
#define GZ_GOLDEN_B_REG 0x0024
#define GZ_AWB_CHECKSUM_REG 0x0025
#define GZ_LSC_FLAG_REG 0X003A
#define GZ_LSC_DATA_START_REG 0x003B
#define GZ_LSC_CHECKSUM_REG 0x0233
#define GZ_VCM_FLAG_REG 0X0788
#define GZ_VCM_DIR_REG 0X0789
#define GZ_VCM_START_REG 0X078C
#define GZ_VCM_END_REG 0X078A
#define GZ_VCM_CHECKSUM_REG 0x0790
#define GZ_SPC_FLAG_REG 0X0CE1
#define GZ_SPC_DATA_START_REG 0x0CE2
#define GZ_SPC_CHECKSUM_REG 0x0d60
struct imx258_otp_info {
u32 flag; //bit[7]: info bit[6]:wb bit[5]:vcm bit[4]:lenc bit[3]:spc
u32 module_id;
u32 lens_id;
u32 year;
u32 month;
u32 day;
u32 rg_ratio;
u32 bg_ratio;
u32 rg_golden;
u32 bg_golden;
int vcm_start;
int vcm_end;
int vcm_dir;
u8 lenc[504];
u8 spc[126];
};
/* imx258_eeprom device structure */
struct imx258_eeprom_device {
struct v4l2_subdev sd;
struct i2c_client *client;
struct imx258_otp_info *otp;
};
#endif /* IMX258_EEPROM_HEAD_H */

1364
drivers/media/i2c/imx317.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
* imx323 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
*/
#include <linux/clk.h>
@@ -13,12 +15,17 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -60,6 +67,8 @@
/* h_offs 35 v_offs 14 */
#define PIX_FORMAT MEDIA_BUS_FMT_SBGGR10_1X10
#define IMX323_NAME "imx323"
struct cam_regulator {
char name[32];
int val;
@@ -106,7 +115,12 @@ struct imx323 {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct imx323_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_imx323(sd) container_of(sd, struct imx323, subdev)
@@ -370,6 +384,76 @@ static int imx323_enable_test_pattern(struct imx323 *imx323, u32 pattern)
return 0;
}
static void imx323_get_module_inf(struct imx323 *imx323,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, IMX323_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, imx323->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, imx323->len_name, sizeof(inf->base.lens));
}
static long imx323_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct imx323 *imx323 = to_imx323(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
imx323_get_module_inf(imx323, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long imx323_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = imx323_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = imx323_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int __imx323_start_stream(struct imx323 *imx323)
{
int ret;
@@ -445,6 +529,37 @@ static int imx323_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
static int imx323_s_power(struct v4l2_subdev *sd, int on)
{
struct imx323 *imx323 = to_imx323(sd);
struct i2c_client *client = imx323->client;
int ret = 0;
mutex_lock(&imx323->mutex);
/* If the power state is not modified - no work to do. */
if (imx323->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
imx323->power_on = true;
} else {
pm_runtime_put(&client->dev);
imx323->power_on = false;
}
unlock_and_return:
mutex_unlock(&imx323->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 imx323_cal_delay(u32 cycles)
{
@@ -576,6 +691,14 @@ static const struct v4l2_subdev_internal_ops imx323_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops imx323_core_ops = {
.s_power = imx323_s_power,
.ioctl = imx323_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = imx323_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops imx323_video_ops = {
.s_stream = imx323_s_stream,
.g_mbus_config = imx323_g_mbus_config,
@@ -590,6 +713,7 @@ static const struct v4l2_subdev_pad_ops imx323_pad_ops = {
};
static const struct v4l2_subdev_ops imx323_subdev_ops = {
.core = &imx323_core_ops,
.video = &imx323_video_ops,
.pad = &imx323_pad_ops,
};
@@ -710,7 +834,7 @@ static int imx323_check_sensor_id(struct imx323 *imx323,
IMX323_REG_VALUE_08BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%x), ret(%d)\n", id, ret);
return ret;
return -ENODEV;
}
dev_info(dev, "Detected IMX323 sensor\n");
@@ -735,14 +859,34 @@ static int imx323_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct imx323 *imx323;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
imx323 = devm_kzalloc(dev, sizeof(*imx323), GFP_KERNEL);
if (!imx323)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&imx323->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&imx323->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&imx323->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&imx323->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
imx323->client = client;
imx323->cur_mode = &supported_modes[0];
@@ -784,17 +928,27 @@ static int imx323_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &imx323_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
imx323->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &imx323->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &imx323->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(imx323->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
imx323->module_index, facing,
IMX323_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -855,7 +1009,7 @@ static const struct i2c_device_id imx323_match_id[] = {
static struct i2c_driver imx323_i2c_driver = {
.driver = {
.name = "imx323",
.name = IMX323_NAME,
.pm = &imx323_pm_ops,
.of_match_table = of_match_ptr(imx323_of_match),
},

1386
drivers/media/i2c/imx327.c Normal file

File diff suppressed because it is too large Load Diff

1246
drivers/media/i2c/jx_h65.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ov2685 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/clk.h>
@@ -14,16 +18,19 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0)
#define CHIP_ID 0x2685
#define OV2685_REG_CHIP_ID 0x300a
#define OV2685_XVCLK_FREQ 24000000
#define REG_SC_CTRL_MODE 0x0100
#define SC_CTRL_MODE_STANDBY 0x0
#define SC_CTRL_MODE_STREAMING BIT(0)
@@ -44,7 +51,7 @@
#define OV2685_REG_TEST_PATTERN 0x5080
#define OV2685_TEST_PATTERN_DISABLED 0x00
#define OV2685_TEST_PATTERN_COLOR_BAR 0x80
#define OV2685_TEST_PATTERN_RANDOM 0x81
#define OV2685_TEST_PATTERN_RND 0x81
#define OV2685_TEST_PATTERN_COLOR_BAR_FADE 0x88
#define OV2685_TEST_PATTERN_BW_SQUARE 0x92
#define OV2685_TEST_PATTERN_COLOR_SQUARE 0x82
@@ -58,13 +65,7 @@
#define OV2685_LANES 1
#define OV2685_BITS_PER_SAMPLE 10
static const char * const ov2685_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
"dvdd", /* Digital core power */
};
#define OV2685_NUM_SUPPLIES ARRAY_SIZE(ov2685_supply_names)
#define OV2685_NAME "ov2685"
struct regval {
u16 addr;
@@ -83,8 +84,10 @@ struct ov2685_mode {
struct ov2685 {
struct i2c_client *client;
struct clk *xvclk;
struct regulator *avdd_regulator; /* Analog power */
struct regulator *dovdd_regulator; /* Digital I/O power */
/* use internal DVDD power */
struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES];
bool streaming;
struct mutex mutex;
@@ -98,8 +101,11 @@ struct ov2685 {
struct v4l2_ctrl_handler ctrl_handler;
const struct ov2685_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_ov2685(sd) container_of(sd, struct ov2685, subdev)
/* PLL settings bases on 24M xvclk */
@@ -119,7 +125,7 @@ static struct regval ov2685_1600x1200_regs[] = {
{0x3087, 0x00},
{0x3501, 0x4e},
{0x3502, 0xe0},
{0x3503, 0x27},
{0x3503, 0x07},
{0x350b, 0x36},
{0x3600, 0xb4},
{0x3603, 0x35},
@@ -215,17 +221,17 @@ static const s64 link_freq_menu_items[] = {
static const char * const ov2685_test_pattern_menu[] = {
"Disabled",
"Color Bar",
"RND PATTERN",
"Color Bar FADE",
"Random Data",
"Black White Square",
"Color Square"
"BW SQUARE",
"COLOR SQUARE"
};
static const int ov2685_test_pattern_val[] = {
OV2685_TEST_PATTERN_DISABLED,
OV2685_TEST_PATTERN_COLOR_BAR,
OV2685_TEST_PATTERN_RND,
OV2685_TEST_PATTERN_COLOR_BAR_FADE,
OV2685_TEST_PATTERN_RANDOM,
OV2685_TEST_PATTERN_BW_SQUARE,
OV2685_TEST_PATTERN_COLOR_SQUARE,
};
@@ -243,9 +249,10 @@ static const struct ov2685_mode supported_modes[] = {
/* Write registers up to 4 at a time */
static int ov2685_write_reg(struct i2c_client *client, u16 reg,
u32 len, u32 val)
unsigned int len, u32 val)
{
u32 val_i, buf_i;
int buf_i;
int val_i;
u8 buf[6];
u8 *val_p;
__be32 val_be;
@@ -273,8 +280,7 @@ static int ov2685_write_reg(struct i2c_client *client, u16 reg,
static int ov2685_write_array(struct i2c_client *client,
const struct regval *regs)
{
int ret = 0;
u32 i;
int i, ret = 0;
for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
ret = ov2685_write_reg(client, regs[i].addr,
@@ -285,7 +291,7 @@ static int ov2685_write_array(struct i2c_client *client,
/* Read registers up to 4 at a time */
static int ov2685_read_reg(struct i2c_client *client, u16 reg,
u32 len, u32 *val)
unsigned int len, u32 *val)
{
struct i2c_msg msgs[2];
u8 *data_be_p;
@@ -318,12 +324,12 @@ static int ov2685_read_reg(struct i2c_client *client, u16 reg,
return 0;
}
static void ov2685_fill_fmt(const struct ov2685_mode *mode,
static void ov2685_fill_fmt(struct ov2685 *ov2685,
struct v4l2_mbus_framefmt *fmt)
{
fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
fmt->width = mode->width;
fmt->height = mode->height;
fmt->width = ov2685->cur_mode->width;
fmt->height = ov2685->cur_mode->height;
fmt->field = V4L2_FIELD_NONE;
}
@@ -334,8 +340,7 @@ static int ov2685_set_fmt(struct v4l2_subdev *sd,
struct ov2685 *ov2685 = to_ov2685(sd);
struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
/* only one mode supported for now */
ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
ov2685_fill_fmt(ov2685, mbus_fmt);
return 0;
}
@@ -347,7 +352,7 @@ static int ov2685_get_fmt(struct v4l2_subdev *sd,
struct ov2685 *ov2685 = to_ov2685(sd);
struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
ov2685_fill_fmt(ov2685, mbus_fmt);
return 0;
}
@@ -360,7 +365,6 @@ static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;
code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
return 0;
}
@@ -383,16 +387,34 @@ static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
return 0;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov2685_cal_delay(u32 cycles)
static inline void ov2685_set_exposure(struct ov2685 *ov2685, s32 val)
{
return DIV_ROUND_UP(cycles, OV2685_XVCLK_FREQ / 1000 / 1000);
ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE,
OV2685_REG_VALUE_24BIT, val << 4);
}
static inline void ov2685_set_gain(struct ov2685 *ov2685, s32 val)
{
ov2685_write_reg(ov2685->client, OV2685_REG_GAIN,
OV2685_REG_VALUE_16BIT, val & OV2685_GAIN_MAX);
}
static inline void ov2685_set_vts(struct ov2685 *ov2685, s32 val)
{
val += ov2685->cur_mode->height;
ov2685_write_reg(ov2685->client, OV2685_REG_VTS,
OV2685_REG_VALUE_16BIT, val);
}
static inline void ov2685_enable_test_pattern(struct ov2685 *ov2685, u32 pat)
{
ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN,
OV2685_REG_VALUE_08BIT, ov2685_test_pattern_val[pat]);
}
static int __ov2685_power_on(struct ov2685 *ov2685)
{
int ret;
u32 delay_us;
struct device *dev = &ov2685->client->dev;
ret = clk_prepare_enable(ov2685->xvclk);
@@ -400,33 +422,37 @@ static int __ov2685_power_on(struct ov2685 *ov2685)
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
clk_set_rate(ov2685->xvclk, 24000000);
gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
ret = regulator_bulk_enable(OV2685_NUM_SUPPLIES, ov2685->supplies);
/* AVDD and DOVDD may rise in any order */
ret = regulator_enable(ov2685->avdd_regulator);
if (ret < 0) {
dev_err(dev, "Failed to enable regulators\n");
goto disable_clk;
dev_err(dev, "Failed to enable AVDD regulator\n");
goto disable_xvclk;
}
/* The minimum delay between power supplies and reset rising can be 0 */
ret = regulator_enable(ov2685->dovdd_regulator);
if (ret < 0) {
dev_err(dev, "Failed to enable DOVDD regulator\n");
goto disable_avdd;
}
/* The minimum delay between AVDD and reset rising can be 0 */
gpiod_set_value_cansleep(ov2685->reset_gpio, 0);
/* 8192 xvclk cycles prior to the first SCCB transaction */
delay_us = ov2685_cal_delay(8192);
usleep_range(delay_us, delay_us * 2);
/* 8192 xvclk cycles prior to the first SCCB transaction.
* NOTE: An additional 1ms must be added to wait for
* SCCB to become stable when using internal DVDD.
*/
usleep_range(1350, 1500);
/* HACK: ov2685 would output messy data after reset(R0103),
* writing register before .s_stream() as a workaround
*/
ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list);
if (ret)
goto disable_supplies;
return 0;
disable_supplies:
regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
disable_clk:
return ret;
disable_avdd:
regulator_disable(ov2685->avdd_regulator);
disable_xvclk:
clk_disable_unprepare(ov2685->xvclk);
return ret;
@@ -435,14 +461,100 @@ disable_clk:
static void __ov2685_power_off(struct ov2685 *ov2685)
{
/* 512 xvclk cycles after the last SCCB transaction or MIPI frame end */
u32 delay_us = ov2685_cal_delay(512);
usleep_range(delay_us, delay_us * 2);
usleep_range(30, 50);
clk_disable_unprepare(ov2685->xvclk);
gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
regulator_disable(ov2685->dovdd_regulator);
regulator_disable(ov2685->avdd_regulator);
}
static int ov2685_s_power(struct v4l2_subdev *sd, int on)
{
struct ov2685 *ov2685 = to_ov2685(sd);
int ret = 0;
mutex_lock(&ov2685->mutex);
if (on)
ret = pm_runtime_get_sync(&ov2685->client->dev);
else
ret = pm_runtime_put(&ov2685->client->dev);
mutex_unlock(&ov2685->mutex);
return ret;
}
static void ov2685_get_module_inf(struct ov2685 *ov2685,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV2685_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov2685->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov2685->len_name, sizeof(inf->base.lens));
}
static long ov2685_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov2685 *ov2685 = to_ov2685(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
ov2685_get_module_inf(ov2685, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ov2685_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = ov2685_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov2685_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int ov2685_s_stream(struct v4l2_subdev *sd, int on)
{
struct ov2685 *ov2685 = to_ov2685(sd);
@@ -456,33 +568,27 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&ov2685->client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler);
if (ret) {
pm_runtime_put(&client->dev);
goto unlock_and_return;
}
/* In case these controls are set before streaming */
ov2685_set_exposure(ov2685, ov2685->exposure->val);
ov2685_set_gain(ov2685, ov2685->anal_gain->val);
ov2685_set_vts(ov2685, ov2685->vblank->val);
ov2685_enable_test_pattern(ov2685, ov2685->test_pattern->val);
ret = ov2685_write_reg(client, REG_SC_CTRL_MODE,
OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STREAMING);
if (ret) {
pm_runtime_put(&client->dev);
if (ret)
goto unlock_and_return;
}
} else {
ov2685_write_reg(client, REG_SC_CTRL_MODE,
ret = ov2685_write_reg(client, REG_SC_CTRL_MODE,
OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STANDBY);
pm_runtime_put(&ov2685->client->dev);
if (ret)
goto unlock_and_return;
}
ov2685->streaming = on;
unlock_and_return:
mutex_unlock(&ov2685->mutex);
return ret;
}
@@ -496,7 +602,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
/* Initialize try_fmt */
ov2685_fill_fmt(&supported_modes[0], try_fmt);
ov2685_fill_fmt(ov2685, try_fmt);
mutex_unlock(&ov2685->mutex);
@@ -504,16 +610,27 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
}
#endif
static int __maybe_unused ov2685_runtime_resume(struct device *dev)
static int ov2685_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov2685 *ov2685 = to_ov2685(sd);
int ret;
return __ov2685_power_on(ov2685);
ret = __ov2685_power_on(ov2685);
if (ret)
return ret;
if (ov2685->streaming) {
ret = ov2685_s_stream(sd, 1);
if (ret)
__ov2685_power_off(ov2685);
}
return ret;
}
static int __maybe_unused ov2685_runtime_suspend(struct device *dev)
static int ov2685_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
@@ -534,67 +651,66 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl)
struct ov2685 *ov2685 = container_of(ctrl->handler,
struct ov2685, ctrl_handler);
struct i2c_client *client = ov2685->client;
s64 max_expo;
int ret;
s64 max;
int ret = 0;
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
case V4L2_CID_VBLANK:
/* Update max exposure while meeting expected vblanking */
max_expo = ov2685->cur_mode->height + ctrl->val - 4;
max = ov2685->cur_mode->height + ctrl->val - 4;
__v4l2_ctrl_modify_range(ov2685->exposure,
ov2685->exposure->minimum, max_expo,
ov2685->exposure->minimum, max,
ov2685->exposure->step,
ov2685->exposure->default_value);
break;
}
if (pm_runtime_get_if_in_use(&client->dev) <= 0)
return 0;
pm_runtime_get_sync(&client->dev);
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
ret = ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE,
OV2685_REG_VALUE_24BIT, ctrl->val << 4);
ov2685_set_exposure(ov2685, ctrl->val);
break;
case V4L2_CID_ANALOGUE_GAIN:
ret = ov2685_write_reg(ov2685->client, OV2685_REG_GAIN,
OV2685_REG_VALUE_16BIT, ctrl->val);
ov2685_set_gain(ov2685, ctrl->val);
break;
case V4L2_CID_VBLANK:
ret = ov2685_write_reg(ov2685->client, OV2685_REG_VTS,
OV2685_REG_VALUE_16BIT,
ctrl->val + ov2685->cur_mode->height);
ov2685_set_vts(ov2685, ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
ret = ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN,
OV2685_REG_VALUE_08BIT,
ov2685_test_pattern_val[ctrl->val]);
ov2685_enable_test_pattern(ov2685, ctrl->val);
break;
default:
dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
__func__, ctrl->id, ctrl->val);
ret = -EINVAL;
break;
};
pm_runtime_put(&client->dev);
return ret;
}
static const struct v4l2_subdev_video_ops ov2685_video_ops = {
static struct v4l2_subdev_core_ops ov2685_core_ops = {
.s_power = ov2685_s_power,
.ioctl = ov2685_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = ov2685_compat_ioctl32,
#endif
};
static struct v4l2_subdev_video_ops ov2685_video_ops = {
.s_stream = ov2685_s_stream,
};
static const struct v4l2_subdev_pad_ops ov2685_pad_ops = {
static struct v4l2_subdev_pad_ops ov2685_pad_ops = {
.enum_mbus_code = ov2685_enum_mbus_code,
.enum_frame_size = ov2685_enum_frame_sizes,
.get_fmt = ov2685_get_fmt,
.set_fmt = ov2685_set_fmt,
};
static const struct v4l2_subdev_ops ov2685_subdev_ops = {
static struct v4l2_subdev_ops ov2685_subdev_ops = {
.core = &ov2685_core_ops,
.video = &ov2685_video_ops,
.pad = &ov2685_pad_ops,
};
@@ -620,7 +736,7 @@ static int ov2685_initialize_controls(struct ov2685 *ov2685)
handler = &ov2685->ctrl_handler;
mode = ov2685->cur_mode;
ret = v4l2_ctrl_handler_init(handler, 8);
ret = v4l2_ctrl_handler_init(handler, 1);
if (ret)
return ret;
handler->lock = &ov2685->mutex;
@@ -663,34 +779,31 @@ static int ov2685_initialize_controls(struct ov2685 *ov2685)
0, 0, ov2685_test_pattern_menu);
if (handler->error) {
ret = handler->error;
dev_err(&ov2685->client->dev,
"Failed to init controls(%d)\n", ret);
goto err_free_handler;
v4l2_ctrl_handler_free(handler);
return handler->error;
}
ov2685->subdev.ctrl_handler = handler;
return 0;
err_free_handler:
v4l2_ctrl_handler_free(handler);
return ret;
}
static int ov2685_check_sensor_id(struct ov2685 *ov2685,
struct i2c_client *client)
{
struct device *dev = &ov2685->client->dev;
int ret;
u32 id = 0;
int id, ret;
ret = ov2685_read_reg(client, OV2685_REG_CHIP_ID,
OV2685_REG_VALUE_16BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
ret = __ov2685_power_on(ov2685);
if (ret)
return ret;
ov2685_read_reg(client, OV2685_REG_CHIP_ID,
OV2685_REG_VALUE_16BIT, &id);
__ov2685_power_off(ov2685);
if (id != CHIP_ID) {
dev_err(dev, "Wrong camera sensor id(%04x)\n", id);
return -EINVAL;
}
dev_info(dev, "Detected OV%04x sensor\n", CHIP_ID);
@@ -698,29 +811,38 @@ static int ov2685_check_sensor_id(struct ov2685 *ov2685,
return 0;
}
static int ov2685_configure_regulators(struct ov2685 *ov2685)
{
int i;
for (i = 0; i < OV2685_NUM_SUPPLIES; i++)
ov2685->supplies[i].supply = ov2685_supply_names[i];
return devm_regulator_bulk_get(&ov2685->client->dev,
OV2685_NUM_SUPPLIES,
ov2685->supplies);
}
static int ov2685_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov2685 *ov2685;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov2685 = devm_kzalloc(dev, sizeof(*ov2685), GFP_KERNEL);
if (!ov2685)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov2685->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov2685->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov2685->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov2685->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ov2685->client = client;
ov2685->cur_mode = &supported_modes[0];
@@ -729,13 +851,6 @@ static int ov2685_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ov2685->reset_gpio)) {
@@ -743,59 +858,66 @@ static int ov2685_probe(struct i2c_client *client,
return -EINVAL;
}
ret = ov2685_configure_regulators(ov2685);
if (ret) {
dev_err(dev, "Failed to get power regulators\n");
return ret;
ov2685->avdd_regulator = devm_regulator_get(dev, "avdd");
if (IS_ERR(ov2685->avdd_regulator)) {
dev_err(dev, "Failed to get avdd-supply\n");
return -EINVAL;
}
ov2685->dovdd_regulator = devm_regulator_get(dev, "dovdd");
if (IS_ERR(ov2685->dovdd_regulator)) {
dev_err(dev, "Failed to get dovdd-supply\n");
return -EINVAL;
}
mutex_init(&ov2685->mutex);
v4l2_i2c_subdev_init(&ov2685->subdev, client, &ov2685_subdev_ops);
ret = ov2685_initialize_controls(ov2685);
if (ret)
goto err_destroy_mutex;
ret = __ov2685_power_on(ov2685);
if (ret)
goto err_free_handler;
goto destroy_mutex;
ret = ov2685_check_sensor_id(ov2685, client);
if (ret)
goto err_power_off;
return ret;
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
ov2685->subdev.internal_ops = &ov2685_internal_ops;
ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov2685->pad.flags = MEDIA_PAD_FL_SOURCE;
ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad);
if (ret < 0)
goto err_power_off;
goto free_ctrl_handler;
#endif
ret = v4l2_async_register_subdev(&ov2685->subdev);
sd = &ov2685->subdev;
memset(facing, 0, sizeof(facing));
if (strcmp(ov2685->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov2685->module_index, facing,
OV2685_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
goto clean_entity;
}
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_idle(dev);
return 0;
err_clean_entity:
clean_entity:
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&ov2685->subdev.entity);
#endif
err_power_off:
__ov2685_power_off(ov2685);
err_free_handler:
free_ctrl_handler:
v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
err_destroy_mutex:
destroy_mutex:
mutex_destroy(&ov2685->mutex);
return ret;
@@ -803,37 +925,28 @@ err_destroy_mutex:
static int ov2685_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov2685 *ov2685 = to_ov2685(sd);
struct ov2685 *ov2685 = i2c_get_clientdata(client);
v4l2_async_unregister_subdev(sd);
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&sd->entity);
#endif
__ov2685_power_off(ov2685);
v4l2_async_unregister_subdev(&ov2685->subdev);
media_entity_cleanup(&ov2685->subdev.entity);
v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
mutex_destroy(&ov2685->mutex);
pm_runtime_disable(&client->dev);
if (!pm_runtime_status_suspended(&client->dev))
__ov2685_power_off(ov2685);
pm_runtime_set_suspended(&client->dev);
return 0;
}
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id ov2685_of_match[] = {
{ .compatible = "ovti,ov2685" },
{},
};
MODULE_DEVICE_TABLE(of, ov2685_of_match);
#endif
static struct i2c_driver ov2685_i2c_driver = {
.driver = {
.name = "ov2685",
.name = OV2685_NAME,
.owner = THIS_MODULE,
.pm = &ov2685_pm_ops,
.of_match_table = of_match_ptr(ov2685_of_match),
.of_match_table = ov2685_of_match
},
.probe = &ov2685_probe,
.remove = &ov2685_remove,

View File

@@ -3,6 +3,9 @@
* ov2718 driver
*
* Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
*/
#include <linux/clk.h>
@@ -14,6 +17,9 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
@@ -28,6 +34,8 @@
#include <linux/mfd/syscon.h>
#include <linux/rk-preisp.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -89,6 +97,8 @@
#define OF_CAMERA_MODULE_REGULATORS "rockchip,regulator-names"
#define OF_CAMERA_MODULE_REGULATOR_VOLTAGES "rockchip,regulator-voltages"
#define OV2718_NAME "ov2718"
struct ov2718_gpio {
int pltfrm_gpio;
const char *label;
@@ -144,11 +154,16 @@ struct ov2718 {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
bool has_devnode;
const struct ov2718_mode *cur_mode;
const struct ov2718_mode *support_modes;
u32 support_modes_num;
struct ov2718_regulators regulators;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_ov2718(sd) container_of(sd, struct ov2718, subdev)
@@ -4275,6 +4290,16 @@ static void ov2718_get_hcg_reg(u32 gain, u32 *again_reg, u32 *dgain_reg)
}
}
static void ov2718_get_module_inf(struct ov2718 *ov2718,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV2718_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov2718->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov2718->len_name, sizeof(inf->base.lens));
}
static long ov2718_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov2718 *ov2718 = to_ov2718(sd);
@@ -4373,13 +4398,90 @@ static long ov2718_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
l_dgain,
s_dgain);
break;
case RKMODULE_GET_MODULE_INFO:
ov2718_get_module_inf(ov2718, (struct rkmodule_inf *)arg);
break;
default:
return -ENOTTY;
return -ENOIOCTLCMD;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ov2718_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = ov2718_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov2718_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int ov2718_s_power(struct v4l2_subdev *sd, int on)
{
struct ov2718 *ov2718 = to_ov2718(sd);
struct i2c_client *client = ov2718->client;
int ret = 0;
mutex_lock(&ov2718->mutex);
/* If the power state is not modified - no work to do. */
if (ov2718->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ov2718->power_on = true;
} else {
pm_runtime_put(&client->dev);
ov2718->power_on = false;
}
unlock_and_return:
mutex_unlock(&ov2718->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov2718_cal_delay(u32 cycles)
{
@@ -4400,13 +4502,16 @@ static int __ov2718_power_on(struct ov2718 *ov2718)
if (ret < 0)
dev_err(dev, "could not set pins\n");
}
ret = clk_set_rate(ov2718->xvclk, OV2718_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(ov2718->xvclk) != OV2718_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov2718->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
if (ov2718->regulators.regulator) {
for (i = 0; i < ov2718->regulators.cnt; i++) {
regulator = ov2718->regulators.regulator + i;
@@ -4554,7 +4659,11 @@ static const struct v4l2_subdev_pad_ops ov2718_pad_ops = {
};
static const struct v4l2_subdev_core_ops ov2718_core_ops = {
.s_power = ov2718_s_power,
.ioctl = ov2718_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = ov2718_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_ops ov2718_subdev_ops = {
@@ -4785,6 +4894,10 @@ static int ov2718_check_sensor_id(struct ov2718 *ov2718,
usleep_range(1000, 2000);
continue;
}
if (id != CHIP_ID)
return -ENODEV;
dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
return 0;
@@ -4792,7 +4905,6 @@ static int ov2718_check_sensor_id(struct ov2718 *ov2718,
static int ov2718_analyze_dts(struct ov2718 *ov2718)
{
int ret;
int elem_size, elem_index;
const char *str = "";
struct property *prop;
@@ -4805,13 +4917,6 @@ static int ov2718_analyze_dts(struct ov2718 *ov2718)
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(ov2718->xvclk, OV2718_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov2718->xvclk) != OV2718_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ov2718->pinctrl = devm_pinctrl_get(dev);
if (!IS_ERR(ov2718->pinctrl)) {
@@ -4918,14 +5023,34 @@ static int ov2718_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov2718 *ov2718;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov2718 = devm_kzalloc(dev, sizeof(*ov2718), GFP_KERNEL);
if (!ov2718)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov2718->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov2718->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov2718->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov2718->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ov2718->client = client;
ret = ov2718_analyze_dts(ov2718);
@@ -4963,18 +5088,28 @@ static int ov2718_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov2718_internal_ops;
if (ov2718->has_devnode)
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov2718->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &ov2718->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov2718->pad);
if (ret < 0)
goto err_power_off;
#endif
if (ov2718->has_devnode) {
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(ov2718->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov2718->module_index, facing,
OV2718_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -5037,7 +5172,7 @@ static const struct i2c_device_id ov2718_match_id[] = {
static struct i2c_driver ov2718_i2c_driver = {
.driver = {
.name = "ov2718",
.name = OV2718_NAME,
.pm = &ov2718_pm_ops,
.of_match_table = of_match_ptr(ov2718_of_match),
},

View File

@@ -3,6 +3,9 @@
* ov2735 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
*/
#include <linux/clk.h>
@@ -14,11 +17,16 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -85,6 +93,8 @@
#define ANALOG_GAIN_STEP 1
#define ANALOG_GAIN_DEFAULT 0x10
#define OV2735_NAME "ov2735"
static const char * const ov2735_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
@@ -126,7 +136,12 @@ struct ov2735 {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct ov2735_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_ov2735(sd) container_of(sd, struct ov2735, subdev)
@@ -504,14 +519,80 @@ static int ov2735_enable_test_pattern(struct ov2735 *ov2735, u32 pattern)
val);
}
static void ov2735_get_module_inf(struct ov2735 *ov2735,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV2735_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov2735->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov2735->len_name, sizeof(inf->base.lens));
}
static long ov2735_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov2735 *ov2735 = to_ov2735(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
ov2735_get_module_inf(ov2735, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ov2735_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = ov2735_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov2735_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int __ov2735_start_stream(struct ov2735 *ov2735)
{
int ret;
ret = ov2735_write_array(ov2735->client, ov2735_global_regs);
if (ret)
return ret;
mdelay(3);
ret = ov2735_write_array(ov2735->client, ov2735->cur_mode->reg_list);
if (ret)
return ret;
@@ -577,6 +658,44 @@ unlock_and_return:
return ret;
}
static int ov2735_s_power(struct v4l2_subdev *sd, int on)
{
struct ov2735 *ov2735 = to_ov2735(sd);
struct i2c_client *client = ov2735->client;
int ret = 0;
mutex_lock(&ov2735->mutex);
/* If the power state is not modified - no work to do. */
if (ov2735->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ret = ov2735_write_array(ov2735->client, ov2735_global_regs);
if (ret) {
v4l2_err(sd, "could not set init registers\n");
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ov2735->power_on = true;
} else {
pm_runtime_put(&client->dev);
ov2735->power_on = false;
}
unlock_and_return:
mutex_unlock(&ov2735->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov2735_cal_delay(u32 cycles)
{
@@ -610,11 +729,14 @@ static int __ov2735_power_on(struct ov2735 *ov2735)
gpiod_set_value_cansleep(ov2735->reset_gpio, 1);
usleep_range(2000, 5000);
}
if (!IS_ERR(ov2735->xvclk)) {
ret = clk_prepare_enable(ov2735->xvclk);
if (ret < 0)
dev_info(dev, "Failed to enable xvclk\n");
}
ret = clk_set_rate(ov2735->xvclk, OV2735_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(ov2735->xvclk) != OV2735_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov2735->xvclk);
if (ret < 0)
dev_info(dev, "Failed to enable xvclk\n");
/* 8192 cycles prior to first SCCB transaction */
delay_us = ov2735_cal_delay(8192);
@@ -691,6 +813,14 @@ static const struct v4l2_subdev_internal_ops ov2735_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops ov2735_core_ops = {
.s_power = ov2735_s_power,
.ioctl = ov2735_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = ov2735_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops ov2735_video_ops = {
.s_stream = ov2735_s_stream,
};
@@ -703,6 +833,7 @@ static const struct v4l2_subdev_pad_ops ov2735_pad_ops = {
};
static const struct v4l2_subdev_ops ov2735_subdev_ops = {
.core = &ov2735_core_ops,
.video = &ov2735_video_ops,
.pad = &ov2735_pad_ops,
};
@@ -852,7 +983,7 @@ static int ov2735_check_sensor_id(struct ov2735 *ov2735,
ret = ov2735_write_reg(ov2735->client, PAGE_SELECT_REG, PAGE_ZERO);
ret |= ov2735_read_reg(ov2735->client, OV2735_PIDH_ADDR, &pidh);
ret |= ov2735_read_reg(ov2735->client, OV2735_PIDL_ADDR, &pidl);
if (IS_ERR_VALUE(ret)) {
if (ret) {
dev_err(dev,
"register read failed, camera module powered off?\n");
goto err;
@@ -891,14 +1022,34 @@ static int ov2735_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov2735 *ov2735;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov2735 = devm_kzalloc(dev, sizeof(*ov2735), GFP_KERNEL);
if (!ov2735)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov2735->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov2735->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov2735->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov2735->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ov2735->client = client;
ov2735->cur_mode = &supported_modes[0];
@@ -907,13 +1058,6 @@ static int ov2735_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(ov2735->xvclk, OV2735_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov2735->xvclk) != OV2735_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ov2735->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ov2735->reset_gpio))
@@ -947,17 +1091,27 @@ static int ov2735_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov2735_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov2735->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &ov2735->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov2735->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(ov2735->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov2735->module_index, facing,
OV2735_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1018,7 +1172,7 @@ static const struct i2c_device_id ov2735_match_id[] = {
static struct i2c_driver ov2735_i2c_driver = {
.driver = {
.name = "ov2735",
.name = OV2735_NAME,
.pm = &ov2735_pm_ops,
.of_match_table = of_match_ptr(ov2735_of_match),
},
@@ -1041,4 +1195,5 @@ device_initcall_sync(sensor_mod_init);
module_exit(sensor_mod_exit);
MODULE_DESCRIPTION("OmniVision ov2735 sensor driver");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL v2");

View File

@@ -3,6 +3,10 @@
* ov4689 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
* V0.0X01.0X03 fix gain range.
*/
#include <linux/clk.h>
@@ -14,12 +18,17 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <linux/pinctrl/consumer.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -46,10 +55,10 @@
#define OV4689_GAIN_H_MASK 0x07
#define OV4689_GAIN_H_SHIFT 8
#define OV4689_GAIN_L_MASK 0xff
#define OV4689_GAIN_MIN 0x10
#define OV4689_GAIN_MAX 0xf8
#define OV4689_GAIN_MIN 0x80
#define OV4689_GAIN_MAX 0x7f8
#define OV4689_GAIN_STEP 1
#define OV4689_GAIN_DEFAULT 0x10
#define OV4689_GAIN_DEFAULT 0x80
#define OV4689_REG_TEST_PATTERN 0x5040
#define OV4689_TEST_PATTERN_ENABLE 0x80
@@ -69,6 +78,8 @@
#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
#define OV4689_NAME "ov4689"
static const char * const ov4689_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
@@ -114,7 +125,12 @@ struct ov4689 {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct ov4689_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_ov4689(sd) container_of(sd, struct ov4689, subdev)
@@ -635,14 +651,80 @@ static int ov4689_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
static void ov4689_get_module_inf(struct ov4689 *ov4689,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV4689_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov4689->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov4689->len_name, sizeof(inf->base.lens));
}
static long ov4689_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov4689 *ov4689 = to_ov4689(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
ov4689_get_module_inf(ov4689, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ov4689_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = ov4689_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov4689_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int __ov4689_start_stream(struct ov4689 *ov4689)
{
int ret;
ret = ov4689_write_array(ov4689->client, ov4689_global_regs);
if (ret)
return ret;
ret = ov4689_write_array(ov4689->client, ov4689->cur_mode->reg_list);
if (ret)
return ret;
@@ -701,6 +783,44 @@ unlock_and_return:
return ret;
}
static int ov4689_s_power(struct v4l2_subdev *sd, int on)
{
struct ov4689 *ov4689 = to_ov4689(sd);
struct i2c_client *client = ov4689->client;
int ret = 0;
mutex_lock(&ov4689->mutex);
/* If the power state is not modified - no work to do. */
if (ov4689->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ret = ov4689_write_array(ov4689->client, ov4689_global_regs);
if (ret) {
v4l2_err(sd, "could not set init registers\n");
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ov4689->power_on = true;
} else {
pm_runtime_put(&client->dev);
ov4689->power_on = false;
}
unlock_and_return:
mutex_unlock(&ov4689->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov4689_cal_delay(u32 cycles)
{
@@ -719,13 +839,16 @@ static int __ov4689_power_on(struct ov4689 *ov4689)
if (ret < 0)
dev_err(dev, "could not set pins\n");
}
ret = clk_set_rate(ov4689->xvclk, OV4689_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(ov4689->xvclk) != OV4689_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov4689->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
if (!IS_ERR(ov4689->reset_gpio))
gpiod_set_value_cansleep(ov4689->reset_gpio, 0);
@@ -826,6 +949,14 @@ static const struct v4l2_subdev_internal_ops ov4689_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops ov4689_core_ops = {
.s_power = ov4689_s_power,
.ioctl = ov4689_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = ov4689_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops ov4689_video_ops = {
.s_stream = ov4689_s_stream,
.g_frame_interval = ov4689_g_frame_interval,
@@ -839,6 +970,7 @@ static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {
};
static const struct v4l2_subdev_ops ov4689_subdev_ops = {
.core = &ov4689_core_ops,
.video = &ov4689_video_ops,
.pad = &ov4689_pad_ops,
};
@@ -983,7 +1115,7 @@ static int ov4689_check_sensor_id(struct ov4689 *ov4689,
OV4689_REG_VALUE_16BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
return ret;
return -ENODEV;
}
dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
@@ -1007,14 +1139,34 @@ static int ov4689_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov4689 *ov4689;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov4689 = devm_kzalloc(dev, sizeof(*ov4689), GFP_KERNEL);
if (!ov4689)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov4689->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov4689->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov4689->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov4689->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ov4689->client = client;
ov4689->cur_mode = &supported_modes[0];
@@ -1023,13 +1175,6 @@ static int ov4689_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(ov4689->xvclk, OV4689_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov4689->xvclk) != OV4689_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ov4689->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ov4689->reset_gpio))
@@ -1080,17 +1225,27 @@ static int ov4689_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov4689_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov4689->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &ov4689->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(ov4689->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov4689->module_index, facing,
OV4689_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1151,7 +1306,7 @@ static const struct i2c_device_id ov4689_match_id[] = {
static struct i2c_driver ov4689_i2c_driver = {
.driver = {
.name = "ov4689",
.name = OV4689_NAME,
.pm = &ov4689_pm_ops,
.of_match_table = of_match_ptr(ov4689_of_match),
},

1506
drivers/media/i2c/ov5648.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
* ov5695 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
*/
#include <linux/clk.h>
@@ -14,11 +16,16 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -69,6 +76,12 @@
#define OV5695_LANES 2
#define OV5695_BITS_PER_SAMPLE 10
#define I2C_M_WR 0
#define I2C_MSG_MAX 300
#define I2C_DATA_MAX (I2C_MSG_MAX * 3)
#define OV5695_NAME "ov5695"
static const char * const ov5695_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
@@ -96,6 +109,7 @@ struct ov5695 {
struct i2c_client *client;
struct clk *xvclk;
struct gpio_desc *reset_gpio;
struct gpio_desc *pwdn_gpio;
struct regulator_bulk_data supplies[OV5695_NUM_SUPPLIES];
struct v4l2_subdev subdev;
@@ -109,7 +123,12 @@ struct ov5695 {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct ov5695_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_ov5695(sd) container_of(sd, struct ov5695, subdev)
@@ -384,175 +403,18 @@ static const struct regval ov5695_1920x1080_regs[] = {
* mipi_datarate per lane 840Mbps
*/
static const struct regval ov5695_1296x972_regs[] = {
{0x0103, 0x01},
{0x0100, 0x00},
{0x0300, 0x04},
{0x0301, 0x00},
{0x0302, 0x69},
{0x0303, 0x00},
{0x0304, 0x00},
{0x0305, 0x01},
{0x0307, 0x00},
{0x030b, 0x00},
{0x030c, 0x00},
{0x030d, 0x1e},
{0x030e, 0x04},
{0x030f, 0x03},
{0x0312, 0x01},
{0x3000, 0x00},
{0x3002, 0xa1},
{0x3008, 0x00},
{0x3010, 0x00},
{0x3016, 0x32},
{0x3022, 0x51},
{0x3106, 0x15},
{0x3107, 0x01},
{0x3108, 0x05},
{0x3500, 0x00},
{0x3501, 0x3e},
{0x3502, 0x00},
{0x3503, 0x08},
{0x3504, 0x03},
{0x3505, 0x8c},
{0x3507, 0x03},
{0x3508, 0x00},
{0x3509, 0x10},
{0x350c, 0x00},
{0x350d, 0x80},
{0x3510, 0x00},
{0x3511, 0x02},
{0x3512, 0x00},
{0x3601, 0x55},
{0x3602, 0x58},
{0x3611, 0x58},
{0x3614, 0x30},
{0x3615, 0x77},
{0x3621, 0x08},
{0x3624, 0x40},
{0x3633, 0x0c},
{0x3634, 0x0c},
{0x3635, 0x0c},
{0x3636, 0x0c},
{0x3638, 0x00},
{0x3639, 0x00},
{0x363a, 0x00},
{0x363b, 0x00},
{0x363c, 0xff},
{0x363d, 0xfa},
{0x3650, 0x44},
{0x3651, 0x44},
{0x3652, 0x44},
{0x3653, 0x44},
{0x3654, 0x44},
{0x3655, 0x44},
{0x3656, 0x44},
{0x3657, 0x44},
{0x3660, 0x00},
{0x3661, 0x00},
{0x3662, 0x00},
{0x366a, 0x00},
{0x366e, 0x0c},
{0x3673, 0x04},
{0x3700, 0x14},
{0x3703, 0x0c},
{0x3706, 0x24},
{0x3714, 0x27},
{0x3715, 0x01},
{0x3716, 0x00},
{0x3717, 0x02},
{0x3733, 0x10},
{0x3734, 0x40},
{0x373f, 0xa0},
{0x3765, 0x20},
{0x37a1, 0x1d},
{0x37a8, 0x26},
{0x37ab, 0x14},
{0x37c2, 0x04},
{0x37c3, 0xf0},
{0x37cb, 0x09},
{0x37cc, 0x13},
{0x37cd, 0x1f},
{0x37ce, 0x1f},
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
{0x3803, 0x00},
{0x3804, 0x0a},
{0x3805, 0x3f},
{0x3806, 0x07},
{0x3807, 0xaf},
{0x3808, 0x05},
{0x3809, 0x10},
{0x380a, 0x03},
{0x380b, 0xcc},
{0x380c, 0x02},
{0x380d, 0xe4},
{0x380e, 0x03},
{0x380f, 0xf4},
{0x3810, 0x00},
{0x3811, 0x00},
{0x3812, 0x00},
{0x3813, 0x06},
{0x3814, 0x03},
{0x3815, 0x01},
{0x3816, 0x03},
{0x3817, 0x01},
{0x3818, 0x00},
{0x3819, 0x00},
{0x381a, 0x00},
{0x381b, 0x01},
{0x3820, 0x8b},
{0x3821, 0x01},
{0x3c80, 0x08},
{0x3c82, 0x00},
{0x3c83, 0x00},
{0x3c88, 0x00},
{0x3d85, 0x14},
{0x3f02, 0x08},
{0x3f03, 0x10},
{0x4008, 0x02},
{0x4009, 0x09},
{0x404e, 0x20},
{0x4501, 0x00},
{0x4502, 0x10},
{0x4800, 0x00},
{0x481f, 0x2a},
{0x4837, 0x13},
{0x5000, 0x13},
{0x5780, 0x3e},
{0x5781, 0x0f},
{0x5782, 0x44},
{0x5783, 0x02},
{0x5784, 0x01},
{0x5785, 0x01},
{0x5786, 0x00},
{0x5787, 0x04},
{0x5788, 0x02},
{0x5789, 0x0f},
{0x578a, 0xfd},
{0x578b, 0xf5},
{0x578c, 0xf5},
{0x578d, 0x03},
{0x578e, 0x08},
{0x578f, 0x0c},
{0x5790, 0x08},
{0x5791, 0x06},
{0x5792, 0x00},
{0x5793, 0x52},
{0x5794, 0xa3},
{0x5b00, 0x00},
{0x5b01, 0x1c},
{0x5b02, 0x00},
{0x5b03, 0x7f},
{0x5b05, 0x6c},
{0x5e10, 0xfc},
{0x4010, 0xf1},
{0x3503, 0x08},
{0x3505, 0x8c},
{0x3507, 0x03},
{0x3508, 0x00},
{0x3509, 0xf8},
{0x0100, 0x01},
{REG_NULL, 0x00}
};
@@ -733,14 +595,58 @@ static int ov5695_write_reg(struct i2c_client *client, u16 reg,
static int ov5695_write_array(struct i2c_client *client,
const struct regval *regs)
{
u32 i;
u8 *data;
u32 i, j = 0, k = 0;
int ret = 0;
struct i2c_msg *msg;
for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
ret = ov5695_write_reg(client, regs[i].addr,
OV5695_REG_VALUE_08BIT, regs[i].val);
msg = kmalloc((sizeof(struct i2c_msg) * I2C_MSG_MAX),
GFP_KERNEL);
if (!msg)
return -ENOMEM;
return ret;
data = kmalloc((sizeof(unsigned char) * I2C_DATA_MAX),
GFP_KERNEL);
if (!data) {
kfree(msg);
return -ENOMEM;
}
for (i = 0; regs[i].addr != REG_NULL; i++) {
(msg + j)->addr = client->addr;
(msg + j)->flags = I2C_M_WR;
(msg + j)->buf = (data + k);
data[k + 0] = (u8)(regs[i].addr >> 8);
data[k + 1] = (u8)(regs[i].addr & 0xFF);
data[k + 2] = (u8)(regs[i].val & 0xFF);
k = k + 3;
(msg + j)->len = 3;
if (j++ == (I2C_MSG_MAX - 1)) {
ret = i2c_transfer(client->adapter, msg, j);
if (ret < 0) {
kfree(msg);
kfree(data);
return ret;
}
j = 0;
k = 0;
}
}
if (j != 0) {
ret = i2c_transfer(client->adapter, msg, j);
if (ret < 0) {
kfree(msg);
kfree(data);
return ret;
}
}
kfree(msg);
kfree(data);
return 0;
}
/* Read registers up to 4 at a time */
@@ -753,7 +659,7 @@ static int ov5695_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
__be16 reg_addr_be = cpu_to_be16(reg);
int ret;
if (len > 4)
if (len > 4 || !len)
return -EINVAL;
data_be_p = (u8 *)&data_be;
@@ -911,19 +817,102 @@ static int ov5695_enable_test_pattern(struct ov5695 *ov5695, u32 pattern)
OV5695_REG_VALUE_08BIT, val);
}
static int ov5695_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *fi)
{
struct ov5695 *ov5695 = to_ov5695(sd);
const struct ov5695_mode *mode = ov5695->cur_mode;
mutex_lock(&ov5695->mutex);
fi->interval.numerator = 10000;
fi->interval.denominator = mode->max_fps * 10000;
mutex_unlock(&ov5695->mutex);
return 0;
}
static void ov5695_get_module_inf(struct ov5695 *ov5695,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV5695_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov5695->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov5695->len_name, sizeof(inf->base.lens));
}
static long ov5695_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov5695 *ov5695 = to_ov5695(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
ov5695_get_module_inf(ov5695, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ov5695_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = ov5695_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov5695_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int __ov5695_start_stream(struct ov5695 *ov5695)
{
int ret;
ret = ov5695_write_array(ov5695->client, ov5695_global_regs);
if (ret)
return ret;
ret = ov5695_write_array(ov5695->client, ov5695->cur_mode->reg_list);
if (ret)
return ret;
/* In case these controls are set before streaming */
ret = __v4l2_ctrl_handler_setup(&ov5695->ctrl_handler);
mutex_unlock(&ov5695->mutex);
ret = v4l2_ctrl_handler_setup(&ov5695->ctrl_handler);
mutex_lock(&ov5695->mutex);
if (ret)
return ret;
@@ -974,6 +963,44 @@ unlock_and_return:
return ret;
}
static int ov5695_s_power(struct v4l2_subdev *sd, int on)
{
struct ov5695 *ov5695 = to_ov5695(sd);
struct i2c_client *client = ov5695->client;
int ret = 0;
mutex_lock(&ov5695->mutex);
/* If the power state is not modified - no work to do. */
if (ov5695->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ret = ov5695_write_array(ov5695->client, ov5695_global_regs);
if (ret) {
v4l2_err(sd, "could not set init registers\n");
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ov5695->power_on = true;
} else {
pm_runtime_put(&client->dev);
ov5695->power_on = false;
}
unlock_and_return:
mutex_unlock(&ov5695->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov5695_cal_delay(u32 cycles)
{
@@ -986,13 +1013,21 @@ static int __ov5695_power_on(struct ov5695 *ov5695)
u32 delay_us;
struct device *dev = &ov5695->client->dev;
ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov5695->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
if (!IS_ERR(ov5695->reset_gpio))
gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies);
if (ret < 0) {
@@ -1000,7 +1035,11 @@ static int __ov5695_power_on(struct ov5695 *ov5695)
goto disable_clk;
}
gpiod_set_value_cansleep(ov5695->reset_gpio, 0);
if (!IS_ERR(ov5695->reset_gpio))
gpiod_set_value_cansleep(ov5695->reset_gpio, 0);
if (!IS_ERR(ov5695->pwdn_gpio))
gpiod_set_value_cansleep(ov5695->pwdn_gpio, 1);
/* 8192 cycles prior to first SCCB transaction */
delay_us = ov5695_cal_delay(8192);
@@ -1016,12 +1055,15 @@ disable_clk:
static void __ov5695_power_off(struct ov5695 *ov5695)
{
if (!IS_ERR(ov5695->pwdn_gpio))
gpiod_set_value_cansleep(ov5695->pwdn_gpio, 0);
clk_disable_unprepare(ov5695->xvclk);
gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
if (!IS_ERR(ov5695->reset_gpio))
gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies);
}
static int __maybe_unused ov5695_runtime_resume(struct device *dev)
static int ov5695_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
@@ -1030,7 +1072,7 @@ static int __maybe_unused ov5695_runtime_resume(struct device *dev)
return __ov5695_power_on(ov5695);
}
static int __maybe_unused ov5695_runtime_suspend(struct device *dev)
static int ov5695_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
@@ -1074,8 +1116,17 @@ static const struct v4l2_subdev_internal_ops ov5695_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops ov5695_core_ops = {
.s_power = ov5695_s_power,
.ioctl = ov5695_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = ov5695_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops ov5695_video_ops = {
.s_stream = ov5695_s_stream,
.g_frame_interval = ov5695_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops ov5695_pad_ops = {
@@ -1086,6 +1137,7 @@ static const struct v4l2_subdev_pad_ops ov5695_pad_ops = {
};
static const struct v4l2_subdev_ops ov5695_subdev_ops = {
.core = &ov5695_core_ops,
.video = &ov5695_video_ops,
.pad = &ov5695_pad_ops,
};
@@ -1110,7 +1162,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
break;
}
if (pm_runtime_get_if_in_use(&client->dev) <= 0)
if (pm_runtime_get(&client->dev) <= 0)
return 0;
switch (ctrl->id) {
@@ -1127,7 +1179,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_L,
OV5695_REG_VALUE_08BIT,
ctrl->val & OV5695_DIGI_GAIN_L_MASK);
ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_H,
ret |= ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_H,
OV5695_REG_VALUE_08BIT,
ctrl->val >> OV5695_DIGI_GAIN_H_SHIFT);
break;
@@ -1143,7 +1195,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
__func__, ctrl->id, ctrl->val);
break;
};
}
pm_runtime_put(&client->dev);
@@ -1240,7 +1292,7 @@ static int ov5695_check_sensor_id(struct ov5695 *ov5695,
OV5695_REG_VALUE_24BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
return ret;
return -ENODEV;
}
dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
@@ -1264,14 +1316,34 @@ static int ov5695_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov5695 *ov5695;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov5695 = devm_kzalloc(dev, sizeof(*ov5695), GFP_KERNEL);
if (!ov5695)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov5695->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov5695->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov5695->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov5695->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ov5695->client = client;
ov5695->cur_mode = &supported_modes[0];
@@ -1280,20 +1352,16 @@ static int ov5695_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ov5695->reset_gpio)) {
dev_err(dev, "Failed to get reset-gpios\n");
return -EINVAL;
dev_warn(dev, "Failed to get reset-gpios\n");
}
ov5695->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
if (IS_ERR(ov5695->pwdn_gpio))
dev_warn(dev, "Failed to get pwdn-gpios\n");
ret = ov5695_configure_regulators(ov5695);
if (ret) {
dev_err(dev, "Failed to get power regulators\n");
@@ -1318,7 +1386,8 @@ static int ov5695_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov5695_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov5695->pad.flags = MEDIA_PAD_FL_SOURCE;
@@ -1328,7 +1397,16 @@ static int ov5695_probe(struct i2c_client *client,
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(ov5695->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov5695->module_index, facing,
OV5695_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1382,17 +1460,34 @@ static const struct of_device_id ov5695_of_match[] = {
MODULE_DEVICE_TABLE(of, ov5695_of_match);
#endif
static const struct i2c_device_id ov5695_match_id[] = {
{ "ovti,ov5695", 0 },
{ },
};
static struct i2c_driver ov5695_i2c_driver = {
.driver = {
.name = "ov5695",
.name = OV5695_NAME,
.pm = &ov5695_pm_ops,
.of_match_table = of_match_ptr(ov5695_of_match),
},
.probe = &ov5695_probe,
.remove = &ov5695_remove,
.id_table = ov5695_match_id,
};
module_i2c_driver(ov5695_i2c_driver);
static int __init sensor_mod_init(void)
{
return i2c_add_driver(&ov5695_i2c_driver);
}
static void __exit sensor_mod_exit(void)
{
i2c_del_driver(&ov5695_i2c_driver);
}
device_initcall_sync(sensor_mod_init);
module_exit(sensor_mod_exit);
MODULE_DESCRIPTION("OmniVision ov5695 sensor driver");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,9 @@
* ov7750 driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
*/
#include <linux/clk.h>
@@ -14,12 +17,17 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <linux/pinctrl/consumer.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -72,6 +80,8 @@
#define OF_CAMERA_PINCTRL_DEFAULT "rockchip,camera_default"
#define OF_CAMERA_PINCTRL_SLEEP "rockchip,camera_sleep"
#define OV7750_NAME "ov7750"
static const struct regval *ov7750_global_regs;
static const char * const ov7750_supply_names[] = {
@@ -119,7 +129,12 @@ struct ov7750 {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct ov7750_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_ov7750(sd) container_of(sd, struct ov7750, subdev)
@@ -597,14 +612,80 @@ static int ov7750_enable_test_pattern(struct ov7750 *ov7750, u32 pattern)
val);
}
static void ov7750_get_module_inf(struct ov7750 *ov7750,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, OV7750_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, ov7750->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, ov7750->len_name, sizeof(inf->base.lens));
}
static long ov7750_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct ov7750 *ov7750 = to_ov7750(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
ov7750_get_module_inf(ov7750, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOTTY;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long ov7750_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = ov7750_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = ov7750_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int __ov7750_start_stream(struct ov7750 *ov7750)
{
int ret;
ret = ov7750_write_array(ov7750->client, ov7750_global_regs);
if (ret)
return ret;
ret = ov7750_write_array(ov7750->client, ov7750->cur_mode->reg_list);
if (ret)
return ret;
@@ -667,6 +748,44 @@ unlock_and_return:
return ret;
}
static int ov7750_s_power(struct v4l2_subdev *sd, int on)
{
struct ov7750 *ov7750 = to_ov7750(sd);
struct i2c_client *client = ov7750->client;
int ret = 0;
mutex_lock(&ov7750->mutex);
/* If the power state is not modified - no work to do. */
if (ov7750->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ret = ov7750_write_array(ov7750->client, ov7750_global_regs);
if (ret) {
v4l2_err(sd, "could not set init registers\n");
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
ov7750->power_on = true;
} else {
pm_runtime_put(&client->dev);
ov7750->power_on = false;
}
unlock_and_return:
mutex_unlock(&ov7750->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 ov7750_cal_delay(u32 cycles)
{
@@ -686,6 +805,11 @@ static int __ov7750_power_on(struct ov7750 *ov7750)
dev_err(dev, "could not set pins\n");
}
ret = clk_set_rate(ov7750->xvclk, OV7750_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(ov7750->xvclk) != OV7750_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(ov7750->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
@@ -792,6 +916,14 @@ static const struct v4l2_subdev_internal_ops ov7750_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops ov7750_core_ops = {
.s_power = ov7750_s_power,
.ioctl = ov7750_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = ov7750_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops ov7750_video_ops = {
.s_stream = ov7750_s_stream,
};
@@ -804,6 +936,7 @@ static const struct v4l2_subdev_pad_ops ov7750_pad_ops = {
};
static const struct v4l2_subdev_ops ov7750_subdev_ops = {
.core = &ov7750_core_ops,
.video = &ov7750_video_ops,
.pad = &ov7750_pad_ops,
};
@@ -955,7 +1088,7 @@ static int ov7750_check_sensor_id(struct ov7750 *ov7750,
OV7750_REG_VALUE_16BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
return ret;
return -ENODEV;
}
ret = ov7750_read_reg(client, OV7750_CHIP_REVISION_REG,
@@ -990,14 +1123,34 @@ static int ov7750_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov7750 *ov7750;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov7750 = devm_kzalloc(dev, sizeof(*ov7750), GFP_KERNEL);
if (!ov7750)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov7750->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov7750->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov7750->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov7750->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
ov7750->client = client;
ov7750->cur_mode = &supported_modes[0];
@@ -1006,13 +1159,6 @@ static int ov7750_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(ov7750->xvclk, OV7750_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(ov7750->xvclk) != OV7750_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ov7750->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ov7750->reset_gpio))
@@ -1061,17 +1207,27 @@ static int ov7750_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov7750_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov7750->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &ov7750->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov7750->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(ov7750->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov7750->module_index, facing,
OV7750_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1132,7 +1288,7 @@ static const struct i2c_device_id ov7750_match_id[] = {
static struct i2c_driver ov7750_i2c_driver = {
.driver = {
.name = "ov7750",
.name = OV7750_NAME,
.pm = &ov7750_pm_ops,
.of_match_table = of_match_ptr(ov7750_of_match),
},
@@ -1155,4 +1311,5 @@ device_initcall_sync(sensor_mod_init);
module_exit(sensor_mod_exit);
MODULE_DESCRIPTION("OmniVision ov7750 sensor driver");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL v2");

2999
drivers/media/i2c/ov8858.c Normal file

File diff suppressed because it is too large Load Diff

1172
drivers/media/i2c/ov9281.c Normal file

File diff suppressed because it is too large Load Diff

1293
drivers/media/i2c/ov9750.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,9 @@
* sc031gs driver
*
* Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
*
* V0.0X01.0X01 add poweron function.
* V0.0X01.0X02 fix mclk issue when probe multiple camera.
*/
#include <linux/clk.h>
@@ -14,11 +17,16 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/rk-camera-module.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02)
#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
#endif
@@ -66,6 +74,8 @@
#define SC031GS_BITS_PER_SAMPLE 10
#endif
#define SC031GS_NAME "sc031gs"
static const char * const sc031gs_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
@@ -106,7 +116,12 @@ struct sc031gs {
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct sc031gs_mode *cur_mode;
u32 module_index;
const char *module_facing;
const char *module_name;
const char *len_name;
};
#define to_sc031gs(sd) container_of(sd, struct sc031gs, subdev)
@@ -128,6 +143,7 @@ static const struct regval sc031gs_global_regs[] = {
{0x3018, 0x1f},
{0x3019, 0xff},
{0x301c, 0xb4},
{0x3028, 0x82},
{0x320c, 0x03},
{0x320d, 0x6e},
// {0x320e, 0x02}, //120fps
@@ -197,9 +213,10 @@ static const struct regval sc031gs_global_regs[] = {
{0x4500, 0x59},
{0x4501, 0xc4},
{0x5011, 0x00},
// {0x0100, 0x01},
{0x0100, 0x01},
{0x4418, 0x08},
{0x4419, 0x8a},
{0x4419, 0x8e},
{0x0100, 0x00},
// test pattern
// {0x4501, 0xac},
// {0x5011, 0x01},
@@ -282,8 +299,10 @@ static const struct regval sc031gs_global_regs[] = {
{0x4501, 0xc4},
{0x4603, 0x00},
{0x5011, 0x00},
{0x0100, 0x01},
{0x4418, 0x08},
{0x4419, 0x8a},
{0x4419, 0x8e},
{0x0100, 0x00},
{REG_NULL, 0x00},
#endif
};
@@ -353,6 +372,8 @@ static int sc031gs_write_array(struct i2c_client *client,
for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) {
ret = sc031gs_write_reg(client, regs[i].addr,
SC031GS_REG_VALUE_08BIT, regs[i].val);
if (regs[i].addr == 0x0100 && regs[i].val == 0x01)
msleep(10);
}
return ret;
@@ -526,6 +547,76 @@ static int sc031gs_enable_test_pattern(struct sc031gs *sc031gs, u32 pattern)
SC031GS_REG_VALUE_08BIT, val);
}
static void sc031gs_get_module_inf(struct sc031gs *sc031gs,
struct rkmodule_inf *inf)
{
memset(inf, 0, sizeof(*inf));
strlcpy(inf->base.sensor, SC031GS_NAME, sizeof(inf->base.sensor));
strlcpy(inf->base.module, sc031gs->module_name,
sizeof(inf->base.module));
strlcpy(inf->base.lens, sc031gs->len_name, sizeof(inf->base.lens));
}
static long sc031gs_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct sc031gs *sc031gs = to_sc031gs(sd);
long ret = 0;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
sc031gs_get_module_inf(sc031gs, (struct rkmodule_inf *)arg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long sc031gs_compat_ioctl32(struct v4l2_subdev *sd,
unsigned int cmd, unsigned long arg)
{
void __user *up = compat_ptr(arg);
struct rkmodule_inf *inf;
struct rkmodule_awb_cfg *cfg;
long ret;
switch (cmd) {
case RKMODULE_GET_MODULE_INFO:
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
if (!inf) {
ret = -ENOMEM;
return ret;
}
ret = sc031gs_ioctl(sd, cmd, inf);
if (!ret)
ret = copy_to_user(up, inf, sizeof(*inf));
kfree(inf);
break;
case RKMODULE_AWB_CFG:
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) {
ret = -ENOMEM;
return ret;
}
ret = copy_from_user(cfg, up, sizeof(*cfg));
if (!ret)
ret = sc031gs_ioctl(sd, cmd, cfg);
kfree(cfg);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
#endif
static int sc031gs_set_ctrl_gain(struct sc031gs *sc031gs, u32 a_gain)
{
int ret = 0;
@@ -559,12 +650,12 @@ static int sc031gs_set_ctrl_gain(struct sc031gs *sc031gs, u32 a_gain)
if (a_gain < 0x20) {
ret |= sc031gs_write_reg(sc031gs->client, 0x3314,
SC031GS_REG_VALUE_08BIT, 0x3a);
SC031GS_REG_VALUE_08BIT, 0x42);
ret |= sc031gs_write_reg(sc031gs->client, 0x3317,
SC031GS_REG_VALUE_08BIT, 0x20);
} else {
ret |= sc031gs_write_reg(sc031gs->client, 0x3314,
SC031GS_REG_VALUE_08BIT, 0x44);
SC031GS_REG_VALUE_08BIT, 0x4f);
ret |= sc031gs_write_reg(sc031gs->client, 0x3317,
SC031GS_REG_VALUE_08BIT, 0x0f);
}
@@ -659,6 +750,37 @@ static int sc031gs_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
static int sc031gs_s_power(struct v4l2_subdev *sd, int on)
{
struct sc031gs *sc031gs = to_sc031gs(sd);
struct i2c_client *client = sc031gs->client;
int ret = 0;
mutex_lock(&sc031gs->mutex);
/* If the power state is not modified - no work to do. */
if (sc031gs->power_on == !!on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
goto unlock_and_return;
}
sc031gs->power_on = true;
} else {
pm_runtime_put(&client->dev);
sc031gs->power_on = false;
}
unlock_and_return:
mutex_unlock(&sc031gs->mutex);
return ret;
}
/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 sc031gs_cal_delay(u32 cycles)
{
@@ -671,6 +793,11 @@ static int __sc031gs_power_on(struct sc031gs *sc031gs)
u32 delay_us;
struct device *dev = &sc031gs->client->dev;
ret = clk_set_rate(sc031gs->xvclk, SC031GS_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(sc031gs->xvclk) != SC031GS_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(sc031gs->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
@@ -772,6 +899,14 @@ static const struct v4l2_subdev_internal_ops sc031gs_internal_ops = {
};
#endif
static const struct v4l2_subdev_core_ops sc031gs_core_ops = {
.s_power = sc031gs_s_power,
.ioctl = sc031gs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = sc031gs_compat_ioctl32,
#endif
};
static const struct v4l2_subdev_video_ops sc031gs_video_ops = {
.s_stream = sc031gs_s_stream,
.g_frame_interval = sc031gs_g_frame_interval,
@@ -788,6 +923,7 @@ static const struct v4l2_subdev_pad_ops sc031gs_pad_ops = {
};
static const struct v4l2_subdev_ops sc031gs_subdev_ops = {
.core = &sc031gs_core_ops,
.video = &sc031gs_video_ops,
.pad = &sc031gs_pad_ops,
};
@@ -927,7 +1063,7 @@ static int sc031gs_check_sensor_id(struct sc031gs *sc031gs,
SC031GS_REG_VALUE_16BIT, &id);
if (id != CHIP_ID) {
dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
return ret;
return -ENODEV;
}
dev_info(dev, "Detected SC031GS CHIP ID = 0x%04x sensor\n", CHIP_ID);
@@ -951,14 +1087,34 @@ static int sc031gs_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct sc031gs *sc031gs;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
sc031gs = devm_kzalloc(dev, sizeof(*sc031gs), GFP_KERNEL);
if (!sc031gs)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&sc031gs->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&sc031gs->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&sc031gs->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&sc031gs->len_name);
if (ret) {
dev_err(dev, "could not get module information!\n");
return -EINVAL;
}
sc031gs->client = client;
sc031gs->cur_mode = &supported_modes[0];
@@ -967,13 +1123,6 @@ static int sc031gs_probe(struct i2c_client *client,
dev_err(dev, "Failed to get xvclk\n");
return -EINVAL;
}
ret = clk_set_rate(sc031gs->xvclk, SC031GS_XVCLK_FREQ);
if (ret < 0) {
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
return ret;
}
if (clk_get_rate(sc031gs->xvclk) != SC031GS_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
sc031gs->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(sc031gs->reset_gpio))
@@ -1006,17 +1155,27 @@ static int sc031gs_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &sc031gs_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
sc031gs->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
ret = media_entity_init(&sd->entity, 1, &sc031gs->pad, 0);
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &sc031gs->pad);
if (ret < 0)
goto err_power_off;
#endif
ret = v4l2_async_register_subdev(sd);
memset(facing, 0, sizeof(facing));
if (strcmp(sc031gs->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
sc031gs->module_index, facing,
SC031GS_NAME, dev_name(sd->dev));
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
dev_err(dev, "v4l2 async register subdev failed\n");
goto err_clean_entity;
@@ -1077,7 +1236,7 @@ static const struct i2c_device_id sc031gs_match_id[] = {
static struct i2c_driver sc031gs_i2c_driver = {
.driver = {
.name = "sc031gs",
.name = SC031GS_NAME,
.pm = &sc031gs_pm_ops,
.of_match_table = of_match_ptr(sc031gs_of_match),
},

1191
drivers/media/i2c/sc132gs.c Normal file

File diff suppressed because it is too large Load Diff