summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Brown <oliver.brown@freescale.com>2013-09-08 15:05:28 -0500
committerOliver Brown <oliver.brown@freescale.com>2013-09-11 09:02:06 -0500
commit5d2f8ba6ca8b87df67f5587c8e230cd52748e6f1 (patch)
treee77040a37e2194f75f2855d4a9c783609e21f29c
parentc378fd1a9e96772e75e360c707fe7b9074d15236 (diff)
ENGR00278667-1 [mxc_v4l2_capture]: Add adv7180 driver in 3.10.9 Kernel
Copied file from 3.5.7 Kernel commit de6459732a23402cbe520812bf4202299330fd68 Author: Oliver Brown <oliver.brown@freescale.com> Date: Mon Jun 24 16:41:17 2013 -0500 Added missing call to clk_disable_unprepare() in adv7180_probe. Signed-off-by: Oliver Brown <oliver.brown@freescale.com>
-rw-r--r--drivers/media/platform/mxc/capture/Kconfig6
-rw-r--r--drivers/media/platform/mxc/capture/Makefile3
-rw-r--r--drivers/media/platform/mxc/capture/adv7180.c1344
3 files changed, 1353 insertions, 0 deletions
diff --git a/drivers/media/platform/mxc/capture/Kconfig b/drivers/media/platform/mxc/capture/Kconfig
index 6f253c1e45f5..cee7aa31f2d1 100644
--- a/drivers/media/platform/mxc/capture/Kconfig
+++ b/drivers/media/platform/mxc/capture/Kconfig
@@ -30,6 +30,12 @@ config MXC_CAMERA_OV5640_MIPI
---help---
If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
+config MXC_TVIN_ADV7180
+ tristate "Analog Device adv7180 TV Decoder Input support"
+ depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+ ---help---
+ If you plan to use the adv7180 video decoder with your MXC system, say Y here.
+
choice
prompt "Select Overlay Rounting"
default MXC_IPU_DEVICE_QUEUE_SDC
diff --git a/drivers/media/platform/mxc/capture/Makefile b/drivers/media/platform/mxc/capture/Makefile
index 0f5eb3d10192..4303c0a2ccdf 100644
--- a/drivers/media/platform/mxc/capture/Makefile
+++ b/drivers/media/platform/mxc/capture/Makefile
@@ -16,3 +16,6 @@ obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o
ov5640_camera_mipi-objs := ov5640_mipi.o
obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi.o
+
+adv7180_tvin-objs := adv7180.o
+obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o
diff --git a/drivers/media/platform/mxc/capture/adv7180.c b/drivers/media/platform/mxc/capture/adv7180.c
new file mode 100644
index 000000000000..ae17d7f25ff6
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/adv7180.c
@@ -0,0 +1,1344 @@
+/*
+ * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file adv7180.c
+ *
+ * @brief Analog Device ADV7180 video decoder functions
+ *
+ * @ingroup Camera
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-int-device.h>
+#include "mxc_v4l2_capture.h"
+
+#define ADV7180_VOLTAGE_ANALOG 1800000
+#define ADV7180_VOLTAGE_DIGITAL_CORE 1800000
+#define ADV7180_VOLTAGE_DIGITAL_IO 3300000
+#define ADV7180_VOLTAGE_PLL 1800000
+
+static struct regulator *dvddio_regulator;
+static struct regulator *dvdd_regulator;
+static struct regulator *avdd_regulator;
+static struct regulator *pvdd_regulator;
+static int pwn_gpio;
+
+static int adv7180_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *id);
+static int adv7180_detach(struct i2c_client *client);
+
+static const struct i2c_device_id adv7180_id[] = {
+ {"adv7180", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
+
+static struct i2c_driver adv7180_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7180",
+ },
+ .probe = adv7180_probe,
+ .remove = adv7180_detach,
+ .id_table = adv7180_id,
+};
+
+/*!
+ * Maintains the information on the current state of the sensor.
+ */
+struct sensor {
+ struct sensor_data sen;
+ v4l2_std_id std_id;
+} adv7180_data;
+
+
+/*! List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt_t
+ */
+typedef enum {
+ ADV7180_NTSC = 0, /*!< Locked on (M) NTSC video signal. */
+ ADV7180_PAL, /*!< (B, G, H, I, N)PAL video signal. */
+ ADV7180_NOT_LOCKED, /*!< Not locked on a signal. */
+} video_fmt_idx;
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define ADV7180_STD_MAX (ADV7180_PAL + 1)
+
+/*! Video format structure. */
+typedef struct {
+ int v4l2_id; /*!< Video for linux ID. */
+ char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */
+ u16 raw_width; /*!< Raw width. */
+ u16 raw_height; /*!< Raw height. */
+ u16 active_width; /*!< Active width. */
+ u16 active_height; /*!< Active height. */
+} video_fmt_t;
+
+/*! Description of video formats supported.
+ *
+ * PAL: raw=720x625, active=720x576.
+ * NTSC: raw=720x525, active=720x480.
+ */
+static video_fmt_t video_fmts[] = {
+ { /*! NTSC */
+ .v4l2_id = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .raw_width = 720, /* SENS_FRM_WIDTH */
+ .raw_height = 525, /* SENS_FRM_HEIGHT */
+ .active_width = 720, /* ACT_FRM_WIDTH plus 1 */
+ .active_height = 480, /* ACT_FRM_WIDTH plus 1 */
+ },
+ { /*! (B, G, H, I, N) PAL */
+ .v4l2_id = V4L2_STD_PAL,
+ .name = "PAL",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ },
+ { /*! Unlocked standard */
+ .v4l2_id = V4L2_STD_ALL,
+ .name = "Autodetect",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ },
+};
+
+/*!* Standard index of ADV7180. */
+static video_fmt_idx video_idx = ADV7180_PAL;
+
+/*! @brief This mutex is used to provide mutual exclusion.
+ *
+ * Create a mutex that can be used to provide mutually exclusive
+ * read/write access to the globally accessible data structures
+ * and variables that were defined above.
+ */
+static DEFINE_MUTEX(mutex);
+
+#define IF_NAME "adv7180"
+#define ADV7180_INPUT_CTL 0x00 /* Input Control */
+#define ADV7180_STATUS_1 0x10 /* Status #1 */
+#define ADV7180_BRIGHTNESS 0x0a /* Brightness */
+#define ADV7180_IDENT 0x11 /* IDENT */
+#define ADV7180_VSYNC_FIELD_CTL_1 0x31 /* VSYNC Field Control #1 */
+#define ADV7180_MANUAL_WIN_CTL 0x3d /* Manual Window Control */
+#define ADV7180_SD_SATURATION_CB 0xe3 /* SD Saturation Cb */
+#define ADV7180_SD_SATURATION_CR 0xe4 /* SD Saturation Cr */
+#define ADV7180_PWR_MNG 0x0f /* Power Management */
+
+/* supported controls */
+/* This hasn't been fully implemented yet.
+ * This is how it should work, though. */
+static struct v4l2_queryctrl adv7180_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0, /* check this value */
+ .maximum = 255, /* check this value */
+ .step = 1, /* check this value */
+ .default_value = 127, /* check this value */
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0, /* check this value */
+ .maximum = 255, /* check this value */
+ .step = 0x1, /* check this value */
+ .default_value = 127, /* check this value */
+ .flags = 0,
+ }
+};
+
+static inline void adv7180_power_down(int enable)
+{
+ gpio_set_value_cansleep(pwn_gpio, !enable);
+ msleep(2);
+}
+
+static int adv7180_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ dvddio_regulator = devm_regulator_get(dev, "DOVDD");
+
+ if (!IS_ERR(dvddio_regulator)) {
+ regulator_set_voltage(dvddio_regulator,
+ ADV7180_VOLTAGE_DIGITAL_IO,
+ ADV7180_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(dvddio_regulator);
+ if (ret) {
+ dev_err(dev, "set io voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set io voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get io voltage\n");
+ }
+
+ dvdd_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(dvdd_regulator)) {
+ regulator_set_voltage(dvdd_regulator,
+ ADV7180_VOLTAGE_DIGITAL_CORE,
+ ADV7180_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(dvdd_regulator);
+ if (ret) {
+ dev_err(dev, "set core voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set core voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get core voltage\n");
+ }
+
+ avdd_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(avdd_regulator)) {
+ regulator_set_voltage(avdd_regulator,
+ ADV7180_VOLTAGE_ANALOG,
+ ADV7180_VOLTAGE_ANALOG);
+ ret = regulator_enable(avdd_regulator);
+ if (ret) {
+ dev_err(dev, "set analog voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set analog voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get analog voltage\n");
+ }
+
+ pvdd_regulator = devm_regulator_get(dev, "PVDD");
+ if (!IS_ERR(pvdd_regulator)) {
+ regulator_set_voltage(pvdd_regulator,
+ ADV7180_VOLTAGE_PLL,
+ ADV7180_VOLTAGE_PLL);
+ ret = regulator_enable(pvdd_regulator);
+ if (ret) {
+ dev_err(dev, "set pll voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set pll voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get pll voltage\n");
+ }
+
+ return ret;
+}
+
+
+/***********************************************************************
+ * I2C transfert.
+ ***********************************************************************/
+
+/*! Read one register from a ADV7180 i2c slave device.
+ *
+ * @param *reg register in the device we wish to access.
+ *
+ * @return 0 if success, an error code otherwise.
+ */
+static inline int adv7180_read(u8 reg)
+{
+ int val;
+
+ val = i2c_smbus_read_byte_data(adv7180_data.sen.i2c_client, reg);
+ if (val < 0) {
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:read reg error: reg=%2x\n", __func__, reg);
+ return -1;
+ }
+ return val;
+}
+
+/*! Write one register of a ADV7180 i2c slave device.
+ *
+ * @param *reg register in the device we wish to access.
+ *
+ * @return 0 if success, an error code otherwise.
+ */
+static int adv7180_write_reg(u8 reg, u8 val)
+{
+ s32 ret;
+
+ ret = i2c_smbus_write_byte_data(adv7180_data.sen.i2c_client, reg, val);
+ if (ret < 0) {
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:write reg error:reg=%2x,val=%2x\n", __func__,
+ reg, val);
+ return -1;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * mxc_v4l2_capture interface.
+ ***********************************************************************/
+
+/*!
+ * Return attributes of current video standard.
+ * Since this device autodetects the current standard, this function also
+ * sets the values that need to be changed if the standard changes.
+ * There is no set std equivalent function.
+ *
+ * @return None.
+ */
+static void adv7180_get_std(v4l2_std_id *std)
+{
+ int tmp;
+ int idx;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n");
+
+ /* Read the AD_RESULT to get the detect output video standard */
+ tmp = adv7180_read(ADV7180_STATUS_1) & 0x70;
+
+ mutex_lock(&mutex);
+ if (tmp == 0x40) {
+ /* PAL */
+ *std = V4L2_STD_PAL;
+ idx = ADV7180_PAL;
+ } else if (tmp == 0) {
+ /*NTSC*/
+ *std = V4L2_STD_NTSC;
+ idx = ADV7180_NTSC;
+ } else {
+ *std = V4L2_STD_ALL;
+ idx = ADV7180_NOT_LOCKED;
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "Got invalid video standard!\n");
+ }
+ mutex_unlock(&mutex);
+
+ /* This assumes autodetect which this device uses. */
+ if (*std != adv7180_data.std_id) {
+ video_idx = idx;
+ adv7180_data.std_id = *std;
+ adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
+ adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
+ }
+}
+
+/***********************************************************************
+ * IOCTL Functions from v4l2_int_ioctl_desc.
+ ***********************************************************************/
+
+/*!
+ * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num
+ * s: pointer to standard V4L2 device structure
+ * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
+ *
+ * Gets slave interface parameters.
+ * Calculates the required xclk value to support the requested
+ * clock parameters in p. This value is returned in the p
+ * parameter.
+ *
+ * vidioc_int_g_ifparm returns platform-specific information about the
+ * interface settings used by the sensor.
+ *
+ * Called on open.
+ */
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n");
+
+ if (s == NULL) {
+ pr_err(" ERROR!! no slave device set!\n");
+ return -1;
+ }
+
+ /* Initialize structure to 0s then set any non-0 values. */
+ memset(p, 0, sizeof(*p));
+ p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */
+ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+ p->u.bt656.nobt_hs_inv = 1;
+ p->u.bt656.bt_sync_correct = 1;
+
+ /* ADV7180 has a dedicated clock so no clock settings needed. */
+
+ return 0;
+}
+
+/*!
+ * Sets the camera power.
+ *
+ * s pointer to the camera device
+ * on if 1, power is to be turned on. 0 means power is to be turned off
+ *
+ * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ * This is called on open, close, suspend and resume.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct sensor *sensor = s->priv;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_s_power\n");
+
+ if (on && !sensor->sen.on) {
+ if (adv7180_write_reg(ADV7180_PWR_MNG, 0x04) != 0)
+ return -EIO;
+
+ /*
+ * FIXME:Additional 400ms to wait the chip to be stable?
+ * This is a workaround for preview scrolling issue.
+ */
+ msleep(400);
+ } else if (!on && sensor->sen.on) {
+ if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0)
+ return -EIO;
+ }
+
+ sensor->sen.on = on;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_parm\n");
+
+ switch (a->type) {
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->sen.streamcap.capability;
+ cparm->timeperframe = sensor->sen.streamcap.timeperframe;
+ cparm->capturemode = sensor->sen.streamcap.capturemode;
+ break;
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ break;
+
+ default:
+ pr_debug("ioctl_g_parm:type is unknown %d\n", a->type);
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ *
+ * This driver cannot change these settings.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_parm\n");
+
+ switch (a->type) {
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct sensor *sensor = s->priv;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n");
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug(" Returning size of %dx%d\n",
+ sensor->sen.pix.width, sensor->sen.pix.height);
+ f->fmt.pix = sensor->sen.pix;
+ break;
+
+ case V4L2_BUF_TYPE_PRIVATE: {
+ v4l2_std_id std;
+ adv7180_get_std(&std);
+ f->fmt.pix.pixelformat = (u32)std;
+ }
+ break;
+
+ default:
+ f->fmt.pix = sensor->sen.pix;
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * from the video_control[] array. Otherwise, returns -EINVAL if the
+ * control is not supported.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n");
+
+ for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++)
+ if (qc->id && qc->id == adv7180_qctrl[i].id) {
+ memcpy(qc, &(adv7180_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array. Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int ret = 0;
+ int sat = 0;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n");
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BRIGHTNESS\n");
+ adv7180_data.sen.brightness = adv7180_read(ADV7180_BRIGHTNESS);
+ vc->value = adv7180_data.sen.brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_CONTRAST\n");
+ vc->value = adv7180_data.sen.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_SATURATION\n");
+ sat = adv7180_read(ADV7180_SD_SATURATION_CB);
+ adv7180_data.sen.saturation = sat;
+ vc->value = adv7180_data.sen.saturation;
+ break;
+ case V4L2_CID_HUE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HUE\n");
+ vc->value = adv7180_data.sen.hue;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_DO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_RED_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_RED_BALANCE\n");
+ vc->value = adv7180_data.sen.red;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BLUE_BALANCE\n");
+ vc->value = adv7180_data.sen.blue;
+ break;
+ case V4L2_CID_GAMMA:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAMMA\n");
+ break;
+ case V4L2_CID_EXPOSURE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_EXPOSURE\n");
+ vc->value = adv7180_data.sen.ae_mode;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTOGAIN\n");
+ break;
+ case V4L2_CID_GAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAIN\n");
+ break;
+ case V4L2_CID_HFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HFLIP\n");
+ break;
+ case V4L2_CID_VFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_VFLIP\n");
+ break;
+ default:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " Default case\n");
+ vc->value = 0;
+ ret = -EPERM;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array). Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int retval = 0;
+ u8 tmp;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n");
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BRIGHTNESS\n");
+ tmp = vc->value;
+ adv7180_write_reg(ADV7180_BRIGHTNESS, tmp);
+ adv7180_data.sen.brightness = vc->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_CONTRAST\n");
+ break;
+ case V4L2_CID_SATURATION:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_SATURATION\n");
+ tmp = vc->value;
+ adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp);
+ adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp);
+ adv7180_data.sen.saturation = vc->value;
+ break;
+ case V4L2_CID_HUE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HUE\n");
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_DO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_RED_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_RED_BALANCE\n");
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BLUE_BALANCE\n");
+ break;
+ case V4L2_CID_GAMMA:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAMMA\n");
+ break;
+ case V4L2_CID_EXPOSURE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_EXPOSURE\n");
+ break;
+ case V4L2_CID_AUTOGAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTOGAIN\n");
+ break;
+ case V4L2_CID_GAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAIN\n");
+ break;
+ case V4L2_CID_HFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HFLIP\n");
+ break;
+ case V4L2_CID_VFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_VFLIP\n");
+ break;
+ default:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " Default case\n");
+ retval = -EPERM;
+ break;
+ }
+
+ return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index >= 1)
+ return -EINVAL;
+
+ fsize->discrete.width = video_fmts[video_idx].active_width;
+ fsize->discrete.height = video_fmts[video_idx].active_height;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ * VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+ ((struct v4l2_dbg_chip_ident *)id)->match.type =
+ V4L2_CHIP_MATCH_I2C_DRIVER;
+ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name,
+ "adv7180_decoder");
+ ((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_ADV7180;
+
+ return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n");
+ return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n");
+ return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module.
+ */
+static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = {
+
+ {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init},
+
+ /*!
+ * Delinitialise the dev. at slave detach.
+ * The complement of ioctl_dev_init.
+ */
+/* {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */
+
+ {vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power},
+ {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm},
+/* {vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
+/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
+ {vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init},
+
+ /*!
+ * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+/* {vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */
+
+ /*!
+ * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.
+ * This ioctl is used to negotiate the image capture size and
+ * pixel format without actually making it take effect.
+ */
+/* {vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
+
+ {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap},
+
+ /*!
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */
+/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */
+
+ {vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm},
+ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm},
+ {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl},
+ {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl},
+ {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl},
+ {vidioc_int_enum_framesizes_num,
+ (v4l2_int_ioctl_func *) ioctl_enum_framesizes},
+ {vidioc_int_g_chip_ident_num,
+ (v4l2_int_ioctl_func *)ioctl_g_chip_ident},
+};
+
+static struct v4l2_int_slave adv7180_slave = {
+ .ioctls = adv7180_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc),
+};
+
+static struct v4l2_int_device adv7180_int_device = {
+ .module = THIS_MODULE,
+ .name = "adv7180",
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &adv7180_slave,
+ },
+};
+
+
+/***********************************************************************
+ * I2C client and driver.
+ ***********************************************************************/
+
+/*! ADV7180 Reset function.
+ *
+ * @return None.
+ */
+static void adv7180_hard_reset(bool cvbs)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "In adv7180:adv7180_hard_reset\n");
+
+ if (cvbs) {
+ /* Set CVBS input on AIN1 */
+ adv7180_write_reg(ADV7180_INPUT_CTL, 0x00);
+ } else {
+ /*
+ * Set YPbPr input on AIN1,4,5 and normal
+ * operations(autodection of all stds).
+ */
+ adv7180_write_reg(ADV7180_INPUT_CTL, 0x09);
+ }
+
+ /* Datasheet recommends */
+ adv7180_write_reg(0x01, 0xc8);
+ adv7180_write_reg(0x02, 0x04);
+ adv7180_write_reg(0x03, 0x00);
+ adv7180_write_reg(0x04, 0x45);
+ adv7180_write_reg(0x05, 0x00);
+ adv7180_write_reg(0x06, 0x02);
+ adv7180_write_reg(0x07, 0x7F);
+ adv7180_write_reg(0x08, 0x80);
+ adv7180_write_reg(0x0A, 0x00);
+ adv7180_write_reg(0x0B, 0x00);
+ adv7180_write_reg(0x0C, 0x36);
+ adv7180_write_reg(0x0D, 0x7C);
+ adv7180_write_reg(0x0E, 0x00);
+ adv7180_write_reg(0x0F, 0x00);
+ adv7180_write_reg(0x13, 0x00);
+ adv7180_write_reg(0x14, 0x12);
+ adv7180_write_reg(0x15, 0x00);
+ adv7180_write_reg(0x16, 0x00);
+ adv7180_write_reg(0x17, 0x01);
+ adv7180_write_reg(0x18, 0x93);
+ adv7180_write_reg(0xF1, 0x19);
+ adv7180_write_reg(0x1A, 0x00);
+ adv7180_write_reg(0x1B, 0x00);
+ adv7180_write_reg(0x1C, 0x00);
+ adv7180_write_reg(0x1D, 0x40);
+ adv7180_write_reg(0x1E, 0x00);
+ adv7180_write_reg(0x1F, 0x00);
+ adv7180_write_reg(0x20, 0x00);
+ adv7180_write_reg(0x21, 0x00);
+ adv7180_write_reg(0x22, 0x00);
+ adv7180_write_reg(0x23, 0xC0);
+ adv7180_write_reg(0x24, 0x00);
+ adv7180_write_reg(0x25, 0x00);
+ adv7180_write_reg(0x26, 0x00);
+ adv7180_write_reg(0x27, 0x58);
+ adv7180_write_reg(0x28, 0x00);
+ adv7180_write_reg(0x29, 0x00);
+ adv7180_write_reg(0x2A, 0x00);
+ adv7180_write_reg(0x2B, 0xE1);
+ adv7180_write_reg(0x2C, 0xAE);
+ adv7180_write_reg(0x2D, 0xF4);
+ adv7180_write_reg(0x2E, 0x00);
+ adv7180_write_reg(0x2F, 0xF0);
+ adv7180_write_reg(0x30, 0x00);
+ adv7180_write_reg(0x31, 0x12);
+ adv7180_write_reg(0x32, 0x41);
+ adv7180_write_reg(0x33, 0x84);
+ adv7180_write_reg(0x34, 0x00);
+ adv7180_write_reg(0x35, 0x02);
+ adv7180_write_reg(0x36, 0x00);
+ adv7180_write_reg(0x37, 0x01);
+ adv7180_write_reg(0x38, 0x80);
+ adv7180_write_reg(0x39, 0xC0);
+ adv7180_write_reg(0x3A, 0x10);
+ adv7180_write_reg(0x3B, 0x05);
+ adv7180_write_reg(0x3C, 0x58);
+ adv7180_write_reg(0x3D, 0xB2);
+ adv7180_write_reg(0x3E, 0x64);
+ adv7180_write_reg(0x3F, 0xE4);
+ adv7180_write_reg(0x40, 0x90);
+ adv7180_write_reg(0x41, 0x01);
+ adv7180_write_reg(0x42, 0x7E);
+ adv7180_write_reg(0x43, 0xA4);
+ adv7180_write_reg(0x44, 0xFF);
+ adv7180_write_reg(0x45, 0xB6);
+ adv7180_write_reg(0x46, 0x12);
+ adv7180_write_reg(0x48, 0x00);
+ adv7180_write_reg(0x49, 0x00);
+ adv7180_write_reg(0x4A, 0x00);
+ adv7180_write_reg(0x4B, 0x00);
+ adv7180_write_reg(0x4C, 0x00);
+ adv7180_write_reg(0x4D, 0xEF);
+ adv7180_write_reg(0x4E, 0x08);
+ adv7180_write_reg(0x4F, 0x08);
+ adv7180_write_reg(0x50, 0x08);
+ adv7180_write_reg(0x51, 0x24);
+ adv7180_write_reg(0x52, 0x0B);
+ adv7180_write_reg(0x53, 0x4E);
+ adv7180_write_reg(0x54, 0x80);
+ adv7180_write_reg(0x55, 0x00);
+ adv7180_write_reg(0x56, 0x10);
+ adv7180_write_reg(0x57, 0x00);
+ adv7180_write_reg(0x58, 0x00);
+ adv7180_write_reg(0x59, 0x00);
+ adv7180_write_reg(0x5A, 0x00);
+ adv7180_write_reg(0x5B, 0x00);
+ adv7180_write_reg(0x5C, 0x00);
+ adv7180_write_reg(0x5D, 0x00);
+ adv7180_write_reg(0x5E, 0x00);
+ adv7180_write_reg(0x5F, 0x00);
+ adv7180_write_reg(0x60, 0x00);
+ adv7180_write_reg(0x61, 0x00);
+ adv7180_write_reg(0x62, 0x20);
+ adv7180_write_reg(0x63, 0x00);
+ adv7180_write_reg(0x64, 0x00);
+ adv7180_write_reg(0x65, 0x00);
+ adv7180_write_reg(0x66, 0x00);
+ adv7180_write_reg(0x67, 0x03);
+ adv7180_write_reg(0x68, 0x01);
+ adv7180_write_reg(0x69, 0x00);
+ adv7180_write_reg(0x6A, 0x00);
+ adv7180_write_reg(0x6B, 0xC0);
+ adv7180_write_reg(0x6C, 0x00);
+ adv7180_write_reg(0x6D, 0x00);
+ adv7180_write_reg(0x6E, 0x00);
+ adv7180_write_reg(0x6F, 0x00);
+ adv7180_write_reg(0x70, 0x00);
+ adv7180_write_reg(0x71, 0x00);
+ adv7180_write_reg(0x72, 0x00);
+ adv7180_write_reg(0x73, 0x10);
+ adv7180_write_reg(0x74, 0x04);
+ adv7180_write_reg(0x75, 0x01);
+ adv7180_write_reg(0x76, 0x00);
+ adv7180_write_reg(0x77, 0x3F);
+ adv7180_write_reg(0x78, 0xFF);
+ adv7180_write_reg(0x79, 0xFF);
+ adv7180_write_reg(0x7A, 0xFF);
+ adv7180_write_reg(0x7B, 0x1E);
+ adv7180_write_reg(0x7C, 0xC0);
+ adv7180_write_reg(0x7D, 0x00);
+ adv7180_write_reg(0x7E, 0x00);
+ adv7180_write_reg(0x7F, 0x00);
+ adv7180_write_reg(0x80, 0x00);
+ adv7180_write_reg(0x81, 0xC0);
+ adv7180_write_reg(0x82, 0x04);
+ adv7180_write_reg(0x83, 0x00);
+ adv7180_write_reg(0x84, 0x0C);
+ adv7180_write_reg(0x85, 0x02);
+ adv7180_write_reg(0x86, 0x03);
+ adv7180_write_reg(0x87, 0x63);
+ adv7180_write_reg(0x88, 0x5A);
+ adv7180_write_reg(0x89, 0x08);
+ adv7180_write_reg(0x8A, 0x10);
+ adv7180_write_reg(0x8B, 0x00);
+ adv7180_write_reg(0x8C, 0x40);
+ adv7180_write_reg(0x8D, 0x00);
+ adv7180_write_reg(0x8E, 0x40);
+ adv7180_write_reg(0x8F, 0x00);
+ adv7180_write_reg(0x90, 0x00);
+ adv7180_write_reg(0x91, 0x50);
+ adv7180_write_reg(0x92, 0x00);
+ adv7180_write_reg(0x93, 0x00);
+ adv7180_write_reg(0x94, 0x00);
+ adv7180_write_reg(0x95, 0x00);
+ adv7180_write_reg(0x96, 0x00);
+ adv7180_write_reg(0x97, 0xF0);
+ adv7180_write_reg(0x98, 0x00);
+ adv7180_write_reg(0x99, 0x00);
+ adv7180_write_reg(0x9A, 0x00);
+ adv7180_write_reg(0x9B, 0x00);
+ adv7180_write_reg(0x9C, 0x00);
+ adv7180_write_reg(0x9D, 0x00);
+ adv7180_write_reg(0x9E, 0x00);
+ adv7180_write_reg(0x9F, 0x00);
+ adv7180_write_reg(0xA0, 0x00);
+ adv7180_write_reg(0xA1, 0x00);
+ adv7180_write_reg(0xA2, 0x00);
+ adv7180_write_reg(0xA3, 0x00);
+ adv7180_write_reg(0xA4, 0x00);
+ adv7180_write_reg(0xA5, 0x00);
+ adv7180_write_reg(0xA6, 0x00);
+ adv7180_write_reg(0xA7, 0x00);
+ adv7180_write_reg(0xA8, 0x00);
+ adv7180_write_reg(0xA9, 0x00);
+ adv7180_write_reg(0xAA, 0x00);
+ adv7180_write_reg(0xAB, 0x00);
+ adv7180_write_reg(0xAC, 0x00);
+ adv7180_write_reg(0xAD, 0x00);
+ adv7180_write_reg(0xAE, 0x60);
+ adv7180_write_reg(0xAF, 0x00);
+ adv7180_write_reg(0xB0, 0x00);
+ adv7180_write_reg(0xB1, 0x60);
+ adv7180_write_reg(0xB2, 0x1C);
+ adv7180_write_reg(0xB3, 0x54);
+ adv7180_write_reg(0xB4, 0x00);
+ adv7180_write_reg(0xB5, 0x00);
+ adv7180_write_reg(0xB6, 0x00);
+ adv7180_write_reg(0xB7, 0x13);
+ adv7180_write_reg(0xB8, 0x03);
+ adv7180_write_reg(0xB9, 0x33);
+ adv7180_write_reg(0xBF, 0x02);
+ adv7180_write_reg(0xC0, 0x00);
+ adv7180_write_reg(0xC1, 0x00);
+ adv7180_write_reg(0xC2, 0x00);
+ adv7180_write_reg(0xC3, 0x00);
+ adv7180_write_reg(0xC4, 0x00);
+ adv7180_write_reg(0xC5, 0x81);
+ adv7180_write_reg(0xC6, 0x00);
+ adv7180_write_reg(0xC7, 0x00);
+ adv7180_write_reg(0xC8, 0x00);
+ adv7180_write_reg(0xC9, 0x04);
+ adv7180_write_reg(0xCC, 0x69);
+ adv7180_write_reg(0xCD, 0x00);
+ adv7180_write_reg(0xCE, 0x01);
+ adv7180_write_reg(0xCF, 0xB4);
+ adv7180_write_reg(0xD0, 0x00);
+ adv7180_write_reg(0xD1, 0x10);
+ adv7180_write_reg(0xD2, 0xFF);
+ adv7180_write_reg(0xD3, 0xFF);
+ adv7180_write_reg(0xD4, 0x7F);
+ adv7180_write_reg(0xD5, 0x7F);
+ adv7180_write_reg(0xD6, 0x3E);
+ adv7180_write_reg(0xD7, 0x08);
+ adv7180_write_reg(0xD8, 0x3C);
+ adv7180_write_reg(0xD9, 0x08);
+ adv7180_write_reg(0xDA, 0x3C);
+ adv7180_write_reg(0xDB, 0x9B);
+ adv7180_write_reg(0xDC, 0xAC);
+ adv7180_write_reg(0xDD, 0x4C);
+ adv7180_write_reg(0xDE, 0x00);
+ adv7180_write_reg(0xDF, 0x00);
+ adv7180_write_reg(0xE0, 0x14);
+ adv7180_write_reg(0xE1, 0x80);
+ adv7180_write_reg(0xE2, 0x80);
+ adv7180_write_reg(0xE3, 0x80);
+ adv7180_write_reg(0xE4, 0x80);
+ adv7180_write_reg(0xE5, 0x25);
+ adv7180_write_reg(0xE6, 0x44);
+ adv7180_write_reg(0xE7, 0x63);
+ adv7180_write_reg(0xE8, 0x65);
+ adv7180_write_reg(0xE9, 0x14);
+ adv7180_write_reg(0xEA, 0x63);
+ adv7180_write_reg(0xEB, 0x55);
+ adv7180_write_reg(0xEC, 0x55);
+ adv7180_write_reg(0xEE, 0x00);
+ adv7180_write_reg(0xEF, 0x4A);
+ adv7180_write_reg(0xF0, 0x44);
+ adv7180_write_reg(0xF1, 0x0C);
+ adv7180_write_reg(0xF2, 0x32);
+ adv7180_write_reg(0xF3, 0x00);
+ adv7180_write_reg(0xF4, 0x3F);
+ adv7180_write_reg(0xF5, 0xE0);
+ adv7180_write_reg(0xF6, 0x69);
+ adv7180_write_reg(0xF7, 0x10);
+ adv7180_write_reg(0xF8, 0x00);
+ adv7180_write_reg(0xF9, 0x03);
+ adv7180_write_reg(0xFA, 0xFA);
+ adv7180_write_reg(0xFB, 0x40);
+}
+
+/*! ADV7180 I2C attach function.
+ *
+ * @param *adapter struct i2c_adapter *.
+ *
+ * @return Error code indicating success or failure.
+ */
+
+/*!
+ * ADV7180 I2C probe function.
+ * Function set in i2c_driver struct.
+ * Called by insmod.
+ *
+ * @param *adapter I2C adapter descriptor.
+ *
+ * @return Error code indicating success or failure.
+ */
+static int adv7180_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rev_id;
+ int ret = 0;
+ u32 cvbs = true;
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+
+ printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data);
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "setup pinctrl failed\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_err(dev, "no sensor pwdn pin available\n");
+ return -ENODEV;
+ }
+ ret = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "adv7180_pwdn");
+ if (ret < 0) {
+ dev_err(dev, "no power pin available!\n");
+ return ret;
+ }
+
+ adv7180_regulator_enable(dev);
+
+ adv7180_power_down(0);
+
+ msleep(1);
+
+ /* Set initial values for the sensor struct. */
+ memset(&adv7180_data, 0, sizeof(adv7180_data));
+ adv7180_data.sen.i2c_client = client;
+ adv7180_data.sen.streamcap.timeperframe.denominator = 30;
+ adv7180_data.sen.streamcap.timeperframe.numerator = 1;
+ adv7180_data.std_id = V4L2_STD_ALL;
+ video_idx = ADV7180_NOT_LOCKED;
+ adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
+ adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
+ adv7180_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; /* YUV422 */
+ adv7180_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */
+ adv7180_data.sen.on = true;
+
+ adv7180_data.sen.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(adv7180_data.sen.sensor_clk)) {
+ dev_err(dev, "get mclk failed\n");
+ return PTR_ERR(adv7180_data.sen.sensor_clk);
+ }
+
+ ret = of_property_read_u32(dev->of_node, "mclk",
+ &adv7180_data.sen.mclk);
+ if (ret) {
+ dev_err(dev, "mclk frequency is invalid\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(
+ dev->of_node, "mclk_source",
+ (u32 *) &(adv7180_data.sen.mclk_source));
+ if (ret) {
+ dev_err(dev, "mclk_source invalid\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "csi_id",
+ &(adv7180_data.sen.csi));
+ if (ret) {
+ dev_err(dev, "csi_id invalid\n");
+ return ret;
+ }
+
+ clk_prepare_enable(adv7180_data.sen.sensor_clk);
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:adv7180 probe i2c address is 0x%02X\n",
+ __func__, adv7180_data.sen.i2c_client->addr);
+
+ /*! Read the revision ID of the tvin chip */
+ rev_id = adv7180_read(ADV7180_IDENT);
+ dev_dbg(dev,
+ "%s:Analog Device adv7%2X0 detected!\n", __func__,
+ rev_id);
+
+ ret = of_property_read_u32(dev->of_node, "cvbs", &(cvbs));
+ if (ret) {
+ dev_err(dev, "cvbs setting is not found\n");
+ cvbs = true;
+ }
+
+ /*! ADV7180 initialization. */
+ adv7180_hard_reset(cvbs);
+
+ pr_debug(" type is %d (expect %d)\n",
+ adv7180_int_device.type, v4l2_int_type_slave);
+ pr_debug(" num ioctls is %d\n",
+ adv7180_int_device.u.slave->num_ioctls);
+
+ /* This function attaches this structure to the /dev/video0 device.
+ * The pointer in priv points to the adv7180_data structure here.*/
+ adv7180_int_device.priv = &adv7180_data;
+ ret = v4l2_int_device_register(&adv7180_int_device);
+
+ clk_disable_unprepare(adv7180_data.sen.sensor_clk);
+
+ return ret;
+}
+
+/*!
+ * ADV7180 I2C detach function.
+ * Called on rmmod.
+ *
+ * @param *client struct i2c_client*.
+ *
+ * @return Error code indicating success or failure.
+ */
+static int adv7180_detach(struct i2c_client *client)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:Removing %s video decoder @ 0x%02X from adapter %s\n",
+ __func__, IF_NAME, client->addr << 1, client->adapter->name);
+
+ /* Power down via i2c */
+ adv7180_write_reg(ADV7180_PWR_MNG, 0x24);
+
+ if (dvddio_regulator)
+ regulator_disable(dvddio_regulator);
+
+ if (dvdd_regulator)
+ regulator_disable(dvdd_regulator);
+
+ if (avdd_regulator)
+ regulator_disable(avdd_regulator);
+
+ if (pvdd_regulator)
+ regulator_disable(pvdd_regulator);
+
+ v4l2_int_device_unregister(&adv7180_int_device);
+
+ return 0;
+}
+
+/*!
+ * ADV7180 init function.
+ * Called on insmod.
+ *
+ * @return Error code indicating success or failure.
+ */
+static __init int adv7180_init(void)
+{
+ u8 err = 0;
+
+ pr_debug("In adv7180_init\n");
+
+ /* Tells the i2c driver what functions to call for this driver. */
+ err = i2c_add_driver(&adv7180_i2c_driver);
+ if (err != 0)
+ pr_err("%s:driver registration failed, error=%d\n",
+ __func__, err);
+
+ return err;
+}
+
+/*!
+ * ADV7180 cleanup function.
+ * Called on rmmod.
+ *
+ * @return Error code indicating success or failure.
+ */
+static void __exit adv7180_clean(void)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_clean\n");
+ i2c_del_driver(&adv7180_i2c_driver);
+}
+
+module_init(adv7180_init);
+module_exit(adv7180_clean);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver");
+MODULE_LICENSE("GPL");