summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/soc_camera
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/soc_camera')
-rw-r--r--drivers/media/i2c/soc_camera/Kconfig18
-rw-r--r--drivers/media/i2c/soc_camera/Makefile3
-rw-r--r--drivers/media/i2c/soc_camera/adv7280.c834
-rw-r--r--drivers/media/i2c/soc_camera/ap1302.c558
-rw-r--r--drivers/media/i2c/soc_camera/ov5640.c1842
-rw-r--r--drivers/media/i2c/soc_camera/tc358743.c1104
6 files changed, 3334 insertions, 1025 deletions
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig
index 4e8b50bf64ec..085553dc2d00 100644
--- a/drivers/media/i2c/soc_camera/Kconfig
+++ b/drivers/media/i2c/soc_camera/Kconfig
@@ -12,6 +12,12 @@ config SOC_CAMERA_AR0330
help
This driver supports AR0330 camera from Aptina
+config SOC_CAMERA_AP1302
+ tristate "AP1302 ISP support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports AP1302 ISP from Aptina
+
config SOC_CAMERA_IMX074
tristate "imx074 support"
depends on SOC_CAMERA && I2C
@@ -115,3 +121,15 @@ config SOC_CAMERA_TW9910
depends on SOC_CAMERA && I2C
help
This is a tw9910 video driver
+
+config SOC_CAMERA_TC358743
+ tristate "tc358743 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a tc358743 video driver
+
+config SOC_CAMERA_ADV7280
+ tristate "adv7280m support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a adv7280 video decoder driver
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
index faea5137dc83..9bf568334d84 100644
--- a/drivers/media/i2c/soc_camera/Makefile
+++ b/drivers/media/i2c/soc_camera/Makefile
@@ -17,3 +17,6 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
+obj-$(CONFIG_SOC_CAMERA_AP1302) += ap1302.o
+obj-$(CONFIG_SOC_CAMERA_TC358743) += tc358743.o
+obj-$(CONFIG_SOC_CAMERA_ADV7280) += adv7280.o
diff --git a/drivers/media/i2c/soc_camera/adv7280.c b/drivers/media/i2c/soc_camera/adv7280.c
new file mode 100644
index 000000000000..d5e7391b6b75
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/adv7280.c
@@ -0,0 +1,834 @@
+/*
+ * ADV7280 camera decoder driver, based on ADV7180 driver
+ *
+ * Copyright (c) 2014 Antmicro Ltd <www.antmicro.com>
+ * Based on ADV7180 video decoder driver,
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define DRIVER_NAME "adv7280"
+
+#define HW_DEINT /* Enable hardware deinterlacer */
+#define CSI
+#define VPP_SLAVE_ADDRESS 0x42
+#define CSI_SLAVE_ADDRESS 0x44
+
+/* User Sub Map Regs */
+#define ADV7280_INPUT_CONTROL 0x00
+#define ADV7280_VIDEO_SELECTION_1 0x01
+#define ADV7280_VIDEO_SELECTION_2 0x02
+#define ADV7280_OUTPUT_CONTROL 0x03
+#define ADV7280_EXTENDED_OUTPUT_CONTROL 0x04
+#define ADV7280_AUTODETECT_ENABLE 0x07
+#define ADV7280_ADI_CONTROL_1 0x0E
+#define ADV7280_POWER_MANAGEMENT 0x0F
+#define ADV7280_STATUS_1 0x10
+#define ADV7280_IDENT 0x11
+#define ADV7280_SHAPING_FILTER_CONTROL_1 0x17
+#define ADV7280_ADI_CONTROL_2 0x1D
+#define ADV7280_PIXEL_DELAY_CONTROL 0x27
+#define ADV7280_VPP_SLAVE_ADDRESS 0xFD
+#define ADV7280_CSI_TX_SLAVE_ADDRESS 0xFE
+#define ADV7280_OUTPUT_SYNC_SELECT_2 0x6B
+
+/* VPP regs (Video Postprocessor) */
+#define VPP_DEINT_RESET 0x41
+#define VPP_I2C_DEINT_ENABLE 0x55
+#define VPP_ADV_TIMING_MODE_EN 0x5B
+
+/* CSI regs (Camera Serial Interface, MIPI-CSI2) */
+#define CSI_CSITX_PWRDN 0x00
+#define CSI_DPHY_PWRDN_CTL 0xDE
+
+/* other */
+#define ADV7280_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
+#define ADV7280_AUTODETECT_DEFAULT 0x7f
+
+#define ADV7280_INPUT_CONTROL_COMPOSITE_IN1 0x00
+#define ADV7280_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
+
+#define ADV7280_INPUT_CONTROL_NTSC_M 0x50
+#define ADV7280_INPUT_CONTROL_PAL60 0x60
+#define ADV7280_INPUT_CONTROL_NTSC_443 0x70
+#define ADV7280_INPUT_CONTROL_PAL_BG 0x80
+#define ADV7280_INPUT_CONTROL_PAL_N 0x90
+#define ADV7280_INPUT_CONTROL_PAL_M 0xa0
+#define ADV7280_INPUT_CONTROL_PAL_M_PED 0xb0
+#define ADV7280_INPUT_CONTROL_PAL_COMB_N 0xc0
+#define ADV7280_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
+#define ADV7280_INPUT_CONTROL_PAL_SECAM 0xe0
+
+#define ADV7280_ADI_CTRL_IRQ_SPACE 0x20
+
+#define ADV7280_STATUS1_IN_LOCK 0x01
+#define ADV7280_STATUS1_AUTOD_MASK 0x70
+#define ADV7280_STATUS1_AUTOD_NTSM_M_J 0x00
+#define ADV7280_STATUS1_AUTOD_NTSC_4_43 0x10
+#define ADV7280_STATUS1_AUTOD_PAL_M 0x20
+#define ADV7280_STATUS1_AUTOD_PAL_60 0x30
+#define ADV7280_STATUS1_AUTOD_PAL_B_G 0x40
+#define ADV7280_STATUS1_AUTOD_SECAM 0x50
+#define ADV7280_STATUS1_AUTOD_PAL_COMB 0x60
+#define ADV7280_STATUS1_AUTOD_SECAM_525 0x70
+
+#define ADV7280_ICONF1_ADI 0x40
+#define ADV7280_ICONF1_ACTIVE_LOW 0x01
+#define ADV7280_ICONF1_PSYNC_ONLY 0x10
+
+#define ADV7280_IMR1_ADI 0x44
+#define ADV7280_IMR2_ADI 0x48
+#define ADV7280_IRQ3_AD_CHANGE 0x08
+#define ADV7280_ISR3_ADI 0x4A
+#define ADV7280_ICR3_ADI 0x4B
+#define ADV7280_IMR3_ADI 0x4C
+#define ADV7280_IMR4_ADI 0x50
+
+struct adv7280_state {
+ struct v4l2_subdev sd;
+ struct work_struct work;
+ struct mutex mutex; /* mutual excl. when accessing chip */
+ int irq;
+ v4l2_std_id curr_norm;
+ bool autodetect;
+ int active_input;
+};
+
+static v4l2_std_id adv7280_std_to_v4l2(u8 status1)
+{
+ switch (status1 & ADV7280_STATUS1_AUTOD_MASK) {
+ case ADV7280_STATUS1_AUTOD_NTSM_M_J:
+ return V4L2_STD_NTSC;
+ case ADV7280_STATUS1_AUTOD_NTSC_4_43:
+ return V4L2_STD_NTSC_443;
+ case ADV7280_STATUS1_AUTOD_PAL_M:
+ return V4L2_STD_PAL_M;
+ case ADV7280_STATUS1_AUTOD_PAL_60:
+ return V4L2_STD_PAL_60;
+ case ADV7280_STATUS1_AUTOD_PAL_B_G:
+ return V4L2_STD_PAL;
+ case ADV7280_STATUS1_AUTOD_SECAM:
+ return V4L2_STD_SECAM;
+ case ADV7280_STATUS1_AUTOD_PAL_COMB:
+ return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
+ case ADV7280_STATUS1_AUTOD_SECAM_525:
+ return V4L2_STD_SECAM;
+ default:
+ return V4L2_STD_UNKNOWN;
+ }
+}
+
+static int v4l2_std_to_adv7280(v4l2_std_id std)
+{
+ if (std == V4L2_STD_PAL_60)
+ return ADV7280_INPUT_CONTROL_PAL60;
+ if (std == V4L2_STD_NTSC_443)
+ return ADV7280_INPUT_CONTROL_NTSC_443;
+ if (std == V4L2_STD_PAL_N)
+ return ADV7280_INPUT_CONTROL_PAL_N;
+ if (std == V4L2_STD_PAL_M)
+ return ADV7280_INPUT_CONTROL_PAL_M;
+ if (std == V4L2_STD_PAL_Nc)
+ return ADV7280_INPUT_CONTROL_PAL_COMB_N;
+
+ if (std & V4L2_STD_PAL)
+ return ADV7280_INPUT_CONTROL_PAL_BG;
+ if (std & V4L2_STD_NTSC)
+ return ADV7280_INPUT_CONTROL_NTSC_M;
+ if (std & V4L2_STD_SECAM)
+ return ADV7280_INPUT_CONTROL_PAL_SECAM;
+
+ return -EINVAL;
+}
+
+static int adv7280_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ i2c_smbus_write_byte_data(client, reg, val);
+ return 0;
+}
+
+static u32 adv7280_status_to_v4l2(u8 status1)
+{
+ if (!(status1 & ADV7280_STATUS1_IN_LOCK))
+ return V4L2_IN_ST_NO_SIGNAL;
+
+ return 0;
+}
+
+static int __adv7280_status(struct i2c_client *client, u32 *status,
+ v4l2_std_id *std)
+{
+ int status1 = i2c_smbus_read_byte_data(client, ADV7280_STATUS_1);
+
+ if (status1 < 0)
+ return status1;
+
+ if (status)
+ *status = adv7280_status_to_v4l2(status1);
+ if (std)
+ *std = adv7280_std_to_v4l2(status1);
+
+ return 0;
+}
+
+static inline struct adv7280_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct adv7280_state, sd);
+}
+
+static int adv7280_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct adv7280_state *state = to_state(sd);
+ int err = mutex_lock_interruptible(&state->mutex);
+ if (err)
+ return err;
+
+ /* when we are interrupt driven we know the state */
+ if (!state->autodetect || state->irq > 0)
+ *std = state->curr_norm;
+ else
+ err = __adv7280_status(v4l2_get_subdevdata(sd), NULL, std);
+
+ mutex_unlock(&state->mutex);
+ return err;
+}
+
+static int adv7280_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ struct adv7280_state *state = to_state(sd);
+ int ret = mutex_lock_interruptible(&state->mutex);
+ if (ret)
+ return ret;
+
+ ret = __adv7280_status(v4l2_get_subdevdata(sd), status, NULL);
+ mutex_unlock(&state->mutex);
+ return ret;
+}
+
+/*
+static int adv7280_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7280, 0);
+}
+*/
+
+static int adv7280_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct adv7280_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = mutex_lock_interruptible(&state->mutex);
+ if (ret)
+ return ret;
+
+ /* all standards -> autodetect */
+ if (std == V4L2_STD_ALL) {
+ ret = adv7280_write_reg(client,
+ ADV7280_INPUT_CONTROL,
+ ADV7280_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM |
+ (ADV7280_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input));
+ if (ret < 0)
+ goto out;
+
+ __adv7280_status(client, NULL, &state->curr_norm);
+ state->autodetect = true;
+ } else {
+ ret = v4l2_std_to_adv7280(std) |
+ (ADV7280_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input);
+ if (ret < 0)
+ goto out;
+
+ ret = adv7280_write_reg(client,
+ ADV7280_INPUT_CONTROL, ret);
+ if (ret < 0)
+ goto out;
+
+ state->curr_norm = std;
+ state->autodetect = false;
+ }
+ ret = 0;
+out:
+ mutex_unlock(&state->mutex);
+ return ret;
+}
+
+/*
+static int adv7280_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+*/
+
+/* Request bus settings on camera side */
+/*
+static unsigned long adv7280_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+*/
+
+static enum v4l2_mbus_pixelcode adv7280_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+};
+
+static int adv7280_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ enum v4l2_colorspace cspace;
+ enum v4l2_mbus_pixelcode code = mf->code;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cspace = V4L2_COLORSPACE_SMPTE170M;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mf->code = code;
+ mf->colorspace = cspace;
+
+ return adv7280_s_std(sd, V4L2_STD_ALL);
+}
+
+static int adv7280_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+#ifdef HW_DEINT
+ mf->field = V4L2_FIELD_NONE;
+#else
+ mf->field = V4L2_FIELD_INTERLACED_TB;
+#endif
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ /* PAL, line aligned to 64B */
+ mf->width = 736;
+ mf->height = 576;
+
+ return 0;
+}
+
+static int adv7280_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_subdev_desc *scsd = soc_camera_i2c_to_desc(client);
+
+ return soc_camera_set_power(&client->dev, scsd, on);
+}
+
+static int adv7280_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(adv7280_codes))
+ return -EINVAL;
+
+ *code = adv7280_codes[index];
+
+ return 0;
+}
+
+/*
+static struct soc_camera_ops adv7280_ops = {
+ .set_bus_param = adv7280_set_bus_param,
+ .query_bus_param = adv7280_query_bus_param,
+};
+*/
+
+static const struct v4l2_subdev_video_ops adv7280_video_ops = {
+ .s_mbus_fmt = adv7280_s_fmt,
+ .try_mbus_fmt = adv7280_try_fmt,
+ .enum_mbus_fmt = adv7280_enum_fmt,
+ .querystd = adv7280_querystd,
+ .g_input_status = adv7280_g_input_status,
+};
+
+static const struct v4l2_subdev_core_ops adv7280_core_ops = {
+ //.g_chip_ident = adv7280_g_chip_ident,
+ .s_std = adv7280_s_std,
+ .s_power = adv7280_s_power,
+};
+
+static const struct v4l2_subdev_ops adv7280_subdev_ops = {
+ .core = &adv7280_core_ops,
+ .video = &adv7280_video_ops,
+};
+
+static void adv7280_work(struct work_struct *work)
+{
+ struct adv7280_state *state = container_of(work, struct adv7280_state,
+ work);
+ struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+ u8 isr3;
+
+ mutex_lock(&state->mutex);
+ adv7280_write_reg(client, ADV7280_ADI_CONTROL_1,
+ ADV7280_ADI_CTRL_IRQ_SPACE);
+ isr3 = i2c_smbus_read_byte_data(client, ADV7280_ISR3_ADI);
+ /* clear */
+ adv7280_write_reg(client, ADV7280_ICR3_ADI, isr3);
+ adv7280_write_reg(client, ADV7280_ADI_CONTROL_1, 0);
+
+ if (isr3 & ADV7280_IRQ3_AD_CHANGE && state->autodetect)
+ __adv7280_status(client, NULL, &state->curr_norm);
+ mutex_unlock(&state->mutex);
+
+ enable_irq(state->irq);
+}
+
+static irqreturn_t adv7280_irq(int irq, void *devid)
+{
+ struct adv7280_state *state = devid;
+
+ schedule_work(&state->work);
+
+ disable_irq_nosync(state->irq);
+
+ return IRQ_HANDLED;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct adv7280_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 val;
+
+ if (i < 6) {
+ state->active_input = i;
+ val = i2c_smbus_read_byte_data(client,
+ ADV7280_INPUT_CONTROL);
+ val &= 0xf0;
+ val |= (ADV7280_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input);
+ return adv7280_write_reg(client,
+ ADV7280_INPUT_CONTROL, val);
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct adv7280_state *state = to_state(sd);
+
+ *i = state->active_input;
+
+ return 0;
+}
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+static int adv7280_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adv7280_state *state;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct v4l2_subdev *sd;
+ u8 ident;
+ int ret;
+ struct v4l2_ioctl_ops *ops;
+ struct i2c_client vpp_client = {
+ .flags = client->flags,
+ .addr = VPP_SLAVE_ADDRESS,
+ .name = "ADV7180_VPP_SLAVE",
+ .adapter = client->adapter,
+ .dev = client->dev,
+ };
+ struct i2c_client csi_client = {
+ .flags = client->flags,
+ .addr = CSI_SLAVE_ADDRESS,
+ .name = "ADV7180_CSI_SLAVE",
+ .adapter = client->adapter,
+ .dev = client->dev,
+ };
+
+ printk("probe, id=%s\n", id->name);
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ state = kzalloc(sizeof(struct adv7280_state), GFP_KERNEL);
+ if (state == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ident = i2c_smbus_read_byte_data(client, ADV7280_IDENT);
+ v4l_info(client, "ident reg is 0x%02x\n", ident);
+
+ state->irq = client->irq;
+ INIT_WORK(&state->work, adv7280_work);
+ mutex_init(&state->mutex);
+ state->autodetect = true;
+ state->active_input = 0; // input 1
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &adv7280_subdev_ops);
+ //icd->ops = &adv7280_ops;
+
+ /* Reset */
+ ret = adv7280_write_reg(client,
+ ADV7280_POWER_MANAGEMENT, 0xA0);
+ if (ret < 0)
+ goto err_unreg_subdev;
+ msleep(10);
+
+ /* Initialize adv7280 */
+ /* Exit Power Down Mode */
+ ret = adv7280_write_reg(client,
+ ADV7280_POWER_MANAGEMENT, 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ ADV7280_ADI_CONTROL_1, 0x80);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ 0x9C, 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ 0x9C, 0xFF);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* Enter User Sub Map */
+ ret = adv7280_write_reg(client,
+ ADV7280_ADI_CONTROL_1, 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* Enable Pixel & Sync output drivers */
+ ret = adv7280_write_reg(client,
+ ADV7280_OUTPUT_CONTROL, 0x0C);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* Power-up INTRQ, HS & VS pads */
+ ret = adv7280_write_reg(client,
+ ADV7280_EXTENDED_OUTPUT_CONTROL, 0x07);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* Enable SH1 */
+ /*
+ ret = adv7280_write_reg(client,
+ ADV7280_SHAPING_FILTER_CONTROL_1, 0x41);
+ if (ret < 0)
+ goto err_unreg_subdev;
+ */
+
+ /* Disable comb filtering */
+ /*
+ ret = adv7280_write_reg(client,
+ 0x39, 0x24);
+ if (ret < 0)
+ goto err_unreg_subdev;
+ */
+
+ /* Enable LLC output driver */
+ ret = adv7280_write_reg(client,
+ ADV7280_ADI_CONTROL_2, 0x40);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* VSYNC on VS/FIELD/SFL pin */
+ ret = adv7280_write_reg(client,
+ ADV7280_OUTPUT_SYNC_SELECT_2, 0x01);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* Enable autodetection */
+ ret = adv7280_write_reg(client, ADV7280_INPUT_CONTROL,
+ ADV7280_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM |
+ (ADV7280_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input));
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ ret = adv7280_write_reg(client, ADV7280_AUTODETECT_ENABLE,
+ ADV7280_AUTODETECT_DEFAULT);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* ITU-R BT.656-4 compatible
+ ret = adv7280_write_reg(client,
+ ADV7280_EXTENDED_OUTPUT_CONTROL,
+ ADV7280_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
+ if (ret < 0)
+ goto err_unreg_subdev;
+ */
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ 0x52, 0xCD);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ 0x80, 0x51);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ 0x81, 0x51);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(client,
+ 0x82, 0x68);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+#ifdef HW_DEINT
+ /* Set VPP Map */
+ ret = adv7280_write_reg(client,
+ ADV7280_VPP_SLAVE_ADDRESS, (VPP_SLAVE_ADDRESS << 1));
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* VPP - not documented */
+ ret = adv7280_write_reg(&vpp_client,
+ 0xA3, 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* VPP - Enbable Advanced Timing Mode */
+ ret = adv7280_write_reg(&vpp_client,
+ VPP_ADV_TIMING_MODE_EN, 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* VPP - Enable Deinterlacer */
+ ret = adv7280_write_reg(&vpp_client,
+ VPP_I2C_DEINT_ENABLE, 0x80);
+ if (ret < 0)
+ goto err_unreg_subdev;
+#endif
+
+#ifdef CSI
+ /* Set CSI Map */
+ ret = adv7280_write_reg(client,
+ ADV7280_CSI_TX_SLAVE_ADDRESS, (CSI_SLAVE_ADDRESS << 1));
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* Power up MIPI D-PHY */
+ ret = adv7280_write_reg(&csi_client,
+ CSI_DPHY_PWRDN_CTL, 0x02);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+
+ ret = adv7280_write_reg(&csi_client,
+ 0x02 , 0x18);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(&csi_client,
+ 0xD2 , 0xF7);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(&csi_client,
+ 0xD8 , 0x65);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(&csi_client,
+ 0xE0 , 0x09);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* analog devices recommends */
+ ret = adv7280_write_reg(&csi_client,
+ 0x2C , 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* MIPI-CSI2 power up */
+ ret = adv7280_write_reg(&csi_client,
+ CSI_CSITX_PWRDN , 0x00);
+ if (ret < 0)
+ goto err_unreg_subdev;
+#endif
+
+ /* read current norm */
+ __adv7280_status(client, NULL, &state->curr_norm);
+
+ /* register for interrupts */
+ if (state->irq > 0) {
+ ret = request_irq(state->irq, adv7280_irq, 0, DRIVER_NAME,
+ state);
+ if (ret)
+ goto err_unreg_subdev;
+
+ ret = adv7280_write_reg(client, ADV7280_ADI_CONTROL_1,
+ ADV7280_ADI_CTRL_IRQ_SPACE);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* config the Interrupt pin to be active low */
+ ret = adv7280_write_reg(client, ADV7280_ICONF1_ADI,
+ ADV7280_ICONF1_ACTIVE_LOW | ADV7280_ICONF1_PSYNC_ONLY);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ ret = adv7280_write_reg(client, ADV7280_IMR1_ADI, 0);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ ret = adv7280_write_reg(client, ADV7280_IMR2_ADI, 0);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ /* enable AD change interrupts interrupts */
+ ret = adv7280_write_reg(client, ADV7280_IMR3_ADI,
+ ADV7280_IRQ3_AD_CHANGE);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ ret = adv7280_write_reg(client, ADV7280_IMR4_ADI, 0);
+ if (ret < 0)
+ goto err_unreg_subdev;
+
+ ret = adv7280_write_reg(client, ADV7280_ADI_CONTROL_1,
+ 0);
+ if (ret < 0)
+ goto err_unreg_subdev;
+ }
+
+ /*
+ * this is the only way to support more than one input as soc_camera
+ * assumes in its own vidioc_s(g)_input implementation that only one
+ * input is present we have to override that with our own handlers.
+ */
+ /*
+ ops = (struct v4l2_ioctl_ops*)icd->vdev->ioctl_ops;
+ ops->vidioc_s_input = &vidioc_s_input;
+ ops->vidioc_g_input = &vidioc_g_input;
+ */
+
+ return 0;
+
+err_unreg_subdev:
+ mutex_destroy(&state->mutex);
+ v4l2_device_unregister_subdev(sd);
+ kfree(state);
+err:
+ printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret);
+ return ret;
+}
+
+static int adv7280_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct adv7280_state *state = to_state(sd);
+
+ if (state->irq > 0) {
+ free_irq(client->irq, state);
+ if (cancel_work_sync(&state->work)) {
+ /*
+ * Work was pending, therefore we need to enable
+ * IRQ here to balance the disable_irq() done in the
+ * interrupt handler.
+ */
+ enable_irq(state->irq);
+ }
+ }
+
+ mutex_destroy(&state->mutex);
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+ return 0;
+}
+
+static const struct i2c_device_id adv7280_id[] = {
+ {"adv7280", 0},
+ {"adv7280-M", 1},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, adv7280_id);
+
+static struct i2c_driver adv7280_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+ .probe = adv7280_probe,
+ .remove = adv7280_remove,
+ .id_table = adv7280_id,
+};
+
+static __init int adv7280_init(void)
+{
+ return i2c_add_driver(&adv7280_driver);
+}
+
+static __exit void adv7280_exit(void)
+{
+ i2c_del_driver(&adv7280_driver);
+}
+
+module_init(adv7280_init);
+module_exit(adv7280_exit);
+
+MODULE_DESCRIPTION("Analog Devices ADV7280/ADV7280-M video decoder driver");
+MODULE_AUTHOR("Wojciech Bieganski <wbieganski@antmicro.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/i2c/soc_camera/ap1302.c b/drivers/media/i2c/soc_camera/ap1302.c
new file mode 100644
index 000000000000..00a4315bcc39
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ap1302.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) Antmicro Ltd. All rights reserved.
+ * based on ov5640 driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+
+#define AP1302_NAME "ap1302"
+#define AP1302_CHIP_ID 0x0265
+#define AP1302_FW_WINDOW_OFFSET 0x8000
+#define AP1302_FW_WINDOW_SIZE 0x2000
+
+#define REG_CHIP_VERSION 0x0000
+#define REG_CHIP_REV 0x0050
+
+#define REG_ERROR 0x0006
+#define REG_CTRL 0x1000
+#define REG_ENABLE 0x1008
+#define REG_PREVIEW_WIDTH 0x2000
+#define REG_PREVIEW_HEIGHT 0x2002
+#define REG_PREVIEW_ROI_X0 0x2004
+#define REG_PREVIEW_ROI_Y0 0x2006
+#define REG_PREVIEW_ROI_X1 0x2008
+#define REG_PREVIEW_ENABLE 0x2010
+#define REG_PREVIEW_OUT_FMT 0x2012
+#define REG_PREVIEW_SENSOR_MODE 0x2014
+#define REG_PREVIEW_MAX_FPS 0x2020
+#define REG_PREVIEW_AE_USG 0x2022
+#define REG_PREVIEW_HINF_CTRL 0x2030
+#define REG_PREVIEW_HINF_SPOOF_W 0x2032
+#define REG_PREVIEW_HINF_SPOOF_H 0x2034
+#define REG_AE_CTRL 0x5002
+#define REG_AE_MANUAL_GAIN 0x5006
+#define REG_AE_MANUAL_EXP_TIME 0x500C
+#define REG_AE_BV_MIN 0x5010
+#define REG_AF_CTRL 0x5058
+#define REG_AWB_MANUAL_TEMP 0x510A
+#define REG_BOOTDATA_STAGE 0x6002
+#define REG_GAMMA 0x700A
+#define REG_CLS_LOCK_CONN 0x54C2
+#define REG_PREVIEW_DIV_HINF_MIPI 0x2064
+#define REG_SIPS_CRC 0xF052
+
+#define FW_OFFSET 0x8000
+#define FW_PLL_SIZE 832
+#define FW_CHUNK_SIZE 0x600
+
+#define REG_16B 2
+#define REG_32B 4
+
+static int ap1302_write_reg(struct i2c_client*, u16, u32, int);
+
+enum {
+ AP1302_MODE_640x480,
+ AP1302_MODE_1280x720,
+ AP1302_MODE_1920x1080,
+ AP1302_MODE_4224x3156,
+ AP1302_SIZE_LAST,
+};
+
+#define to_ap1302(sd) container_of(sd, struct ap1302_priv, subdev)
+
+struct ap1302_priv {
+ struct v4l2_subdev subdev;
+ struct v4l2_mbus_framefmt mf;
+
+ int ident;
+ u16 chip_id;
+ u8 revision;
+
+ int mode;
+
+ struct i2c_client *client;
+ const struct firmware *fw;
+};
+
+static enum v4l2_mbus_pixelcode ap1302_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+};
+
+static const struct v4l2_frmsize_discrete ap1302_frmsizes[AP1302_SIZE_LAST] = {
+ {640, 480},
+ {1280, 720},
+ {1920, 1080},
+ {4224, 3156},
+};
+
+static int ap1302_find_mode(u32 width, u32 height)
+{
+ int i;
+
+ for (i = 0; i < AP1302_SIZE_LAST; i++) {
+ if ((ap1302_frmsizes[i].width >= width) &&
+ (ap1302_frmsizes[i].height >= height))
+ break;
+ }
+
+ /* If not found, select biggest */
+ if (i >= AP1302_SIZE_LAST)
+ i = AP1302_SIZE_LAST - 1;
+
+ return i;
+}
+
+static void ap1302_set_default_fmt(struct ap1302_priv *priv)
+{
+ struct v4l2_mbus_framefmt *mf = &priv->mf;
+
+ mf->width = ap1302_frmsizes[AP1302_MODE_640x480].width;
+ mf->height = ap1302_frmsizes[AP1302_MODE_640x480].height;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+}
+
+/* Start/Stop streaming from the device */
+static int ap1302_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ap1302_priv *priv = to_ap1302(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (!enable) {
+ ap1302_set_default_fmt(priv);
+ return 0;
+ }
+
+ ap1302_write_reg(client, REG_PREVIEW_OUT_FMT, 0x0030, REG_16B);
+ ap1302_write_reg(client, REG_PREVIEW_WIDTH, priv->mf.width, REG_16B);
+ ap1302_write_reg(client, REG_PREVIEW_HEIGHT, priv->mf.height, REG_16B);
+ ap1302_write_reg(client, REG_PREVIEW_SENSOR_MODE, (priv->mf.height > 1080) ? 0x0040 : 0x0041, REG_16B);
+ ap1302_write_reg(client, REG_PREVIEW_HINF_SPOOF_W, 0x0000, REG_16B);
+ ap1302_write_reg(client, REG_PREVIEW_HINF_SPOOF_H, 0x0000, REG_16B);
+
+ return ret;
+}
+
+static int ap1302_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ int mode;
+
+ mode = ap1302_find_mode(mf->width, mf->height);
+ mf->width = ap1302_frmsizes[mode].width;
+ mf->height = ap1302_frmsizes[mode].height;
+
+ mf->field = V4L2_FIELD_NONE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+/* set the format we will capture in */
+static int ap1302_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct ap1302_priv *priv = to_ap1302(sd);
+ int ret;
+
+ ret = ap1302_try_fmt(sd, mf);
+ if (ret < 0)
+ return ret;
+
+ priv->mode = ap1302_find_mode(mf->width, mf->height);
+
+ memcpy(&priv->mf, mf, sizeof(struct v4l2_mbus_framefmt));
+
+ return 0;
+}
+
+static int ap1302_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct ap1302_priv *priv = to_ap1302(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_subdev_desc *scsd = soc_camera_i2c_to_desc(client);
+
+ if (on)
+ ap1302_s_fmt(sd, &priv->mf);
+
+ return soc_camera_set_power(&client->dev, scsd, on);
+}
+
+static int ap1302_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ap1302_codes))
+ return -EINVAL;
+
+ *code = ap1302_codes[index];
+
+ return 0;
+}
+
+static int ap1302_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ return 0;
+}
+
+static int ap1302_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ return 0;
+}
+
+static int ap1302_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ return 0;
+}
+
+/* Get chip identification */
+static int ap1302_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct ap1302_priv *priv = to_ap1302(sd);
+
+ id->ident = priv->ident;
+ id->revision = priv->revision;
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ap1302_video_ops = {
+ .s_stream = ap1302_s_stream,
+ .s_mbus_fmt = ap1302_s_fmt,
+ .try_mbus_fmt = ap1302_try_fmt,
+ .enum_mbus_fmt = ap1302_enum_fmt,
+ .cropcap = ap1302_cropcap,
+ .g_crop = ap1302_g_crop,
+ .querystd = ap1302_querystd,
+};
+
+ int (*reset)(struct v4l2_subdev *sd, u32 val);
+
+static struct v4l2_subdev_core_ops ap1302_core_ops = {
+ .g_chip_ident = ap1302_g_chip_ident,
+ .s_power = ap1302_s_power,
+};
+
+static struct v4l2_subdev_ops ap1302_subdev_ops = {
+ .core = &ap1302_core_ops,
+ .video = &ap1302_video_ops,
+};
+
+static int ap1302_read_reg(struct i2c_client *client, u16 addr, u16 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[4];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = data + 2;
+
+ err = i2c_transfer(client->adapter, msg, REG_16B);
+
+ if (err != 2)
+ return -EINVAL;
+
+ *val = (data[2] << 8) | data[3];
+
+ return 0;
+}
+
+static int ap1302_write_reg(struct i2c_client *client, u16 addr, u32 value, int size)
+{
+ int count;
+ struct i2c_msg msg[1];
+ unsigned char data[6];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+
+ if (size == 1) {
+ data[2] = (u8) (value & 0xff);
+ }
+ else if (size == 2) {
+ data[2] = (u8) (value >> 8);
+ data[3] = (u8) (value & 0xff);
+ }
+ else if (size == 4) {
+ data[2] = (u8) (value >> 24);
+ data[3] = (u8) (value >> 16);
+ data[4] = (u8) (value >> 8);
+ data[5] = (u8) (value & 0xff);
+ }
+ else
+ return -1;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = (size + 2);
+ msg[0].buf = data;
+
+ count = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (count == ARRAY_SIZE(msg)) {
+ return 0;
+ }
+ dev_err(&client->dev,
+ "ap1302: i2c transfer failed, addr: %x, value: %02x\n",
+ addr, (u32)value);
+ return -EIO;
+}
+
+static int ap1302_write_bulk_reg(struct i2c_client *client, u16 reg_addr, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+ u8 data_with_addr[len+2];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data_with_addr[0] = (u8)(reg_addr >> 8);
+ data_with_addr[1] = (u8)(reg_addr & 0xFF);
+ memcpy((u8*)&data_with_addr[2], data, len);
+
+ len = (len + 2);
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data_with_addr;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ dev_err(&client->dev, "ap1302: i2c transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ap1302_request_firmware(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ap1302_priv *priv = to_ap1302(sd);
+ int ret;
+ ret = request_firmware(&priv->fw, "ap1302_fw.bin", &client->dev);
+ if (ret)
+ dev_err(&client->dev,
+ "ap1302_request_firmware failed. ret=%d\n", ret);
+ return ret;
+}
+
+static int ap1302_write_firmware(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ap1302_priv *priv = to_ap1302(sd);
+ int err = 0;
+ u16 pos = 0, ppos = 0, smpos = 0;
+ int fw_size = priv->fw->size;
+ u8 *fw_data = (u8 *)(priv->fw->data);
+ u32 packet_size = 0, sm_packet_size = 0;
+
+ err += ap1302_write_reg(client, REG_SIPS_CRC, 0xFFFF, REG_16B);
+
+ /* write pll firmware */
+ err += ap1302_write_bulk_reg(client, 0x8000, fw_data, FW_PLL_SIZE);
+
+ /* write the rest of the firmware */
+ err += ap1302_write_reg(client, REG_BOOTDATA_STAGE, 0x0002, REG_16B);
+ pos = FW_PLL_SIZE;
+ ppos = FW_PLL_SIZE;
+
+ /* split fw into packets (8192B) */
+ for (pos = FW_PLL_SIZE; pos < fw_size; pos += packet_size) {
+ if (fw_size - pos < AP1302_FW_WINDOW_SIZE - ppos)
+ packet_size = fw_size - pos;
+ else
+ packet_size = AP1302_FW_WINDOW_SIZE - ppos;
+
+ /* split each packet into chunks (each having FW_CHUNK_SIZE) */
+ sm_packet_size = FW_CHUNK_SIZE;
+ for (smpos = 0; smpos < packet_size; smpos += sm_packet_size) {
+ if ((smpos + sm_packet_size) > packet_size)
+ sm_packet_size = packet_size - smpos;
+ err += ap1302_write_bulk_reg(client, (FW_OFFSET + ppos + smpos),
+ (u8 *)(fw_data + pos + smpos), sm_packet_size);
+ }
+
+ msleep(10);
+
+ ppos += packet_size;
+ if (ppos >= AP1302_FW_WINDOW_SIZE)
+ ppos = 0;
+ }
+
+ /* TODO: check CRC and ERROR regs */
+ ap1302_write_reg(client, REG_BOOTDATA_STAGE, 0xFFFF, REG_16B);
+
+ return err;
+}
+
+static int ap1302_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ap1302_priv *priv;
+ struct soc_camera_subdev_desc *scsd;
+ u16 chip_id = 0;
+ int ret = 0;
+
+ /* Checking soc-camera interface */
+ scsd = soc_camera_i2c_to_desc(client);
+ if (!scsd) {
+ dev_err(&client->dev, "Missing soc_camera_link for driver\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&client->dev, sizeof(struct ap1302_priv),
+ GFP_KERNEL);
+ if (!priv) {
+ dev_err(&client->dev, "Failed to allocate private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ap1302_subdev_ops);
+
+ priv->client = client;
+
+ soc_camera_power_on(&client->dev, scsd);
+
+ /* TODO: this should be moved to boardfile, because
+ * now the driver works only on Jetson TK1 */
+ gpio_set_value(219, 0);
+ msleep(100);
+ gpio_set_value(219, 1);
+ msleep(100);
+
+ ap1302_set_default_fmt(priv);
+
+ ap1302_read_reg(client, REG_CHIP_VERSION, &chip_id);
+ printk(KERN_INFO "AP1302 chip id = 0x%04x\n", chip_id);
+ if (chip_id != 0x265) {
+ soc_camera_power_off(&client->dev, scsd);
+ return -1;
+ }
+
+ ret = ap1302_request_firmware(&(priv->subdev));
+ if (ret) {
+ dev_err(&client->dev, "Cannot request ap1302 firmware.\n");
+ return -1;
+ }
+
+ /* loading firmware */
+ ret += ap1302_write_firmware(&(priv->subdev));
+
+ /* configuring isp */
+ ret += ap1302_write_reg(client, REG_PREVIEW_WIDTH, 0x0280, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HEIGHT, 0x01E0, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_OUT_FMT, 0x0030, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_MAX_FPS, 0xF000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HINF_CTRL, 0x0034, REG_16B);
+ ret += ap1302_write_reg(client, REG_AF_CTRL, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_ENABLE, 0x0086, REG_16B);
+ ret += ap1302_write_reg(client, REG_AE_BV_MIN, 0x0100, REG_16B);
+ ret += ap1302_write_reg(client, REG_AE_MANUAL_GAIN, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_AE_CTRL, 0x002A, REG_16B);
+ ret += ap1302_write_reg(client, REG_ENABLE, 0x0001, REG_16B);
+ ret += ap1302_write_reg(client, REG_AE_MANUAL_EXP_TIME, 0x00003CF0, REG_32B);
+ ret += ap1302_write_reg(client, REG_AWB_MANUAL_TEMP, 0x11F8, REG_16B);
+ ret += ap1302_write_reg(client, REG_GAMMA, 0x2000, REG_16B);
+ ret += ap1302_write_reg(client, REG_CLS_LOCK_CONN, 0x0024, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_ROI_X0, 0x8000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_ROI_X1, 0x7FFF, REG_16B);
+ ret += ap1302_write_reg(client, REG_CLS_LOCK_CONN, 0x0024, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_DIV_HINF_MIPI, 0x00030000, REG_32B);
+ ret += ap1302_write_reg(client, REG_CTRL, 0x0001, REG_16B);
+ ret += ap1302_write_reg(client, REG_CTRL, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_AE_USG, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_WIDTH, 0x0280, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HEIGHT, 0x01E0, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_SENSOR_MODE, 0x0041, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HINF_SPOOF_W, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HINF_SPOOF_H, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_OUT_FMT, 0x0030, REG_16B);
+
+ /* setting default mode: 640x480 */
+ ret += ap1302_write_reg(client, REG_PREVIEW_WIDTH, 0x0280, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HEIGHT, 0x01E0, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_SENSOR_MODE, 0x0041, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HINF_SPOOF_W, 0x0000, REG_16B);
+ ret += ap1302_write_reg(client, REG_PREVIEW_HINF_SPOOF_H, 0x0000, REG_16B);
+
+ return ret;
+}
+
+static int ap1302_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id ap1302_id[] = {
+ { "ap1302", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ap1302_id);
+
+static struct i2c_driver ap1302_i2c_driver = {
+ .driver = {
+ .name = "ap1302",
+ },
+ .probe = ap1302_probe,
+ .remove = ap1302_remove,
+ .id_table = ap1302_id,
+};
+
+static int __init ap1302_module_init(void)
+{
+ return i2c_add_driver(&ap1302_i2c_driver);
+}
+
+static void __exit ap1302_module_exit(void)
+{
+ i2c_del_driver(&ap1302_i2c_driver);
+}
+
+module_init(ap1302_module_init);
+module_exit(ap1302_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for AP1302 ISP from ON Semiconductor");
+MODULE_AUTHOR("Wojciech Bieganski <wbieganski@antmicro.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov5640.c b/drivers/media/i2c/soc_camera/ov5640.c
index 38315b514407..acd532b8b7d3 100644
--- a/drivers/media/i2c/soc_camera/ov5640.c
+++ b/drivers/media/i2c/soc_camera/ov5640.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2013 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2016-2017 Antmicro Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -30,1073 +31,853 @@ struct ov5640_reg {
#define OV5640_TABLE_WAIT_MS 0
#define OV5640_TABLE_END 1
+/* System and IO Pad Control [0x3000 ~ 0x3052] */
+#define OV5640_SYSTEM_RESET_00 0x3000 /* default 0x30 -> all 0x00 */
+#define OV5640_SYSTEM_RESET_01 0x3001 /* default 0x08 */
+#define OV5640_SYSTEM_RESET_02 0x3002 /* default 0x1c */
+#define OV5640_SYSTEM_RESET_03 0x3003 /* default 0x00 */
+#define OV5640_SYSTEM_CLK_EN_00 0x3004 /* default 0xcf -> all 0xff */
+#define OV5640_SYSTEM_CLK_EN_01 0x3005 /* default 0xf7 */
+#define OV5640_SYSTEM_CLK_EN_02 0x3006 /* default 0xe3 -> all 0xc3 */
+#define OV5640_SYSTEM_CLK_EN_03 0x3007 /* default 0xff */
+#define OV5640_SYSTEM_CTRL 0x3008 /* default 0x02 all -> (0x82, 0x42, 0x02) */
+#define OV5640_CHIP_ID_H 0x300a /* default 0x56 */
+#define OV5640_CHIP_ID_L 0x300b /* default 0x40 */
+#define OV5640_SYSTEM_MIPI_CTRL 0x300e /* default 0x58 -> all 0x45 */
+#define OV5640_IO_CTRL_01 0x3017 /* default 0x00 */
+#define OV5640_IO_CTRL_02 0x3018 /* default 0x00 */
+#define OV5640_SYSTEM_CTRL_2D 0x302d /* default ---- -> all 0x60 !! */
+#define OV5640_SYSTEM_CTRL_2E 0x302e /* default ---- -> all 0x08 !! */
+#define OV5640_SC_PLL_CTRL0 0x3034 /* default 0x1a -> all 0x18 MIPI_MODE */
+#define OV5640_SC_PLL_CTRL1 0x3035 /* default 0x11 -> 0x11 0x11 0x21 0x14 */
+#define OV5640_SC_PLL_CTRL2 0x3036 /* default 0x69 -> 0x7d 0x54 0x70 0x70 */
+#define OV5640_SC_PLL_CTRL3 0x3037 /* default 0x03 -> all 0x13 */
+#define OV5640_SC_PLL_CTRL5 0x3039 /* not use */
+
+#define SYSTEM_CTRL_SRST 0x80 /* Bit[7]: Software reset */
+#define SYSTEM_CTRL_PDOWN 0x40 /* Bit[6]: Software power down */
+#define MIPI_MODE_8BIT 0x08 /* Bit[3:0]: MIPI bit mode - 8-bit mode */
+#define MIPI_MODE_10BIT 0x0a /* Bit[3:0]: MIPI bit mode - 10-bit mode */
+
+/* SCCB Control [0x3100 ~ 0x3108] */
+#define OV5640_SCCB_SYSTEM_CTRL 0x3103 /* default 0x00 -> all 0x03 */
+#define OV5640_SCCB_SCLK 0x3108 /* default 0x16 -> all 0x01 */
+
+/* VCM Control [0x3600 ~ 0x3606] */
+#define OV5640_VCM_DEBUG_MODE_0 0x3600 /* default ---- -> all 0x08 */
+#define OV5640_VCM_DEBUG_MODE_1 0x3601 /* default ---- -> all 0x33 */
+
+/* Timing Control [0x3800 ~ 0x3821] */
+#define OV5640_TIMING_HS_H 0x3800 /* default 0x00 -> 0x00 0x01 0x00 0x00 X_ADDR_ST */
+#define OV5640_TIMING_HS_L 0x3801 /* default 0x00 -> 0x00 0x50 0x00 0x00 */
+#define OV5640_TIMING_VS_H 0x3802 /* default 0x00 -> 0x00 0x01 0x00 0x00 Y_ADDR_ST */
+#define OV5640_TIMING_VS_L 0x3803 /* default 0x00 -> 0x00 0xaa 0x00 0x04 */
+#define OV5640_TIMING_HW_H 0x3804 /* default 0x0a -> 0x0a 0x08 0x0a 0x0a X_ADDR_END */
+#define OV5640_TIMING_HW_L 0x3805 /* default 0x3f -> 0x3f 0xef 0x3f 0x3f 2623 */
+#define OV5640_TIMING_VH_H 0x3806 /* default 0x07 -> 0x07 0x05 0x07 0x07 Y_ADDR_END */
+#define OV5640_TIMING_VH_L 0x3807 /* default 0x9f -> 0x9f 0xf9 0x9f 0x9b */
+#define OV5640_TIMING_DVPHO_H 0x3808 /* default 0x0a -> 0x0a 0x07 0x05 0x02 width[11:8] */
+#define OV5640_TIMING_DVPHO_L 0x3809 /* default 0x20 -> 0x30 0x90 0x18 0x80 width[7:0] */
+#define OV5640_TIMING_DVPVO_H 0x380a /* default 0x07 -> 0x07 0x04 0x03 0x01 height[11:8] */
+#define OV5640_TIMING_DVPVO_L 0x380b /* default 0x98 -> 0x9c 0x48 0xcc 0xe0 height[7:0] */
+#define OV5640_TIMING_HTS_H 0x380c /* default 0x0b -> 0x0b 0x09 0x07 0x07 */
+#define OV5640_TIMING_HTS_L 0x380d /* default 0x1c -> 0x1c 0xc4 0x5e 0x68 */
+#define OV5640_TIMING_VTS_H 0x380e /* default 0x07 -> 0x07 0x04 0x03 0x03 */
+#define OV5640_TIMING_VTS_L 0x380f /* default 0xb0 -> 0xb0 0x60 0xde 0xd8 */
+#define OV5640_TIMING_HOFFSET_H 0x3810 /* default 0x00 */
+#define OV5640_TIMING_HOFFSET_L 0x3811 /* default 0x10 -> 0x08 0x08 0x06 0x10 */
+#define OV5640_TIMING_VOFFSET_H 0x3812 /* default 0x00 */
+#define OV5640_TIMING_VOFFSET_L 0x3813 /* default 0x04 -> 0x02 0x04 0x02 0x06 */
+#define OV5640_TIMING_X_INC 0x3814 /* default 0x11 -> 0x11 0x11 0x31 0x31 */
+#define OV5640_TIMING_Y_INC 0x3815 /* default 0x11 -> 0x11 0x11 0x31 0x31 */
+#define OV5640_TIMING_REG20 0x3820 /* default 0x40 */
+#define OV5640_TIMING_REG21 0x3821 /* default 0x00 -> 0x06 0x06 0x07 0x07 */
+#define REG20_SENSOR_VFLIP 0x02
+#define REG20_SENSOR_ISP_FLIP 0x04
+#define REG21_BINNING_EN 0x01
+#define REG21_SENSOR_MIRROR 0x02
+#define REG21_ISP_MIRROR 0x04
+
+#define OV5640_ADDR_H(x) ((x >> 8 ) & 0x0f)
+#define OV5640_ADDR_L(x) (x & 0xff)
+#define OV5640_WIDTH_H(x) ((x >> 8 ) & 0x0f)
+#define OV5640_WIDTH_L(x) (x & 0xff)
+#define OV5640_HEIGHT_H(x) ((x >> 8 ) & 0x0f)
+#define OV5640_HEIGHT_L(x) (x & 0xff)
+#define OV5640_HTS_H(x) ((x >> 8 ) & 0x1f)
+#define OV5640_HTS_L(x) (x & 0xff)
+#define OV5640_VTS_H(x) ((x >> 8 ) & 0xff)
+#define OV5640_VTS_L(x) (x & 0xff)
+#define OV5640_H_OFFSET_H(x) ((x >> 8 ) & 0x0F)
+#define OV5640_H_OFFSET_L(x) (x & 0xff)
+#define OV5640_V_OFFSET_H(x) ((x >> 8 ) & 0x03)
+#define OV5640_V_OFFSET_L(x) (x & 0xff)
+
+/* AEC/AGC power down domain control [0x3A00 ~ 0x3A25] */
+#define OV5640_AEC_CTRL_0F 0x3a0f /* default 0x78 -> all 0x30 */
+#define OV5640_AEC_CTRL_10 0x3a10 /* default 0x68 -> all 0x28 */
+#define OV5640_AEC_CTRL_11 0x3a11 /* default 0xd0 -> all 0x60 */
+#define OV5640_AEC_CTRL_1B 0x3a1b /* default 0x78 -> all 0x30 */
+#define OV5640_AEC_CTRL_1E 0x3a1e /* default 0x68 -> all 0x26 */
+#define OV5640_AEC_CTRL_1F 0x3a1f /* default 0x40 -> all 0x14 */
+#define OV5640_AEC_MAX_EXPO60_H 0x3a02 /* default 0x3d -> 0x07 0x04 0x03 0x03 */
+#define OV5640_AEC_MAX_EXPO60_L 0x3a03 /* default 0x80 -> 0xb6 0x60 0xd8 0xd8 */
+#define OV5640_AEC_B50_STEP_H 0x3a08 /* default 0x01 */
+#define OV5640_AEC_B50_STEP_L 0x3a09 /* default 0x27 -> 0x27 0x50 0x27 0x27 */
+#define OV5640_AEC_B60_STEP_H 0x3a0a /* default 0x00 -> 0x00 0x01 0x00 0x00 */
+#define OV5640_AEC_B60_STEP_L 0x3a0b /* default 0xf6 -> 0xf6 0x18 0xf6 0xf6 */
+#define OV5640_AEC_CTRL_0D 0x3a0d /* default 0x08 -> 0x06 0x03 0x03 0x03 */
+#define OV5640_AEC_CTRL_0E 0x3a0e /* default 0x06 -> 0x06 0x04 0x04 0x04 */
+#define OV5640_AEC_CTRL_13 0x3a13 /* default 0x40 -> all 0x43 */
+#define OV5640_AEC_MAX_EXPO_H 0x3a14 /* default 0x0e -> 0x07 0x04 0x03 0x03 */
+#define OV5640_AEC_MAX_EXPO_L 0x3a15 /* default 0x40 -> 0xb0 0xd0 0xd8 0xd8 */
+#define OV5640_AEC_GAIN_CEILING_0 0x3a18 /* default 0x03 -> all 0x00 */
+#define OV5640_AEC_GAIN_CEILING_1 0x3a19 /* default 0xE0 -> all 0xf8 */
+
+/* 50/60Hz detector control [0x3C00 ~ 0x3C1E] */
+#define OV5640_5060_CTRL_01 0x3c01 /* default 0x00 -> all 0x34 */
+#define OV5640_5060_CTRL_04 0x3c04 /* default 0x20 -> all 0x28 */
+#define OV5640_5060_CTRL_05 0x3c05 /* default 0x70 -> all 0x98 */
+
+#define OV5640_5060_THRESHOLD_1_H 0x3c06 /* default 0x00 -> all 0x00 */
+#define OV5640_5060_THRESHOLD_1_L 0x3c07 /* default 0x00 -> all 0x07 0x07 0x07 0x07 0x08 */
+#define OV5640_5060_THRESHOLD_2_H 0x3c08 /* default 0x01 -> all 0x00 */
+#define OV5640_5060_THRESHOLD_2_L 0x3c09 /* default 0x2c -> all 0x1c */
+#define OV5640_5060_SAMPLE_NUM_H 0x3c0a /* default 0x4e -> all 0x9c */
+#define OV5640_5060_SAMPLE_NUM_L 0x3c0b /* default 0x1f -> all 0x40 */
+
+/* BLC Control [0x4000 ~ 0x4033] */
+#define OV5640_BLC_CTRL_01 0x4001 /* default 0x00 -> 0x02 */
+#define OV5640_BLC_CTRL_04 0x4004 /* default 0x08 -> 0x06 0x06 0x02 0x02 */
+
+/* MIPI control [0x4800 ~ 0x4837] */
+#define OV5640_MIPI_CTRL_00 0x4800 /* default 0x04 */
+#define OV5640_MIPI_CTRL_01 0x4801 /* not use */
+#define OV5640_MIPI_CTRL_05 0x4805 /* not use */
+#define OV5640_MIPI_PCLK_PERIOD 0x4837 /* default 0x10 -> 0x0a 0x0a 0x10 0x44 */
+
+/* Format Control [0x4300 ~ 0x430D] */
+#define FMT_CTRL_00 0x4300 /* default 0xF8 -> all 0x32 */
+
+/* Format Control */
+#define FMT_YUV422 0x30
+/* Output sequence */
+#define OFMT_YUYV 0x00
+#define OFMT_YVYU 0x01
+#define OFMT_UYVY 0x02
+#define OFMT_VYUY 0x03
+
+/* ISP Control [0x5000 ~ 0x5063] */
+#define OV5640_ISP_CTRL_00 0x5000 /* default 0x06 -> all 0xa7 */
+#define OV5640_ISP_CTRL_01 0x5001 /* default 0x01 -> 0x83 0x83 0x83 0xa3 */
+#define OV5640_ISP_MUX_CTRL 0x501F /* default 0x00 -> all 0x00 (000: ISP YUV422) */
+#define OV5640_ISP_DEBUG_25 0x5025 /* default ---- -> all 0x00 */
+#define OV5640_ISP_TEST 0x503D /* default 0x00 */
+#define OV5640_ISP_DEBUG_3E 0x503E /* default ---- */
+#define OV5640_ISP_DEBUG_46 0x5046 /* default ---- */
+
+#define ISP_SCALE_DIGITAL 0x80 /* Special digital effect */
+#define ISP_SCALE_EN 0x20 /* Scale enable */
+#define ISP_AUTO_BALANCE_EN 0x01 /* Auto white balance enable */
+#define ISP_COLOR_MATRIX_EN 0x02 /* Color matrix enable */
+#define ISP_TEST_EN 0x80
+#define ISP_TEST_00 0x00 /* 00: Standard eight color bar */
+#define ISP_TEST_01 0x01 /* 01: Gradual change at vertical mode 1 */
+#define ISP_TEST_10 0x02 /* 10: Gradual change at horizontal */
+#define ISP_TEST_11 0x03 /* 11: Gradual change at vertical mode 2 */
+#define ISP_TEST_TRANSPARENT 0x20 /* Transparent */
+#define ISP_TEST_ROLLING 0x40 /* Rolling */
+
+/* AWB Control [0x5180 ~ 0x51D0] */
+#define OV5640_AWB_CTRL_00 0x5180 /* default 0xff */
+#define OV5640_AWB_CTRL_01 0x5181 /* default 0x58 -> all 0xf2 */
+#define OV5640_AWB_CTRL_02 0x5182 /* default 0x11 -> all 0x00 */
+#define OV5640_AWB_CTRL_03 0x5183 /* default 0x90 -> all 0x14 */
+#define OV5640_AWB_CTRL_04 0x5184 /* default 0x25 */
+#define OV5640_AWB_CTRL_05 0x5185 /* default 0x24 */
+#define OV5640_AWB_CTRL_06 0x5186 /* default ---- -> all 0x09 */
+#define OV5640_AWB_CTRL_07 0x5187 /* default ---- -> all 0x09 */
+#define OV5640_AWB_CTRL_08 0x5188 /* default ---- -> all 0x09 */
+#define OV5640_AWB_CTRL_09 0x5189 /* default ---- -> all 0x75 */
+#define OV5640_AWB_CTRL_10 0x518a /* default ---- -> all 0x54 */
+#define OV5640_AWB_CTRL_11 0x518b /* default ---- -> all 0xe0 */
+#define OV5640_AWB_CTRL_12 0x518c /* default ---- -> all 0xb2 */
+#define OV5640_AWB_CTRL_13 0x518d /* default ---- -> all 0x42 */
+#define OV5640_AWB_CTRL_14 0x518e /* default ---- -> all 0x3d */
+#define OV5640_AWB_CTRL_15 0x518f /* default ---- -> all 0x56 */
+#define OV5640_AWB_CTRL_16 0x5190 /* default ---- -> all 0x46 */
+#define OV5640_AWB_CTRL_17 0x5191 /* default 0xff -> all 0xf8 */
+#define OV5640_AWB_CTRL_18 0x5192 /* default 0x00 -> all 0x04 */
+#define OV5640_AWB_CTRL_19 0x5193 /* default 0xf0 -> all 0x70 */
+#define OV5640_AWB_CTRL_20 0x5194 /* default 0xf0 */
+#define OV5640_AWB_CTRL_21 0x5195 /* default 0xf0 */
+#define OV5640_AWB_CTRL_22 0x5196 /* default 0x03 */
+#define OV5640_AWB_CTRL_23 0x5197 /* default 0x02 -> all 0x01 */
+#define OV5640_AWB_CTRL_24 0x5198 /* default ---- -> all 0x04 */
+#define OV5640_AWB_CTRL_25 0x5199 /* default ---- -> all 0x12 */
+#define OV5640_AWB_CTRL_26 0x519a /* default ---- -> all 0x04 */
+#define OV5640_AWB_CTRL_27 0x519b /* default ---- -> all 0x00 */
+#define OV5640_AWB_CTRL_28 0x519c /* default ---- -> all 0x06 */
+#define OV5640_AWB_CTRL_29 0x519d /* default ---- -> all 0x82 */
+#define OV5640_AWB_CTRL_30 0x519e /* default 0x02 -> all 0x38 */
+
+/* CIP Control [0x5300 ~ 0x530F] */
+#define OV5640_CIP_SH_MT_THRES_1 0x5300 /* default 0x08 */
+#define OV5640_CIP_SH_MT_THRES_2 0x5301 /* default 0x48 -> all 0x30 */
+#define OV5640_CIP_SH_MT_OFFSET_1 0x5302 /* default 0x18 -> all 0x10 */
+#define OV5640_CIP_SH_MT_OFFSET_2 0x5303 /* default 0x0e -> all 0x00 */
+#define OV5640_CIP_DNS_THRES_1 0x5304 /* default 0x08 */
+#define OV5640_CIP_DNS_THRES_2 0x5305 /* default 0x48 -> all 0x30 */
+#define OV5640_CIP_DNS_OFFSET_1 0x5306 /* default 0x09 -> all 0x08 */
+#define OV5640_CIP_DNS_OFFSET_2 0x5307 /* default 0x16 */
+#define OV5640_CIP_SH_TH_THRES_1 0x5309 /* default 0x08 */
+#define OV5640_CIP_SH_TH_THRES_2 0x530a /* default 0x48 -> all 0x30 */
+#define OV5640_CIP_SH_TH_OFFSET_1 0x530b /* default 0x04 */
+#define OV5640_CIP_SH_TH_OFFSET_2 0x530c /* default 0x06 */
+
+/* CMX Control [0x5380 ~ 0x538B] */
+#define OV5640_CMX1 0x5381 /* default 0x20 -> all 0x1e */
+#define OV5640_CMX2 0x5382 /* default 0x64 -> all 0x5b */
+#define OV5640_CMX3 0x5383 /* default 0x08 */
+#define OV5640_CMX4 0x5384 /* default 0x30 -> all 0x0a */
+#define OV5640_CMX5 0x5385 /* default 0x80 -> all 0x7e */
+#define OV5640_CMX6 0x5386 /* default 0xc0 -> all 0x88 */
+#define OV5640_CMX7 0x5387 /* default 0xa0 -> all 0x7c */
+#define OV5640_CMX8 0x5388 /* default 0x98 -> all 0x6c */
+#define OV5640_CMX9 0x5389 /* default 0x08 -> all 0x10 */
+#define OV5640_CMX_SIGN_0 0x538A /* default 0x01 */
+#define OV5640_CMX_SIGN_1 0x538B /* default 0x98 */
+
+/* Gamma Control [0x5480 ~ 0x5490] */
+#define OV5640_GAMMA_CTRL_00 0x5480 /* default 0x00 -> all 0x01 */
+#define OV5640_GAMMA_YST_00 0x5481 /* default 0x26 -> all 0x08 */
+#define OV5640_GAMMA_YST_01 0x5482 /* default 0x35 -> all 0x14 */
+
+#define OV5640_GAMMA_YST_02 0x5483 /* default 0x48 -> all 0x28 */
+#define OV5640_GAMMA_YST_03 0x5484 /* default 0x57 -> all 0x51 */
+#define OV5640_GAMMA_YST_04 0x5485 /* default 0x63 -> all 0x65 */
+#define OV5640_GAMMA_YST_05 0x5486 /* default 0x6e -> all 0x71 */
+
+#define OV5640_GAMMA_YST_06 0x5487 /* default 0x77 -> all 0x7d */
+#define OV5640_GAMMA_YST_07 0x5488 /* default 0x80 -> all 0x87 */
+#define OV5640_GAMMA_YST_08 0x5489 /* default 0x88 -> all 0x91 */
+#define OV5640_GAMMA_YST_09 0x548a /* default 0x96 -> all 0x9a */
+#define OV5640_GAMMA_YST_0A 0x548b /* default 0xa3 -> all 0xaa */
+#define OV5640_GAMMA_YST_0B 0x548c /* default 0xaf -> all 0xb8 */
+#define OV5640_GAMMA_YST_0C 0x548d /* default 0xc5 -> all 0xcd */
+#define OV5640_GAMMA_YST_0D 0x548e /* default 0xd7 -> all 0xdd */
+#define OV5640_GAMMA_YST_0E 0x548f /* default 0xe8 -> all 0xea */
+#define OV5640_GAMMA_YST_0F 0x5490 /* default 0x0f -> all 0x1d */
+
+/* SDE Control [0x5580 ~ 0x558C] */
+#define OV5640_SDE_CTRL_0 0x5580 /* default 0x00 -> all 0x02 */
+#define OV5640_SDE_CTRL_3 0x5583 /* default 0x40 */
+#define OV5640_SDE_CTRL_4 0x5584 /* default 0x40 -> all 0x10 */
+#define OV5640_SDE_CTRL_9 0x5589 /* default 0x01 -> all 0x10 */
+#define OV5640_SDE_CTRL_10 0x558a /* default 0x01 -> all 0x00 */
+#define OV5640_SDE_CTRL_11 0x558b /* default 0xff -> all 0xf8 */
+
+/* LENC Control [0x5800 ~ 0x5849] */
+#define OV5640_LENC_GMTRX_00 0x5800 /* default 0x10 -> all 0x23 */
+#define OV5640_LENC_GMTRX_01 0x5801 /* default 0x10 -> all 0x14 */
+#define OV5640_LENC_GMTRX_02 0x5802 /* default 0x10 -> all 0x0f */
+#define OV5640_LENC_GMTRX_03 0x5803 /* default 0x10 -> all 0x0f */
+#define OV5640_LENC_GMTRX_04 0x5804 /* default 0x10 -> all 0x12 */
+#define OV5640_LENC_GMTRX_05 0x5805 /* default 0x10 -> all 0x26 */
+#define OV5640_LENC_GMTRX_10 0x5806 /* default 0x10 -> all 0x0c */
+#define OV5640_LENC_GMTRX_11 0x5807 /* default 0x08 */
+#define OV5640_LENC_GMTRX_12 0x5808 /* default 0x08 -> all 0x05 */
+#define OV5640_LENC_GMTRX_13 0x5809 /* default 0x08 -> all 0x05 */
+#define OV5640_LENC_GMTRX_14 0x580a /* default 0x08 -> all */
+#define OV5640_LENC_GMTRX_15 0x580b /* default 0x10 -> all 0x0d */
+#define OV5640_LENC_GMTRX_20 0x580c /* default 0x10 -> all 0x08 */
+#define OV5640_LENC_GMTRX_21 0x580d /* default 0x08 -> all 0x03 */
+#define OV5640_LENC_GMTRX_22 0x580e /* default 0x00 */
+#define OV5640_LENC_GMTRX_23 0x580f /* default 0x00 */
+#define OV5640_LENC_GMTRX_24 0x5810 /* default 0x08 -> all 0x03 */
+#define OV5640_LENC_GMTRX_25 0x5811 /* default 0x10 -> all 0x09 */
+#define OV5640_LENC_GMTRX_30 0x5812 /* default 0x10 -> all 0x07 */
+#define OV5640_LENC_GMTRX_31 0x5813 /* default 0x08 -> all 0x03 */
+#define OV5640_LENC_GMTRX_32 0x5814 /* default 0x00 */
+#define OV5640_LENC_GMTRX_33 0x5815 /* default 0x00 -> all 0x01 */
+#define OV5640_LENC_GMTRX_34 0x5816 /* default 0x08 -> all 0x03 */
+#define OV5640_LENC_GMTRX_35 0x5817 /* default 0x10 -> all 0x08 */
+#define OV5640_LENC_GMTRX_40 0x5818 /* default 0x10 -> all 0x0d */
+#define OV5640_LENC_GMTRX_41 0x5819 /* default 0x08 */
+#define OV5640_LENC_GMTRX_42 0x581a /* default 0x08 -> all 0x05 */
+#define OV5640_LENC_GMTRX_43 0x581b /* default 0x08 -> all 0x06 */
+#define OV5640_LENC_GMTRX_44 0x581c /* default 0x08 */
+#define OV5640_LENC_GMTRX_45 0x581d /* default 0x10 -> all 0x0e */
+#define OV5640_LENC_GMTRX_50 0x581e /* default 0x10 -> all 0x29 */
+#define OV5640_LENC_GMTRX_51 0x581f /* default 0x10 -> all 0x17 */
+#define OV5640_LENC_GMTRX_52 0x5820 /* default 0x10 -> all 0x11 */
+#define OV5640_LENC_GMTRX_53 0x5821 /* default 0x10 -> all 0x11 */
+#define OV5640_LENC_GMTRX_54 0x5822 /* default 0x10 -> all 0x15 */
+#define OV5640_LENC_GMTRX_55 0x5823 /* default 0x10 -> all 0x28 */
+#define OV5640_LENC_BRMATRX_00 0x5824 /* default 0xaa -> all 0x46 */
+#define OV5640_LENC_BRMATRX_01 0x5825 /* default 0xaa -> all 0x26 */
+#define OV5640_LENC_BRMATRX_02 0x5826 /* default 0xaa -> all 0x08 */
+#define OV5640_LENC_BRMATRX_03 0x5827 /* default 0xaa -> all 0x26 */
+#define OV5640_LENC_BRMATRX_04 0x5828 /* default 0xaa -> all 0x64 */
+#define OV5640_LENC_BRMATRX_05 0x5829 /* default 0xaa -> all 0x26 */
+#define OV5640_LENC_BRMATRX_06 0x582a /* default 0x99 -> all 0x24 */
+#define OV5640_LENC_BRMATRX_07 0x582b /* default 0x99 -> all 0x22 */
+#define OV5640_LENC_BRMATRX_08 0x582c /* default 0x99 -> all 0x24 */
+#define OV5640_LENC_BRMATRX_09 0x582d /* default 0xaa -> all 0x24 */
+#define OV5640_LENC_BRMATRX_20 0x582e /* default 0xaa -> all 0x06 */
+#define OV5640_LENC_BRMATRX_21 0x582f /* default 0x99 -> all 0x22 */
+#define OV5640_LENC_BRMATRX_22 0x5830 /* default 0x88 -> all 0x40 */
+#define OV5640_LENC_BRMATRX_23 0x5831 /* default 0x99 -> all 0x42 */
+#define OV5640_LENC_BRMATRX_24 0x5832 /* default 0xaa -> all 0x24 */
+#define OV5640_LENC_BRMATRX_30 0x5833 /* default 0xaa -> all 0x26 */
+#define OV5640_LENC_BRMATRX_31 0x5834 /* default 0x99 -> all 0x24 */
+#define OV5640_LENC_BRMATRX_32 0x5835 /* default 0x99 -> all 0x22 */
+#define OV5640_LENC_BRMATRX_33 0x5836 /* default 0x99 -> all 0x22 */
+#define OV5640_LENC_BRMATRX_34 0x5837 /* default 0xaa -> all 0x26 */
+#define OV5640_LENC_BRMATRX_40 0x5838 /* default 0xaa -> all 0x44 */
+#define OV5640_LENC_BRMATRX_41 0x5839 /* default 0xaa -> all 0x24 */
+#define OV5640_LENC_BRMATRX_42 0x583a /* default 0xaa -> all 0x26 */
+#define OV5640_LENC_BRMATRX_43 0x583b /* default 0xaa -> all 0x28 */
+#define OV5640_LENC_BRMATRX_44 0x583c /* default 0xaa -> all 0x42 */
+#define OV5640_LENC_BR_OFFSET 0x583d /* default 0x88 -> all 0xce */
+
+
static struct ov5640_reg mode_2592x1944[] = {
/* PLL Control MIPI bit rate/lane = 672MHz, 16-bit mode.
- * Output size: 2608x1948 (0, 0) - (2623, 1951),
+ * Output size: 2592x1944 (0, 0) - (2623, 1951),
* Line Length = 2844, Frame Length = 1968
+ * Scaling method: full resolution (dummy 16 pixel
+ * horizontal, 8 lines) 2608x1952 with dummy
*/
- {0x3103, 0x11},
- {0x3008, 0x82},
- {OV5640_TABLE_WAIT_MS, 5},
- {0x3008, 0x42},
- {0x3103, 0x03},
- {0x3017, 0x00},
- {0x3018, 0x00},
- {0x3034, 0x18},
- {0x3035, 0x11},
- {0x3036, 0x7d},
- {0x3037, 0x13},
- {0x3108, 0x01},
- {0x3630, 0x36},
- {0x3631, 0x0e},
- {0x3632, 0xe2},
- {0x3633, 0x12},
- {0x3621, 0xe0},
- {0x3704, 0xa0},
- {0x3703, 0x5a},
- {0x3715, 0x78},
- {0x3717, 0x01},
- {0x370b, 0x60},
- {0x3705, 0x1a},
- {0x3905, 0x02},
- {0x3906, 0x10},
- {0x3901, 0x0a},
- {0x3731, 0x12},
- {0x3600, 0x08},
- {0x3601, 0x33},
- {0x302d, 0x60},
- {0x3620, 0x52},
- {0x371b, 0x20},
- {0x471c, 0x50},
- {0x3a13, 0x43},
- {0x3a18, 0x00},
- {0x3a19, 0xf8},
- {0x3635, 0x13},
- {0x3636, 0x03},
- {0x3634, 0x40},
- {0x3622, 0x01},
- {0x3c01, 0x34},
- {0x3c04, 0x28},
- {0x3c05, 0x98},
- {0x3c06, 0x00},
- {0x3c07, 0x07},
- {0x3c08, 0x00},
- {0x3c09, 0x1c},
- {0x3c0a, 0x9c},
- {0x3c0b, 0x40},
- {0x3820, 0x40},
- {0x3821, 0x06},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x00},
- {0x3804, 0x0a},
- {0x3805, 0x3f},
- {0x3806, 0x07},
- {0x3807, 0x9f},
- {0x3808, 0x0a},
- {0x3809, 0x30},
- {0x380a, 0x07},
- {0x380b, 0x9c},
- {0x380c, 0x0b},
- {0x380d, 0x1c},
- {0x380e, 0x07},
- {0x380f, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x02},
- {0x3618, 0x04},
+
+ {OV5640_SC_PLL_CTRL0, 0x10 | MIPI_MODE_8BIT },
+ {OV5640_SC_PLL_CTRL1, 0x11},
+ {OV5640_SC_PLL_CTRL2, 0x7d}, /* default 0x69 PLL multipier */
+ {OV5640_SC_PLL_CTRL3, 0x03 | (1<<4) }, /* default 0x03 PLL divided by 2 */
+
+ {OV5640_MIPI_CTRL_00, 0x04},
+ {OV5640_MIPI_PCLK_PERIOD, 0x0a},
+
+ {OV5640_ISP_CTRL_00, 0xa7},
+ {OV5640_ISP_CTRL_01, 0x83},
+ {OV5640_ISP_MUX_CTRL, 0x00},
+
+ /* Timing Control */
+ {OV5640_TIMING_HS_H, OV5640_ADDR_H(0) },
+ {OV5640_TIMING_HS_L, OV5640_ADDR_L(0) },
+ {OV5640_TIMING_VS_H, OV5640_ADDR_H(0) },
+ {OV5640_TIMING_VS_L, OV5640_ADDR_L(0) },
+ {OV5640_TIMING_HW_H, OV5640_ADDR_H(2623) },
+ {OV5640_TIMING_HW_L, OV5640_ADDR_L(2623) },
+ {OV5640_TIMING_VH_H, OV5640_ADDR_H(1951) },
+ {OV5640_TIMING_VH_L, OV5640_ADDR_L(1951) },
+ {OV5640_TIMING_DVPHO_H, OV5640_WIDTH_H(2592) },
+ {OV5640_TIMING_DVPHO_L, OV5640_WIDTH_L(2592) },
+ {OV5640_TIMING_DVPVO_H, OV5640_HEIGHT_H(1944) },
+ {OV5640_TIMING_DVPVO_L, OV5640_HEIGHT_L(1944) },
+ {OV5640_TIMING_HTS_H, OV5640_HTS_H(2844) },
+ {OV5640_TIMING_HTS_L, OV5640_HTS_L(2844) },
+ {OV5640_TIMING_VTS_H, OV5640_VTS_H(1968) },
+ {OV5640_TIMING_VTS_L, OV5640_VTS_L(1968) },
+ {OV5640_TIMING_HOFFSET_H, OV5640_H_OFFSET_H(16) }, // (2623-2592-1)/2
+ {OV5640_TIMING_HOFFSET_L, OV5640_H_OFFSET_L(16) },
+ {OV5640_TIMING_VOFFSET_H, OV5640_V_OFFSET_H(4) }, // (1951-1944-1)/2
+ {OV5640_TIMING_VOFFSET_L, OV5640_V_OFFSET_L(4) },
+ {OV5640_TIMING_X_INC, 0x11},
+ {OV5640_TIMING_Y_INC, 0x11},
+ {OV5640_TIMING_REG20, 0x40},
+ {OV5640_TIMING_REG21, 0},
+
+ /* magic registers */
{0x3612, 0x2b},
+ {0x3618, 0x04},
{0x3708, 0x64},
{0x3709, 0x12},
{0x370c, 0x00},
- {0x3a02, 0x07},
- {0x3a03, 0xb0},
- {0x3a08, 0x01},
- {0x3a09, 0x27},
- {0x3a0a, 0x00},
- {0x3a0b, 0xf6},
- {0x3a0e, 0x06},
- {0x3a0d, 0x08},
- {0x3a14, 0x07},
- {0x3a15, 0xb0},
- {0x4001, 0x02},
- {0x4004, 0x06},
- {0x3000, 0x00},
- {0x3002, 0x1c},
- {0x3004, 0xff},
- {0x3006, 0xc3},
- {0x300e, 0x45},
- {0x302e, 0x08},
- {0x4300, 0x32},
- {0x4800, 0x24},
- {0x4837, 0x0a},
- {0x501f, 0x00},
- {0x440e, 0x00},
- {0x5000, 0xa7},
- {0x5001, 0x83},
- {0x5180, 0xff},
- {0x5181, 0xf2},
- {0x5182, 0x00},
- {0x5183, 0x14},
- {0x5184, 0x25},
- {0x5185, 0x24},
- {0x5186, 0x09},
- {0x5187, 0x09},
- {0x5188, 0x09},
- {0x5189, 0x75},
- {0x518a, 0x54},
- {0x518b, 0xe0},
- {0x518c, 0xb2},
- {0x518d, 0x42},
- {0x518e, 0x3d},
- {0x518f, 0x56},
- {0x5190, 0x46},
- {0x5191, 0xf8},
- {0x5192, 0x04},
- {0x5193, 0x70},
- {0x5194, 0xf0},
- {0x5195, 0xf0},
- {0x5196, 0x03},
- {0x5197, 0x01},
- {0x5198, 0x04},
- {0x5199, 0x12},
- {0x519a, 0x04},
- {0x519b, 0x00},
- {0x519c, 0x06},
- {0x519d, 0x82},
- {0x519e, 0x38},
- {0x5381, 0x1e},
- {0x5382, 0x5b},
- {0x5383, 0x08},
- {0x5384, 0x0a},
- {0x5385, 0x7e},
- {0x5386, 0x88},
- {0x5387, 0x7c},
- {0x5388, 0x6c},
- {0x5389, 0x10},
- {0x538a, 0x01},
- {0x538b, 0x98},
- {0x5300, 0x08},
- {0x5301, 0x30},
- {0x5302, 0x10},
- {0x5303, 0x00},
- {0x5304, 0x08},
- {0x5305, 0x30},
- {0x5306, 0x08},
- {0x5307, 0x16},
- {0x5309, 0x08},
- {0x530a, 0x30},
- {0x530b, 0x04},
- {0x530c, 0x06},
- {0x5480, 0x01},
- {0x5481, 0x08},
- {0x5482, 0x14},
- {0x5483, 0x28},
- {0x5484, 0x51},
- {0x5485, 0x65},
- {0x5486, 0x71},
- {0x5487, 0x7d},
- {0x5488, 0x87},
- {0x5489, 0x91},
- {0x548a, 0x9a},
- {0x548b, 0xaa},
- {0x548c, 0xb8},
- {0x548d, 0xcd},
- {0x548e, 0xdd},
- {0x548f, 0xea},
- {0x5490, 0x1d},
- {0x5580, 0x02},
- {0x5583, 0x40},
- {0x5584, 0x10},
- {0x5589, 0x10},
- {0x558a, 0x00},
- {0x558b, 0xf8},
- {0x5800, 0x23},
- {0x5801, 0x14},
- {0x5802, 0x0f},
- {0x5803, 0x0f},
- {0x5804, 0x12},
- {0x5805, 0x26},
- {0x5806, 0x0c},
- {0x5807, 0x08},
- {0x5808, 0x05},
- {0x5809, 0x05},
- {0x580a, 0x08},
- {0x580b, 0x0d},
- {0x580c, 0x08},
- {0x580d, 0x03},
- {0x580e, 0x00},
- {0x580f, 0x00},
- {0x5810, 0x03},
- {0x5811, 0x09},
- {0x5812, 0x07},
- {0x5813, 0x03},
- {0x5814, 0x00},
- {0x5815, 0x01},
- {0x5816, 0x03},
- {0x5817, 0x08},
- {0x5818, 0x0d},
- {0x5819, 0x08},
- {0x581a, 0x05},
- {0x581b, 0x06},
- {0x581c, 0x08},
- {0x581d, 0x0e},
- {0x581e, 0x29},
- {0x581f, 0x17},
- {0x5820, 0x11},
- {0x5821, 0x11},
- {0x5822, 0x15},
- {0x5823, 0x28},
- {0x5824, 0x46},
- {0x5825, 0x26},
- {0x5826, 0x08},
- {0x5827, 0x26},
- {0x5828, 0x64},
- {0x5829, 0x26},
- {0x582a, 0x24},
- {0x582b, 0x22},
- {0x582c, 0x24},
- {0x582d, 0x24},
- {0x582e, 0x06},
- {0x582f, 0x22},
- {0x5830, 0x40},
- {0x5831, 0x42},
- {0x5832, 0x24},
- {0x5833, 0x26},
- {0x5834, 0x24},
- {0x5835, 0x22},
- {0x5836, 0x22},
- {0x5837, 0x26},
- {0x5838, 0x44},
- {0x5839, 0x24},
- {0x583a, 0x26},
- {0x583b, 0x28},
- {0x583c, 0x42},
- {0x583d, 0xce},
- {0x5025, 0x00},
- {0x3a0f, 0x30},
- {0x3a10, 0x28},
- {0x3a1b, 0x30},
- {0x3a1e, 0x26},
- {0x3a11, 0x60},
- {0x3a1f, 0x14},
- {0x3008, 0x02},
+
+ /* AEC/AGC Power Down Domain Control */
+ {OV5640_AEC_MAX_EXPO60_H, 0x07},
+ {OV5640_AEC_MAX_EXPO60_L, 0xb0},
+ {OV5640_AEC_B50_STEP_H, 0x01},
+ {OV5640_AEC_B50_STEP_L, 0x27},
+ {OV5640_AEC_B60_STEP_H, 0x00},
+ {OV5640_AEC_B60_STEP_L, 0xf6},
+ {OV5640_AEC_CTRL_0E, 0x06},
+ {OV5640_AEC_CTRL_0D, 0x08},
+ {OV5640_AEC_MAX_EXPO_H, 0x07},
+ {OV5640_AEC_MAX_EXPO_L, 0xb0},
+ {OV5640_AEC_CTRL_13, 0x43},
+ {OV5640_AEC_GAIN_CEILING_0, 0x00},
+ {OV5640_AEC_GAIN_CEILING_1, 0xf8},
+ {OV5640_AEC_CTRL_0F, 0x30},
+ {OV5640_AEC_CTRL_10, 0x28},
+ {OV5640_AEC_CTRL_1B, 0x30},
+ {OV5640_AEC_CTRL_1E, 0x26},
+ {OV5640_AEC_CTRL_11, 0x60},
+ {OV5640_AEC_CTRL_1F, 0x14},
+
+ {OV5640_SYSTEM_CTRL, 0x02},
{OV5640_TABLE_END, 0x0000}
};
static struct ov5640_reg mode_1920x1080[] = {
/* PLL Control MIPI bit rate/lane = 672MHz, 16-bit mode.
- * Output size: 1936x1096 (336, 426) - (2287, 1529),
+ * Output size: 1936x1088 (336, 426) - (2287, 1529),
* Line Length = 2500, Frame Length = 1120.
+ * Scaling method: cropping from full resolution
+ * 1936x1088 with dummy pixels
*/
- {0x3103, 0x11},
- {0x3008, 0x82},
- {OV5640_TABLE_WAIT_MS, 5},
- {0x3008, 0x42},
- {0x3103, 0x03},
- {0x3017, 0x00},
- {0x3018, 0x00},
- {0x3034, 0x18},
- {0x3035, 0x11},
- {0x3036, 0x54},
- {0x3037, 0x13},
- {0x3108, 0x01},
- {0x3630, 0x36},
- {0x3631, 0x0e},
- {0x3632, 0xe2},
- {0x3633, 0x12},
- {0x3621, 0xe0},
- {0x3704, 0xa0},
- {0x3703, 0x5a},
- {0x3715, 0x78},
- {0x3717, 0x01},
- {0x370b, 0x60},
- {0x3705, 0x1a},
- {0x3905, 0x02},
- {0x3906, 0x10},
- {0x3901, 0x0a},
- {0x3731, 0x12},
- {0x3600, 0x08},
- {0x3601, 0x33},
- {0x302d, 0x60},
- {0x3620, 0x52},
- {0x371b, 0x20},
- {0x471c, 0x50},
- {0x3a13, 0x43},
- {0x3a18, 0x00},
- {0x3a19, 0xf8},
- {0x3635, 0x13},
- {0x3636, 0x03},
- {0x3634, 0x40},
- {0x3622, 0x01},
- {0x3c01, 0x34},
- {0x3c04, 0x28},
- {0x3c05, 0x98},
- {0x3c06, 0x00},
- {0x3c07, 0x07},
- {0x3c08, 0x00},
- {0x3c09, 0x1c},
- {0x3c0a, 0x9c},
- {0x3c0b, 0x40},
- {0x3820, 0x40},
- {0x3821, 0x06},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x3800, 0x01},
- {0x3801, 0x50},
- {0x3802, 0x01},
- {0x3803, 0xaa},
- {0x3804, 0x08},
- {0x3805, 0xef},
- {0x3806, 0x05},
- {0x3807, 0xf9},
- {0x3808, 0x07},
- {0x3809, 0x90},
- {0x380a, 0x04},
- {0x380b, 0x48},
- {0x380c, 0x09},
- {0x380d, 0xc4},
- {0x380e, 0x04},
- {0x380f, 0x60},
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3618, 0x04},
+
+ {OV5640_SC_PLL_CTRL0, 0x10 | MIPI_MODE_8BIT },
+ {OV5640_SC_PLL_CTRL1, 0x11},
+ {OV5640_SC_PLL_CTRL2, 0x54}, /* default 0x69 PLL multipier */
+ {OV5640_SC_PLL_CTRL3, 0x03 | (1<<4) }, /* default 0x03 PLL divided by 2 */
+
+ {OV5640_MIPI_CTRL_00, 0x04},
+ {OV5640_MIPI_PCLK_PERIOD, 0x0a},
+
+ {OV5640_ISP_CTRL_00, 0xa7},
+ {OV5640_ISP_CTRL_01, 0x83},
+ {OV5640_ISP_MUX_CTRL, 0x00},
+
+ /* Timing Control */
+ {OV5640_TIMING_HS_H, OV5640_ADDR_H(336) },
+ {OV5640_TIMING_HS_L, OV5640_ADDR_L(336) },
+ {OV5640_TIMING_VS_H, OV5640_ADDR_H(426) },
+ {OV5640_TIMING_VS_L, OV5640_ADDR_L(426) },
+ {OV5640_TIMING_HW_H, OV5640_ADDR_H(2287) },
+ {OV5640_TIMING_HW_L, OV5640_ADDR_L(2287) },
+ {OV5640_TIMING_VH_H, OV5640_ADDR_H(1529) },
+ {OV5640_TIMING_VH_L, OV5640_ADDR_L(1529) },
+ {OV5640_TIMING_DVPHO_H, OV5640_WIDTH_H(1920) }, //1936
+ {OV5640_TIMING_DVPHO_L, OV5640_WIDTH_L(1920) },
+ {OV5640_TIMING_DVPVO_H, OV5640_HEIGHT_H(1080) }, //1088
+ {OV5640_TIMING_DVPVO_L, OV5640_HEIGHT_L(1080) },
+ {OV5640_TIMING_HTS_H, OV5640_HTS_H(2500) },
+ {OV5640_TIMING_HTS_L, OV5640_HTS_L(2500) },
+ {OV5640_TIMING_VTS_H, OV5640_VTS_H(1120) },
+ {OV5640_TIMING_VTS_L, OV5640_VTS_L(1120) },
+ {OV5640_TIMING_HOFFSET_H, OV5640_H_OFFSET_H(15) }, // (2287-336-1936-1)/2
+ {OV5640_TIMING_HOFFSET_L, OV5640_H_OFFSET_L(15) },
+ {OV5640_TIMING_VOFFSET_H, OV5640_V_OFFSET_H(11) }, // (1529-426-1088-1)/2
+ {OV5640_TIMING_VOFFSET_L, OV5640_V_OFFSET_L(11) },
+ {OV5640_TIMING_X_INC, 0x11},
+ {OV5640_TIMING_Y_INC, 0x11},
+ {OV5640_TIMING_REG20, 0x40},
+ {OV5640_TIMING_REG21, 0},
+
+ /* magic registers */
{0x3612, 0x2b},
+ {0x3618, 0x04},
{0x3708, 0x64},
{0x3709, 0x12},
{0x370c, 0x00},
- {0x3a02, 0x04},
- {0x3a03, 0x60},
- {0x3a08, 0x01},
- {0x3a09, 0x50},
- {0x3a0a, 0x01},
- {0x3a0b, 0x18},
- {0x3a0e, 0x03},
- {0x3a0d, 0x04},
- {0x3a14, 0x04},
- {0x3a15, 0x60},
- {0x4001, 0x02},
- {0x4004, 0x06},
- {0x3000, 0x00},
- {0x3002, 0x1c},
- {0x3004, 0xff},
- {0x3006, 0xc3},
- {0x300e, 0x45},
- {0x302e, 0x08},
- {0x4300, 0x32},
- {0x501f, 0x00},
- {0x4713, 0x02},
- {0x4407, 0x04},
- {0x440e, 0x00},
- {0x460b, 0x37},
- {0x460c, 0x20},
- {0x4800, 0x24},
- {0x4837, 0x0a},
- {0x3824, 0x04},
- {0x5000, 0xa7},
- {0x5001, 0x83},
- {0x5180, 0xff},
- {0x5181, 0xf2},
- {0x5182, 0x00},
- {0x5183, 0x14},
- {0x5184, 0x25},
- {0x5185, 0x24},
- {0x5186, 0x09},
- {0x5187, 0x09},
- {0x5188, 0x09},
- {0x5189, 0x75},
- {0x518a, 0x54},
- {0x518b, 0xe0},
- {0x518c, 0xb2},
- {0x518d, 0x42},
- {0x518e, 0x3d},
- {0x518f, 0x56},
- {0x5190, 0x46},
- {0x5191, 0xf8},
- {0x5192, 0x04},
- {0x5193, 0x70},
- {0x5194, 0xf0},
- {0x5195, 0xf0},
- {0x5196, 0x03},
- {0x5197, 0x01},
- {0x5198, 0x04},
- {0x5199, 0x12},
- {0x519a, 0x04},
- {0x519b, 0x00},
- {0x519c, 0x06},
- {0x519d, 0x82},
- {0x519e, 0x38},
- {0x5381, 0x1e},
- {0x5382, 0x5b},
- {0x5383, 0x08},
- {0x5384, 0x0a},
- {0x5385, 0x7e},
- {0x5386, 0x88},
- {0x5387, 0x7c},
- {0x5388, 0x6c},
- {0x5389, 0x10},
- {0x538a, 0x01},
- {0x538b, 0x98},
- {0x5300, 0x08},
- {0x5301, 0x30},
- {0x5302, 0x10},
- {0x5303, 0x00},
- {0x5304, 0x08},
- {0x5305, 0x30},
- {0x5306, 0x08},
- {0x5307, 0x16},
- {0x5309, 0x08},
- {0x530a, 0x30},
- {0x530b, 0x04},
- {0x530c, 0x06},
- {0x5480, 0x01},
- {0x5481, 0x08},
- {0x5482, 0x14},
- {0x5483, 0x28},
- {0x5484, 0x51},
- {0x5485, 0x65},
- {0x5486, 0x71},
- {0x5487, 0x7d},
-
- {0x5488, 0x87},
- {0x5489, 0x91},
- {0x548a, 0x9a},
- {0x548b, 0xaa},
- {0x548c, 0xb8},
- {0x548d, 0xcd},
- {0x548e, 0xdd},
- {0x548f, 0xea},
- {0x5490, 0x1d},
- {0x5580, 0x02},
- {0x5583, 0x40},
- {0x5584, 0x10},
- {0x5589, 0x10},
- {0x558a, 0x00},
- {0x558b, 0xf8},
- {0x5800, 0x23},
- {0x5801, 0x14},
- {0x5802, 0x0f},
- {0x5803, 0x0f},
- {0x5804, 0x12},
- {0x5805, 0x26},
- {0x5806, 0x0c},
- {0x5807, 0x08},
- {0x5808, 0x05},
- {0x5809, 0x05},
- {0x580a, 0x08},
- {0x580b, 0x0d},
- {0x580c, 0x08},
- {0x580d, 0x03},
- {0x580e, 0x00},
- {0x580f, 0x00},
- {0x5810, 0x03},
- {0x5811, 0x09},
- {0x5812, 0x07},
- {0x5813, 0x03},
- {0x5814, 0x00},
- {0x5815, 0x01},
- {0x5816, 0x03},
- {0x5817, 0x08},
- {0x5818, 0x0d},
- {0x5819, 0x08},
- {0x581a, 0x05},
- {0x581b, 0x06},
- {0x581c, 0x08},
- {0x581d, 0x0e},
- {0x581e, 0x29},
- {0x581f, 0x17},
- {0x5820, 0x11},
- {0x5821, 0x11},
- {0x5822, 0x15},
- {0x5823, 0x28},
- {0x5824, 0x46},
- {0x5825, 0x26},
- {0x5826, 0x08},
- {0x5827, 0x26},
- {0x5828, 0x64},
- {0x5829, 0x26},
- {0x582a, 0x24},
- {0x582b, 0x22},
- {0x582c, 0x24},
- {0x582d, 0x24},
- {0x582e, 0x06},
- {0x582f, 0x22},
- {0x5830, 0x40},
- {0x5831, 0x42},
- {0x5832, 0x24},
- {0x5833, 0x26},
- {0x5834, 0x24},
- {0x5835, 0x22},
- {0x5836, 0x22},
- {0x5837, 0x26},
- {0x5838, 0x44},
- {0x5839, 0x24},
- {0x583a, 0x26},
- {0x583b, 0x28},
- {0x583c, 0x42},
- {0x583d, 0xce},
- {0x5025, 0x00},
- {0x3a0f, 0x30},
- {0x3a10, 0x28},
- {0x3a1b, 0x30},
- {0x3a1e, 0x26},
- {0x3a11, 0x60},
- {0x3a1f, 0x14},
- {0x3008, 0x02},
+
+ /* AEC/AGC Power Down Domain Control */
+ {OV5640_AEC_MAX_EXPO60_H, 0x04},
+ {OV5640_AEC_MAX_EXPO60_L, 0x60},
+ {OV5640_AEC_B50_STEP_H, 0x01},
+ {OV5640_AEC_B50_STEP_L, 0x50},
+ {OV5640_AEC_B60_STEP_H, 0x01},
+ {OV5640_AEC_B60_STEP_L, 0x18},
+ {OV5640_AEC_CTRL_0E, 0x03},
+ {OV5640_AEC_CTRL_0D, 0x04},
+ {OV5640_AEC_MAX_EXPO_H, 0x04},
+ {OV5640_AEC_MAX_EXPO_L, 0x60},
+ {OV5640_AEC_CTRL_13, 0x43},
+ {OV5640_AEC_GAIN_CEILING_0, 0x00},
+ {OV5640_AEC_GAIN_CEILING_1, 0xf8},
+ {OV5640_AEC_CTRL_0F, 0x30},
+ {OV5640_AEC_CTRL_10, 0x28},
+ {OV5640_AEC_CTRL_1B, 0x30},
+ {OV5640_AEC_CTRL_1E, 0x26},
+ {OV5640_AEC_CTRL_11, 0x60},
+ {OV5640_AEC_CTRL_1F, 0x14},
+
+ {OV5640_SYSTEM_CTRL, 0x02},
{OV5640_TABLE_END, 0x0000}
};
-static struct ov5640_reg mode_1296x972[] = {
+static struct ov5640_reg mode_1280x960[] = {
/* PLL Control MIPI bit rate/lane = 448MHz, 16-bit mode.
* Output size: 1304x972 (0, 0) - (2623, 1951),
* Line Length = 1886, Frame Length = 990.
+ * Scaling method: subsampling in vertical and horizontal
+ * 1296x968 supports 2x2 binning
*/
- {0x3103, 0x11},
- {0x3008, 0x82},
- {OV5640_TABLE_WAIT_MS, 5},
- {0x3008, 0x42},
- {0x3103, 0x03},
- {0x3017, 0x00},
- {0x3018, 0x00},
- {0x3034, 0x18},
- {0x3035, 0x21},
- {0x3036, 0x70},
- {0x3037, 0x13},
- {0x3108, 0x01},
- {0x3630, 0x36},
- {0x3631, 0x0e},
- {0x3632, 0xe2},
- {0x3633, 0x12},
- {0x3621, 0xe0},
- {0x3704, 0xa0},
- {0x3703, 0x5a},
- {0x3715, 0x78},
- {0x3717, 0x01},
- {0x370b, 0x60},
- {0x3705, 0x1a},
- {0x3905, 0x02},
- {0x3906, 0x10},
- {0x3901, 0x0a},
- {0x3731, 0x12},
- {0x3600, 0x08},
- {0x3601, 0x33},
- {0x302d, 0x60},
- {0x3620, 0x52},
- {0x371b, 0x20},
- {0x471c, 0x50},
- {0x3a13, 0x43},
- {0x3a18, 0x00},
- {0x3a19, 0xf8},
- {0x3635, 0x13},
- {0x3636, 0x03},
- {0x3634, 0x40},
- {0x3622, 0x01},
- {0x3c01, 0x34},
- {0x3c04, 0x28},
- {0x3c05, 0x98},
- {0x3c06, 0x00},
- {0x3c07, 0x07},
- {0x3c08, 0x00},
- {0x3c09, 0x1c},
- {0x3c0a, 0x9c},
- {0x3c0b, 0x40},
- {0x3820, 0x41},
- {0x3821, 0x07},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x00},
- {0x3804, 0x0a},
- {0x3805, 0x3f},
- {0x3806, 0x07},
- {0x3807, 0x9f},
- {0x3808, 0x05},
- {0x3809, 0x18},
- {0x380a, 0x03},
- {0x380b, 0xcc},
- {0x380c, 0x07},
- {0x380d, 0x5e},
- {0x380e, 0x03},
- {0x380f, 0xde},
- {0x3810, 0x00},
- {0x3811, 0x06},
- {0x3812, 0x00},
- {0x3813, 0x02},
- {0x3618, 0x00},
+
+ {OV5640_SC_PLL_CTRL0, 0x10 | MIPI_MODE_8BIT },
+ {OV5640_SC_PLL_CTRL1, 0x21},
+ {OV5640_SC_PLL_CTRL2, 0x70}, /* default 0x69 PLL multipier */
+ {OV5640_SC_PLL_CTRL3, 0x03 | (1<<4) }, /* default 0x03 PLL divided by 2 */
+
+ {OV5640_MIPI_CTRL_00, 0x04},
+ {OV5640_MIPI_PCLK_PERIOD, 0x10},
+
+ {OV5640_ISP_CTRL_00, 0xa7},
+ {OV5640_ISP_CTRL_01, 0x83},
+ {OV5640_ISP_MUX_CTRL, 0x00},
+
+ /* Timing Control */
+ {OV5640_TIMING_HS_H, OV5640_ADDR_H(0) },
+ {OV5640_TIMING_HS_L, OV5640_ADDR_L(0) },
+ {OV5640_TIMING_VS_H, OV5640_ADDR_H(0) },
+ {OV5640_TIMING_VS_L, OV5640_ADDR_L(0) },
+ {OV5640_TIMING_HW_H, OV5640_ADDR_H(2623) },
+ {OV5640_TIMING_HW_L, OV5640_ADDR_L(2623) },
+ {OV5640_TIMING_VH_H, OV5640_ADDR_H(1951) },
+ {OV5640_TIMING_VH_L, OV5640_ADDR_L(1951) },
+ {OV5640_TIMING_DVPHO_H, OV5640_WIDTH_H(1280) },
+ {OV5640_TIMING_DVPHO_L, OV5640_WIDTH_L(1280) },
+ {OV5640_TIMING_DVPVO_H, OV5640_HEIGHT_H(960) },
+ {OV5640_TIMING_DVPVO_L, OV5640_HEIGHT_L(960) },
+ {OV5640_TIMING_HTS_H, OV5640_HTS_H(1886) },
+ {OV5640_TIMING_HTS_L, OV5640_HTS_L(1886) },
+ {OV5640_TIMING_VTS_H, OV5640_VTS_H(990) },
+ {OV5640_TIMING_VTS_L, OV5640_VTS_L(990) },
+ {OV5640_TIMING_HOFFSET_H, OV5640_H_OFFSET_H(31) }, // (2623-0-(1280*2)-1)/2
+ {OV5640_TIMING_HOFFSET_L, OV5640_H_OFFSET_L(31) },
+ {OV5640_TIMING_VOFFSET_H, OV5640_V_OFFSET_H(15) }, // (1951-0-(960*2)-1)/2
+ {OV5640_TIMING_VOFFSET_L, OV5640_V_OFFSET_L(15) },
+ {OV5640_TIMING_X_INC, 0x11 | (3<<4) },
+ {OV5640_TIMING_Y_INC, 0x11 | (3<<4) },
+ {OV5640_TIMING_REG20, 0x40},
+ {OV5640_TIMING_REG21, REG21_BINNING_EN},
+
+ /* magic registers */
{0x3612, 0x29},
+ {0x3618, 0x00},
{0x3708, 0x62},
{0x3709, 0x52},
{0x370c, 0x03},
- {0x3a02, 0x03},
- {0x3a03, 0xd8},
- {0x3a08, 0x01},
- {0x3a09, 0x27},
- {0x3a0a, 0x00},
- {0x3a0b, 0xf6},
- {0x3a0e, 0x03},
- {0x3a0d, 0x04},
- {0x3a14, 0x03},
- {0x3a15, 0xd8},
- {0x4001, 0x02},
- {0x4004, 0x02},
- {0x3000, 0x00},
- {0x3002, 0x1c},
- {0x3004, 0xff},
- {0x3006, 0xc3},
- {0x300e, 0x45},
- {0x302e, 0x08},
- {0x4300, 0x32},
- {0x501f, 0x00},
- {0x4713, 0x02},
- {0x4407, 0x04},
- {0x440e, 0x00},
- {0x460b, 0x37},
- {0x460c, 0x20},
- {0x4800, 0x24},
- {0x4837, 0x10},
- {0x3824, 0x04},
- {0x5000, 0xa7},
- {0x5001, 0x83},
- {0x5180, 0xff},
- {0x5181, 0xf2},
- {0x5182, 0x00},
- {0x5183, 0x14},
- {0x5184, 0x25},
- {0x5185, 0x24},
- {0x5186, 0x09},
- {0x5187, 0x09},
- {0x5188, 0x09},
- {0x5189, 0x75},
- {0x518a, 0x54},
- {0x518b, 0xe0},
- {0x518c, 0xb2},
- {0x518d, 0x42},
- {0x518e, 0x3d},
- {0x518f, 0x56},
- {0x5190, 0x46},
- {0x5191, 0xf8},
- {0x5192, 0x04},
- {0x5193, 0x70},
- {0x5194, 0xf0},
- {0x5195, 0xf0},
- {0x5196, 0x03},
- {0x5197, 0x01},
- {0x5198, 0x04},
- {0x5199, 0x12},
- {0x519a, 0x04},
- {0x519b, 0x00},
- {0x519c, 0x06},
- {0x519d, 0x82},
- {0x519e, 0x38},
- {0x5381, 0x1e},
- {0x5382, 0x5b},
- {0x5383, 0x08},
- {0x5384, 0x0a},
- {0x5385, 0x7e},
- {0x5386, 0x88},
- {0x5387, 0x7c},
- {0x5388, 0x6c},
- {0x5389, 0x10},
- {0x538a, 0x01},
- {0x538b, 0x98},
- {0x5300, 0x08},
- {0x5301, 0x30},
- {0x5302, 0x10},
- {0x5303, 0x00},
- {0x5304, 0x08},
- {0x5305, 0x30},
- {0x5306, 0x08},
- {0x5307, 0x16},
- {0x5309, 0x08},
- {0x530a, 0x30},
- {0x530b, 0x04},
- {0x530c, 0x06},
- {0x5480, 0x01},
- {0x5481, 0x08},
- {0x5482, 0x14},
- {0x5483, 0x28},
- {0x5484, 0x51},
- {0x5485, 0x65},
- {0x5486, 0x71},
- {0x5487, 0x7d},
- {0x5488, 0x87},
- {0x5489, 0x91},
- {0x548a, 0x9a},
- {0x548b, 0xaa},
- {0x548c, 0xb8},
- {0x548d, 0xcd},
- {0x548e, 0xdd},
- {0x548f, 0xea},
- {0x5490, 0x1d},
- {0x5580, 0x02},
- {0x5583, 0x40},
- {0x5584, 0x10},
- {0x5589, 0x10},
- {0x558a, 0x00},
- {0x558b, 0xf8},
- {0x5800, 0x23},
- {0x5801, 0x14},
- {0x5802, 0x0f},
- {0x5803, 0x0f},
- {0x5804, 0x12},
- {0x5805, 0x26},
- {0x5806, 0x0c},
- {0x5807, 0x08},
- {0x5808, 0x05},
- {0x5809, 0x05},
- {0x580a, 0x08},
- {0x580b, 0x0d},
- {0x580c, 0x08},
- {0x580d, 0x03},
- {0x580e, 0x00},
- {0x580f, 0x00},
- {0x5810, 0x03},
- {0x5811, 0x09},
- {0x5812, 0x07},
- {0x5813, 0x03},
- {0x5814, 0x00},
- {0x5815, 0x01},
- {0x5816, 0x03},
- {0x5817, 0x08},
- {0x5818, 0x0d},
- {0x5819, 0x08},
- {0x581a, 0x05},
- {0x581b, 0x06},
- {0x581c, 0x08},
- {0x581d, 0x0e},
- {0x581e, 0x29},
- {0x581f, 0x17},
- {0x5820, 0x11},
- {0x5821, 0x11},
- {0x5822, 0x15},
- {0x5823, 0x28},
- {0x5824, 0x46},
- {0x5825, 0x26},
- {0x5826, 0x08},
- {0x5827, 0x26},
- {0x5828, 0x64},
- {0x5829, 0x26},
- {0x582a, 0x24},
- {0x582b, 0x22},
- {0x582c, 0x24},
- {0x582d, 0x24},
- {0x582e, 0x06},
- {0x582f, 0x22},
- {0x5830, 0x40},
- {0x5831, 0x42},
- {0x5832, 0x24},
- {0x5833, 0x26},
- {0x5834, 0x24},
- {0x5835, 0x22},
- {0x5836, 0x22},
- {0x5837, 0x26},
- {0x5838, 0x44},
- {0x5839, 0x24},
- {0x583a, 0x26},
- {0x583b, 0x28},
- {0x583c, 0x42},
- {0x583d, 0xce},
- {0x5025, 0x00},
- {0x3a0f, 0x30},
- {0x3a10, 0x28},
- {0x3a1b, 0x30},
- {0x3a1e, 0x26},
- {0x3a11, 0x60},
- {0x3a1f, 0x14},
- {0x3008, 0x02},
+
+ /* AEC/AGC Power Down Domain Control */
+ {OV5640_AEC_MAX_EXPO60_H, 0x03},
+ {OV5640_AEC_MAX_EXPO60_L, 0xd8},
+ {OV5640_AEC_B50_STEP_H, 0x01},
+ {OV5640_AEC_B50_STEP_L, 0x27},
+ {OV5640_AEC_B60_STEP_H, 0x00},
+ {OV5640_AEC_B60_STEP_L, 0xf6},
+ {OV5640_AEC_CTRL_0E, 0x03},
+ {OV5640_AEC_CTRL_0D, 0x04},
+ {OV5640_AEC_MAX_EXPO_H, 0x03},
+ {OV5640_AEC_MAX_EXPO_L, 0xd8},
+ {OV5640_AEC_CTRL_13, 0x43},
+ {OV5640_AEC_GAIN_CEILING_0, 0x00},
+ {OV5640_AEC_GAIN_CEILING_1, 0xf8},
+ {OV5640_AEC_CTRL_0F, 0x30},
+ {OV5640_AEC_CTRL_10, 0x28},
+ {OV5640_AEC_CTRL_1B, 0x30},
+ {OV5640_AEC_CTRL_1E, 0x26},
+ {OV5640_AEC_CTRL_11, 0x60},
+ {OV5640_AEC_CTRL_1F, 0x14},
+
+ {OV5640_SYSTEM_CTRL, 0x02},
{OV5640_TABLE_END, 0x0000}
};
static struct ov5640_reg mode_640x480[] = {
- {0x3103, 0x11},
- {0x3008, 0x82},
- {OV5640_TABLE_WAIT_MS, 5},
- {0x3008, 0x42},
- {0x3103, 0x03},
- {0x3017, 0x00},
- {0x3018, 0x00},
- {0x3034, 0x18},
- {0x3035, 0x14},
- {0x3036, 0x70},
- {0x3037, 0x13},
- {0x4800, 0x24}, /* noncontinuous clock */
- {0x3108, 0x01},
- {0x3630, 0x36},
- {0x3631, 0x0e},
- {0x3632, 0xe2},
- {0x3633, 0x12},
- {0x3621, 0xe0},
- {0x3704, 0xa0},
- {0x3703, 0x5a},
- {0x3715, 0x78},
- {0x3717, 0x01},
- {0x370b, 0x60},
- {0x3705, 0x1a},
- {0x3905, 0x02},
- {0x3906, 0x10},
- {0x3901, 0x0a},
- {0x3731, 0x12},
- {0x3600, 0x08},
- {0x3601, 0x33},
- {0x302d, 0x60},
- {0x3620, 0x52},
- {0x371b, 0x20},
- {0x471c, 0x50},
- {0x3a13, 0x43},
- {0x3a18, 0x00},
- {0x3a19, 0xf8},
- {0x3635, 0x13},
- {0x3636, 0x03},
- {0x3634, 0x40},
- {0x3622, 0x01},
- {0x3c01, 0x34},
- {0x3c04, 0x28},
- {0x3c05, 0x98},
- {0x3c06, 0x00},
- {0x3c07, 0x08},
- {0x3c08, 0x00},
- {0x3c09, 0x1c},
- {0x3c0a, 0x9c},
- {0x3c0b, 0x40},
- {0x3820, 0x41},
- {0x3821, 0x07},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x04},
- {0x3804, 0x0a},
- {0x3805, 0x3f},
- {0x3806, 0x07},
- {0x3807, 0x9b},
- {0x3808, 0x02},
- {0x3809, 0x80},
- {0x380a, 0x01},
- {0x380b, 0xe0},
- {0x380c, 0x07},
- {0x380d, 0x68},
- {0x380e, 0x03},
- {0x380f, 0xd8},
- {0x3810, 0x00},
- {0x3811, 0x10},
- {0x3812, 0x00},
- {0x3813, 0x06},
- {0x3618, 0x00},
+ /* PLL Control MIPI bit rate/lane = ?MHz, 16-bit mode.
+ * Output size: 640x480 (0, 4) - (2623, 1951),
+ * Line Length = 1896, Frame Length = 984.
+ * Scaling method: subsampling from 1280x960
+ * 648x484 with dummy
+ * supports 2x2 binning
+ */
+
+ {OV5640_SC_PLL_CTRL0, 0x10 | MIPI_MODE_8BIT },
+ {OV5640_SC_PLL_CTRL1, 0x14},
+ {OV5640_SC_PLL_CTRL2, 0x70}, /* default 0x69 PLL multipier */
+ {OV5640_SC_PLL_CTRL3, 0x03 | (1<<4) }, /* default 0x03 PLL divided by 2 */
+
+ {OV5640_MIPI_CTRL_00, 0x04},
+ {OV5640_MIPI_PCLK_PERIOD, 0x44},
+
+ {OV5640_ISP_CTRL_00, 0xa7},
+ {OV5640_ISP_CTRL_01, 0x83 | ISP_SCALE_EN},
+ {OV5640_ISP_MUX_CTRL, 0x00},
+
+ /* Timing Control */
+ {OV5640_TIMING_HS_H, OV5640_ADDR_H(0) },
+ {OV5640_TIMING_HS_L, OV5640_ADDR_L(0) },
+ {OV5640_TIMING_VS_H, OV5640_ADDR_H(0) },
+ {OV5640_TIMING_VS_L, OV5640_ADDR_L(4) },
+ {OV5640_TIMING_HW_H, OV5640_ADDR_H(2623) },
+ {OV5640_TIMING_HW_L, OV5640_ADDR_L(2623) },
+ {OV5640_TIMING_VH_H, OV5640_ADDR_H(1947) },
+ {OV5640_TIMING_VH_L, OV5640_ADDR_L(1947) },
+ {OV5640_TIMING_DVPHO_H, OV5640_WIDTH_H(640) },
+ {OV5640_TIMING_DVPHO_L, OV5640_WIDTH_L(640) },
+ {OV5640_TIMING_DVPVO_H, OV5640_HEIGHT_H(480) },
+ {OV5640_TIMING_DVPVO_L, OV5640_HEIGHT_L(480) },
+ {OV5640_TIMING_HTS_H, OV5640_HTS_H(1896) },
+ {OV5640_TIMING_HTS_L, OV5640_HTS_L(1896) },
+ {OV5640_TIMING_VTS_H, OV5640_VTS_H(984) },
+ {OV5640_TIMING_VTS_L, OV5640_VTS_L(984) },
+ {OV5640_TIMING_HOFFSET_H, OV5640_H_OFFSET_H(31) }, // (2623-0-(640*2*2)-1)/2
+ {OV5640_TIMING_HOFFSET_L, OV5640_H_OFFSET_L(31) },
+ {OV5640_TIMING_VOFFSET_H, OV5640_V_OFFSET_H(11) }, // (1947-4-(480*2*2)-1)/2
+ {OV5640_TIMING_VOFFSET_L, OV5640_V_OFFSET_L(11) },
+ {OV5640_TIMING_X_INC, 0x11 | (3<<4) },
+ {OV5640_TIMING_Y_INC, 0x11 | (3<<4) },
+ {OV5640_TIMING_REG20, 0x40},
+ {OV5640_TIMING_REG21, REG21_BINNING_EN},
+
+ /* magic registers */
{0x3612, 0x29},
+ {0x3618, 0x00},
{0x3708, 0x64},
{0x3709, 0x52},
{0x370c, 0x03},
/* AEC/AGC Power Down Domain Control */
- {0x3a02, 0x03},
- {0x3a03, 0xd8},
- {0x3a08, 0x01},
- {0x3a09, 0x27},
- {0x3a0a, 0x00},
- {0x3a0b, 0xf6},
- {0x3a0e, 0x03},
- {0x3a0d, 0x04},
- {0x3a14, 0x03},
- {0x3a15, 0xd8},
-
- {0x4001, 0x02},
- {0x4004, 0x02},
- {0x3000, 0x00},
- {0x3002, 0x1c},
- {0x3004, 0xff},
- {0x3006, 0xc3},
- {0x300e, 0x45},
- {0x302e, 0x08},
- /* org:30 bit[3:0]
- 0x0:YUYV 0x1:YVYU 0x2:UYVY
- 0x3:VYUY 0xF:UYVY 0x4~0xE:Not-allowed
- */
- {0x4300, 0x32},
- {0x501f, 0x00},
- {0x4713, 0x03},
- {0x4407, 0x04},
- {0x440e, 0x00},
- {0x460b, 0x35},
- {0x460c, 0x22},
- {0x4837, 0x44},
- {0x3824, 0x02},
- {0x5000, 0xa7},
- {0x5001, 0xa3},
+ {OV5640_AEC_MAX_EXPO60_H, 0x03},
+ {OV5640_AEC_MAX_EXPO60_L, 0xd8},
+ {OV5640_AEC_B50_STEP_H, 0x01},
+ {OV5640_AEC_B50_STEP_L, 0x27},
+ {OV5640_AEC_B60_STEP_H, 0x00},
+ {OV5640_AEC_B60_STEP_L, 0xf6},
+ {OV5640_AEC_CTRL_0E, 0x03},
+ {OV5640_AEC_CTRL_0D, 0x04},
+ {OV5640_AEC_MAX_EXPO_H, 0x03},
+ {OV5640_AEC_MAX_EXPO_L, 0xd8},
+ {OV5640_AEC_CTRL_13, 0x43},
+ {OV5640_AEC_GAIN_CEILING_0, 0x00},
+ {OV5640_AEC_GAIN_CEILING_1, 0xf8},
+ {OV5640_AEC_CTRL_0F, 0x30},
+ {OV5640_AEC_CTRL_10, 0x28},
+ {OV5640_AEC_CTRL_1B, 0x30},
+ {OV5640_AEC_CTRL_1E, 0x26},
+ {OV5640_AEC_CTRL_11, 0x60},
+ {OV5640_AEC_CTRL_1F, 0x14},
+
+ {OV5640_SYSTEM_CTRL, 0x02},
+ {OV5640_TABLE_END, 0x0000},
+};
+
+static struct ov5640_reg mode_common_registers[] = {
+
+ /* SCCB Control */
+ {OV5640_SCCB_SYSTEM_CTRL, 0x03}, /* Clock from PLL */
+ {OV5640_SCCB_SCLK, 0x01}, /* PCLK = pll_clki, SCLK = pll_clki/2 */
+
+ /* System Control */
+ {OV5640_SYSTEM_CTRL, 0x02 | SYSTEM_CTRL_SRST }, /* Software reset */
+ {OV5640_TABLE_WAIT_MS, 5},
+ {OV5640_SYSTEM_CTRL, 0x02 | SYSTEM_CTRL_PDOWN }, /* Software power down */
+ {OV5640_SYSTEM_RESET_00, 0x00},
+ {OV5640_SYSTEM_RESET_01, 0x00},
+ {OV5640_SYSTEM_RESET_02, 0x1c},
+ {OV5640_SYSTEM_CLK_EN_00, 0xff},
+ {OV5640_SYSTEM_CLK_EN_02, 0xc3},
+ {OV5640_SYSTEM_MIPI_CTRL, 0x45},
+
+ {OV5640_SYSTEM_CTRL_2D, 0x60}, /* magic values */
+ {OV5640_SYSTEM_CTRL_2E, 0x08}, /* magic values */
+
+ /* Format Control */
+ {FMT_CTRL_00, FMT_YUV422 | OFMT_UYVY },
+
+ /* VCM Control */
+/* {OV5640_VCM_DEBUG_MODE_0, 0x08},*/
+/* {OV5640_VCM_DEBUG_MODE_1, 0x33},*/
+
+ /* 50/60Hz detector control */
+ {OV5640_5060_CTRL_01, 0x34},
+ {OV5640_5060_CTRL_04, 0x28},
+ {OV5640_5060_CTRL_05, 0x98},
+ {OV5640_5060_THRESHOLD_1_H, 0x00},
+ {OV5640_5060_THRESHOLD_1_L, 0x07},
+ {OV5640_5060_THRESHOLD_2_H, 0x00},
+ {OV5640_5060_THRESHOLD_2_L, 0x1c},
+ {OV5640_5060_SAMPLE_NUM_H, 0x9c},
+ {OV5640_5060_SAMPLE_NUM_L, 0x40},
+
+ /* BLC Control */
+ {OV5640_BLC_CTRL_01, 0x02},
+ {OV5640_BLC_CTRL_04, 0x06},
/* AWB Control */
- {0x5180, 0xff},
- {0x5181, 0xf2},
- {0x5182, 0x00},
- {0x5183, 0x14},
- {0x5184, 0x25},
- {0x5185, 0x24},
- {0x5186, 0x09},
- {0x5187, 0x09},
- {0x5188, 0x09},
- {0x5189, 0x75},
- {0x518a, 0x54},
- {0x518b, 0xe0},
- {0x518c, 0xb2},
- {0x518d, 0x42},
- {0x518e, 0x3d},
- {0x518d, 0x56},
- {0x5190, 0x46},
- {0x5191, 0xf8},
- {0x5192, 0x04},
- {0x5193, 0x70},
- {0x5194, 0xf0},
- {0x5195, 0xf0},
- {0x5196, 0x03},
- {0x5197, 0x01},
- {0x5198, 0x04},
- {0x5199, 0x12},
- {0x519a, 0x04},
- {0x519b, 0x00},
- {0x519c, 0x06},
- {0x519d, 0x82},
- {0x519e, 0x38},
+ {OV5640_AWB_CTRL_00, 0xff},
+ {OV5640_AWB_CTRL_01, 0xf2},
+ {OV5640_AWB_CTRL_02, 0x00},
+ {OV5640_AWB_CTRL_03, 0x14},
+ {OV5640_AWB_CTRL_04, 0x25},
+ {OV5640_AWB_CTRL_05, 0x24},
+ {OV5640_AWB_CTRL_06, 0x09},
+ {OV5640_AWB_CTRL_07, 0x09},
+ {OV5640_AWB_CTRL_08, 0x09},
+ {OV5640_AWB_CTRL_09, 0x75},
+ {OV5640_AWB_CTRL_10, 0x54},
+ {OV5640_AWB_CTRL_11, 0xe0},
+ {OV5640_AWB_CTRL_12, 0xb2},
+ {OV5640_AWB_CTRL_13, 0x42},
+ {OV5640_AWB_CTRL_14, 0x3d},
+ {OV5640_AWB_CTRL_15, 0x56},
+ {OV5640_AWB_CTRL_16, 0x46},
+ {OV5640_AWB_CTRL_17, 0xf8},
+ {OV5640_AWB_CTRL_18, 0x04},
+ {OV5640_AWB_CTRL_19, 0x70},
+ {OV5640_AWB_CTRL_20, 0xf0},
+ {OV5640_AWB_CTRL_21, 0xf0},
+ {OV5640_AWB_CTRL_22, 0x03},
+ {OV5640_AWB_CTRL_23, 0x01},
+ {OV5640_AWB_CTRL_24, 0x04},
+ {OV5640_AWB_CTRL_25, 0x12},
+ {OV5640_AWB_CTRL_26, 0x04},
+ {OV5640_AWB_CTRL_27, 0x00},
+ {OV5640_AWB_CTRL_28, 0x06},
+ {OV5640_AWB_CTRL_29, 0x82},
+ {OV5640_AWB_CTRL_30, 0x38},
/* CMX Control */
- {0x5381, 0x1e},
- {0x5382, 0x5b},
- {0x5383, 0x08},
- {0x5384, 0x0a},
- {0x5385, 0x7e},
- {0x5386, 0x88},
- {0x5387, 0x7c},
- {0x5388, 0x6c},
- {0x5389, 0x10},
- {0x538a, 0x01},
- {0x538b, 0x98},
+ {OV5640_CMX1, 0x1e},
+ {OV5640_CMX2, 0x5b},
+ {OV5640_CMX3, 0x08},
+ {OV5640_CMX4, 0x0a},
+ {OV5640_CMX5, 0x7e},
+ {OV5640_CMX6, 0x88},
+ {OV5640_CMX7, 0x7c},
+ {OV5640_CMX8, 0x6c},
+ {OV5640_CMX9, 0x10},
+ {OV5640_CMX_SIGN_0, 0x01},
+ {OV5640_CMX_SIGN_1, 0x98},
/* CIP Control */
- {0x5300, 0x08},
- {0x5301, 0x30},
- {0x5302, 0x10},
- {0x5303, 0x00},
- {0x5304, 0x08},
- {0x5305, 0x30},
- {0x5306, 0x08},
- {0x5307, 0x16},
- {0x5309, 0x08},
- {0x530a, 0x30},
- {0x530b, 0x04},
- {0x530c, 0x06},
+ {OV5640_CIP_SH_MT_THRES_1, 0x08},
+ {OV5640_CIP_SH_MT_THRES_2, 0x30},
+ {OV5640_CIP_SH_MT_OFFSET_1, 0x10},
+ {OV5640_CIP_SH_MT_OFFSET_2, 0x00},
+ {OV5640_CIP_DNS_THRES_1, 0x08},
+ {OV5640_CIP_DNS_THRES_2, 0x30},
+ {OV5640_CIP_DNS_OFFSET_1, 0x08},
+ {OV5640_CIP_DNS_OFFSET_2, 0x16},
+ {OV5640_CIP_SH_TH_THRES_1, 0x08},
+ {OV5640_CIP_SH_TH_THRES_2, 0x30},
+ {OV5640_CIP_SH_TH_OFFSET_1, 0x04},
+ {OV5640_CIP_SH_TH_OFFSET_2, 0x06},
/* Gamma Control */
- {0x5480, 0x01},
- {0x5481, 0x08},
- {0x5482, 0x14},
- {0x5483, 0x28},
- {0x5484, 0x51},
- {0x5485, 0x65},
- {0x5486, 0x71},
- {0x5487, 0x7d},
- {0x5488, 0x87},
- {0x5489, 0x91},
- {0x548a, 0x9a},
- {0x548b, 0xaa},
- {0x548c, 0xb8},
- {0x548d, 0xcd},
- {0x548e, 0xdd},
- {0x548f, 0xea},
- {0x5490, 0x1d},
+ {OV5640_GAMMA_CTRL_00, 0x01},
+ {OV5640_GAMMA_YST_00, 0x08},
+ {OV5640_GAMMA_YST_01, 0x14},
+ {OV5640_GAMMA_YST_02, 0x28},
+ {OV5640_GAMMA_YST_03, 0x51},
+ {OV5640_GAMMA_YST_04, 0x65},
+ {OV5640_GAMMA_YST_05, 0x71},
+ {OV5640_GAMMA_YST_06, 0x7d},
+ {OV5640_GAMMA_YST_07, 0x87},
+ {OV5640_GAMMA_YST_08, 0x91},
+ {OV5640_GAMMA_YST_09, 0x9a},
+ {OV5640_GAMMA_YST_0A, 0xaa},
+ {OV5640_GAMMA_YST_0B, 0xb8},
+ {OV5640_GAMMA_YST_0C, 0xcd},
+ {OV5640_GAMMA_YST_0D, 0xdd},
+ {OV5640_GAMMA_YST_0E, 0xea},
+ {OV5640_GAMMA_YST_0F, 0x1d},
/* SDE Control */
- {0x5580, 0x02},
- {0x5583, 0x40},
- {0x5584, 0x10},
- {0x5589, 0x10},
- {0x558a, 0x00},
- {0x558b, 0xf8},
+ {OV5640_SDE_CTRL_0, 0x02},
+ {OV5640_SDE_CTRL_3, 0x40},
+ {OV5640_SDE_CTRL_4, 0x10},
+ {OV5640_SDE_CTRL_9, 0x10},
+ {OV5640_SDE_CTRL_10, 0x00},
+ {OV5640_SDE_CTRL_11, 0xf8},
/* LENC Control */
- {0x5800, 0x23},
- {0x5801, 0x14},
- {0x5802, 0x0f},
- {0x5803, 0x0f},
- {0x5804, 0x12},
- {0x5805, 0x26},
- {0x5806, 0x0c},
- {0x5807, 0x08},
- {0x5808, 0x05},
- {0x5809, 0x05},
- {0x580a, 0x08},
- {0x580b, 0x0d},
- {0x580c, 0x08},
- {0x580d, 0x03},
- {0x580e, 0x00},
- {0x580f, 0x00},
- {0x5810, 0x03},
- {0x5811, 0x09},
- {0x5812, 0x07},
- {0x5813, 0x03},
- {0x5814, 0x00},
- {0x5815, 0x01},
- {0x5816, 0x03},
- {0x5817, 0x08},
- {0x5818, 0x0d},
- {0x5819, 0x08},
- {0x581a, 0x05},
- {0x581b, 0x06},
- {0x581c, 0x08},
- {0x581d, 0x0e},
- {0x581e, 0x29},
- {0x581f, 0x17},
- {0x5820, 0x11},
- {0x5821, 0x11},
- {0x5822, 0x15},
- {0x5823, 0x28},
- {0x5824, 0x46},
- {0x5825, 0x26},
- {0x5826, 0x08},
- {0x5827, 0x26},
- {0x5828, 0x64},
- {0x5829, 0x26},
- {0x582a, 0x24},
- {0x582b, 0x22},
- {0x582c, 0x24},
- {0x582d, 0x24},
- {0x582e, 0x06},
- {0x582f, 0x22},
- {0x5830, 0x40},
- {0x5831, 0x42},
- {0x5832, 0x24},
- {0x5833, 0x26},
- {0x5834, 0x24},
- {0x5835, 0x22},
- {0x5836, 0x22},
- {0x5837, 0x26},
- {0x5838, 0x44},
- {0x5839, 0x24},
- {0x583a, 0x26},
- {0x583b, 0x28},
- {0x583c, 0x42},
- {0x583d, 0xce},
-
- {0x5025, 0x00},
- {0x3a0f, 0x30},
- {0x3a10, 0x28},
- {0x3a1b, 0x30},
- {0x3a1e, 0x26},
- {0x3a11, 0x60},
- {0x3a1f, 0x14},
- {0x3008, 0x02},
+ {OV5640_LENC_GMTRX_00, 0x23},
+ {OV5640_LENC_GMTRX_01, 0x14},
+ {OV5640_LENC_GMTRX_02, 0x0f},
+ {OV5640_LENC_GMTRX_03, 0x0f},
+ {OV5640_LENC_GMTRX_04, 0x12},
+ {OV5640_LENC_GMTRX_05, 0x26},
+ {OV5640_LENC_GMTRX_10, 0x0c},
+ {OV5640_LENC_GMTRX_11, 0x08},
+ {OV5640_LENC_GMTRX_12, 0x05},
+ {OV5640_LENC_GMTRX_13, 0x05},
+ {OV5640_LENC_GMTRX_14, 0x08},
+ {OV5640_LENC_GMTRX_15, 0x0d},
+ {OV5640_LENC_GMTRX_20, 0x08},
+ {OV5640_LENC_GMTRX_21, 0x03},
+ {OV5640_LENC_GMTRX_22, 0x00},
+ {OV5640_LENC_GMTRX_23, 0x00},
+ {OV5640_LENC_GMTRX_24, 0x03},
+ {OV5640_LENC_GMTRX_25, 0x09},
+ {OV5640_LENC_GMTRX_30, 0x07},
+ {OV5640_LENC_GMTRX_31, 0x03},
+ {OV5640_LENC_GMTRX_32, 0x00},
+ {OV5640_LENC_GMTRX_33, 0x01},
+ {OV5640_LENC_GMTRX_34, 0x03},
+ {OV5640_LENC_GMTRX_35, 0x08},
+ {OV5640_LENC_GMTRX_40, 0x0d},
+ {OV5640_LENC_GMTRX_41, 0x08},
+ {OV5640_LENC_GMTRX_42, 0x05},
+ {OV5640_LENC_GMTRX_43, 0x06},
+ {OV5640_LENC_GMTRX_44, 0x08},
+ {OV5640_LENC_GMTRX_45, 0x0e},
+ {OV5640_LENC_GMTRX_50, 0x29},
+ {OV5640_LENC_GMTRX_51, 0x17},
+ {OV5640_LENC_GMTRX_52, 0x11},
+ {OV5640_LENC_GMTRX_53, 0x11},
+ {OV5640_LENC_GMTRX_54, 0x15},
+ {OV5640_LENC_GMTRX_55, 0x28},
+ {OV5640_LENC_BRMATRX_00, 0x46},
+ {OV5640_LENC_BRMATRX_01, 0x26},
+ {OV5640_LENC_BRMATRX_02, 0x08},
+ {OV5640_LENC_BRMATRX_03, 0x26},
+ {OV5640_LENC_BRMATRX_04, 0x64},
+ {OV5640_LENC_BRMATRX_05, 0x26},
+ {OV5640_LENC_BRMATRX_06, 0x24},
+ {OV5640_LENC_BRMATRX_07, 0x22},
+ {OV5640_LENC_BRMATRX_08, 0x24},
+ {OV5640_LENC_BRMATRX_09, 0x24},
+ {OV5640_LENC_BRMATRX_20, 0x06},
+ {OV5640_LENC_BRMATRX_21, 0x22},
+ {OV5640_LENC_BRMATRX_22, 0x40},
+ {OV5640_LENC_BRMATRX_23, 0x42},
+ {OV5640_LENC_BRMATRX_24, 0x24},
+ {OV5640_LENC_BRMATRX_30, 0x26},
+ {OV5640_LENC_BRMATRX_31, 0x24},
+ {OV5640_LENC_BRMATRX_32, 0x22},
+ {OV5640_LENC_BRMATRX_33, 0x22},
+ {OV5640_LENC_BRMATRX_34, 0x26},
+ {OV5640_LENC_BRMATRX_40, 0x44},
+ {OV5640_LENC_BRMATRX_41, 0x24},
+ {OV5640_LENC_BRMATRX_42, 0x26},
+ {OV5640_LENC_BRMATRX_43, 0x28},
+ {OV5640_LENC_BRMATRX_44, 0x42},
+ {OV5640_LENC_BR_OFFSET, 0xce},
+
+ /* magic registers */
+ {0x3620, 0x52},
+ {0x3621, 0xe0},
+ {0x3622, 0x01},
+ {0x3630, 0x36},
+ {0x3631, 0x0e},
+ {0x3632, 0xe2},
+ {0x3633, 0x12},
+ {0x3634, 0x40},
+ {0x3635, 0x13},
+ {0x3636, 0x03},
+ {0x3703, 0x5a},
+ {0x3704, 0xa0},
+ {0x3705, 0x1a},
+ {0x370b, 0x60},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x371b, 0x20},
+ {0x3731, 0x12},
+ {0x3901, 0x0a},
+ {0x3905, 0x02},
+ {0x3906, 0x10},
+ {0x471c, 0x50},
+
{OV5640_TABLE_END, 0x0000},
};
enum {
OV5640_MODE_640x480,
- OV5640_MODE_1296x972,
+ OV5640_MODE_1280x960,
OV5640_MODE_1920x1080,
OV5640_MODE_2592x1944,
OV5640_SIZE_LAST,
@@ -1104,7 +885,7 @@ enum {
static struct ov5640_reg *mode_table[] = {
[OV5640_MODE_640x480] = mode_640x480,
- [OV5640_MODE_1296x972] = mode_1296x972,
+ [OV5640_MODE_1280x960] = mode_1280x960,
[OV5640_MODE_1920x1080] = mode_1920x1080,
[OV5640_MODE_2592x1944] = mode_2592x1944,
};
@@ -1113,9 +894,9 @@ static int test_pattern;
module_param(test_pattern, int, 0644);
static struct ov5640_reg tp_cbars[] = {
- {0x503D, 0x80},
- {0x503E, 0x00},
- {0x5046, 0x01},
+ {OV5640_ISP_TEST, ISP_TEST_EN | ISP_TEST_00 | ISP_TEST_TRANSPARENT | ISP_TEST_ROLLING },
+ {OV5640_ISP_DEBUG_3E, 0x00},
+ {OV5640_ISP_DEBUG_46, 0x01},
{OV5640_TABLE_END, 0x0000}
};
@@ -1143,7 +924,7 @@ static enum v4l2_mbus_pixelcode ov5640_codes[] = {
static const struct v4l2_frmsize_discrete ov5640_frmsizes[OV5640_SIZE_LAST] = {
{640, 480},
- {1296, 972},
+ {1280, 960},
{1920, 1080},
{2592, 1944},
};
@@ -1217,8 +998,9 @@ static int ov5640_write_reg(struct i2c_client *client, u16 addr, u8 value)
msg[0].buf = data;
count = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
- if (count == ARRAY_SIZE(msg))
+ if (count == ARRAY_SIZE(msg)) {
return 0;
+ }
dev_err(&client->dev,
"ov5840: i2c transfer failed, addr: %x, value: %02x\n",
addr, (u32)value);
@@ -1314,6 +1096,10 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
+ ret = ov5640_write_table(priv, mode_common_registers);
+ if (ret)
+ return ret;
+
ret = ov5640_write_table(priv, mode_table[priv->mode]);
if (ret)
return ret;
@@ -1365,12 +1151,12 @@ static int ov5640_s_power(struct v4l2_subdev *sd, int on)
{
struct ov5640_priv *priv = to_ov5640(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *scsd = soc_camera_i2c_to_desc(client);
if (on)
ov5640_s_fmt(sd, &priv->mf);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, scsd, on);
}
static int ov5640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
@@ -1409,6 +1195,11 @@ static int ov5640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
return 0;
}
+static int ov5640_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ return 0;
+}
+
/* Get chip identification */
static int ov5640_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
@@ -1462,6 +1253,7 @@ static struct v4l2_subdev_video_ops ov5640_video_ops = {
.enum_mbus_fmt = ov5640_enum_fmt,
.cropcap = ov5640_cropcap,
.g_crop = ov5640_g_crop,
+ .querystd = ov5640_querystd,
};
@@ -1486,13 +1278,13 @@ static int ov5640_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov5640_priv *priv;
- struct soc_camera_link *icl;
+ struct soc_camera_subdev_desc *scsd;
u8 chip_id_hi, chip_id_lo;
int ret;
/* Checking soc-camera interface */
- icl = soc_camera_i2c_to_link(client);
- if (!icl) {
+ scsd = soc_camera_i2c_to_desc(client);
+ if (!scsd) {
dev_err(&client->dev, "Missing soc_camera_link for driver\n");
return -EINVAL;
}
@@ -1513,14 +1305,14 @@ static int ov5640_probe(struct i2c_client *client,
/*
* check and show product ID and manufacturer ID
*/
- soc_camera_power_on(&client->dev, icl);
- ret = ov5640_read_reg(client, 0x300A, &chip_id_hi);
+ soc_camera_power_on(&client->dev, scsd);
+ ret = ov5640_read_reg(client, OV5640_CHIP_ID_H, &chip_id_hi);
if (ret < 0) {
dev_err(&client->dev, "Failure to read Chip ID (high byte)\n");
return ret;
}
- ret = ov5640_read_reg(client, 0x300B, &chip_id_lo);
+ ret = ov5640_read_reg(client, OV5640_CHIP_ID_L, &chip_id_lo);
if (ret < 0) {
dev_err(&client->dev, "Failure to read Chip ID (low byte)\n");
return ret;
@@ -1534,7 +1326,7 @@ static int ov5640_probe(struct i2c_client *client,
ret = -ENODEV;
return ret;
}
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, scsd);
ov5640_set_default_fmt(priv);
diff --git a/drivers/media/i2c/soc_camera/tc358743.c b/drivers/media/i2c/soc_camera/tc358743.c
new file mode 100644
index 000000000000..7a63b1ec019a
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/tc358743.c
@@ -0,0 +1,1104 @@
+/*
+ * based on OV5640 driver and TC358743 driver for i.MX6
+ *
+ * author: Antmicro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#define PLLCTL0 0x0020
+#define PLLCTL1 0x0022
+
+#define MASK_PLL_PRD 0xf000
+#define SET_PLL_PRD(prd) ((((prd) - 1) << 12) & MASK_PLL_PRD)
+
+#define MASK_PLL_FBD 0x01ff
+#define SET_PLL_FBD(fbd) (((fbd) - 1) & MASK_PLL_FBD)
+
+#define MASK_CKEN 0x0010
+#define MASK_RESETB 0x0002
+#define MASK_PLL_EN 0x0001
+
+#define MASK_NOL_1 0
+#define MASK_NOL_2 2
+#define MASK_NOL_3 4
+#define MASK_NOL_4 6
+
+/* this is true for 27 MHz refclk */
+#define REFCLK_PRE_DIVIDER 9
+#define SET_PLL_FREQ(x) (SET_PLL_PRD(REFCLK_PRE_DIVIDER) | SET_PLL_FBD(DIV_ROUND_UP(x,3)))
+
+#define FRS_BW_25 0x0
+#define FRS_BW_33 0x1
+#define FRS_BW_50 0x2
+#define FRS_BW_MAX 0x3
+
+#define MASK_PLL_FRS 0x0f00
+#define SET_PLL_FRS(frs,bw) (((frs | bw) << 8) & MASK_PLL_FRS)
+#define GET_FRS(x) (x < 125) ? 0xC : (x < 250) ? 0x8 : (x < 500) ? 0x4 : 0x0
+
+#define HCNT_MASK 0x3f
+#define CALC_HDR_CNT(prep, zero) ((zero & HCNT_MASK) << 8) | (prep & HCNT_MASK)
+
+#define SYS_STATUS 0x8520
+#define CSI_STATUS 0x0410
+#define MASK_S_WSYNC 0x0400
+#define VI_STATUS0 0x8521
+#define VI_STATUS1 0x8522
+#define AU_STATUS0 0x8523
+#define VI_STATUS2 0x8525
+#define VI_STATUS3 0x8528
+
+#define EDID_MODE 0x85C7
+#define MASK_EDID_SPEED 0x40
+#define MASK_EDID_MODE 0x03
+#define MASK_EDID_MODE_DISABLE 0x00
+#define MASK_EDID_MODE_DDC2B 0x01
+#define MASK_EDID_MODE_E_DDC 0x02
+#define EDID_LEN1 0x85CA
+#define EDID_LEN2 0x85CB
+
+
+#define SYSCTL 0x0002
+#define CONFCTL 0x0004
+#define MASK_AUTOINDEX 0x0004
+#define FIFOCTL 0x0006
+#define INTSTATUS 0x0014
+#define INTMASK 0x0016
+#define PHY_RST 0x8535
+#define MASK_RESET_CTRL 0x01 /* Reset active low */
+
+#define HPD_CTL 0x8544
+#define MASK_HPD_CTL0 0x10
+#define MASK_HPD_OUT0 0x01
+
+#define BKSV 0x8800
+
+#define CSI_CONFW 0x0500
+#define MASK_MODE_SET 0xa0000000
+#define MASK_ADDRESS_CSI_CONTROL 0x03000000
+#define MASK_CSI_MODE 0x8000
+#define MASK_HTXTOEN 0x0400
+#define MASK_TXHSMD 0x0080
+#define MASK_HSCKMD 0x0020
+#define HSTXVREGEN 0x0234
+#define TXOPTIONCNTRL 0x0238
+#define MASK_CONTCLKMODE 0x00000001
+#define STARTCNTRL 0x0204
+#define MASK_START 0x00000001
+#define CLW_CNTRL 0x0140
+#define MASK_CLW_LANEDISABLE 0x0001
+
+#define D0W_CNTRL 0x0144
+#define MASK_D0W_LANEDISABLE 0x0001
+
+#define D1W_CNTRL 0x0148
+#define MASK_D1W_LANEDISABLE 0x0001
+
+#define D2W_CNTRL 0x014C
+#define MASK_D2W_LANEDISABLE 0x0001
+
+#define D3W_CNTRL 0x0150
+#define MASK_D3W_LANEDISABLE 0x0001
+
+#define LINEINITCNT 0x0210
+#define LPTXTIMECNT 0x0214
+#define TCLK_HEADERCNT 0x0218
+#define TCLK_TRAILCNT 0x021C
+#define THS_HEADERCNT 0x0220
+#define TWAKEUP 0x0224
+#define TCLK_POSTCNT 0x0228
+#define THS_TRAILCNT 0x022C
+
+#define CSI_START 0x0518
+#define MASK_STRT 0x00000001
+
+#define PHY_CTL1 0x8532
+#define PHY_CTL2 0x8533 /* Not in REF_01 */
+#define PHY_BIAS 0x8536 /* Not in REF_01 */
+#define PHY_CSQ 0x853F /* Not in REF_01 */
+#define DDC_CTL 0x8543
+
+#define SYS_FREQ0 0x8540
+#define SYS_FREQ1 0x8541
+
+#define NCO_F0_MOD 0x8670
+#define MASK_NCO_F0_MOD_27MHZ 0x01
+
+
+#define LOCKDET_REF0 0x8630
+#define LOCKDET_REF1 0x8631
+#define LOCKDET_REF2 0x8632
+
+#define SYS_INT 0x8502
+#define MASK_I_DDC 0x01
+#define SYS_INTM 0x8512
+#define PACKET_INTM 0x8514
+#define CBIT_INTM 0x8515
+#define AUDIO_INTM 0x8516
+#define PHY_CTL0 0x8531
+#define MASK_PHY_CTL 0x01
+#define ANA_CTL 0x8545
+#define MASK_APPL_PCSX 0x30
+#define MASK_APPL_PCSX_NORMAL 0x30
+
+#define MASK_ANALOG_ON 0x01
+
+
+#define AVM_CTL 0x8546
+
+
+#define MASK_PHY_AUTO_RST4 0x04
+#define MASK_PHY_AUTO_RST3 0x02
+#define MASK_PHY_AUTO_RST2 0x01
+
+#define VOUT_SET2 0x8573
+#define MASK_VOUT_422FIL_100 0x40
+#define MASK_SEL422 0x80
+#define MASK_VOUTCOLORMODE_AUTO 0x01
+#define MASK_VOUTCOLORMODE_THROUGH 0x00
+#define MASK_VOUTCOLORMODE_MANUAL 0x03
+
+#define VOUT_SET3 0x8574
+#define MASK_VOUT_EXTCNT 0x08
+
+#define PK_INT_MODE 0x8709
+#define NO_PKT_LIMIT 0x870B
+#define NO_PKT_CLR 0x870C
+#define ERR_PK_LIMIT 0x870D
+#define NO_GDB_LIMIT 0x9007
+#define NO_PKT_LIMIT2 0x870E
+
+#define INIT_END 0x854A
+#define MASK_INIT_END 0x01
+
+
+#define HDCP_MODE 0x8560
+#define HDCP_REG1 0x8563
+#define HDCP_REG2 0x8564
+#define HDCP_REG3 0x85D1
+
+#define EDID_LEN2 0x85CB
+#define EDID_MODE 0x85C7
+
+#define FH_MIN0 0x85AA
+#define FH_MIN1 0x85AB
+#define FH_MAX0 0x85AC
+#define FH_MAX1 0x85AD
+
+#define DE_WIDTH_H_LO 0x8582
+#define DE_WIDTH_H_HI 0x8583
+#define DE_WIDTH_V_LO 0x8588
+#define DE_WIDTH_V_HI 0x8589
+#define H_SIZE_LO 0x858A
+#define H_SIZE_HI 0x858B
+#define V_SIZE_LO 0x858C
+#define V_SIZE_HI 0x858D
+#define FV_CNT_LO 0x85A1
+#define FV_CNT_HI 0x85A2
+
+
+#define MASK_IRRST 0x0800
+#define MASK_CECRST 0x0400
+#define MASK_CTXRST 0x0200
+#define MASK_HDMIRST 0x0100
+
+#define MASK_AUDCHNUM_2 0x0c00
+#define MASK_AUTOINDEX 0x0004
+#define MASK_ABUFEN 0x0002
+#define MASK_VBUFEN 0x0001
+#define MASK_AUDOUTSEL_I2S 0x0010
+
+#define MASK_YCBCRFMT 0x00c0
+
+#define MASK_YCBCRFMT_422_12_BIT 0x0040
+#define MASK_YCBCRFMT_COLORBAR 0x0080
+#define MASK_YCBCRFMT_422_8_BIT 0x00c0
+
+#define MASK_YCBCRFMT_444 0x0000
+
+#define MASK_INFRMEN 0x0020
+#define PHY_EN 0x8534
+#define MASK_ENABLE_PHY 0x01
+
+#define MASK_PWRISO 0x8000
+
+#define VI_MODE 0x8570
+#define MASK_RGB_DVI 0x8
+
+#define VI_REP 0x8576
+#define MASK_VOUT_COLOR_SEL 0xe0
+#define MASK_VOUT_COLOR_RGB_FULL 0x00
+#define MASK_VOUT_COLOR_RGB_LIMITED 0x20
+#define MASK_VOUT_COLOR_601_YCBCR_FULL 0x40
+#define MASK_VOUT_COLOR_601_YCBCR_LIMITED 0x60
+#define MASK_VOUT_COLOR_709_YCBCR_FULL 0x80
+#define MASK_VOUT_COLOR_709_YCBCR_LIMITED 0xa0
+#define MASK_VOUT_COLOR_FULL_TO_LIMITED 0xc0
+#define MASK_VOUT_COLOR_LIMITED_TO_FULL 0xe0
+#define MASK_IN_REP_HEN 0x10
+#define MASK_IN_REP 0x0f
+
+/* status regs */
+#define SYS_STATUS 0x8520
+#define MASK_S_SYNC 0x80
+#define MASK_S_AVMUTE 0x40
+#define MASK_S_HDCP 0x20
+#define MASK_S_HDMI 0x10
+#define MASK_S_PHY_SCDT 0x08
+#define MASK_S_PHY_PLL 0x04
+#define MASK_S_TMDS 0x02
+#define MASK_S_DDC5V 0x01
+#define CSI_STATUS 0x0410
+#define MASK_S_WSYNC 0x0400
+#define MASK_S_TXACT 0x0200
+#define MASK_S_RXACT 0x0100
+#define MASK_S_HLT 0x0001
+#define VI_STATUS1 0x8522
+#define MASK_S_V_GBD 0x08
+#define MASK_S_DEEPCOLOR 0x0c
+#define MASK_S_V_422 0x02
+#define MASK_S_V_INTERLACE 0x01
+#define AU_STATUS0 0x8523
+#define MASK_S_A_SAMPLE 0x01
+#define VI_STATUS3 0x8528
+#define MASK_S_V_COLOR 0x1e
+#define MASK_LIMITED 0x01
+
+#define HDMI_DET 0x8552 /* Not in REF_01 */
+#define MASK_HDMI_DET_MOD1 0x80
+#define MASK_HDMI_DET_MOD0 0x40
+#define MASK_HDMI_DET_V 0x30
+#define MASK_HDMI_DET_V_SYNC 0x00
+#define MASK_HDMI_DET_V_ASYNC_25MS 0x10
+#define MASK_HDMI_DET_V_ASYNC_50MS 0x20
+#define MASK_HDMI_DET_V_ASYNC_100MS 0x30
+#define MASK_HDMI_DET_NUM 0x0f
+
+#define HV_RST 0x85AF /* Not in REF_01 */
+#define MASK_H_PI_RST 0x20
+#define MASK_V_PI_RST 0x10
+
+#define MASK_DDC5V_MODE_100MS 2
+
+#define VI_MUTE 0x857F
+#define MASK_AUTO_MUTE 0xc0
+#define MASK_VI_MUTE 0x10
+
+#define FORCE_MUTE 0x8600
+#define MASK_FORCE_AMUTE 0x10
+
+#define BCAPS 0x8840
+#define BSTATUS1 0x8842
+
+#define MASK_MAX_EXCED 0x08
+#define MASK_REPEATER 0x40
+#define MASK_READY 0x20
+
+#define MASK_HDMI_RSVD 0x80
+
+#define VOUT_SET0 0x8571
+#define VOUT_SET1 0x8572
+
+#define CMD_AUD 0x8601
+#define MASK_CMD_BUFINIT 0x04
+#define MASK_CMD_LOCKDET 0x02
+#define MASK_CMD_MUTE 0x01
+
+#define MASK_FORCE_DMUTE 0x01
+
+#define ERR_PK_LIMIT 0x870D
+#define NO_PKT_LIMIT2 0x870E
+#define PK_AVI_0HEAD 0x8710
+#define PK_AVI_1HEAD 0x8711
+#define PK_AVI_2HEAD 0x8712
+#define PK_AVI_0BYTE 0x8713
+#define PK_AVI_1BYTE 0x8714
+#define PK_AVI_2BYTE 0x8715
+#define PK_AVI_3BYTE 0x8716
+#define PK_AVI_4BYTE 0x8717
+#define PK_AVI_5BYTE 0x8718
+#define PK_AVI_6BYTE 0x8719
+#define PK_AVI_7BYTE 0x871A
+#define PK_AVI_8BYTE 0x871B
+#define PK_AVI_9BYTE 0x871C
+#define PK_AVI_10BYTE 0x871D
+#define PK_AVI_11BYTE 0x871E
+#define PK_AVI_12BYTE 0x871F
+#define PK_AVI_13BYTE 0x8720
+#define PK_AVI_14BYTE 0x8721
+#define PK_AVI_15BYTE 0x8722
+#define PK_AVI_16BYTE 0x8723
+
+struct reg_value {
+ u16 addr;
+ u32 val;
+ u32 flags;
+};
+
+struct _reg_size
+{
+ u16 startaddr, endaddr;
+ int size;
+}
+
+tc358743_read_reg_size [] =
+{
+ {0x0000, 0x005a, 2},
+ {0x0140, 0x0150, 4},
+ {0x0204, 0x0238, 4},
+ {0x040c, 0x0418, 4},
+ {0x044c, 0x0454, 4},
+ {0x0500, 0x0518, 4},
+ {0x0600, 0x06cc, 4},
+ {0x7000, 0x7100, 2},
+ {0x8500, 0x8bff, 1},
+ {0x8c00, 0x8fff, 4},
+ {0x9000, 0x90ff, 1},
+ {0x9100, 0x92ff, 1},
+ {0, 0, 0},
+};
+
+typedef struct timings_regs {
+ uint32_t frequency;
+ uint32_t line_init_cnt;
+ uint32_t tlpx_time_cnt;
+
+ uint32_t tclk_prepare_cnt;
+ uint32_t tclk_zero_cnt;
+
+ uint32_t tclk_trail_cnt; /* Don't care in continous clk mode */
+
+ uint32_t ths_prepare_cnt;
+ uint32_t ths_zero_cnt;
+
+ uint32_t twakeup_cnt;
+ uint32_t tclk_post_cnt; /* Don't care in continous clk mode */
+
+ uint32_t ths_trail_cnt;
+
+ uint32_t fifo_delay;
+} timings_regs;
+
+timings_regs timings[] = {
+ /* 640x480 @ 75 */
+ { 500, 3328, 1, 1, 7, 0, 1, 0, 16384, 5, 0, 256},
+ /* 800x600 @ 75 */
+ { 594, 3712, 3, 3, 20, 0, 3, 1, 18562, 8, 2, 180},
+ /* 1024x768 @ 75 */
+ { 600, 7689, 3, 2, 20, 0, 3, 0, 18944, 8, 2, 128},
+ /* 1280x720 @ 60 */
+ { 825, 5160, 5, 4, 29, 0, 5, 5, 18000, 0, 4, 180},
+ /* 1280x1024 @ 75 and 1920x1080 @ 60 */
+ { 1075, 6000, 5, 4, 29, 0, 5, 80, 18000, 0, 4, 256},
+ {},
+};
+
+static struct reg_value tc358743_reset[] = {
+ {CONFCTL, 0, 100},
+
+ {PHY_RST, 0x0, 100},
+ {PHY_RST, 0x1, 100},
+ {PHY_EN, 0, 100},
+ {PHY_EN, 1, 100},
+
+ /* reset */
+ {SYSCTL, MASK_IRRST | MASK_CECRST | MASK_CTXRST | MASK_HDMIRST, 100},
+ {SYSCTL, 0x00000000, 1000},
+
+ /* set ref frequency to 27 MHz */
+ {SYS_FREQ0, (2700) & 0xFF, 0},
+ {SYS_FREQ1, (2700 >> 8) & 0xFF, 0},
+
+ {LOCKDET_REF0, (270000) & 0xFF, 0},
+ {LOCKDET_REF1, (270000 >> 8) & 0xFF, 0},
+ {LOCKDET_REF2, (270000 >> 16) & 0xFF, 0},
+ {FH_MIN0, (270) & 0xFF, 0},
+ {FH_MIN1, (270 >> 8) & 0xFF, 0},
+ {FH_MAX0, (27 * 66) & 0xFF, 0},
+ {FH_MAX1, ((27 * 66) >> 8) & 0xFF, 0},
+ {NCO_F0_MOD, MASK_NCO_F0_MOD_27MHZ, 0},
+};
+
+static timings_regs tc358743_get_best_timings(uint32_t frequency) {
+ int count = 0;
+ timings_regs best_timings = {};
+ while (1) {
+ if (timings[count].frequency == 0) break;
+ best_timings = timings[count];
+ if (timings[count].frequency >= frequency) break;
+ count++;
+ }
+ return best_timings;
+}
+
+static struct reg_value tc358743_2lanes_start[] = {
+ {CLW_CNTRL, 0x0000, 0},
+
+ /* Make all lanes active */
+ {D0W_CNTRL, 0x0000, 0},
+ {D1W_CNTRL, 0x0000, 0},
+
+ {D2W_CNTRL, 0x0000, 0},
+ {D3W_CNTRL, 0x0000, 0},
+ {HSTXVREGEN, 0x001f, 0},
+
+ /* Continuous clock mode */
+ {TXOPTIONCNTRL, MASK_CONTCLKMODE, 0},
+ {STARTCNTRL, MASK_START, 0},
+ {CSI_START, MASK_STRT, 0},
+
+ /* Use two lanes */
+ {CSI_CONFW, MASK_MODE_SET | MASK_ADDRESS_CSI_CONTROL | MASK_CSI_MODE | MASK_TXHSMD | MASK_HSCKMD | MASK_NOL_2, 0},
+
+ /* Output Control */
+ {CONFCTL, MASK_VBUFEN | MASK_INFRMEN | MASK_YCBCRFMT_422_8_BIT | MASK_AUTOINDEX, 0},
+};
+
+static struct reg_value tc358743_setting_hdmi[] = {
+ /* HDMI interrupt mask */
+ {SYS_INT, 0x0000, 100},
+ {SYS_INTM, 0x0000, 0},
+ {PACKET_INTM, 0x0000, 0},
+ {CBIT_INTM, 0x0000, 0},
+ {AUDIO_INTM, 0x0000, 0},
+
+ {PHY_CTL0, MASK_PHY_CTL, 0},
+ /* HDMI PHY */
+ {PHY_CTL1, 0x0080, 0},
+ {PHY_BIAS, 0x0040, 0},
+ {PHY_CSQ, 0x000a, 0},
+
+ {HDMI_DET, MASK_HDMI_DET_V_SYNC | MASK_HDMI_DET_MOD0 | MASK_HDMI_DET_MOD1, 0},
+ {HV_RST, MASK_H_PI_RST | MASK_V_PI_RST, 0},
+ {PHY_CTL2, MASK_PHY_AUTO_RST2 | MASK_PHY_AUTO_RST3 | MASK_PHY_AUTO_RST4, 0},
+
+ /* HDMI system */
+ {DDC_CTL, 0x0030 | MASK_DDC5V_MODE_100MS, 0},
+ {ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON, 0},
+ {AVM_CTL, 0x002d, 0},
+ {VI_MODE, MASK_RGB_DVI, 0},
+ {VI_MUTE, MASK_AUTO_MUTE, 0},
+ {CMD_AUD, MASK_CMD_MUTE, 0},
+
+ /* EDID */
+ {EDID_MODE, 0x0001, 2},
+ {EDID_LEN2, 0x0001, 0},
+
+ {BCAPS, MASK_REPEATER | MASK_READY, 0}, /* Turn off HDMI */
+ {BSTATUS1, MASK_MAX_EXCED, 0},
+
+ /* HDCP Settings */
+ {HDCP_REG3, 0x0001, 0},
+ {HDCP_MODE, 0x0024, 0},
+ {HDCP_REG1, 0x0011, 0},
+ {HDCP_REG2, 0x000f, 0},
+
+ /* RGB to YUV Conversion */
+ {VOUT_SET0, 0x0002,0},
+ {VOUT_SET2, MASK_VOUTCOLORMODE_AUTO | MASK_SEL422 | MASK_VOUT_422FIL_100, 0},
+ {VOUT_SET3, MASK_VOUT_EXTCNT, 0},
+ {VI_REP, MASK_VOUT_COLOR_601_YCBCR_LIMITED, 0},
+
+ /* InfoFrame extraction */
+ {PK_INT_MODE, 0x00ff, 0},
+ {NO_PKT_LIMIT, 0x002c, 0},
+ {NO_PKT_CLR, 0x0053, 0},
+ {ERR_PK_LIMIT, 0x0001, 0},
+ {NO_PKT_LIMIT2, 0x0030, 0},
+ {NO_GDB_LIMIT, 0x0010, 0},
+ {INIT_END, MASK_INIT_END, 0},
+};
+
+enum {
+ TC358743_MODE_640x480,
+ TC358743_MODE_800x600,
+ TC358743_MODE_1024x768,
+ TC358743_MODE_1280x720,
+ TC358743_MODE_1280x1024,
+ TC358743_MODE_1680x1050,
+ TC358743_MODE_1920x1080,
+ TC358743_SIZE_LAST,
+};
+
+#define to_tc358743(sd) container_of(sd, struct tc358743_priv, subdev)
+
+struct tc358743_priv {
+ struct v4l2_subdev subdev;
+ struct v4l2_mbus_framefmt mf;
+ int ident;
+ u16 chip_id;
+ u8 revision;
+ int mode;
+ struct i2c_client *client;
+};
+
+static enum v4l2_mbus_pixelcode tc358743_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+};
+
+static const struct v4l2_frmsize_discrete tc358743_frmsizes[TC358743_SIZE_LAST] = {
+ {640, 480},
+ {800, 600},
+ {1024, 768},
+ {1280, 720},
+ {1280, 1024},
+ {1680, 1050},
+ {1920, 1080},
+};
+
+/* EDID taken from BENQ G2220HD display */
+static u8 hdmi_edid[] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x09, 0xd1, 0x21, 0x78, 0x45, 0x54, 0x00, 0x00,
+ 0x26, 0x14, 0x01, 0x03, 0x80, 0x30, 0x1b, 0x78, 0x2e, 0x35, 0x81, 0xa6, 0x56, 0x48, 0x9a, 0x24,
+ 0x12, 0x50, 0x54, 0xa5, 0x6b, 0x80, 0x71, 0x00, 0x81, 0xc0, 0x81, 0x40, 0x81, 0x80, 0xa9, 0xc0,
+ 0xb3, 0x00, 0xd1, 0xc0, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+ 0x45, 0x00, 0xdd, 0x0c, 0x11, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x48, 0x39, 0x41,
+ 0x30, 0x30, 0x34, 0x35, 0x35, 0x53, 0x4c, 0x30, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
+ 0x4c, 0x18, 0x53, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+ 0x00, 0x42, 0x65, 0x6e, 0x51, 0x20, 0x47, 0x32, 0x32, 0x32, 0x30, 0x48, 0x44, 0x0a, 0x00, 0xd7,
+};
+
+static int tc358743_find_mode(u32 width, u32 height)
+{
+ int i;
+
+ for (i = 0; i < TC358743_SIZE_LAST; i++) {
+ if ((tc358743_frmsizes[i].width >= width) &&
+ (tc358743_frmsizes[i].height >= height))
+ break;
+ }
+
+ /* If not found, select the biggest */
+ if (i >= TC358743_SIZE_LAST)
+ i = TC358743_SIZE_LAST - 1;
+
+ return i;
+}
+
+static int get_register_size(u16 reg) {
+ int i = 0;
+ int size = 0;
+ while(0 != tc358743_read_reg_size[i].startaddr ||
+ 0 != tc358743_read_reg_size[i].endaddr ||
+ 0 != tc358743_read_reg_size[i].size)
+ {
+ if(tc358743_read_reg_size[i].startaddr <= reg && tc358743_read_reg_size[i].endaddr >= reg)
+ {
+ size = tc358743_read_reg_size[i].size;
+ break;
+ }
+ i++;
+ }
+ if (size == 0) {
+ printk(KERN_ERR "Unkown register 0x%04x size!!", reg);
+ }
+ return size;
+}
+
+static uint32_t i2c_rd(struct i2c_client *client, u16 reg)
+{
+ int err;
+ uint32_t result = 0;
+ uint8_t *values = (uint8_t*)&result;
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ int n = get_register_size(reg);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = n,
+ .buf = values,
+ },
+ };
+ err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (err != ARRAY_SIZE(msgs)) {
+ pr_err("%s: reading register 0x%x from 0x%x failed\n", __func__, reg, client->addr);
+ }
+ return result;
+}
+
+static int i2c_wr(struct i2c_client *client, u16 reg, u32 val)
+{
+ int i = 0;
+ u32 data = val;
+ u8 au8Buf[6] = {0};
+ int size = get_register_size(reg);
+ int len = get_register_size(reg);
+
+ if(!size) {
+ pr_err("%s:write reg error:reg=%x is not found\n",__func__, reg);
+ return -1;
+ }
+
+ if(size == 3) {
+ size = 2;
+ } else if(size != len) {
+ pr_err("%s:write reg len error:reg=%x %d instead of %d\n",
+ __func__, reg, len, size);
+ return 0;
+ }
+
+ while(len > 0) {
+ i = 0;
+ au8Buf[i++] = (reg >> 8) & 0xff;
+ au8Buf[i++] = reg & 0xff;
+ while(size-- > 0) {
+ au8Buf[i++] = (u8)data;
+ data >>= 8;
+ }
+
+ if (i2c_master_send(client, au8Buf, i) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+ len -= (u8)size;
+ reg += (u16)size;
+ }
+
+ return 0;
+}
+
+static int tc358743_set_pll(struct i2c_client *client, uint32_t frequency)
+{
+ int ret = 0;
+
+ timings_regs timings = tc358743_get_best_timings(frequency);
+ if (timings.frequency == 0) return 1;
+
+ printk(KERN_DEBUG "Setting pll to frequency %d (%d) MHz\n",
+ frequency, timings.frequency);
+
+ ret += i2c_wr(client, FIFOCTL, timings.fifo_delay);
+
+ /* Disable all interrupts except the hdmi-rx */
+ ret += i2c_wr(client, INTSTATUS, 0x0);
+ ret += i2c_wr(client, INTMASK, 0x5ff);
+
+ ret += i2c_wr(client, PLLCTL0, SET_PLL_FREQ(frequency));
+
+ ret += i2c_wr(client, PLLCTL1,
+ SET_PLL_FRS(GET_FRS(frequency), FRS_BW_50) | MASK_RESETB | MASK_PLL_EN);
+ mdelay(1);
+ ret += i2c_wr(client, PLLCTL1,
+ SET_PLL_FRS(GET_FRS(frequency), FRS_BW_50) | MASK_RESETB | MASK_PLL_EN | MASK_CKEN);
+
+ ret += i2c_wr(client, LINEINITCNT, timings.line_init_cnt);
+ ret += i2c_wr(client, LPTXTIMECNT, timings.tlpx_time_cnt);
+
+ ret += i2c_wr(client, TCLK_HEADERCNT,
+ CALC_HDR_CNT(timings.tclk_prepare_cnt, timings.tclk_zero_cnt));
+
+ ret += i2c_wr(client, TCLK_TRAILCNT, timings.tclk_trail_cnt);
+
+ ret += i2c_wr(client, THS_HEADERCNT,
+ CALC_HDR_CNT(timings.ths_prepare_cnt, timings.ths_zero_cnt));
+
+ ret += i2c_wr(client, TWAKEUP, timings.twakeup_cnt);
+ ret += i2c_wr(client, TCLK_POSTCNT, timings.tclk_post_cnt);
+ ret += i2c_wr(client, THS_TRAILCNT, timings.ths_trail_cnt);
+
+ return ret;
+}
+
+static int tc358743_write_table(struct i2c_client *client, struct reg_value table[], int table_length)
+{
+ u32 lines_to_repeat = 0;
+ u32 repeats = 0;
+ u32 delay_ms = 0;
+ u16 addr = 0;
+ u32 val = 0;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < table_length; ++i) {
+ addr = table[i].addr;
+ val = table[i].val;
+ delay_ms = (table[i].flags & 0xffff);
+
+ ret = i2c_wr(client, addr, val);
+ if (ret < 0)
+ break;
+
+ if (delay_ms)
+ msleep(delay_ms);
+
+ if(((table[i].flags >> 16) & (0xff)) != 0) {
+ if(!repeats) {
+ repeats = ((table[i].flags >> 16) & 0xff);
+ lines_to_repeat = ((table[i].flags >> 24) & 0xff);
+ }
+ if(--repeats > 0) {
+ i -= lines_to_repeat;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int tc358743_write_edid(struct i2c_client *client, u8 *edid, int len)
+{
+ int i = 0, off = 0;
+ u8 au8Buf[8+2] = {0};
+ int size = 0;
+ u16 reg;
+
+ reg = 0x8C00;
+ off = 0;
+ size = ARRAY_SIZE(au8Buf)-2;
+ printk(KERN_DEBUG "Write EDID: %d (%d)\n", len, size);
+ while(len > 0)
+ {
+ i = 0;
+ au8Buf[i++] = (reg >> 8) & 0xff;
+ au8Buf[i++] = reg & 0xff;
+ while(i < ARRAY_SIZE(au8Buf))
+ {
+ au8Buf[i++] = edid[off++];
+ }
+
+ if (i2c_master_send(client, au8Buf, i) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, off);
+ return -1;
+ }
+ len -= (u8)size;
+ reg += (u16)size;
+ }
+ printk(KERN_DEBUG "Activate EDID\n");
+ i2c_wr(client, EDID_MODE, MASK_EDID_MODE_DDC2B);
+ i2c_wr(client, EDID_LEN1, 0x00);
+ i2c_wr(client, EDID_LEN2, 0x01);
+ return 0;
+}
+
+static int tc358743_toggle_hpd(struct i2c_client *client, int active)
+{
+ int ret = 0;
+
+ if(active)
+ {
+ ret += i2c_wr(client, HPD_CTL, 0x00);
+ mdelay(500);
+ ret += i2c_wr(client, HPD_CTL, MASK_HPD_CTL0);
+ } else {
+ ret += i2c_wr(client, HPD_CTL, MASK_HPD_CTL0);
+ mdelay(500);
+ ret += i2c_wr(client, HPD_CTL, 0x00);
+ }
+ return ret;
+}
+
+static void tc358743_set_default_fmt(struct tc358743_priv *priv)
+{
+ struct v4l2_mbus_framefmt *mf = &priv->mf;
+
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+}
+
+/* Start/Stop streaming from the device */
+static int tc358743_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct tc358743_priv *priv = to_tc358743(sd);
+
+ if (!enable) {
+ printk(KERN_DEBUG "Disabling stream");
+ i2c_wr(priv->client, CONFCTL, 0);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int tc358743_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ int mode;
+
+ mode = tc358743_find_mode(mf->width, mf->height);
+ mf->width = tc358743_frmsizes[mode].width;
+ mf->height = tc358743_frmsizes[mode].height;
+ mf->field = V4L2_FIELD_NONE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
+
+struct aviInfoFrame {
+ u8 f17;
+ u8 y10;
+ u8 a0;
+ u8 b10;
+ u8 s10;
+ u8 c10;
+ u8 m10;
+ u8 r3210;
+ u8 itc;
+ u8 ec210;
+ u8 q10;
+ u8 sc10;
+ u8 f47;
+ u8 vic;
+ u8 yq10;
+ u8 cn10;
+ u8 pr3210;
+ u16 etb;
+ u16 sbb;
+ u16 elb;
+ u16 srb;
+};
+
+static inline bool is_hdmi(struct v4l2_subdev *sd)
+{
+ struct tc358743_priv *priv = to_tc358743(sd);
+ return i2c_rd(priv->client, SYS_STATUS) & MASK_S_HDMI;
+}
+
+/* set the format we will capture in */
+static int tc358743_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct tc358743_priv *priv = to_tc358743(sd);
+ int ret;
+ uint32_t v2, v, width, height, v_size, h_size, fv_cnt, fps;
+
+ ret = tc358743_try_fmt(sd, mf);
+ if (ret < 0)
+ return ret;
+
+ priv->mode = tc358743_find_mode(mf->width, mf->height);
+
+ memcpy(&priv->mf, mf, sizeof(struct v4l2_mbus_framefmt));
+
+ tc358743_write_table(priv->client, tc358743_reset, ARRAY_SIZE(tc358743_reset));
+ tc358743_write_table(priv->client, tc358743_setting_hdmi, ARRAY_SIZE(tc358743_setting_hdmi));
+ msleep(100);
+
+ v = i2c_rd(priv->client, DE_WIDTH_H_LO);
+ v2 = i2c_rd(priv->client, DE_WIDTH_H_HI) & 0x1f;
+ width = (v2 << 8) + v;
+ v = i2c_rd(priv->client, DE_WIDTH_V_LO);
+ v2 = i2c_rd(priv->client, DE_WIDTH_V_HI) & 0x1f;
+ height = (v2 << 8) + v;
+ v = i2c_rd(priv->client, H_SIZE_LO);
+ v2 = i2c_rd(priv->client, H_SIZE_HI) & 0x1f;
+ h_size = (v2 << 8) + v;
+ v = i2c_rd(priv->client, V_SIZE_LO);
+ v2 = i2c_rd(priv->client, V_SIZE_HI) & 0x3f;
+ v_size = ((v2 << 8) + v) / 2;
+ v = i2c_rd(priv->client, FV_CNT_LO);
+ v2 = i2c_rd(priv->client, FV_CNT_HI) & 0x3;
+ fv_cnt = (v2 << 8) + v;
+ fps = fv_cnt > 0 ? DIV_ROUND_CLOSEST(10000, fv_cnt) : 0;
+
+ printk(KERN_DEBUG "Image is %dx%d@%d, ~%d Gbps bandwidth (~%dMHz/lane)",
+ width, height, fps,
+ DIV_ROUND_UP(fps*width*height*16, 1000*1000),
+ DIV_ROUND_UP(fps*width*height*8, 1000*1000));
+
+ if (width * fps == 0) {
+ printk(KERN_ERR "width or fps 0");
+ return 0;
+ }
+
+ if ((width != mf->width)) {
+ printk(KERN_ERR "Wrong width (%d vs %d)", width, mf->width);
+ return 0;
+ }
+
+ /* XXX the chip sometimes miscalculates the height of the image,
+ * therefore, we base the output mostly on the width of the image */
+ if (width == 1920) {
+ /* works for 1920x1080 @ 60 */
+ ret = tc358743_set_pll(priv->client, 1075);
+ /* 872 is in the middle between 1024 and 720, should be a safe
+ * value for both 1280x720 and 1280x1024 */
+ } else if (width == 1280 && height >= 872) {
+ /* works on 1280x1024 @ 75 */
+ ret = tc358743_set_pll(priv->client, 1075);
+ } else if (width == 1280 && height < 872) {
+ /* works on 1280x720 @ 60 */
+ ret = tc358743_set_pll(priv->client, 825);
+ } else if (width == 1024) {
+ /* works on 1024x768 @ 75 */
+ ret = tc358743_set_pll(priv->client, 600);
+ } else if (width >= 800) {
+ /* works for 800x600@75 */
+ ret = tc358743_set_pll(priv->client, 594);
+ } else if (width == 640) {
+ /* works on 640x480 @ 75 */
+ ret = tc358743_set_pll(priv->client, 500);
+ } else {
+ return 0;
+ }
+
+ tc358743_write_table(priv->client,
+ tc358743_2lanes_start,
+ ARRAY_SIZE(tc358743_2lanes_start));
+
+ return ret;
+}
+
+static int tc358743_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(tc358743_codes))
+ return -EINVAL;
+
+ *code = tc358743_codes[index];
+
+ return 0;
+}
+
+/* Get chip identification */
+static int tc358743_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct tc358743_priv *priv = to_tc358743(sd);
+
+ id->ident = priv->ident;
+ id->revision = priv->revision;
+
+ return 0;
+}
+
+static int tc358743_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_subdev_desc *scsd = soc_camera_i2c_to_desc(client);
+
+ return soc_camera_set_power(&client->dev, scsd, on);
+}
+
+static struct v4l2_subdev_video_ops tc358743_video_ops = {
+ .s_stream = tc358743_s_stream,
+ .s_mbus_fmt = tc358743_s_fmt,
+ .try_mbus_fmt = tc358743_try_fmt,
+ .enum_mbus_fmt = tc358743_enum_fmt,
+};
+
+static struct v4l2_subdev_core_ops tc358743_core_ops = {
+ .g_chip_ident = tc358743_g_chip_ident,
+ .s_power = tc358743_s_power,
+};
+
+static struct v4l2_subdev_ops tc358743_subdev_ops = {
+ .core = &tc358743_core_ops,
+ .video = &tc358743_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int tc358743_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct tc358743_priv *priv;
+ struct soc_camera_subdev_desc *scsd;
+ int ret = 0;
+
+ /* Checking soc-camera interface */
+ scsd = client->dev.platform_data;
+ if (!scsd) {
+ dev_err(&client->dev, "Missing soc_camera_link for driver\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&client->dev, sizeof(struct tc358743_priv),
+ GFP_KERNEL);
+ if (!priv) {
+ dev_err(&client->dev, "Failed to allocate private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &tc358743_subdev_ops);
+
+ priv->client = client;
+ priv->ident = V4L2_IDENT_OV5640;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ soc_camera_power_on(&client->dev, scsd);
+
+ tc358743_set_default_fmt(priv);
+ tc358743_write_table(client, tc358743_reset, ARRAY_SIZE(tc358743_reset));
+ tc358743_write_table(client, tc358743_setting_hdmi, ARRAY_SIZE(tc358743_setting_hdmi));
+
+ if((ret = tc358743_write_edid(client, hdmi_edid, ARRAY_SIZE(hdmi_edid))))
+ printk(KERN_ERR "%s: Fail to write EDID to tc35874!\n", __FUNCTION__);
+
+ tc358743_toggle_hpd(client, 1);
+
+ soc_camera_power_off(&client->dev, scsd);
+
+ return ret;
+}
+
+static int tc358743_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id tc358743_id[] = {
+ { "tc358743", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tc358743_id);
+
+static struct i2c_driver tc358743_i2c_driver = {
+ .driver = {
+ .name = "tc358743",
+ .owner = THIS_MODULE,
+ },
+ .probe = tc358743_probe,
+ .remove = tc358743_remove,
+ .id_table = tc358743_id,
+};
+
+static int __init tc358743_module_init(void)
+{
+ return i2c_add_driver(&tc358743_i2c_driver);
+}
+
+static void __exit tc358743_module_exit(void)
+{
+ i2c_del_driver(&tc358743_i2c_driver);
+}
+
+module_init(tc358743_module_init);
+module_exit(tc358743_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for Toshiba TC358743 HDMI to CSI-2 bridge");
+MODULE_AUTHOR("Wojciech Bieganski <wbieganski@antmicro.com>");
+MODULE_LICENSE("GPL v2");