summaryrefslogtreecommitdiff
path: root/drivers/staging/media/atomisp/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/atomisp/i2c')
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c313
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc2235.c2
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-lm3554.c2
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c2
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2680.c252
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2722.c2
-rw-r--r--drivers/staging/media/atomisp/i2c/gc0310.h309
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2680.h141
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c42
9 files changed, 535 insertions, 530 deletions
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 273155308fe3..9a11793f34f7 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -16,27 +16,259 @@
*
*/
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/errno.h>
#include <linux/gpio/consumer.h>
-#include <linux/gpio/machine.h>
#include <linux/i2c.h>
-#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#include <linux/io.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-#include "gc0310.h"
+#define GC0310_NATIVE_WIDTH 656
+#define GC0310_NATIVE_HEIGHT 496
+
+#define GC0310_FPS 30
+#define GC0310_SKIP_FRAMES 3
+
+#define GC0310_FOCAL_LENGTH_NUM 278 /* 2.78mm */
+
+#define GC0310_ID 0xa310
+
+#define GC0310_RESET_RELATED 0xFE
+#define GC0310_REGISTER_PAGE_0 0x0
+#define GC0310_REGISTER_PAGE_3 0x3
+
+/*
+ * GC0310 System control registers
+ */
+#define GC0310_SW_STREAM 0x10
+
+#define GC0310_SC_CMMN_CHIP_ID_H 0xf0
+#define GC0310_SC_CMMN_CHIP_ID_L 0xf1
+
+#define GC0310_AEC_PK_EXPO_H 0x03
+#define GC0310_AEC_PK_EXPO_L 0x04
+#define GC0310_AGC_ADJ 0x48
+#define GC0310_DGC_ADJ 0x71
+#define GC0310_GROUP_ACCESS 0x3208
+
+#define GC0310_H_CROP_START_H 0x09
+#define GC0310_H_CROP_START_L 0x0A
+#define GC0310_V_CROP_START_H 0x0B
+#define GC0310_V_CROP_START_L 0x0C
+#define GC0310_H_OUTSIZE_H 0x0F
+#define GC0310_H_OUTSIZE_L 0x10
+#define GC0310_V_OUTSIZE_H 0x0D
+#define GC0310_V_OUTSIZE_L 0x0E
+#define GC0310_H_BLANKING_H 0x05
+#define GC0310_H_BLANKING_L 0x06
+#define GC0310_V_BLANKING_H 0x07
+#define GC0310_V_BLANKING_L 0x08
+#define GC0310_SH_DELAY 0x11
+
+#define GC0310_START_STREAMING 0x94 /* 8-bit enable */
+#define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */
+
+#define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd)
+
+struct gc0310_device {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ /* Protect against concurrent changes to controls */
+ struct mutex input_lock;
+ bool is_streaming;
+
+ struct fwnode_handle *ep_fwnode;
+ struct gpio_desc *reset;
+ struct gpio_desc *powerdown;
+
+ struct gc0310_mode {
+ struct v4l2_mbus_framefmt fmt;
+ } mode;
+
+ struct gc0310_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ } ctrls;
+};
+
+struct gc0310_reg {
+ u8 reg;
+ u8 val;
+};
+
+static const struct gc0310_reg gc0310_reset_register[] = {
+ /* System registers */
+ { 0xfe, 0xf0 },
+ { 0xfe, 0xf0 },
+ { 0xfe, 0x00 },
+
+ { 0xfc, 0x0e }, /* 4e */
+ { 0xfc, 0x0e }, /* 16//4e // [0]apwd [6]regf_clk_gate */
+ { 0xf2, 0x80 }, /* sync output */
+ { 0xf3, 0x00 }, /* 1f//01 data output */
+ { 0xf7, 0x33 }, /* f9 */
+ { 0xf8, 0x05 }, /* 00 */
+ { 0xf9, 0x0e }, /* 0x8e //0f */
+ { 0xfa, 0x11 },
+
+ /* MIPI */
+ { 0xfe, 0x03 },
+ { 0x01, 0x03 }, /* mipi 1lane */
+ { 0x02, 0x22 }, /* 0x33 */
+ { 0x03, 0x94 },
+ { 0x04, 0x01 }, /* fifo_prog */
+ { 0x05, 0x00 }, /* fifo_prog */
+ { 0x06, 0x80 }, /* b0 //YUV ISP data */
+ { 0x11, 0x2a }, /* 1e //LDI set YUV422 */
+ { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */
+ { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */
+ { 0x15, 0x12 }, /* 0x10 //DPHYY_MODE read_ready */
+ { 0x17, 0x01 },
+ { 0x40, 0x08 },
+ { 0x41, 0x00 },
+ { 0x42, 0x00 },
+ { 0x43, 0x00 },
+ { 0x21, 0x02 }, /* 0x01 */
+ { 0x22, 0x02 }, /* 0x01 */
+ { 0x23, 0x01 }, /* 0x05 //Nor:0x05 DOU:0x06 */
+ { 0x29, 0x00 },
+ { 0x2A, 0x25 }, /* 0x05 //data zero 0x7a de */
+ { 0x2B, 0x02 },
+
+ { 0xfe, 0x00 },
+
+ /* CISCTL */
+ { 0x00, 0x2f }, /* 2f//0f//02//01 */
+ { 0x01, 0x0f }, /* 06 */
+ { 0x02, 0x04 },
+ { 0x4f, 0x00 }, /* AEC 0FF */
+ { 0x03, 0x01 }, /* 0x03 //04 */
+ { 0x04, 0xc0 }, /* 0xe8 //58 */
+ { 0x05, 0x00 },
+ { 0x06, 0xb2 }, /* 0x0a //HB */
+ { 0x07, 0x00 },
+ { 0x08, 0x0c }, /* 0x89 //VB */
+ { 0x09, 0x00 }, /* row start */
+ { 0x0a, 0x00 },
+ { 0x0b, 0x00 }, /* col start */
+ { 0x0c, 0x00 },
+ { 0x0d, 0x01 }, /* height */
+ { 0x0e, 0xf2 }, /* 0xf7 //height */
+ { 0x0f, 0x02 }, /* width */
+ { 0x10, 0x94 }, /* 0xa0 //height */
+ { 0x17, 0x14 },
+ { 0x18, 0x1a }, /* 0a//[4]double reset */
+ { 0x19, 0x14 }, /* AD pipeline */
+ { 0x1b, 0x48 },
+ { 0x1e, 0x6b }, /* 3b//col bias */
+ { 0x1f, 0x28 }, /* 20//00//08//txlow */
+ { 0x20, 0x89 }, /* 88//0c//[3:2]DA15 */
+ { 0x21, 0x49 }, /* 48//[3] txhigh */
+ { 0x22, 0xb0 },
+ { 0x23, 0x04 }, /* [1:0]vcm_r */
+ { 0x24, 0x16 }, /* 15 */
+ { 0x34, 0x20 }, /* [6:4] rsg high//range */
+
+ /* BLK */
+ { 0x26, 0x23 }, /* [1]dark_current_en [0]offset_en */
+ { 0x28, 0xff }, /* BLK_limie_value */
+ { 0x29, 0x00 }, /* global offset */
+ { 0x33, 0x18 }, /* offset_ratio */
+ { 0x37, 0x20 }, /* dark_current_ratio */
+ { 0x2a, 0x00 },
+ { 0x2b, 0x00 },
+ { 0x2c, 0x00 },
+ { 0x2d, 0x00 },
+ { 0x2e, 0x00 },
+ { 0x2f, 0x00 },
+ { 0x30, 0x00 },
+ { 0x31, 0x00 },
+ { 0x47, 0x80 }, /* a7 */
+ { 0x4e, 0x66 }, /* select_row */
+ { 0xa8, 0x02 }, /* win_width_dark, same with crop_win_width */
+ { 0xa9, 0x80 },
+
+ /* ISP */
+ { 0x40, 0x06 }, /* 0xff //ff //48 */
+ { 0x41, 0x00 }, /* 0x21 //00//[0]curve_en */
+ { 0x42, 0x04 }, /* 0xcf //0a//[1]awn_en */
+ { 0x44, 0x18 }, /* 0x18 //02 */
+ { 0x46, 0x02 }, /* 0x03 //sync */
+ { 0x49, 0x03 },
+ { 0x4c, 0x20 }, /* 00[5]pretect exp */
+ { 0x50, 0x01 }, /* crop enable */
+ { 0x51, 0x00 },
+ { 0x52, 0x00 },
+ { 0x53, 0x00 },
+ { 0x54, 0x01 },
+ { 0x55, 0x01 }, /* crop window height */
+ { 0x56, 0xf0 },
+ { 0x57, 0x02 }, /* crop window width */
+ { 0x58, 0x90 },
+
+ /* Gain */
+ { 0x70, 0x70 }, /* 70 //80//global gain */
+ { 0x71, 0x20 }, /* pregain gain */
+ { 0x72, 0x40 }, /* post gain */
+ { 0x5a, 0x84 }, /* 84//analog gain 0 */
+ { 0x5b, 0xc9 }, /* c9 */
+ { 0x5c, 0xed }, /* ed//not use pga gain highest level */
+ { 0x77, 0x40 }, /* R gain 0x74 //awb gain */
+ { 0x78, 0x40 }, /* G gain */
+ { 0x79, 0x40 }, /* B gain 0x5f */
+
+ { 0x48, 0x00 },
+ { 0xfe, 0x01 },
+ { 0x0a, 0x45 }, /* [7]col gain mode */
+
+ { 0x3e, 0x40 },
+ { 0x3f, 0x5c },
+ { 0x40, 0x7b },
+ { 0x41, 0xbd },
+ { 0x42, 0xf6 },
+ { 0x43, 0x63 },
+ { 0x03, 0x60 },
+ { 0x44, 0x03 },
+
+ /* Dark / Sun mode related */
+ { 0xfe, 0x01 },
+ { 0x45, 0xa4 }, /* 0xf7 */
+ { 0x46, 0xf0 }, /* 0xff //f0//sun value th */
+ { 0x48, 0x03 }, /* sun mode */
+ { 0x4f, 0x60 }, /* sun_clamp */
+ { 0xfe, 0x00 },
+};
+
+static const struct gc0310_reg gc0310_VGA_30fps[] = {
+ { 0xfe, 0x00 },
+ { 0x0d, 0x01 }, /* height */
+ { 0x0e, 0xf2 }, /* 0xf7 //height */
+ { 0x0f, 0x02 }, /* width */
+ { 0x10, 0x94 }, /* 0xa0 //height */
+
+ { 0x50, 0x01 }, /* crop enable */
+ { 0x51, 0x00 },
+ { 0x52, 0x00 },
+ { 0x53, 0x00 },
+ { 0x54, 0x01 },
+ { 0x55, 0x01 }, /* crop window height */
+ { 0x56, 0xf0 },
+ { 0x57, 0x02 }, /* crop window width */
+ { 0x58, 0x90 },
+
+ { 0xfe, 0x03 },
+ { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */
+ { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */
+
+ { 0xfe, 0x00 },
+};
/*
* gc0310_write_reg_array - Initializes a list of GC0310 registers
@@ -179,7 +411,10 @@ static int gc0310_detect(struct i2c_client *client)
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -ENODEV;
- ret = i2c_smbus_read_word_swapped(client, GC0310_SC_CMMN_CHIP_ID_H);
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret >= 0)
+ ret = i2c_smbus_read_word_swapped(client, GC0310_SC_CMMN_CHIP_ID_H);
+ pm_runtime_put(&client->dev);
if (ret < 0) {
dev_err(&client->dev, "read sensor_id failed: %d\n", ret);
return -ENODEV;
@@ -268,19 +503,6 @@ error_unlock:
return ret;
}
-static int gc0310_s_config(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- ret = pm_runtime_get_sync(&client->dev);
- if (ret >= 0)
- ret = gc0310_detect(client);
-
- pm_runtime_put(&client->dev);
- return ret;
-}
-
static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
@@ -373,12 +595,12 @@ static void gc0310_remove(struct i2c_client *client)
dev_dbg(&client->dev, "gc0310_remove...\n");
- atomisp_unregister_subdev(sd);
- v4l2_device_unregister_subdev(sd);
+ v4l2_async_unregister_subdev(sd);
media_entity_cleanup(&dev->sd.entity);
v4l2_ctrl_handler_free(&dev->ctrls.handler);
+ mutex_destroy(&dev->input_lock);
+ fwnode_handle_put(dev->ep_fwnode);
pm_runtime_disable(&client->dev);
- kfree(dev);
}
static int gc0310_probe(struct i2c_client *client)
@@ -390,19 +612,27 @@ static int gc0310_probe(struct i2c_client *client)
if (!dev)
return -ENOMEM;
- ret = v4l2_get_acpi_sensor_info(&client->dev, NULL);
- if (ret)
- return ret;
+ /*
+ * Sometimes the fwnode graph is initialized by the bridge driver.
+ * Bridge drivers doing this may also add GPIO mappings, wait for this.
+ */
+ dev->ep_fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+ if (!dev->ep_fwnode)
+ return dev_err_probe(&client->dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n");
dev->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(dev->reset))
+ if (IS_ERR(dev->reset)) {
+ fwnode_handle_put(dev->ep_fwnode);
return dev_err_probe(&client->dev, PTR_ERR(dev->reset),
"getting reset GPIO\n");
+ }
dev->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH);
- if (IS_ERR(dev->powerdown))
+ if (IS_ERR(dev->powerdown)) {
+ fwnode_handle_put(dev->ep_fwnode);
return dev_err_probe(&client->dev, PTR_ERR(dev->powerdown),
"getting powerdown GPIO\n");
+ }
mutex_init(&dev->input_lock);
v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops);
@@ -413,7 +643,7 @@ static int gc0310_probe(struct i2c_client *client)
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev);
- ret = gc0310_s_config(&dev->sd);
+ ret = gc0310_detect(client);
if (ret) {
gc0310_remove(client);
return ret;
@@ -422,6 +652,7 @@ static int gc0310_probe(struct i2c_client *client)
dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ dev->sd.fwnode = dev->ep_fwnode;
ret = gc0310_init_controls(dev);
if (ret) {
@@ -435,8 +666,7 @@ static int gc0310_probe(struct i2c_client *client)
return ret;
}
- ret = atomisp_register_sensor_no_gmin(&dev->sd, 1, ATOMISP_INPUT_FORMAT_RAW_8,
- atomisp_bayer_order_grbg);
+ ret = v4l2_async_register_subdev_sensor(&dev->sd);
if (ret) {
gc0310_remove(client);
return ret;
@@ -471,7 +701,6 @@ static int gc0310_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, gc0310_suspend, gc0310_resume, NULL);
static const struct acpi_device_id gc0310_acpi_match[] = {
- {"XXGC0310"},
{"INT0310"},
{},
};
@@ -483,7 +712,7 @@ static struct i2c_driver gc0310_driver = {
.pm = pm_sleep_ptr(&gc0310_pm_ops),
.acpi_match_table = gc0310_acpi_match,
},
- .probe_new = gc0310_probe,
+ .probe = gc0310_probe,
.remove = gc0310_remove,
};
module_i2c_driver(gc0310_driver);
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index cb4c79b483ca..9fa390fbc5f3 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -864,7 +864,7 @@ static struct i2c_driver gc2235_driver = {
.name = "gc2235",
.acpi_match_table = gc2235_acpi_match,
},
- .probe_new = gc2235_probe,
+ .probe = gc2235_probe,
.remove = gc2235_remove,
};
module_i2c_driver(gc2235_driver);
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
index c4ce4cd445d7..cf5d9317b11a 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
@@ -945,7 +945,7 @@ static struct i2c_driver lm3554_driver = {
.pm = &lm3554_pm_ops,
.acpi_match_table = lm3554_acpi_match,
},
- .probe_new = lm3554_probe,
+ .probe = lm3554_probe,
.remove = lm3554_remove,
};
module_i2c_driver(lm3554_driver);
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index 0e5a981dd331..1c6643c442ef 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -1600,7 +1600,7 @@ static struct i2c_driver mt9m114_driver = {
.name = "mt9m114",
.acpi_match_table = mt9m114_acpi_match,
},
- .probe_new = mt9m114_probe,
+ .probe = mt9m114_probe,
.remove = mt9m114_remove,
};
module_i2c_driver(mt9m114_driver);
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
index c079368019e8..4cc2839937af 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
@@ -28,15 +28,13 @@
#include <media/ov_16bit_addr_reg_helpers.h>
#include <media/v4l2-device.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-
#include "ov2680.h"
-static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
- atomisp_bayer_order_bggr,
- atomisp_bayer_order_grbg,
- atomisp_bayer_order_gbrg,
- atomisp_bayer_order_rggb,
+static const struct v4l2_rect ov2680_default_crop = {
+ .left = OV2680_ACTIVE_START_LEFT,
+ .top = OV2680_ACTIVE_START_TOP,
+ .width = OV2680_ACTIVE_WIDTH,
+ .height = OV2680_ACTIVE_HEIGHT,
};
static int ov2680_write_reg_array(struct i2c_client *client,
@@ -54,7 +52,7 @@ static int ov2680_write_reg_array(struct i2c_client *client,
return 0;
}
-static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt)
+static void ov2680_set_bayer_order(struct ov2680_dev *sensor, struct v4l2_mbus_framefmt *fmt)
{
static const int ov2680_hv_flip_bayer_order[] = {
MEDIA_BUS_FMT_SBGGR10_1X10,
@@ -62,7 +60,6 @@ static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbu
MEDIA_BUS_FMT_SGBRG10_1X10,
MEDIA_BUS_FMT_SRGGB10_1X10,
};
- struct camera_mipi_info *ov2680_info;
int hv_flip = 0;
if (sensor->ctrls.vflip->val)
@@ -72,14 +69,9 @@ static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbu
hv_flip += 2;
fmt->code = ov2680_hv_flip_bayer_order[hv_flip];
-
- /* TODO atomisp specific custom API, should be removed */
- ov2680_info = v4l2_get_subdev_hostdata(&sensor->sd);
- if (ov2680_info)
- ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[hv_flip];
}
-static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val)
+static int ov2680_set_vflip(struct ov2680_dev *sensor, s32 val)
{
int ret;
@@ -94,7 +86,7 @@ static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val)
return 0;
}
-static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val)
+static int ov2680_set_hflip(struct ov2680_dev *sensor, s32 val)
{
int ret;
@@ -109,17 +101,17 @@ static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val)
return 0;
}
-static int ov2680_exposure_set(struct ov2680_device *sensor, u32 exp)
+static int ov2680_exposure_set(struct ov2680_dev *sensor, u32 exp)
{
return ov_write_reg24(sensor->client, OV2680_REG_EXPOSURE_PK_HIGH, exp << 4);
}
-static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain)
+static int ov2680_gain_set(struct ov2680_dev *sensor, u32 gain)
{
return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain);
}
-static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value)
+static int ov2680_test_pattern_set(struct ov2680_dev *sensor, int value)
{
int ret;
@@ -140,7 +132,7 @@ static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value)
static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
int ret;
/* Only apply changes to the controls if the device is powered up */
@@ -183,14 +175,17 @@ static int ov2680_init_registers(struct v4l2_subdev *sd)
int ret;
ret = ov_write_reg8(client, OV2680_SW_RESET, 0x01);
+
+ /* Wait for sensor reset */
+ usleep_range(1000, 2000);
+
ret |= ov2680_write_reg_array(client, ov2680_global_setting);
return ret;
}
static struct v4l2_mbus_framefmt *
-__ov2680_get_pad_format(struct ov2680_device *sensor,
- struct v4l2_subdev_state *state,
+__ov2680_get_pad_format(struct ov2680_dev *sensor, struct v4l2_subdev_state *state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
@@ -199,7 +194,17 @@ __ov2680_get_pad_format(struct ov2680_device *sensor,
return &sensor->mode.fmt;
}
-static void ov2680_fill_format(struct ov2680_device *sensor,
+static struct v4l2_rect *
+__ov2680_get_pad_crop(struct ov2680_dev *sensor, struct v4l2_subdev_state *state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(&sensor->sd, state, pad);
+
+ return &sensor->mode.crop;
+}
+
+static void ov2680_fill_format(struct ov2680_dev *sensor,
struct v4l2_mbus_framefmt *fmt,
unsigned int width, unsigned int height)
{
@@ -210,13 +215,15 @@ static void ov2680_fill_format(struct ov2680_device *sensor,
ov2680_set_bayer_order(sensor, fmt);
}
-static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height)
+static void ov2680_calc_mode(struct ov2680_dev *sensor)
{
+ int width = sensor->mode.fmt.width;
+ int height = sensor->mode.fmt.height;
int orig_width = width;
int orig_height = height;
- if (width <= (OV2680_NATIVE_WIDTH / 2) &&
- height <= (OV2680_NATIVE_HEIGHT / 2)) {
+ if (width <= (sensor->mode.crop.width / 2) &&
+ height <= (sensor->mode.crop.height / 2)) {
sensor->mode.binning = true;
width *= 2;
height *= 2;
@@ -224,8 +231,10 @@ static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height
sensor->mode.binning = false;
}
- sensor->mode.h_start = ((OV2680_NATIVE_WIDTH - width) / 2) & ~1;
- sensor->mode.v_start = ((OV2680_NATIVE_HEIGHT - height) / 2) & ~1;
+ sensor->mode.h_start =
+ (sensor->mode.crop.left + (sensor->mode.crop.width - width) / 2) & ~1;
+ sensor->mode.v_start =
+ (sensor->mode.crop.top + (sensor->mode.crop.height - height) / 2) & ~1;
sensor->mode.h_end = min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1,
OV2680_NATIVE_WIDTH - 1);
sensor->mode.v_end = min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1,
@@ -236,31 +245,25 @@ static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height
sensor->mode.vts = OV2680_LINES_PER_FRAME;
}
-static int ov2680_set_mode(struct ov2680_device *sensor)
+static int ov2680_set_mode(struct ov2680_dev *sensor)
{
struct i2c_client *client = sensor->client;
- u8 pll_div, unknown, inc, fmt1, fmt2;
+ u8 sensor_ctrl_0a, inc, fmt1, fmt2;
int ret;
if (sensor->mode.binning) {
- pll_div = 1;
- unknown = 0x23;
+ sensor_ctrl_0a = 0x23;
inc = 0x31;
fmt1 = 0xc2;
fmt2 = 0x01;
} else {
- pll_div = 0;
- unknown = 0x21;
+ sensor_ctrl_0a = 0x21;
inc = 0x11;
fmt1 = 0xc0;
fmt2 = 0x00;
}
- ret = ov_write_reg8(client, 0x3086, pll_div);
- if (ret)
- return ret;
-
- ret = ov_write_reg8(client, 0x370a, unknown);
+ ret = ov_write_reg8(client, OV2680_REG_SENSOR_CTRL_0A, sensor_ctrl_0a);
if (ret)
return ret;
@@ -337,12 +340,18 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
struct v4l2_mbus_framefmt *fmt;
+ const struct v4l2_rect *crop;
unsigned int width, height;
- width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH);
- height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT);
+ crop = __ov2680_get_pad_crop(sensor, sd_state, format->pad, format->which);
+
+ /* Limit set_fmt max size to crop width / height */
+ width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+ OV2680_MIN_CROP_WIDTH, crop->width);
+ height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+ OV2680_MIN_CROP_HEIGHT, crop->height);
fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which);
ov2680_fill_format(sensor, fmt, width, height);
@@ -352,9 +361,9 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- mutex_lock(&sensor->input_lock);
- ov2680_calc_mode(sensor, fmt->width, fmt->height);
- mutex_unlock(&sensor->input_lock);
+ mutex_lock(&sensor->lock);
+ ov2680_calc_mode(sensor);
+ mutex_unlock(&sensor->lock);
return 0;
}
@@ -362,7 +371,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
struct v4l2_mbus_framefmt *fmt;
fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which);
@@ -370,6 +379,105 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
return 0;
}
+static int ov2680_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ mutex_lock(&sensor->lock);
+ sel->r = *__ov2680_get_pad_crop(sensor, state, sel->pad, sel->which);
+ mutex_unlock(&sensor->lock);
+ break;
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV2680_NATIVE_WIDTH;
+ sel->r.height = OV2680_NATIVE_HEIGHT;
+ break;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = OV2680_ACTIVE_START_TOP;
+ sel->r.left = OV2680_ACTIVE_START_LEFT;
+ sel->r.width = OV2680_ACTIVE_WIDTH;
+ sel->r.height = OV2680_ACTIVE_HEIGHT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ov2680_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *__crop;
+ struct v4l2_rect rect;
+
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ /*
+ * Clamp the boundaries of the crop rectangle to the size of the sensor
+ * pixel array. Align to multiples of 2 to ensure Bayer pattern isn't
+ * disrupted.
+ */
+ rect.left = clamp(ALIGN(sel->r.left, 2), OV2680_NATIVE_START_LEFT,
+ OV2680_NATIVE_WIDTH);
+ rect.top = clamp(ALIGN(sel->r.top, 2), OV2680_NATIVE_START_TOP,
+ OV2680_NATIVE_HEIGHT);
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
+ OV2680_MIN_CROP_WIDTH, OV2680_NATIVE_WIDTH);
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
+ OV2680_MIN_CROP_HEIGHT, OV2680_NATIVE_HEIGHT);
+
+ /* Make sure the crop rectangle isn't outside the bounds of the array */
+ rect.width = min_t(unsigned int, rect.width,
+ OV2680_NATIVE_WIDTH - rect.left);
+ rect.height = min_t(unsigned int, rect.height,
+ OV2680_NATIVE_HEIGHT - rect.top);
+
+ __crop = __ov2680_get_pad_crop(sensor, state, sel->pad, sel->which);
+
+ if (rect.width != __crop->width || rect.height != __crop->height) {
+ /*
+ * Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ format = __ov2680_get_pad_format(sensor, state, sel->pad, sel->which);
+ format->width = rect.width;
+ format->height = rect.height;
+ }
+
+ *__crop = rect;
+ sel->r = rect;
+
+ return 0;
+}
+
+static int ov2680_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
+ .format = {
+ .width = 800,
+ .height = 600,
+ },
+ };
+
+ sd_state->pads[0].try_crop = ov2680_default_crop;
+
+ return ov2680_set_fmt(sd, sd_state, &fmt);
+}
+
static int ov2680_detect(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
@@ -405,11 +513,11 @@ static int ov2680_detect(struct i2c_client *client)
static int ov2680_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
- mutex_lock(&sensor->input_lock);
+ mutex_lock(&sensor->lock);
if (sensor->is_streaming == enable) {
dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped");
@@ -442,14 +550,14 @@ static int ov2680_s_stream(struct v4l2_subdev *sd, int enable)
v4l2_ctrl_activate(sensor->ctrls.vflip, !enable);
v4l2_ctrl_activate(sensor->ctrls.hflip, !enable);
- mutex_unlock(&sensor->input_lock);
+ mutex_unlock(&sensor->lock);
return 0;
error_power_down:
pm_runtime_put(sensor->sd.dev);
sensor->is_streaming = false;
error_unlock:
- mutex_unlock(&sensor->input_lock);
+ mutex_unlock(&sensor->lock);
return ret;
}
@@ -550,11 +658,14 @@ static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = {
};
static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
+ .init_cfg = ov2680_init_cfg,
.enum_mbus_code = ov2680_enum_mbus_code,
.enum_frame_size = ov2680_enum_frame_size,
.enum_frame_interval = ov2680_enum_frame_interval,
.get_fmt = ov2680_get_fmt,
.set_fmt = ov2680_set_fmt,
+ .get_selection = ov2680_get_selection,
+ .set_selection = ov2680_set_selection,
};
static const struct v4l2_subdev_ops ov2680_ops = {
@@ -563,7 +674,7 @@ static const struct v4l2_subdev_ops ov2680_ops = {
.sensor = &ov2680_sensor_ops,
};
-static int ov2680_init_controls(struct ov2680_device *sensor)
+static int ov2680_init_controls(struct ov2680_dev *sensor)
{
static const char * const test_pattern_menu[] = {
"Disabled",
@@ -579,7 +690,7 @@ static int ov2680_init_controls(struct ov2680_device *sensor)
v4l2_ctrl_handler_init(hdl, 4);
- hdl->lock = &sensor->input_lock;
+ hdl->lock = &sensor->lock;
ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
@@ -605,39 +716,46 @@ static int ov2680_init_controls(struct ov2680_device *sensor)
static void ov2680_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
dev_dbg(&client->dev, "ov2680_remove...\n");
- atomisp_unregister_subdev(sd);
- v4l2_device_unregister_subdev(sd);
+ v4l2_async_unregister_subdev(&sensor->sd);
media_entity_cleanup(&sensor->sd.entity);
v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+ mutex_destroy(&sensor->lock);
+ fwnode_handle_put(sensor->ep_fwnode);
pm_runtime_disable(&client->dev);
}
static int ov2680_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
- struct ov2680_device *sensor;
+ struct ov2680_dev *sensor;
int ret;
sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return -ENOMEM;
- mutex_init(&sensor->input_lock);
+ mutex_init(&sensor->lock);
sensor->client = client;
v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops);
- ret = v4l2_get_acpi_sensor_info(dev, NULL);
- if (ret)
- return ret;
+ /*
+ * Sometimes the fwnode graph is initialized by the bridge driver.
+ * Bridge drivers doing this may also add GPIO mappings, wait for this.
+ */
+ sensor->ep_fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!sensor->ep_fwnode)
+ return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n");
sensor->powerdown = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
- if (IS_ERR(sensor->powerdown))
+ if (IS_ERR(sensor->powerdown)) {
+ fwnode_handle_put(sensor->ep_fwnode);
return dev_err_probe(dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n");
+ }
pm_runtime_set_suspended(dev);
pm_runtime_enable(dev);
@@ -653,6 +771,7 @@ static int ov2680_probe(struct i2c_client *client)
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ sensor->sd.fwnode = sensor->ep_fwnode;
ret = ov2680_init_controls(sensor);
if (ret) {
@@ -666,10 +785,11 @@ static int ov2680_probe(struct i2c_client *client)
return ret;
}
+ sensor->mode.crop = ov2680_default_crop;
ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT);
+ ov2680_calc_mode(sensor);
- ret = atomisp_register_sensor_no_gmin(&sensor->sd, 1, ATOMISP_INPUT_FORMAT_RAW_10,
- atomisp_bayer_order_bggr);
+ ret = v4l2_async_register_subdev_sensor(&sensor->sd);
if (ret) {
ov2680_remove(client);
return ret;
@@ -681,7 +801,7 @@ static int ov2680_probe(struct i2c_client *client)
static int ov2680_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
gpiod_set_value_cansleep(sensor->powerdown, 1);
return 0;
@@ -690,7 +810,7 @@ static int ov2680_suspend(struct device *dev)
static int ov2680_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct ov2680_dev *sensor = to_ov2680_sensor(sd);
/* according to DS, at least 5ms is needed after DOVDD (enabled by ACPI) */
usleep_range(5000, 6000);
@@ -719,7 +839,7 @@ static struct i2c_driver ov2680_driver = {
.pm = pm_sleep_ptr(&ov2680_pm_ops),
.acpi_match_table = ov2680_acpi_match,
},
- .probe_new = ov2680_probe,
+ .probe = ov2680_probe,
.remove = ov2680_remove,
};
module_i2c_driver(ov2680_driver);
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 5d2e6e2e72f0..6a72691ed5b7 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -1019,7 +1019,7 @@ static struct i2c_driver ov2722_driver = {
.name = "ov2722",
.acpi_match_table = ov2722_acpi_match,
},
- .probe_new = ov2722_probe,
+ .probe = ov2722_probe,
.remove = ov2722_remove,
};
module_i2c_driver(ov2722_driver);
diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h
deleted file mode 100644
index d40406289598..000000000000
--- a/drivers/staging/media/atomisp/i2c/gc0310.h
+++ /dev/null
@@ -1,309 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for GalaxyCore GC0310 VGA camera sensor.
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- */
-
-#ifndef __GC0310_H__
-#define __GC0310_H__
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <linux/spinlock.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <linux/v4l2-mediabus.h>
-#include <media/media-entity.h>
-
-#include "../include/linux/atomisp_platform.h"
-
-#define GC0310_NATIVE_WIDTH 656
-#define GC0310_NATIVE_HEIGHT 496
-
-#define GC0310_FPS 30
-#define GC0310_SKIP_FRAMES 3
-
-#define GC0310_FOCAL_LENGTH_NUM 278 /* 2.78mm */
-
-#define GC0310_ID 0xa310
-
-#define GC0310_RESET_RELATED 0xFE
-#define GC0310_REGISTER_PAGE_0 0x0
-#define GC0310_REGISTER_PAGE_3 0x3
-
-#define GC0310_FINE_INTG_TIME_MIN 0
-#define GC0310_FINE_INTG_TIME_MAX_MARGIN 0
-#define GC0310_COARSE_INTG_TIME_MIN 1
-#define GC0310_COARSE_INTG_TIME_MAX_MARGIN 6
-
-/*
- * GC0310 System control registers
- */
-#define GC0310_SW_STREAM 0x10
-
-#define GC0310_SC_CMMN_CHIP_ID_H 0xf0
-#define GC0310_SC_CMMN_CHIP_ID_L 0xf1
-
-#define GC0310_AEC_PK_EXPO_H 0x03
-#define GC0310_AEC_PK_EXPO_L 0x04
-#define GC0310_AGC_ADJ 0x48
-#define GC0310_DGC_ADJ 0x71
-#if 0
-#define GC0310_GROUP_ACCESS 0x3208
-#endif
-
-#define GC0310_H_CROP_START_H 0x09
-#define GC0310_H_CROP_START_L 0x0A
-#define GC0310_V_CROP_START_H 0x0B
-#define GC0310_V_CROP_START_L 0x0C
-#define GC0310_H_OUTSIZE_H 0x0F
-#define GC0310_H_OUTSIZE_L 0x10
-#define GC0310_V_OUTSIZE_H 0x0D
-#define GC0310_V_OUTSIZE_L 0x0E
-#define GC0310_H_BLANKING_H 0x05
-#define GC0310_H_BLANKING_L 0x06
-#define GC0310_V_BLANKING_H 0x07
-#define GC0310_V_BLANKING_L 0x08
-#define GC0310_SH_DELAY 0x11
-
-#define GC0310_START_STREAMING 0x94 /* 8-bit enable */
-#define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */
-
-/*
- * gc0310 device structure.
- */
-struct gc0310_device {
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct mutex input_lock;
- bool is_streaming;
-
- struct gpio_desc *reset;
- struct gpio_desc *powerdown;
-
- struct gc0310_mode {
- struct v4l2_mbus_framefmt fmt;
- } mode;
-
- struct gc0310_ctrls {
- struct v4l2_ctrl_handler handler;
- struct v4l2_ctrl *exposure;
- struct v4l2_ctrl *gain;
- } ctrls;
-};
-
-/**
- * struct gc0310_reg - MI sensor register format
- * @reg: 16-bit offset to register
- * @val: 8/16/32-bit register value
- *
- * Define a structure for sensor register initialization values
- */
-struct gc0310_reg {
- u8 reg;
- u8 val; /* @set value for read/mod/write, @mask */
-};
-
-#define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd)
-
-/*
- * Register settings for various resolution
- */
-static const struct gc0310_reg gc0310_reset_register[] = {
-/////////////////////////////////////////////////
-///////////////// system reg /////////////////
-/////////////////////////////////////////////////
- { 0xfe, 0xf0 },
- { 0xfe, 0xf0 },
- { 0xfe, 0x00 },
-
- { 0xfc, 0x0e }, /* 4e */
- { 0xfc, 0x0e }, /* 16//4e // [0]apwd [6]regf_clk_gate */
- { 0xf2, 0x80 }, /* sync output */
- { 0xf3, 0x00 }, /* 1f//01 data output */
- { 0xf7, 0x33 }, /* f9 */
- { 0xf8, 0x05 }, /* 00 */
- { 0xf9, 0x0e }, /* 0x8e //0f */
- { 0xfa, 0x11 },
-
-/////////////////////////////////////////////////
-/////////////////// MIPI ////////////////////
-/////////////////////////////////////////////////
- { 0xfe, 0x03 },
- { 0x01, 0x03 }, /* mipi 1lane */
- { 0x02, 0x22 }, /* 0x33 */
- { 0x03, 0x94 },
- { 0x04, 0x01 }, /* fifo_prog */
- { 0x05, 0x00 }, /* fifo_prog */
- { 0x06, 0x80 }, /* b0 //YUV ISP data */
- { 0x11, 0x2a }, /* 1e //LDI set YUV422 */
- { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */
- { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */
- { 0x15, 0x12 }, /* 0x10 //DPHYY_MODE read_ready */
- { 0x17, 0x01 },
- { 0x40, 0x08 },
- { 0x41, 0x00 },
- { 0x42, 0x00 },
- { 0x43, 0x00 },
- { 0x21, 0x02 }, /* 0x01 */
- { 0x22, 0x02 }, /* 0x01 */
- { 0x23, 0x01 }, /* 0x05 //Nor:0x05 DOU:0x06 */
- { 0x29, 0x00 },
- { 0x2A, 0x25 }, /* 0x05 //data zero 0x7a de */
- { 0x2B, 0x02 },
-
- { 0xfe, 0x00 },
-
-/////////////////////////////////////////////////
-///////////////// CISCTL reg /////////////////
-/////////////////////////////////////////////////
- { 0x00, 0x2f }, /* 2f//0f//02//01 */
- { 0x01, 0x0f }, /* 06 */
- { 0x02, 0x04 },
- { 0x4f, 0x00 }, /* AEC 0FF */
- { 0x03, 0x01 }, /* 0x03 //04 */
- { 0x04, 0xc0 }, /* 0xe8 //58 */
- { 0x05, 0x00 },
- { 0x06, 0xb2 }, /* 0x0a //HB */
- { 0x07, 0x00 },
- { 0x08, 0x0c }, /* 0x89 //VB */
- { 0x09, 0x00 }, /* row start */
- { 0x0a, 0x00 },
- { 0x0b, 0x00 }, /* col start */
- { 0x0c, 0x00 },
- { 0x0d, 0x01 }, /* height */
- { 0x0e, 0xf2 }, /* 0xf7 //height */
- { 0x0f, 0x02 }, /* width */
- { 0x10, 0x94 }, /* 0xa0 //height */
- { 0x17, 0x14 },
- { 0x18, 0x1a }, /* 0a//[4]double reset */
- { 0x19, 0x14 }, /* AD pipeline */
- { 0x1b, 0x48 },
- { 0x1e, 0x6b }, /* 3b//col bias */
- { 0x1f, 0x28 }, /* 20//00//08//txlow */
- { 0x20, 0x89 }, /* 88//0c//[3:2]DA15 */
- { 0x21, 0x49 }, /* 48//[3] txhigh */
- { 0x22, 0xb0 },
- { 0x23, 0x04 }, /* [1:0]vcm_r */
- { 0x24, 0x16 }, /* 15 */
- { 0x34, 0x20 }, /* [6:4] rsg high//range */
-
-/////////////////////////////////////////////////
-//////////////////// BLK ////////////////////
-/////////////////////////////////////////////////
- { 0x26, 0x23 }, /* [1]dark_current_en [0]offset_en */
- { 0x28, 0xff }, /* BLK_limie_value */
- { 0x29, 0x00 }, /* global offset */
- { 0x33, 0x18 }, /* offset_ratio */
- { 0x37, 0x20 }, /* dark_current_ratio */
- { 0x2a, 0x00 },
- { 0x2b, 0x00 },
- { 0x2c, 0x00 },
- { 0x2d, 0x00 },
- { 0x2e, 0x00 },
- { 0x2f, 0x00 },
- { 0x30, 0x00 },
- { 0x31, 0x00 },
- { 0x47, 0x80 }, /* a7 */
- { 0x4e, 0x66 }, /* select_row */
- { 0xa8, 0x02 }, /* win_width_dark, same with crop_win_width */
- { 0xa9, 0x80 },
-
-/////////////////////////////////////////////////
-////////////////// ISP reg ///////////////////
-/////////////////////////////////////////////////
- { 0x40, 0x06 }, /* 0xff //ff //48 */
- { 0x41, 0x00 }, /* 0x21 //00//[0]curve_en */
- { 0x42, 0x04 }, /* 0xcf //0a//[1]awn_en */
- { 0x44, 0x18 }, /* 0x18 //02 */
- { 0x46, 0x02 }, /* 0x03 //sync */
- { 0x49, 0x03 },
- { 0x4c, 0x20 }, /* 00[5]pretect exp */
- { 0x50, 0x01 }, /* crop enable */
- { 0x51, 0x00 },
- { 0x52, 0x00 },
- { 0x53, 0x00 },
- { 0x54, 0x01 },
- { 0x55, 0x01 }, /* crop window height */
- { 0x56, 0xf0 },
- { 0x57, 0x02 }, /* crop window width */
- { 0x58, 0x90 },
-
-/////////////////////////////////////////////////
-/////////////////// GAIN ////////////////////
-/////////////////////////////////////////////////
- { 0x70, 0x70 }, /* 70 //80//global gain */
- { 0x71, 0x20 }, /* pregain gain */
- { 0x72, 0x40 }, /* post gain */
- { 0x5a, 0x84 }, /* 84//analog gain 0 */
- { 0x5b, 0xc9 }, /* c9 */
- { 0x5c, 0xed }, /* ed//not use pga gain highest level */
- { 0x77, 0x40 }, /* R gain 0x74 //awb gain */
- { 0x78, 0x40 }, /* G gain */
- { 0x79, 0x40 }, /* B gain 0x5f */
-
- { 0x48, 0x00 },
- { 0xfe, 0x01 },
- { 0x0a, 0x45 }, /* [7]col gain mode */
-
- { 0x3e, 0x40 },
- { 0x3f, 0x5c },
- { 0x40, 0x7b },
- { 0x41, 0xbd },
- { 0x42, 0xf6 },
- { 0x43, 0x63 },
- { 0x03, 0x60 },
- { 0x44, 0x03 },
-
-/////////////////////////////////////////////////
-///////////////// dark sun //////////////////
-/////////////////////////////////////////////////
- { 0xfe, 0x01 },
- { 0x45, 0xa4 }, /* 0xf7 */
- { 0x46, 0xf0 }, /* 0xff //f0//sun value th */
- { 0x48, 0x03 }, /* sun mode */
- { 0x4f, 0x60 }, /* sun_clamp */
- { 0xfe, 0x00 },
-};
-
-static struct gc0310_reg const gc0310_VGA_30fps[] = {
- { 0xfe, 0x00 },
- { 0x0d, 0x01 }, /* height */
- { 0x0e, 0xf2 }, /* 0xf7 //height */
- { 0x0f, 0x02 }, /* width */
- { 0x10, 0x94 }, /* 0xa0 //height */
-
- { 0x50, 0x01 }, /* crop enable */
- { 0x51, 0x00 },
- { 0x52, 0x00 },
- { 0x53, 0x00 },
- { 0x54, 0x01 },
- { 0x55, 0x01 }, /* crop window height */
- { 0x56, 0xf0 },
- { 0x57, 0x02 }, /* crop window width */
- { 0x58, 0x90 },
-
- { 0xfe, 0x03 },
- { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */
- { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */
-
- { 0xfe, 0x00 },
-};
-
-#endif
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h
index baf49eb0659e..d032af245674 100644
--- a/drivers/staging/media/atomisp/i2c/ov2680.h
+++ b/drivers/staging/media/atomisp/i2c/ov2680.h
@@ -30,10 +30,16 @@
#include <linux/v4l2-mediabus.h>
#include <media/media-entity.h>
-#include "../include/linux/atomisp_platform.h"
-
#define OV2680_NATIVE_WIDTH 1616
#define OV2680_NATIVE_HEIGHT 1216
+#define OV2680_NATIVE_START_LEFT 0
+#define OV2680_NATIVE_START_TOP 0
+#define OV2680_ACTIVE_WIDTH 1600
+#define OV2680_ACTIVE_HEIGHT 1200
+#define OV2680_ACTIVE_START_LEFT 8
+#define OV2680_ACTIVE_START_TOP 8
+#define OV2680_MIN_CROP_WIDTH 2
+#define OV2680_MIN_CROP_HEIGHT 2
/* 1704 * 1294 * 30fps = 66MHz pixel clock */
#define OV2680_PIXELS_PER_LINE 1704
@@ -66,6 +72,8 @@
#define OV2680_REG_EXPOSURE_PK_HIGH 0x3500
#define OV2680_REG_GAIN_PK 0x350a
+#define OV2680_REG_SENSOR_CTRL_0A 0x370a
+
#define OV2680_HORIZONTAL_START_H 0x3800 /* Bit[11:8] */
#define OV2680_HORIZONTAL_START_L 0x3801 /* Bit[7:0] */
#define OV2680_VERTICAL_START_H 0x3802 /* Bit[11:8] */
@@ -108,15 +116,18 @@
/*
* ov2680 device structure.
*/
-struct ov2680_device {
+struct ov2680_dev {
struct v4l2_subdev sd;
struct media_pad pad;
- struct mutex input_lock;
+ /* Protect against concurrent changes to controls */
+ struct mutex lock;
struct i2c_client *client;
struct gpio_desc *powerdown;
+ struct fwnode_handle *ep_fwnode;
bool is_streaming;
struct ov2680_mode {
+ struct v4l2_rect crop;
struct v4l2_mbus_framefmt fmt;
bool binning;
u16 h_start;
@@ -152,92 +163,86 @@ struct ov2680_reg {
u32 val; /* @set value for read/mod/write, @mask */
};
-#define to_ov2680_sensor(x) container_of(x, struct ov2680_device, sd)
+#define to_ov2680_sensor(x) container_of(x, struct ov2680_dev, sd)
static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
{
- struct ov2680_device *sensor =
- container_of(ctrl->handler, struct ov2680_device, ctrls.handler);
+ struct ov2680_dev *sensor =
+ container_of(ctrl->handler, struct ov2680_dev, ctrls.handler);
return &sensor->sd;
}
static struct ov2680_reg const ov2680_global_setting[] = {
- {0x0103, 0x01},
- {0x3002, 0x00},
+ /* MIPI PHY, 0x10 -> 0x1c enable bp_c_hs_en_lat and bp_d_hs_en_lat */
{0x3016, 0x1c},
- {0x3018, 0x44},
- {0x3020, 0x00},
- {0x3080, 0x02},
+
+ /* PLL MULT bits 0-7, datasheet default 0x37 for 24MHz extclk, use 0x45 for 19.2 Mhz extclk */
{0x3082, 0x45},
- {0x3084, 0x09},
- {0x3085, 0x04},
+
+ /* R MANUAL set exposure (0x01) and gain (0x02) to manual (hw does not do auto) */
{0x3503, 0x03},
- {0x350b, 0x36},
- {0x3600, 0xb4},
- {0x3603, 0x39},
- {0x3604, 0x24},
- {0x3605, 0x00},
- {0x3620, 0x26},
- {0x3621, 0x37},
- {0x3622, 0x04},
- {0x3628, 0x00},
- {0x3705, 0x3c},
- {0x370c, 0x50},
- {0x370d, 0xc0},
- {0x3718, 0x88},
- {0x3720, 0x00},
- {0x3721, 0x00},
- {0x3722, 0x00},
- {0x3723, 0x00},
- {0x3738, 0x00},
- {0x3717, 0x58},
- {0x3781, 0x80},
- {0x3789, 0x60},
- {0x3800, 0x00},
- {0x3819, 0x04},
+
+ /* Analog control register tweaks */
+ {0x3603, 0x39}, /* Reset value 0x99 */
+ {0x3604, 0x24}, /* Reset value 0x74 */
+ {0x3621, 0x37}, /* Reset value 0x44 */
+
+ /* Sensor control register tweaks */
+ {0x3701, 0x64}, /* Reset value 0x61 */
+ {0x3705, 0x3c}, /* Reset value 0x21 */
+ {0x370c, 0x50}, /* Reset value 0x10 */
+ {0x370d, 0xc0}, /* Reset value 0x00 */
+ {0x3718, 0x88}, /* Reset value 0x80 */
+
+ /* PSRAM tweaks */
+ {0x3781, 0x80}, /* Reset value 0x00 */
+ {0x3784, 0x0c}, /* Reset value 0x00, based on OV2680_R1A_AM10.ovt */
+ {0x3789, 0x60}, /* Reset value 0x50 */
+
+ /* BLC CTRL00 0x01 -> 0x81 set avg_weight to 8 */
{0x4000, 0x81},
- {0x4001, 0x40},
+
+ /* Set black level compensation range to 0 - 3 (default 0 - 11) */
{0x4008, 0x00},
{0x4009, 0x03},
+
+ /* VFIFO R2 0x00 -> 0x02 set Frame reset enable */
{0x4602, 0x02},
+
+ /* MIPI ctrl CLK PREPARE MIN change from 0x26 (38) -> 0x36 (54) */
{0x481f, 0x36},
+
+ /* MIPI ctrl CLK LPX P MIN change from 0x32 (50) -> 0x36 (54) */
{0x4825, 0x36},
- {0x4837, 0x18},
+
+ /* R ISP CTRL2 0x20 -> 0x30, set sof_sel bit */
{0x5002, 0x30},
- {0x5004, 0x04},//manual awb 1x
- {0x5005, 0x00},
- {0x5006, 0x04},
- {0x5007, 0x00},
- {0x5008, 0x04},
- {0x5009, 0x00},
- {0x5080, 0x00},
- {0x5081, 0x41},
- {0x5708, 0x01}, /* add for full size flip off and mirror off 2014/09/11 */
- {0x3701, 0x64}, //add on 14/05/13
- {0x3784, 0x0c}, //based OV2680_R1A_AM10.ovt add on 14/06/13
- {0x5780, 0x3e}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13
- {0x5781, 0x0f},
- {0x5782, 0x04},
- {0x5783, 0x02},
- {0x5784, 0x01},
- {0x5785, 0x01},
- {0x5786, 0x00},
- {0x5787, 0x04},
+
+ /*
+ * Window CONTROL 0x00 -> 0x01, enable manual window control,
+ * this is necessary for full size flip and mirror support.
+ */
+ {0x5708, 0x01},
+
+ /*
+ * DPC CTRL0 0x14 -> 0x3e, set enable_tail, enable_3x3_cluster
+ * and enable_general_tail bits based OV2680_R1A_AM10.ovt.
+ */
+ {0x5780, 0x3e},
+
+ /* DPC MORE CONNECTION CASE THRE 0x0c (12) -> 0x02 (2) */
{0x5788, 0x02},
- {0x5789, 0x00},
- {0x578a, 0x01},
- {0x578b, 0x02},
- {0x578c, 0x03},
- {0x578d, 0x03},
+
+ /* DPC GAIN LIST1 0x0f (15) -> 0x08 (8) */
{0x578e, 0x08},
+
+ /* DPC GAIN LIST2 0x3f (63) -> 0x0c (12) */
{0x578f, 0x0c},
- {0x5790, 0x08},
- {0x5791, 0x04},
+
+ /* DPC THRE RATIO 0x04 (4) -> 0x00 (0) */
{0x5792, 0x00},
- {0x5793, 0x00},
- {0x5794, 0x03}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13
- {0x0100, 0x00}, //stream off
+
{}
};
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
index da8c3b1d3bcd..460a4e34c55b 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
+++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
@@ -726,51 +726,11 @@ static void *ov5693_otp_read(struct v4l2_subdev *sd)
return buf;
}
-static int ov5693_g_priv_int_data(struct v4l2_subdev *sd,
- struct v4l2_private_int_data *priv)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5693_device *dev = to_ov5693_sensor(sd);
- u8 __user *to = priv->data;
- u32 read_size = priv->size;
- int ret;
-
- /* No need to copy data if size is 0 */
- if (!read_size)
- goto out;
-
- if (IS_ERR(dev->otp_data)) {
- dev_err(&client->dev, "OTP data not available");
- return PTR_ERR(dev->otp_data);
- }
-
- /* Correct read_size value only if bigger than maximum */
- if (read_size > OV5693_OTP_DATA_SIZE)
- read_size = OV5693_OTP_DATA_SIZE;
-
- ret = copy_to_user(to, dev->otp_data, read_size);
- if (ret) {
- dev_err(&client->dev, "%s: failed to copy OTP data to user\n",
- __func__);
- return -EFAULT;
- }
-
- pr_debug("%s read_size:%d\n", __func__, read_size);
-
-out:
- /* Return correct size */
- priv->size = dev->otp_size;
-
- return 0;
-}
-
static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
switch (cmd) {
case ATOMISP_IOC_S_EXPOSURE:
return ov5693_s_exposure(sd, arg);
- case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
- return ov5693_g_priv_int_data(sd, arg);
default:
return -EINVAL;
}
@@ -1794,7 +1754,7 @@ static struct i2c_driver ov5693_driver = {
.name = "ov5693",
.acpi_match_table = ov5693_acpi_match,
},
- .probe_new = ov5693_probe,
+ .probe = ov5693_probe,
.remove = ov5693_remove,
};
module_i2c_driver(ov5693_driver);