Staging: HTC Dream: add camera support
authorBrian Swetland <swetland@google.com>
Fri, 17 Jul 2009 12:45:17 +0000 (14:45 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 15 Sep 2009 19:01:43 +0000 (12:01 -0700)
This patch adds driver for HTC Dream camera. I guess driver is
slightly higher quality than usual for staging/ , but it is fairly big
and I don't feel like doing all the cleanups myself. Also some parts
can probably be removed, as they did not end up in shipping hardware..

Signed-off-by: Pavel Machek <pavel@ucw.cz>
Cc: Brian Swetland <swetland@google.com>
Cc: Iliyan Malchev <ibm@android.com>
Cc: San Mehat <san@android.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
23 files changed:
drivers/staging/dream/camera/Kconfig [new file with mode: 0644]
drivers/staging/dream/camera/Makefile [new file with mode: 0644]
drivers/staging/dream/camera/msm_camera.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_io7x.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_io8x.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_v4l2.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_vfe7x.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_vfe7x.h [new file with mode: 0644]
drivers/staging/dream/camera/msm_vfe8x.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_vfe8x.h [new file with mode: 0644]
drivers/staging/dream/camera/msm_vfe8x_proc.c [new file with mode: 0644]
drivers/staging/dream/camera/msm_vfe8x_proc.h [new file with mode: 0644]
drivers/staging/dream/camera/mt9d112.c [new file with mode: 0644]
drivers/staging/dream/camera/mt9d112.h [new file with mode: 0644]
drivers/staging/dream/camera/mt9d112_reg.c [new file with mode: 0644]
drivers/staging/dream/camera/mt9p012.h [new file with mode: 0644]
drivers/staging/dream/camera/mt9p012_fox.c [new file with mode: 0644]
drivers/staging/dream/camera/mt9p012_reg.c [new file with mode: 0644]
drivers/staging/dream/camera/mt9t013.c [new file with mode: 0644]
drivers/staging/dream/camera/mt9t013.h [new file with mode: 0644]
drivers/staging/dream/camera/mt9t013_reg.c [new file with mode: 0644]
drivers/staging/dream/camera/s5k3e2fx.c [new file with mode: 0644]
drivers/staging/dream/camera/s5k3e2fx.h [new file with mode: 0644]

diff --git a/drivers/staging/dream/camera/Kconfig b/drivers/staging/dream/camera/Kconfig
new file mode 100644 (file)
index 0000000..0a3e903
--- /dev/null
@@ -0,0 +1,46 @@
+comment "Qualcomm MSM Camera And Video"
+
+menuconfig MSM_CAMERA
+       bool "Qualcomm MSM camera and video capture support"
+       depends on ARCH_MSM && VIDEO_V4L2_COMMON
+       help
+         Say Y here to enable selecting the video adapters for
+         Qualcomm msm camera and video encoding
+
+config MSM_CAMERA_DEBUG
+       bool "Qualcomm MSM camera debugging with printk"
+       depends on MSM_CAMERA
+       help
+         Enable printk() debug for msm camera
+
+config MSM_CAMERA_FLASH
+       bool "Qualcomm MSM camera flash support"
+       depends on MSM_CAMERA
+       ---help---
+         Enable support for LED flash for msm camera
+
+
+comment "Camera Sensor Selection"
+config MT9T013
+       bool "Sensor mt9t013 (BAYER 3M)"
+       depends on MSM_CAMERA
+       ---help---
+         MICRON 3M Bayer Sensor with AutoFocus
+
+config MT9D112
+       bool "Sensor mt9d112 (YUV 2M)"
+       depends on MSM_CAMERA
+       ---help---
+         MICRON 2M YUV Sensor
+
+config MT9P012
+       bool "Sensor mt9p012 (BAYER 5M)"
+       depends on MSM_CAMERA
+       ---help---
+         MICRON 5M Bayer Sensor with Autofocus
+
+config S5K3E2FX
+       bool "Sensor s5k3e2fx (Samsung 5M)"
+       depends on MSM_CAMERA
+       ---help---
+         Samsung 5M with Autofocus
diff --git a/drivers/staging/dream/camera/Makefile b/drivers/staging/dream/camera/Makefile
new file mode 100644 (file)
index 0000000..4429ae5
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o
+obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
+obj-$(CONFIG_MT9P012) += mt9p012_fox.o mt9p012_reg.o
+obj-$(CONFIG_MSM_CAMERA) += msm_camera.o msm_v4l2.o
+obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
+obj-$(CONFIG_ARCH_MSM) += msm_vfe7x.o msm_io7x.o
+obj-$(CONFIG_ARCH_QSD) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o
diff --git a/drivers/staging/dream/camera/msm_camera.c b/drivers/staging/dream/camera/msm_camera.c
new file mode 100644 (file)
index 0000000..8816599
--- /dev/null
@@ -0,0 +1,2181 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+//FIXME: most allocations need not be GFP_ATOMIC
+/* FIXME: management of mutexes */
+/* FIXME: msm_pmem_region_lookup return values */
+/* FIXME: way too many copy to/from user */
+/* FIXME: does region->active mean free */
+/* FIXME: check limits on command lenghts passed from userspace */
+/* FIXME: __msm_release: which queues should we flush when opencnt != 0 */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <mach/board.h>
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/poll.h>
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+
+#define MSM_MAX_CAMERA_SENSORS 5
+
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
+                               __func__, __LINE__, ((to) ? "to" : "from"))
+#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
+#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+
+static struct class *msm_class;
+static dev_t msm_devno;
+static LIST_HEAD(msm_sensors);
+
+#define __CONTAINS(r, v, l, field) ({                          \
+       typeof(r) __r = r;                                      \
+       typeof(v) __v = v;                                      \
+       typeof(v) __e = __v + l;                                \
+       int res = __v >= __r->field &&                          \
+               __e <= __r->field + __r->len;                   \
+       res;                                                    \
+})
+
+#define CONTAINS(r1, r2, field) ({                             \
+       typeof(r2) __r2 = r2;                                   \
+       __CONTAINS(r1, __r2->field, __r2->len, field);          \
+})
+
+#define IN_RANGE(r, v, field) ({                               \
+       typeof(r) __r = r;                                      \
+       typeof(v) __vv = v;                                     \
+       int res = ((__vv >= __r->field) &&                      \
+               (__vv < (__r->field + __r->len)));              \
+       res;                                                    \
+})
+
+#define OVERLAPS(r1, r2, field) ({                             \
+       typeof(r1) __r1 = r1;                                   \
+       typeof(r2) __r2 = r2;                                   \
+       typeof(__r2->field) __v = __r2->field;                  \
+       typeof(__v) __e = __v + __r2->len - 1;                  \
+       int res = (IN_RANGE(__r1, __v, field) ||                \
+                  IN_RANGE(__r1, __e, field));                 \
+       res;                                                    \
+})
+
+#define MSM_DRAIN_QUEUE_NOSYNC(sync, name) do {                        \
+       struct msm_queue_cmd *qcmd = NULL;                      \
+       CDBG("%s: draining queue "#name"\n", __func__);         \
+       while (!list_empty(&(sync)->name)) {                    \
+               qcmd = list_first_entry(&(sync)->name,          \
+                       struct msm_queue_cmd, list);            \
+               list_del_init(&qcmd->list);                     \
+               kfree(qcmd);                                    \
+       };                                                      \
+} while(0)
+
+#define MSM_DRAIN_QUEUE(sync, name) do {                       \
+       unsigned long flags;                                    \
+       spin_lock_irqsave(&(sync)->name##_lock, flags);         \
+       MSM_DRAIN_QUEUE_NOSYNC(sync, name);                     \
+       spin_unlock_irqrestore(&(sync)->name##_lock, flags);    \
+} while(0)
+
+static int check_overlap(struct hlist_head *ptype,
+                       unsigned long paddr,
+                       unsigned long len)
+{
+       struct msm_pmem_region *region;
+       struct msm_pmem_region t = { .paddr = paddr, .len = len };
+       struct hlist_node *node;
+
+       hlist_for_each_entry(region, node, ptype, list) {
+               if (CONTAINS(region, &t, paddr) ||
+                               CONTAINS(&t, region, paddr) ||
+                               OVERLAPS(region, &t, paddr)) {
+                       printk(KERN_ERR
+                               " region (PHYS %p len %ld)"
+                               " clashes with registered region"
+                               " (paddr %p len %ld)\n",
+                               (void *)t.paddr, t.len,
+                               (void *)region->paddr, region->len);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int msm_pmem_table_add(struct hlist_head *ptype,
+       struct msm_pmem_info *info)
+{
+       struct file *file;
+       unsigned long paddr;
+       unsigned long vstart;
+       unsigned long len;
+       int rc;
+       struct msm_pmem_region *region;
+
+       rc = get_pmem_file(info->fd, &paddr, &vstart, &len, &file);
+       if (rc < 0) {
+               pr_err("msm_pmem_table_add: get_pmem_file fd %d error %d\n",
+                       info->fd, rc);
+               return rc;
+       }
+
+       if (check_overlap(ptype, paddr, len) < 0)
+               return -EINVAL;
+
+       CDBG("%s: type = %d, paddr = 0x%lx, vaddr = 0x%lx\n",
+               __func__,
+               info->type, paddr, (unsigned long)info->vaddr);
+
+       region = kmalloc(sizeof(*region), GFP_KERNEL);
+       if (!region)
+               return -ENOMEM;
+
+       INIT_HLIST_NODE(&region->list);
+
+       region->type = info->type;
+       region->vaddr = info->vaddr;
+       region->paddr = paddr;
+       region->len = len;
+       region->file = file;
+       region->y_off = info->y_off;
+       region->cbcr_off = info->cbcr_off;
+       region->fd = info->fd;
+       region->active = info->active;
+
+       hlist_add_head(&(region->list), ptype);
+
+       return 0;
+}
+
+/* return of 0 means failure */
+static uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
+       int pmem_type, struct msm_pmem_region *reg, uint8_t maxcount)
+{
+       struct msm_pmem_region *region;
+       struct msm_pmem_region *regptr;
+       struct hlist_node *node, *n;
+
+       uint8_t rc = 0;
+
+       regptr = reg;
+
+       hlist_for_each_entry_safe(region, node, n, ptype, list) {
+               if (region->type == pmem_type && region->active) {
+                       *regptr = *region;
+                       rc += 1;
+                       if (rc >= maxcount)
+                               break;
+                       regptr++;
+               }
+       }
+
+       return rc;
+}
+
+static unsigned long msm_pmem_frame_ptov_lookup(struct msm_sync *sync,
+               unsigned long pyaddr,
+               unsigned long pcbcraddr,
+               uint32_t *yoff, uint32_t *cbcroff, int *fd)
+{
+       struct msm_pmem_region *region;
+       struct hlist_node *node, *n;
+
+       hlist_for_each_entry_safe(region, node, n, &sync->frame, list) {
+               if (pyaddr == (region->paddr + region->y_off) &&
+                               pcbcraddr == (region->paddr +
+                                               region->cbcr_off) &&
+                               region->active) {
+                       /* offset since we could pass vaddr inside
+                        * a registerd pmem buffer
+                        */
+                       *yoff = region->y_off;
+                       *cbcroff = region->cbcr_off;
+                       *fd = region->fd;
+                       region->active = 0;
+                       return (unsigned long)(region->vaddr);
+               }
+       }
+
+       return 0;
+}
+
+static unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
+               unsigned long addr, int *fd)
+{
+       struct msm_pmem_region *region;
+       struct hlist_node *node, *n;
+
+       hlist_for_each_entry_safe(region, node, n, &sync->stats, list) {
+               if (addr == region->paddr && region->active) {
+                       /* offset since we could pass vaddr inside a
+                        * registered pmem buffer */
+                       *fd = region->fd;
+                       region->active = 0;
+                       return (unsigned long)(region->vaddr);
+               }
+       }
+
+       return 0;
+}
+
+static unsigned long msm_pmem_frame_vtop_lookup(struct msm_sync *sync,
+               unsigned long buffer,
+               uint32_t yoff, uint32_t cbcroff, int fd)
+{
+       struct msm_pmem_region *region;
+       struct hlist_node *node, *n;
+
+       hlist_for_each_entry_safe(region,
+               node, n, &sync->frame, list) {
+               if (((unsigned long)(region->vaddr) == buffer) &&
+                               (region->y_off == yoff) &&
+                               (region->cbcr_off == cbcroff) &&
+                               (region->fd == fd) &&
+                               (region->active == 0)) {
+
+                       region->active = 1;
+                       return region->paddr;
+               }
+       }
+
+       return 0;
+}
+
+static unsigned long msm_pmem_stats_vtop_lookup(
+               struct msm_sync *sync,
+               unsigned long buffer,
+               int fd)
+{
+       struct msm_pmem_region *region;
+       struct hlist_node *node, *n;
+
+       hlist_for_each_entry_safe(region, node, n, &sync->stats, list) {
+               if (((unsigned long)(region->vaddr) == buffer) &&
+                               (region->fd == fd) && region->active == 0) {
+                       region->active = 1;
+                       return region->paddr;
+               }
+       }
+
+       return 0;
+}
+
+static int __msm_pmem_table_del(struct msm_sync *sync,
+               struct msm_pmem_info *pinfo)
+{
+       int rc = 0;
+       struct msm_pmem_region *region;
+       struct hlist_node *node, *n;
+
+       switch (pinfo->type) {
+       case MSM_PMEM_OUTPUT1:
+       case MSM_PMEM_OUTPUT2:
+       case MSM_PMEM_THUMBAIL:
+       case MSM_PMEM_MAINIMG:
+       case MSM_PMEM_RAW_MAINIMG:
+               hlist_for_each_entry_safe(region, node, n,
+                       &sync->frame, list) {
+
+                       if (pinfo->type == region->type &&
+                                       pinfo->vaddr == region->vaddr &&
+                                       pinfo->fd == region->fd) {
+                               hlist_del(node);
+                               put_pmem_file(region->file);
+                               kfree(region);
+                       }
+               }
+               break;
+
+       case MSM_PMEM_AEC_AWB:
+       case MSM_PMEM_AF:
+               hlist_for_each_entry_safe(region, node, n,
+                       &sync->stats, list) {
+
+                       if (pinfo->type == region->type &&
+                                       pinfo->vaddr == region->vaddr &&
+                                       pinfo->fd == region->fd) {
+                               hlist_del(node);
+                               put_pmem_file(region->file);
+                               kfree(region);
+                       }
+               }
+               break;
+
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
+
+static int msm_pmem_table_del(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_pmem_info info;
+
+       if (copy_from_user(&info, arg, sizeof(info))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       return __msm_pmem_table_del(sync, &info);
+}
+
+static int __msm_get_frame(struct msm_sync *sync,
+               struct msm_frame *frame)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       struct msm_queue_cmd *qcmd = NULL;
+       struct msm_vfe_phy_info *pphy;
+
+       spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
+       if (!list_empty(&sync->prev_frame_q)) {
+               qcmd = list_first_entry(&sync->prev_frame_q,
+                       struct msm_queue_cmd, list);
+               list_del_init(&qcmd->list);
+       }
+       spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
+
+       if (!qcmd) {
+               pr_err("%s: no preview frame.\n", __func__);
+               return -EAGAIN;
+       }
+
+       pphy = (struct msm_vfe_phy_info *)(qcmd->command);
+
+       frame->buffer =
+               msm_pmem_frame_ptov_lookup(sync,
+                       pphy->y_phy,
+                       pphy->cbcr_phy, &(frame->y_off),
+                       &(frame->cbcr_off), &(frame->fd));
+       if (!frame->buffer) {
+               pr_err("%s: cannot get frame, invalid lookup address "
+                       "y=%x cbcr=%x offset=%d\n",
+                       __FUNCTION__,
+                       pphy->y_phy,
+                       pphy->cbcr_phy,
+                       frame->y_off);
+               rc = -EINVAL;
+       }
+
+       CDBG("__msm_get_frame: y=0x%x, cbcr=0x%x, qcmd=0x%x, virt_addr=0x%x\n",
+               pphy->y_phy, pphy->cbcr_phy, (int) qcmd, (int) frame->buffer);
+
+       kfree(qcmd);
+       return rc;
+}
+
+static int msm_get_frame(struct msm_sync *sync, void __user *arg)
+{
+       int rc = 0;
+       struct msm_frame frame;
+
+       if (copy_from_user(&frame,
+                               arg,
+                               sizeof(struct msm_frame))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       rc = __msm_get_frame(sync, &frame);
+       if (rc < 0)
+               return rc;
+
+       if (sync->croplen) {
+               if (frame.croplen > sync->croplen) {
+                       pr_err("msm_get_frame: invalid frame croplen %d\n",
+                               frame.croplen);
+                       return -EINVAL;
+               }
+
+               if (copy_to_user((void *)frame.cropinfo,
+                               sync->cropinfo,
+                               sync->croplen)) {
+                       ERR_COPY_TO_USER();
+                       return -EFAULT;
+               }
+       }
+
+       if (copy_to_user((void *)arg,
+                               &frame, sizeof(struct msm_frame))) {
+               ERR_COPY_TO_USER();
+               rc = -EFAULT;
+       }
+
+       CDBG("Got frame!!!\n");
+
+       return rc;
+}
+
+static int msm_enable_vfe(struct msm_sync *sync, void __user *arg)
+{
+       int rc = -EIO;
+       struct camera_enable_cmd cfg;
+
+       if (copy_from_user(&cfg,
+                       arg,
+                       sizeof(struct camera_enable_cmd))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       if (sync->vfefn.vfe_enable)
+               rc = sync->vfefn.vfe_enable(&cfg);
+
+       CDBG("msm_enable_vfe: returned rc = %d\n", rc);
+       return rc;
+}
+
+static int msm_disable_vfe(struct msm_sync *sync, void __user *arg)
+{
+       int rc = -EIO;
+       struct camera_enable_cmd cfg;
+
+       if (copy_from_user(&cfg,
+                       arg,
+                       sizeof(struct camera_enable_cmd))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       if (sync->vfefn.vfe_disable)
+               rc = sync->vfefn.vfe_disable(&cfg, NULL);
+
+       CDBG("msm_disable_vfe: returned rc = %d\n", rc);
+       return rc;
+}
+
+static struct msm_queue_cmd* __msm_control(struct msm_sync *sync,
+               struct msm_control_device_queue *queue,
+               struct msm_queue_cmd *qcmd,
+               int timeout)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&sync->msg_event_q_lock, flags);
+       list_add_tail(&qcmd->list, &sync->msg_event_q);
+       /* wake up config thread */
+       wake_up(&sync->msg_event_wait);
+       spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
+
+       if (!queue)
+               return NULL;
+
+       /* wait for config status */
+       rc = wait_event_interruptible_timeout(
+                       queue->ctrl_status_wait,
+                       !list_empty_careful(&queue->ctrl_status_q),
+                       timeout);
+       if (list_empty_careful(&queue->ctrl_status_q)) {
+               if (!rc)
+                       rc = -ETIMEDOUT;
+               if (rc < 0) {
+                       pr_err("msm_control: wait_event error %d\n", rc);
+#if 0
+                       /* This is a bit scary.  If we time out too early, we
+                        * will free qcmd at the end of this function, and the
+                        * dsp may do the same when it does respond, so we
+                        * remove the message from the source queue.
+                        */
+                       pr_err("%s: error waiting for ctrl_status_q: %d\n",
+                               __func__, rc);
+                       spin_lock_irqsave(&sync->msg_event_q_lock, flags);
+                       list_del_init(&qcmd->list);
+                       spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
+#endif
+                       return ERR_PTR(rc);
+               }
+       }
+
+       /* control command status is ready */
+       spin_lock_irqsave(&queue->ctrl_status_q_lock, flags);
+       BUG_ON(list_empty(&queue->ctrl_status_q));
+       qcmd = list_first_entry(&queue->ctrl_status_q,
+                       struct msm_queue_cmd, list);
+       list_del_init(&qcmd->list);
+       spin_unlock_irqrestore(&queue->ctrl_status_q_lock, flags);
+
+       return qcmd;
+}
+
+static int msm_control(struct msm_control_device *ctrl_pmsm,
+                       int block,
+                       void __user *arg)
+{
+       int rc = 0;
+
+       struct msm_sync *sync = ctrl_pmsm->pmsm->sync;
+       struct msm_ctrl_cmd udata, *ctrlcmd;
+       struct msm_queue_cmd *qcmd = NULL, *qcmd_temp;
+
+       if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
+               ERR_COPY_FROM_USER();
+               rc = -EFAULT;
+               goto end;
+       }
+
+       qcmd = kmalloc(sizeof(struct msm_queue_cmd) +
+                               sizeof(struct msm_ctrl_cmd) + udata.length,
+                               GFP_KERNEL);
+       if (!qcmd) {
+               pr_err("msm_control: cannot allocate buffer\n");
+               rc = -ENOMEM;
+               goto end;
+       }
+
+       qcmd->type = MSM_CAM_Q_CTRL;
+       qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1);
+       *ctrlcmd = udata;
+       ctrlcmd->value = ctrlcmd + 1;
+
+       if (udata.length) {
+               if (copy_from_user(ctrlcmd->value,
+                               udata.value, udata.length)) {
+                       ERR_COPY_FROM_USER();
+                       rc = -EFAULT;
+                       goto end;
+               }
+       }
+
+       if (!block) {
+               /* qcmd will be set to NULL */
+               qcmd = __msm_control(sync, NULL, qcmd, 0);
+               goto end;
+       }
+
+       qcmd_temp = __msm_control(sync,
+                                 &ctrl_pmsm->ctrl_q,
+                                 qcmd, MAX_SCHEDULE_TIMEOUT);
+
+       if (IS_ERR(qcmd_temp)) {
+               rc = PTR_ERR(qcmd_temp);
+               goto end;
+       }
+       qcmd = qcmd_temp;
+
+       if (qcmd->command) {
+               void __user *to = udata.value;
+               udata = *(struct msm_ctrl_cmd *)qcmd->command;
+               if (udata.length > 0) {
+                       if (copy_to_user(to,
+                                        udata.value,
+                                        udata.length)) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                               goto end;
+                       }
+               }
+               udata.value = to;
+
+               if (copy_to_user((void *)arg, &udata,
+                               sizeof(struct msm_ctrl_cmd))) {
+                       ERR_COPY_TO_USER();
+                       rc = -EFAULT;
+                       goto end;
+               }
+       }
+
+end:
+       /* Note: if we get here as a result of an error, we will free the
+        * qcmd that we kmalloc() in this function.  When we come here as
+        * a result of a successful completion, we are freeing the qcmd that
+        * we dequeued from queue->ctrl_status_q.
+        */
+       if (qcmd)
+               kfree(qcmd);
+
+       CDBG("msm_control: end rc = %d\n", rc);
+       return rc;
+}
+
+static int msm_get_stats(struct msm_sync *sync, void __user *arg)
+{
+       unsigned long flags;
+       int timeout;
+       int rc = 0;
+
+       struct msm_stats_event_ctrl se;
+
+       struct msm_queue_cmd *qcmd = NULL;
+       struct msm_ctrl_cmd  *ctrl = NULL;
+       struct msm_vfe_resp  *data = NULL;
+       struct msm_stats_buf stats;
+
+       if (copy_from_user(&se, arg,
+                       sizeof(struct msm_stats_event_ctrl))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       timeout = (int)se.timeout_ms;
+
+       CDBG("msm_get_stats timeout %d\n", timeout);
+       rc = wait_event_interruptible_timeout(
+                       sync->msg_event_wait,
+                       !list_empty_careful(&sync->msg_event_q),
+                       msecs_to_jiffies(timeout));
+       if (list_empty_careful(&sync->msg_event_q)) {
+               if (rc == 0)
+                       rc = -ETIMEDOUT;
+               if (rc < 0) {
+                       pr_err("msm_get_stats error %d\n", rc);
+                       return rc;
+               }
+       }
+       CDBG("msm_get_stats returned from wait: %d\n", rc);
+
+       spin_lock_irqsave(&sync->msg_event_q_lock, flags);
+       BUG_ON(list_empty(&sync->msg_event_q));
+       qcmd = list_first_entry(&sync->msg_event_q,
+                       struct msm_queue_cmd, list);
+       list_del_init(&qcmd->list);
+       spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
+
+       CDBG("=== received from DSP === %d\n", qcmd->type);
+
+       switch (qcmd->type) {
+       case MSM_CAM_Q_VFE_EVT:
+       case MSM_CAM_Q_VFE_MSG:
+               data = (struct msm_vfe_resp *)(qcmd->command);
+
+               /* adsp event and message */
+               se.resptype = MSM_CAM_RESP_STAT_EVT_MSG;
+
+               /* 0 - msg from aDSP, 1 - event from mARM */
+               se.stats_event.type   = data->evt_msg.type;
+               se.stats_event.msg_id = data->evt_msg.msg_id;
+               se.stats_event.len    = data->evt_msg.len;
+
+               CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type);
+               CDBG("length = %d\n", se.stats_event.len);
+               CDBG("msg_id = %d\n", se.stats_event.msg_id);
+
+               if ((data->type == VFE_MSG_STATS_AF) ||
+                               (data->type == VFE_MSG_STATS_WE)) {
+
+                       stats.buffer =
+                       msm_pmem_stats_ptov_lookup(sync,
+                                       data->phy.sbuf_phy,
+                                       &(stats.fd));
+                       if (!stats.buffer) {
+                               pr_err("%s: msm_pmem_stats_ptov_lookup error\n",
+                                       __FUNCTION__);
+                               rc = -EINVAL;
+                               goto failure;
+                       }
+
+                       if (copy_to_user((void *)(se.stats_event.data),
+                                       &stats,
+                                       sizeof(struct msm_stats_buf))) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                               goto failure;
+                       }
+               } else if ((data->evt_msg.len > 0) &&
+                               (data->type == VFE_MSG_GENERAL)) {
+                       if (copy_to_user((void *)(se.stats_event.data),
+                                       data->evt_msg.data,
+                                       data->evt_msg.len)) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                       }
+               } else if (data->type == VFE_MSG_OUTPUT1 ||
+                       data->type == VFE_MSG_OUTPUT2) {
+                       if (copy_to_user((void *)(se.stats_event.data),
+                                       data->extdata,
+                                       data->extlen)) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                       }
+               } else if (data->type == VFE_MSG_SNAPSHOT && sync->pict_pp) {
+                       struct msm_postproc buf;
+                       struct msm_pmem_region region;
+                       buf.fmnum = msm_pmem_region_lookup(&sync->frame,
+                                       MSM_PMEM_MAINIMG,
+                                       &region, 1);
+                       if (buf.fmnum == 1) {
+                               buf.fmain.buffer = (unsigned long)region.vaddr;
+                               buf.fmain.y_off  = region.y_off;
+                               buf.fmain.cbcr_off = region.cbcr_off;
+                               buf.fmain.fd = region.fd;
+                       } else {
+                               buf.fmnum = msm_pmem_region_lookup(&sync->frame,
+                                               MSM_PMEM_RAW_MAINIMG,
+                                               &region, 1);
+                               if (buf.fmnum == 1) {
+                                       buf.fmain.path = MSM_FRAME_PREV_2;
+                                       buf.fmain.buffer =
+                                               (unsigned long)region.vaddr;
+                                       buf.fmain.fd = region.fd;
+                               }
+                               else {
+                                       pr_err("%s: pmem lookup failed\n",
+                                               __func__);
+                                       rc = -EINVAL;
+                               }
+                       }
+
+                       if (copy_to_user((void *)(se.stats_event.data), &buf,
+                                       sizeof(buf))) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                               goto failure;
+                       }
+                       CDBG("snapshot copy_to_user!\n");
+               }
+               break;
+
+       case MSM_CAM_Q_CTRL:
+               /* control command from control thread */
+               ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
+
+               CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type);
+               CDBG("length = %d\n", ctrl->length);
+
+               if (ctrl->length > 0) {
+                       if (copy_to_user((void *)(se.ctrl_cmd.value),
+                                               ctrl->value,
+                                               ctrl->length)) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                               goto failure;
+                       }
+               }
+
+               se.resptype = MSM_CAM_RESP_CTRL;
+
+               /* what to control */
+               se.ctrl_cmd.type = ctrl->type;
+               se.ctrl_cmd.length = ctrl->length;
+               se.ctrl_cmd.resp_fd = ctrl->resp_fd;
+               break;
+
+       case MSM_CAM_Q_V4L2_REQ:
+               /* control command from v4l2 client */
+               ctrl = (struct msm_ctrl_cmd *)(qcmd->command);
+
+               CDBG("msm_get_stats, qcmd->type = %d\n", qcmd->type);
+               CDBG("length = %d\n", ctrl->length);
+
+               if (ctrl->length > 0) {
+                       if (copy_to_user((void *)(se.ctrl_cmd.value),
+                                       ctrl->value, ctrl->length)) {
+                               ERR_COPY_TO_USER();
+                               rc = -EFAULT;
+                               goto failure;
+                       }
+               }
+
+               /* 2 tells config thread this is v4l2 request */
+               se.resptype = MSM_CAM_RESP_V4L2;
+
+               /* what to control */
+               se.ctrl_cmd.type   = ctrl->type;
+               se.ctrl_cmd.length = ctrl->length;
+               break;
+
+       default:
+               rc = -EFAULT;
+               goto failure;
+       } /* switch qcmd->type */
+
+       if (copy_to_user((void *)arg, &se, sizeof(se))) {
+               ERR_COPY_TO_USER();
+               rc = -EFAULT;
+       }
+
+failure:
+       if (qcmd)
+               kfree(qcmd);
+
+       CDBG("msm_get_stats: %d\n", rc);
+       return rc;
+}
+
+static int msm_ctrl_cmd_done(struct msm_control_device *ctrl_pmsm,
+               void __user *arg)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       struct msm_ctrl_cmd udata, *ctrlcmd;
+       struct msm_queue_cmd *qcmd = NULL;
+
+       if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
+               ERR_COPY_FROM_USER();
+               rc = -EFAULT;
+               goto end;
+       }
+
+       qcmd = kmalloc(sizeof(struct msm_queue_cmd) +
+                       sizeof(struct msm_ctrl_cmd) + udata.length,
+                       GFP_KERNEL);
+       if (!qcmd) {
+               rc = -ENOMEM;
+               goto end;
+       }
+
+       qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1);
+       *ctrlcmd = udata;
+       if (udata.length > 0) {
+               ctrlcmd->value = ctrlcmd + 1;
+               if (copy_from_user(ctrlcmd->value,
+                                       (void *)udata.value,
+                                       udata.length)) {
+                       ERR_COPY_FROM_USER();
+                       rc = -EFAULT;
+                       kfree(qcmd);
+                       goto end;
+               }
+       }
+       else ctrlcmd->value = NULL;
+
+end:
+       CDBG("msm_ctrl_cmd_done: end rc = %d\n", rc);
+       if (rc == 0) {
+               /* wake up control thread */
+               spin_lock_irqsave(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock, flags);
+               list_add_tail(&qcmd->list, &ctrl_pmsm->ctrl_q.ctrl_status_q);
+               wake_up(&ctrl_pmsm->ctrl_q.ctrl_status_wait);
+               spin_unlock_irqrestore(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock, flags);
+       }
+
+       return rc;
+}
+
+static int msm_config_vfe(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_vfe_cfg_cmd cfgcmd;
+       struct msm_pmem_region region[8];
+       struct axidata axi_data;
+       void *data = NULL;
+       int rc = -EIO;
+
+       memset(&axi_data, 0, sizeof(axi_data));
+
+       if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       switch(cfgcmd.cmd_type) {
+       case CMD_STATS_ENABLE:
+               axi_data.bufnum1 =
+                       msm_pmem_region_lookup(&sync->stats,
+                                       MSM_PMEM_AEC_AWB, &region[0],
+                                       NUM_WB_EXP_STAT_OUTPUT_BUFFERS);
+               if (!axi_data.bufnum1) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               axi_data.region = &region[0];
+               data = &axi_data;
+               break;
+       case CMD_STATS_AF_ENABLE:
+               axi_data.bufnum1 =
+                       msm_pmem_region_lookup(&sync->stats,
+                                       MSM_PMEM_AF, &region[0],
+                                       NUM_AF_STAT_OUTPUT_BUFFERS);
+               if (!axi_data.bufnum1) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               axi_data.region = &region[0];
+               data = &axi_data;
+               break;
+       case CMD_GENERAL:
+       case CMD_STATS_DISABLE:
+               break;
+       default:
+               pr_err("%s: unknown command type %d\n",
+                       __FUNCTION__, cfgcmd.cmd_type);
+               return -EINVAL;
+       }
+
+
+       if (sync->vfefn.vfe_config)
+               rc = sync->vfefn.vfe_config(&cfgcmd, data);
+
+       return rc;
+}
+
+static int msm_frame_axi_cfg(struct msm_sync *sync,
+               struct msm_vfe_cfg_cmd *cfgcmd)
+{
+       int rc = -EIO;
+       struct axidata axi_data;
+       void *data = &axi_data;
+       struct msm_pmem_region region[8];
+       int pmem_type;
+
+       memset(&axi_data, 0, sizeof(axi_data));
+
+       switch (cfgcmd->cmd_type) {
+       case CMD_AXI_CFG_OUT1:
+               pmem_type = MSM_PMEM_OUTPUT1;
+               axi_data.bufnum1 =
+                       msm_pmem_region_lookup(&sync->frame, pmem_type,
+                               &region[0], 8);
+               if (!axi_data.bufnum1) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               break;
+
+       case CMD_AXI_CFG_OUT2:
+               pmem_type = MSM_PMEM_OUTPUT2;
+               axi_data.bufnum2 =
+                       msm_pmem_region_lookup(&sync->frame, pmem_type,
+                               &region[0], 8);
+               if (!axi_data.bufnum2) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               break;
+
+       case CMD_AXI_CFG_SNAP_O1_AND_O2:
+               pmem_type = MSM_PMEM_THUMBAIL;
+               axi_data.bufnum1 =
+                       msm_pmem_region_lookup(&sync->frame, pmem_type,
+                               &region[0], 8);
+               if (!axi_data.bufnum1) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+
+               pmem_type = MSM_PMEM_MAINIMG;
+               axi_data.bufnum2 =
+                       msm_pmem_region_lookup(&sync->frame, pmem_type,
+                               &region[axi_data.bufnum1], 8);
+               if (!axi_data.bufnum2) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               break;
+
+       case CMD_RAW_PICT_AXI_CFG:
+               pmem_type = MSM_PMEM_RAW_MAINIMG;
+               axi_data.bufnum2 =
+                       msm_pmem_region_lookup(&sync->frame, pmem_type,
+                               &region[0], 8);
+               if (!axi_data.bufnum2) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               break;
+
+       case CMD_GENERAL:
+               data = NULL;
+               break;
+
+       default:
+               pr_err("%s: unknown command type %d\n",
+                       __FUNCTION__, cfgcmd->cmd_type);
+               return -EINVAL;
+       }
+
+       axi_data.region = &region[0];
+
+       /* send the AXI configuration command to driver */
+       if (sync->vfefn.vfe_config)
+               rc = sync->vfefn.vfe_config(cfgcmd, data);
+
+       return rc;
+}
+
+static int msm_get_sensor_info(struct msm_sync *sync, void __user *arg)
+{
+       int rc = 0;
+       struct msm_camsensor_info info;
+       struct msm_camera_sensor_info *sdata;
+
+       if (copy_from_user(&info,
+                       arg,
+                       sizeof(struct msm_camsensor_info))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       sdata = sync->pdev->dev.platform_data;
+       CDBG("sensor_name %s\n", sdata->sensor_name);
+
+       memcpy(&info.name[0],
+               sdata->sensor_name,
+               MAX_SENSOR_NAME);
+       info.flash_enabled = sdata->flash_type != MSM_CAMERA_FLASH_NONE;
+
+       /* copy back to user space */
+       if (copy_to_user((void *)arg,
+                       &info,
+                       sizeof(struct msm_camsensor_info))) {
+               ERR_COPY_TO_USER();
+               rc = -EFAULT;
+       }
+
+       return rc;
+}
+
+static int __msm_put_frame_buf(struct msm_sync *sync,
+               struct msm_frame *pb)
+{
+       unsigned long pphy;
+       struct msm_vfe_cfg_cmd cfgcmd;
+
+       int rc = -EIO;
+
+       pphy = msm_pmem_frame_vtop_lookup(sync,
+               pb->buffer,
+               pb->y_off, pb->cbcr_off, pb->fd);
+
+       if (pphy != 0) {
+               CDBG("rel: vaddr = 0x%lx, paddr = 0x%lx\n",
+                       pb->buffer, pphy);
+               cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
+               cfgcmd.value    = (void *)pb;
+               if (sync->vfefn.vfe_config)
+                       rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+       } else {
+               pr_err("%s: msm_pmem_frame_vtop_lookup failed\n",
+                       __FUNCTION__);
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
+static int msm_put_frame_buffer(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_frame buf_t;
+
+       if (copy_from_user(&buf_t,
+                               arg,
+                               sizeof(struct msm_frame))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       return __msm_put_frame_buf(sync, &buf_t);
+}
+
+static int __msm_register_pmem(struct msm_sync *sync,
+               struct msm_pmem_info *pinfo)
+{
+       int rc = 0;
+
+       switch (pinfo->type) {
+       case MSM_PMEM_OUTPUT1:
+       case MSM_PMEM_OUTPUT2:
+       case MSM_PMEM_THUMBAIL:
+       case MSM_PMEM_MAINIMG:
+       case MSM_PMEM_RAW_MAINIMG:
+               rc = msm_pmem_table_add(&sync->frame, pinfo);
+               break;
+
+       case MSM_PMEM_AEC_AWB:
+       case MSM_PMEM_AF:
+               rc = msm_pmem_table_add(&sync->stats, pinfo);
+               break;
+
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
+
+static int msm_register_pmem(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_pmem_info info;
+
+       if (copy_from_user(&info, arg, sizeof(info))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       return __msm_register_pmem(sync, &info);
+}
+
+static int msm_stats_axi_cfg(struct msm_sync *sync,
+               struct msm_vfe_cfg_cmd *cfgcmd)
+{
+       int rc = -EIO;
+       struct axidata axi_data;
+       void *data = &axi_data;
+
+       struct msm_pmem_region region[3];
+       int pmem_type = MSM_PMEM_MAX;
+
+       memset(&axi_data, 0, sizeof(axi_data));
+
+       switch (cfgcmd->cmd_type) {
+       case CMD_STATS_AXI_CFG:
+               pmem_type = MSM_PMEM_AEC_AWB;
+               break;
+       case CMD_STATS_AF_AXI_CFG:
+               pmem_type = MSM_PMEM_AF;
+               break;
+       case CMD_GENERAL:
+               data = NULL;
+               break;
+       default:
+               pr_err("%s: unknown command type %d\n",
+                       __FUNCTION__, cfgcmd->cmd_type);
+               return -EINVAL;
+       }
+
+       if (cfgcmd->cmd_type != CMD_GENERAL) {
+               axi_data.bufnum1 =
+                       msm_pmem_region_lookup(&sync->stats, pmem_type,
+                               &region[0], NUM_WB_EXP_STAT_OUTPUT_BUFFERS);
+               if (!axi_data.bufnum1) {
+                       pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+                       return -EINVAL;
+               }
+               axi_data.region = &region[0];
+       }
+
+       /* send the AEC/AWB STATS configuration command to driver */
+       if (sync->vfefn.vfe_config)
+               rc = sync->vfefn.vfe_config(cfgcmd, &axi_data);
+
+       return rc;
+}
+
+static int msm_put_stats_buffer(struct msm_sync *sync, void __user *arg)
+{
+       int rc = -EIO;
+
+       struct msm_stats_buf buf;
+       unsigned long pphy;
+       struct msm_vfe_cfg_cmd cfgcmd;
+
+       if (copy_from_user(&buf, arg,
+                               sizeof(struct msm_stats_buf))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       CDBG("msm_put_stats_buffer\n");
+       pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd);
+
+       if (pphy != 0) {
+               if (buf.type == STAT_AEAW)
+                       cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
+               else if (buf.type == STAT_AF)
+                       cfgcmd.cmd_type = CMD_STATS_AF_BUF_RELEASE;
+               else {
+                       pr_err("%s: invalid buf type %d\n",
+                               __FUNCTION__,
+                               buf.type);
+                       rc = -EINVAL;
+                       goto put_done;
+               }
+
+               cfgcmd.value = (void *)&buf;
+
+               if (sync->vfefn.vfe_config) {
+                       rc = sync->vfefn.vfe_config(&cfgcmd, &pphy);
+                       if (rc < 0)
+                               pr_err("msm_put_stats_buffer: "\
+                                       "vfe_config err %d\n", rc);
+               } else
+                       pr_err("msm_put_stats_buffer: vfe_config is NULL\n");
+       } else {
+               pr_err("msm_put_stats_buffer: NULL physical address\n");
+               rc = -EINVAL;
+       }
+
+put_done:
+       return rc;
+}
+
+static int msm_axi_config(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_vfe_cfg_cmd cfgcmd;
+
+       if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       switch (cfgcmd.cmd_type) {
+       case CMD_AXI_CFG_OUT1:
+       case CMD_AXI_CFG_OUT2:
+       case CMD_AXI_CFG_SNAP_O1_AND_O2:
+       case CMD_RAW_PICT_AXI_CFG:
+               return msm_frame_axi_cfg(sync, &cfgcmd);
+
+       case CMD_STATS_AXI_CFG:
+       case CMD_STATS_AF_AXI_CFG:
+               return msm_stats_axi_cfg(sync, &cfgcmd);
+
+       default:
+               pr_err("%s: unknown command type %d\n",
+                       __FUNCTION__,
+                       cfgcmd.cmd_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __msm_get_pic(struct msm_sync *sync, struct msm_ctrl_cmd *ctrl)
+{
+       unsigned long flags;
+       int rc = 0;
+       int tm;
+
+       struct msm_queue_cmd *qcmd = NULL;
+
+       tm = (int)ctrl->timeout_ms;
+
+       rc = wait_event_interruptible_timeout(
+                       sync->pict_frame_wait,
+                       !list_empty_careful(&sync->pict_frame_q),
+                       msecs_to_jiffies(tm));
+       if (list_empty_careful(&sync->pict_frame_q)) {
+               if (rc == 0)
+                       return -ETIMEDOUT;
+               if (rc < 0) {
+                       pr_err("msm_camera_get_picture, rc = %d\n", rc);
+                       return rc;
+               }
+       }
+
+       spin_lock_irqsave(&sync->pict_frame_q_lock, flags);
+       BUG_ON(list_empty(&sync->pict_frame_q));
+       qcmd = list_first_entry(&sync->pict_frame_q,
+                       struct msm_queue_cmd, list);
+       list_del_init(&qcmd->list);
+       spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags);
+
+       if (qcmd->command != NULL) {
+               struct msm_ctrl_cmd *q =
+                       (struct msm_ctrl_cmd *)qcmd->command;
+               ctrl->type = q->type;
+               ctrl->status = q->status;
+       } else {
+               ctrl->type = -1;
+               ctrl->status = -1;
+       }
+
+       kfree(qcmd);
+       return rc;
+}
+
+static int msm_get_pic(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_ctrl_cmd ctrlcmd_t;
+       int rc;
+
+       if (copy_from_user(&ctrlcmd_t,
+                               arg,
+                               sizeof(struct msm_ctrl_cmd))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       rc = __msm_get_pic(sync, &ctrlcmd_t);
+       if (rc < 0)
+               return rc;
+
+       if (sync->croplen) {
+               if (ctrlcmd_t.length < sync->croplen) {
+                       pr_err("msm_get_pic: invalid len %d\n",
+                               ctrlcmd_t.length);
+                       return -EINVAL;
+               }
+               if (copy_to_user(ctrlcmd_t.value,
+                               sync->cropinfo,
+                               sync->croplen)) {
+                       ERR_COPY_TO_USER();
+                       return -EFAULT;
+               }
+       }
+
+       if (copy_to_user((void *)arg,
+               &ctrlcmd_t,
+               sizeof(struct msm_ctrl_cmd))) {
+               ERR_COPY_TO_USER();
+               return -EFAULT;
+       }
+       return 0;
+}
+
+static int msm_set_crop(struct msm_sync *sync, void __user *arg)
+{
+       struct crop_info crop;
+
+       if (copy_from_user(&crop,
+                               arg,
+                               sizeof(struct crop_info))) {
+               ERR_COPY_FROM_USER();
+               return -EFAULT;
+       }
+
+       if (!sync->croplen) {
+               sync->cropinfo = kmalloc(crop.len, GFP_KERNEL);
+               if (!sync->cropinfo)
+                       return -ENOMEM;
+       } else if (sync->croplen < crop.len)
+               return -EINVAL;
+
+       if (copy_from_user(sync->cropinfo,
+                               crop.info,
+                               crop.len)) {
+               ERR_COPY_FROM_USER();
+               kfree(sync->cropinfo);
+               return -EFAULT;
+       }
+
+       sync->croplen = crop.len;
+
+       return 0;
+}
+
+static int msm_pict_pp_done(struct msm_sync *sync, void __user *arg)
+{
+       struct msm_ctrl_cmd udata;
+       struct msm_ctrl_cmd *ctrlcmd = NULL;
+       struct msm_queue_cmd *qcmd = NULL;
+       unsigned long flags;
+       int rc = 0;
+
+       if (!sync->pict_pp)
+               return -EINVAL;
+
+       if (copy_from_user(&udata, arg, sizeof(struct msm_ctrl_cmd))) {
+               ERR_COPY_FROM_USER();
+               rc = -EFAULT;
+               goto pp_fail;
+       }
+
+       qcmd = kmalloc(sizeof(struct msm_queue_cmd) +
+                       sizeof(struct msm_ctrl_cmd),
+                       GFP_KERNEL);
+       if (!qcmd) {
+               rc = -ENOMEM;
+               goto pp_fail;
+       }
+
+       qcmd->type = MSM_CAM_Q_VFE_MSG;
+       qcmd->command = ctrlcmd = (struct msm_ctrl_cmd *)(qcmd + 1);
+       memset(ctrlcmd, 0, sizeof(struct msm_ctrl_cmd));
+       ctrlcmd->type = udata.type;
+       ctrlcmd->status = udata.status;
+
+       spin_lock_irqsave(&sync->pict_frame_q_lock, flags);
+       list_add_tail(&qcmd->list, &sync->pict_frame_q);
+       spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags);
+       wake_up(&sync->pict_frame_wait);
+
+pp_fail:
+       return rc;
+}
+
+static long msm_ioctl_common(struct msm_device *pmsm,
+               unsigned int cmd,
+               void __user *argp)
+{
+       CDBG("msm_ioctl_common\n");
+       switch (cmd) {
+       case MSM_CAM_IOCTL_REGISTER_PMEM:
+               return msm_register_pmem(pmsm->sync, argp);
+       case MSM_CAM_IOCTL_UNREGISTER_PMEM:
+               return msm_pmem_table_del(pmsm->sync, argp);
+       default:
+               return -EINVAL;
+       }
+}
+
+static long msm_ioctl_config(struct file *filep, unsigned int cmd,
+       unsigned long arg)
+{
+       int rc = -EINVAL;
+       void __user *argp = (void __user *)arg;
+       struct msm_device *pmsm = filep->private_data;
+
+       CDBG("msm_ioctl_config cmd = %d\n", _IOC_NR(cmd));
+
+       switch (cmd) {
+       case MSM_CAM_IOCTL_GET_SENSOR_INFO:
+               rc = msm_get_sensor_info(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_CONFIG_VFE:
+               /* Coming from config thread for update */
+               rc = msm_config_vfe(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_GET_STATS:
+               /* Coming from config thread wait
+                * for vfe statistics and control requests */
+               rc = msm_get_stats(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_ENABLE_VFE:
+               /* This request comes from control thread:
+                * enable either QCAMTASK or VFETASK */
+               rc = msm_enable_vfe(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_DISABLE_VFE:
+               /* This request comes from control thread:
+                * disable either QCAMTASK or VFETASK */
+               rc = msm_disable_vfe(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_VFE_APPS_RESET:
+               msm_camio_vfe_blk_reset();
+               rc = 0;
+               break;
+
+       case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER:
+               rc = msm_put_stats_buffer(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_AXI_CONFIG:
+               rc = msm_axi_config(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_SET_CROP:
+               rc = msm_set_crop(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_PICT_PP: {
+               uint8_t enable;
+               if (copy_from_user(&enable, argp, sizeof(enable))) {
+                       ERR_COPY_FROM_USER();
+                       rc = -EFAULT;
+               } else {
+                       pmsm->sync->pict_pp = enable;
+                       rc = 0;
+               }
+               break;
+       }
+
+       case MSM_CAM_IOCTL_PICT_PP_DONE:
+               rc = msm_pict_pp_done(pmsm->sync, argp);
+               break;
+
+       case MSM_CAM_IOCTL_SENSOR_IO_CFG:
+               rc = pmsm->sync->sctrl.s_config(argp);
+               break;
+
+       case MSM_CAM_IOCTL_FLASH_LED_CFG: {
+               uint32_t led_state;
+               if (copy_from_user(&led_state, argp, sizeof(led_state))) {
+                       ERR_COPY_FROM_USER();
+                       rc = -EFAULT;
+               } else
+                       rc = msm_camera_flash_set_led_state(led_state);
+               break;
+       }
+
+       default:
+               rc = msm_ioctl_common(pmsm, cmd, argp);
+               break;
+       }
+
+       CDBG("msm_ioctl_config cmd = %d DONE\n", _IOC_NR(cmd));
+       return rc;
+}
+
+static int msm_unblock_poll_frame(struct msm_sync *);
+
+static long msm_ioctl_frame(struct file *filep, unsigned int cmd,
+       unsigned long arg)
+{
+       int rc = -EINVAL;
+       void __user *argp = (void __user *)arg;
+       struct msm_device *pmsm = filep->private_data;
+
+
+       switch (cmd) {
+       case MSM_CAM_IOCTL_GETFRAME:
+               /* Coming from frame thread to get frame
+                * after SELECT is done */
+               rc = msm_get_frame(pmsm->sync, argp);
+               break;
+       case MSM_CAM_IOCTL_RELEASE_FRAME_BUFFER:
+               rc = msm_put_frame_buffer(pmsm->sync, argp);
+               break;
+       case MSM_CAM_IOCTL_UNBLOCK_POLL_FRAME:
+               rc = msm_unblock_poll_frame(pmsm->sync);
+               break;
+       default:
+               break;
+       }
+
+       return rc;
+}
+
+
+static long msm_ioctl_control(struct file *filep, unsigned int cmd,
+       unsigned long arg)
+{
+       int rc = -EINVAL;
+       void __user *argp = (void __user *)arg;
+       struct msm_control_device *ctrl_pmsm = filep->private_data;
+       struct msm_device *pmsm = ctrl_pmsm->pmsm;
+
+       switch (cmd) {
+       case MSM_CAM_IOCTL_CTRL_COMMAND:
+               /* Coming from control thread, may need to wait for
+                * command status */
+               rc = msm_control(ctrl_pmsm, 1, argp);
+               break;
+       case MSM_CAM_IOCTL_CTRL_COMMAND_2:
+               /* Sends a message, returns immediately */
+               rc = msm_control(ctrl_pmsm, 0, argp);
+               break;
+       case MSM_CAM_IOCTL_CTRL_CMD_DONE:
+               /* Config thread calls the control thread to notify it
+                * of the result of a MSM_CAM_IOCTL_CTRL_COMMAND.
+                */
+               rc = msm_ctrl_cmd_done(ctrl_pmsm, argp);
+               break;
+       case MSM_CAM_IOCTL_GET_PICTURE:
+               rc = msm_get_pic(pmsm->sync, argp);
+               break;
+       default:
+               rc = msm_ioctl_common(pmsm, cmd, argp);
+               break;
+       }
+
+       return rc;
+}
+
+static int __msm_release(struct msm_sync *sync)
+{
+       struct msm_pmem_region *region;
+       struct hlist_node *hnode;
+       struct hlist_node *n;
+
+       mutex_lock(&sync->lock);
+       if (sync->opencnt)
+               sync->opencnt--;
+
+       if (!sync->opencnt) {
+               /* need to clean up system resource */
+               if (sync->vfefn.vfe_release)
+                       sync->vfefn.vfe_release(sync->pdev);
+
+               if (sync->cropinfo) {
+                       kfree(sync->cropinfo);
+                       sync->cropinfo = NULL;
+                       sync->croplen = 0;
+               }
+
+               hlist_for_each_entry_safe(region, hnode, n,
+                               &sync->frame, list) {
+                       hlist_del(hnode);
+                       put_pmem_file(region->file);
+                       kfree(region);
+               }
+
+               hlist_for_each_entry_safe(region, hnode, n,
+                               &sync->stats, list) {
+                       hlist_del(hnode);
+                       put_pmem_file(region->file);
+                       kfree(region);
+               }
+
+               MSM_DRAIN_QUEUE(sync, msg_event_q);
+               MSM_DRAIN_QUEUE(sync, prev_frame_q);
+               MSM_DRAIN_QUEUE(sync, pict_frame_q);
+
+               sync->sctrl.s_release();
+               wake_unlock(&sync->wake_lock);
+
+               sync->apps_id = NULL;
+               CDBG("msm_release completed!\n");
+       }
+       mutex_unlock(&sync->lock);
+
+       return 0;
+}
+
+static int msm_release_config(struct inode *node, struct file *filep)
+{
+       int rc;
+       struct msm_device *pmsm = filep->private_data;
+       printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name);
+       rc = __msm_release(pmsm->sync);
+       atomic_set(&pmsm->opened, 0);
+       return rc;
+}
+
+static int msm_release_control(struct inode *node, struct file *filep)
+{
+       int rc;
+       struct msm_control_device *ctrl_pmsm = filep->private_data;
+       struct msm_device *pmsm = ctrl_pmsm->pmsm;
+       printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name);
+       rc = __msm_release(pmsm->sync);
+       if (!rc) {
+               MSM_DRAIN_QUEUE(&ctrl_pmsm->ctrl_q, ctrl_status_q);
+               MSM_DRAIN_QUEUE(pmsm->sync, pict_frame_q);
+       }
+       kfree(ctrl_pmsm);
+       return rc;
+}
+
+static int msm_release_frame(struct inode *node, struct file *filep)
+{
+       int rc;
+       struct msm_device *pmsm = filep->private_data;
+       printk("msm_camera: RELEASE %s\n", filep->f_path.dentry->d_name.name);
+       rc = __msm_release(pmsm->sync);
+       if (!rc) {
+               MSM_DRAIN_QUEUE(pmsm->sync, prev_frame_q);
+               atomic_set(&pmsm->opened, 0);
+       }
+       return rc;
+}
+
+static int msm_unblock_poll_frame(struct msm_sync *sync)
+{
+       unsigned long flags;
+       CDBG("msm_unblock_poll_frame\n");
+       spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
+       sync->unblock_poll_frame = 1;
+       wake_up(&sync->prev_frame_wait);
+       spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
+       return 0;
+}
+
+static unsigned int __msm_poll_frame(struct msm_sync *sync,
+               struct file *filep,
+               struct poll_table_struct *pll_table)
+{
+       int rc = 0;
+       unsigned long flags;
+
+       poll_wait(filep, &sync->prev_frame_wait, pll_table);
+
+       spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
+       if (!list_empty_careful(&sync->prev_frame_q))
+               /* frame ready */
+               rc = POLLIN | POLLRDNORM;
+       if (sync->unblock_poll_frame) {
+               CDBG("%s: sync->unblock_poll_frame is true\n", __func__);
+               rc |= POLLPRI;
+               sync->unblock_poll_frame = 0;
+       }
+       spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
+
+       return rc;
+}
+
+static unsigned int msm_poll_frame(struct file *filep,
+       struct poll_table_struct *pll_table)
+{
+       struct msm_device *pmsm = filep->private_data;
+       return __msm_poll_frame(pmsm->sync, filep, pll_table);
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+
+static void *msm_vfe_sync_alloc(int size,
+                       void *syncdata __attribute__((unused)))
+{
+       struct msm_queue_cmd *qcmd =
+               kmalloc(sizeof(struct msm_queue_cmd) + size, GFP_ATOMIC);
+       return qcmd ? qcmd + 1 : NULL;
+}
+
+/*
+ * This function executes in interrupt context.
+ */
+
+static void msm_vfe_sync(struct msm_vfe_resp *vdata,
+               enum msm_queue qtype, void *syncdata)
+{
+       struct msm_queue_cmd *qcmd = NULL;
+       struct msm_queue_cmd *qcmd_frame = NULL;
+       struct msm_vfe_phy_info *fphy;
+
+       unsigned long flags;
+       struct msm_sync *sync = (struct msm_sync *)syncdata;
+       if (!sync) {
+               pr_err("msm_camera: no context in dsp callback.\n");
+               return;
+       }
+
+       qcmd = ((struct msm_queue_cmd *)vdata) - 1;
+       qcmd->type = qtype;
+
+       if (qtype == MSM_CAM_Q_VFE_MSG) {
+               switch(vdata->type) {
+               case VFE_MSG_OUTPUT1:
+               case VFE_MSG_OUTPUT2:
+                       qcmd_frame =
+                               kmalloc(sizeof(struct msm_queue_cmd) +
+                                       sizeof(struct msm_vfe_phy_info),
+                                       GFP_ATOMIC);
+                       if (!qcmd_frame)
+                               goto mem_fail;
+                       fphy = (struct msm_vfe_phy_info *)(qcmd_frame + 1);
+                       *fphy = vdata->phy;
+
+                       qcmd_frame->type = MSM_CAM_Q_VFE_MSG;
+                       qcmd_frame->command = fphy;
+
+                       CDBG("qcmd_frame= 0x%x phy_y= 0x%x, phy_cbcr= 0x%x\n",
+                               (int) qcmd_frame, fphy->y_phy, fphy->cbcr_phy);
+
+                       spin_lock_irqsave(&sync->prev_frame_q_lock, flags);
+                       list_add_tail(&qcmd_frame->list, &sync->prev_frame_q);
+                       wake_up(&sync->prev_frame_wait);
+                       spin_unlock_irqrestore(&sync->prev_frame_q_lock, flags);
+                       CDBG("woke up frame thread\n");
+                       break;
+               case VFE_MSG_SNAPSHOT:
+                       if (sync->pict_pp)
+                               break;
+
+                       CDBG("snapshot pp = %d\n", sync->pict_pp);
+                       qcmd_frame =
+                               kmalloc(sizeof(struct msm_queue_cmd),
+                                       GFP_ATOMIC);
+                       if (!qcmd_frame)
+                               goto mem_fail;
+                       qcmd_frame->type = MSM_CAM_Q_VFE_MSG;
+                       qcmd_frame->command = NULL;
+                               spin_lock_irqsave(&sync->pict_frame_q_lock,
+                               flags);
+                       list_add_tail(&qcmd_frame->list, &sync->pict_frame_q);
+                       wake_up(&sync->pict_frame_wait);
+                       spin_unlock_irqrestore(&sync->pict_frame_q_lock, flags);
+                       CDBG("woke up picture thread\n");
+                       break;
+               default:
+                       CDBG("%s: qtype = %d not handled\n",
+                               __func__, vdata->type);
+                       break;
+               }
+       }
+
+       qcmd->command = (void *)vdata;
+       CDBG("vdata->type = %d\n", vdata->type);
+
+       spin_lock_irqsave(&sync->msg_event_q_lock, flags);
+       list_add_tail(&qcmd->list, &sync->msg_event_q);
+       wake_up(&sync->msg_event_wait);
+       spin_unlock_irqrestore(&sync->msg_event_q_lock, flags);
+       CDBG("woke up config thread\n");
+       return;
+
+mem_fail:
+       kfree(qcmd);
+}
+
+static struct msm_vfe_callback msm_vfe_s = {
+       .vfe_resp = msm_vfe_sync,
+       .vfe_alloc = msm_vfe_sync_alloc,
+};
+
+static int __msm_open(struct msm_sync *sync, const char *const apps_id)
+{
+       int rc = 0;
+
+       mutex_lock(&sync->lock);
+       if (sync->apps_id && strcmp(sync->apps_id, apps_id)) {
+               pr_err("msm_camera(%s): sensor %s is already opened for %s\n",
+                       apps_id,
+                       sync->sdata->sensor_name,
+                       sync->apps_id);
+               rc = -EBUSY;
+               goto msm_open_done;
+       }
+
+       sync->apps_id = apps_id;
+
+       if (!sync->opencnt) {
+               wake_lock(&sync->wake_lock);
+
+               msm_camvfe_fn_init(&sync->vfefn, sync);
+               if (sync->vfefn.vfe_init) {
+                       rc = sync->vfefn.vfe_init(&msm_vfe_s,
+                               sync->pdev);
+                       if (rc < 0) {
+                               pr_err("vfe_init failed at %d\n", rc);
+                               goto msm_open_done;
+                       }
+                       rc = sync->sctrl.s_init(sync->sdata);
+                       if (rc < 0) {
+                               pr_err("sensor init failed: %d\n", rc);
+                               goto msm_open_done;
+                       }
+               } else {
+                       pr_err("no sensor init func\n");
+                       rc = -ENODEV;
+                       goto msm_open_done;
+               }
+
+               if (rc >= 0) {
+                       INIT_HLIST_HEAD(&sync->frame);
+                       INIT_HLIST_HEAD(&sync->stats);
+                       sync->unblock_poll_frame = 0;
+               }
+       }
+       sync->opencnt++;
+
+msm_open_done:
+       mutex_unlock(&sync->lock);
+       return rc;
+}
+
+static int msm_open_common(struct inode *inode, struct file *filep,
+                          int once)
+{
+       int rc;
+       struct msm_device *pmsm =
+               container_of(inode->i_cdev, struct msm_device, cdev);
+
+       CDBG("msm_camera: open %s\n", filep->f_path.dentry->d_name.name);
+
+       if (atomic_cmpxchg(&pmsm->opened, 0, 1) && once) {
+               pr_err("msm_camera: %s is already opened.\n",
+                       filep->f_path.dentry->d_name.name);
+               return -EBUSY;
+       }
+
+       rc = nonseekable_open(inode, filep);
+       if (rc < 0) {
+               pr_err("msm_open: nonseekable_open error %d\n", rc);
+               return rc;
+       }
+
+       rc = __msm_open(pmsm->sync, MSM_APPS_ID_PROP);
+       if (rc < 0)
+               return rc;
+
+       filep->private_data = pmsm;
+
+       CDBG("msm_open() open: rc = %d\n", rc);
+       return rc;
+}
+
+static int msm_open(struct inode *inode, struct file *filep)
+{
+       return msm_open_common(inode, filep, 1);
+}
+
+static int msm_open_control(struct inode *inode, struct file *filep)
+{
+       int rc;
+
+       struct msm_control_device *ctrl_pmsm =
+               kmalloc(sizeof(struct msm_control_device), GFP_KERNEL);
+       if (!ctrl_pmsm)
+               return -ENOMEM;
+
+       rc = msm_open_common(inode, filep, 0);
+       if (rc < 0)
+               return rc;
+
+       ctrl_pmsm->pmsm = filep->private_data;
+       filep->private_data = ctrl_pmsm;
+       spin_lock_init(&ctrl_pmsm->ctrl_q.ctrl_status_q_lock);
+       INIT_LIST_HEAD(&ctrl_pmsm->ctrl_q.ctrl_status_q);
+       init_waitqueue_head(&ctrl_pmsm->ctrl_q.ctrl_status_wait);
+
+       CDBG("msm_open() open: rc = %d\n", rc);
+       return rc;
+}
+
+static int __msm_v4l2_control(struct msm_sync *sync,
+               struct msm_ctrl_cmd *out)
+{
+       int rc = 0;
+
+       struct msm_queue_cmd *qcmd = NULL, *rcmd = NULL;
+       struct msm_ctrl_cmd *ctrl;
+       struct msm_control_device_queue FIXME;
+
+       /* wake up config thread, 4 is for V4L2 application */
+       qcmd = kmalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+       if (!qcmd) {
+               pr_err("msm_control: cannot allocate buffer\n");
+               rc = -ENOMEM;
+               goto end;
+       }
+       qcmd->type = MSM_CAM_Q_V4L2_REQ;
+       qcmd->command = out;
+
+       rcmd = __msm_control(sync, &FIXME, qcmd, out->timeout_ms);
+       if (IS_ERR(rcmd)) {
+               rc = PTR_ERR(rcmd);
+               goto end;
+       }
+
+       ctrl = (struct msm_ctrl_cmd *)(rcmd->command);
+       /* FIXME: we should just set out->length = ctrl->length; */
+       BUG_ON(out->length < ctrl->length);
+       memcpy(out->value, ctrl->value, ctrl->length);
+
+end:
+       if (rcmd) kfree(rcmd);
+       CDBG("__msm_v4l2_control: end rc = %d\n", rc);
+       return rc;
+}
+
+static const struct file_operations msm_fops_config = {
+       .owner = THIS_MODULE,
+       .open = msm_open,
+       .unlocked_ioctl = msm_ioctl_config,
+       .release = msm_release_config,
+};
+
+static const struct file_operations msm_fops_control = {
+       .owner = THIS_MODULE,
+       .open = msm_open_control,
+       .unlocked_ioctl = msm_ioctl_control,
+       .release = msm_release_control,
+};
+
+static const struct file_operations msm_fops_frame = {
+       .owner = THIS_MODULE,
+       .open = msm_open,
+       .unlocked_ioctl = msm_ioctl_frame,
+       .release = msm_release_frame,
+       .poll = msm_poll_frame,
+};
+
+static int msm_setup_cdev(struct msm_device *msm,
+                       int node,
+                       dev_t devno,
+                       const char *suffix,
+                       const struct file_operations *fops)
+{
+       int rc = -ENODEV;
+
+       struct device *device =
+               device_create(msm_class, NULL,
+                       devno, NULL,
+                       "%s%d", suffix, node);
+
+       if (IS_ERR(device)) {
+               rc = PTR_ERR(device);
+               pr_err("msm_camera: error creating device: %d\n", rc);
+               return rc;
+       }
+
+       cdev_init(&msm->cdev, fops);
+       msm->cdev.owner = THIS_MODULE;
+
+       rc = cdev_add(&msm->cdev, devno, 1);
+       if (rc < 0) {
+               pr_err("msm_camera: error adding cdev: %d\n", rc);
+               device_destroy(msm_class, devno);
+               return rc;
+       }
+
+       return rc;
+}
+
+static int msm_tear_down_cdev(struct msm_device *msm, dev_t devno)
+{
+       cdev_del(&msm->cdev);
+       device_destroy(msm_class, devno);
+       return 0;
+}
+
+int msm_v4l2_register(struct msm_v4l2_driver *drv)
+{
+       /* FIXME: support multiple sensors */
+       if (list_empty(&msm_sensors))
+               return -ENODEV;
+
+       drv->sync = list_first_entry(&msm_sensors, struct msm_sync, list);
+       drv->open      = __msm_open;
+       drv->release   = __msm_release;
+       drv->ctrl      = __msm_v4l2_control;
+       drv->reg_pmem  = __msm_register_pmem;
+       drv->get_frame = __msm_get_frame;
+       drv->put_frame = __msm_put_frame_buf;
+       drv->get_pict  = __msm_get_pic;
+       drv->drv_poll  = __msm_poll_frame;
+
+       return 0;
+}
+EXPORT_SYMBOL(msm_v4l2_register);
+
+int msm_v4l2_unregister(struct msm_v4l2_driver *drv)
+{
+       drv->sync = NULL;
+       return 0;
+}
+EXPORT_SYMBOL(msm_v4l2_unregister);
+
+static int msm_sync_init(struct msm_sync *sync,
+               struct platform_device *pdev,
+               int (*sensor_probe)(const struct msm_camera_sensor_info *,
+                               struct msm_sensor_ctrl *))
+{
+       int rc = 0;
+       struct msm_sensor_ctrl sctrl;
+       sync->sdata = pdev->dev.platform_data;
+
+       spin_lock_init(&sync->msg_event_q_lock);
+       INIT_LIST_HEAD(&sync->msg_event_q);
+       init_waitqueue_head(&sync->msg_event_wait);
+
+       spin_lock_init(&sync->prev_frame_q_lock);
+       INIT_LIST_HEAD(&sync->prev_frame_q);
+       init_waitqueue_head(&sync->prev_frame_wait);
+
+       spin_lock_init(&sync->pict_frame_q_lock);
+       INIT_LIST_HEAD(&sync->pict_frame_q);
+       init_waitqueue_head(&sync->pict_frame_wait);
+
+       wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
+
+       rc = msm_camio_probe_on(pdev);
+       if (rc < 0)
+               return rc;
+       rc = sensor_probe(sync->sdata, &sctrl);
+       if (rc >= 0) {
+               sync->pdev = pdev;
+               sync->sctrl = sctrl;
+       }
+       msm_camio_probe_off(pdev);
+       if (rc < 0) {
+               pr_err("msm_camera: failed to initialize %s\n",
+                       sync->sdata->sensor_name);
+               wake_lock_destroy(&sync->wake_lock);
+               return rc;
+       }
+
+       sync->opencnt = 0;
+       mutex_init(&sync->lock);
+       CDBG("initialized %s\n", sync->sdata->sensor_name);
+       return rc;
+}
+
+static int msm_sync_destroy(struct msm_sync *sync)
+{
+       wake_lock_destroy(&sync->wake_lock);
+       return 0;
+}
+
+static int msm_device_init(struct msm_device *pmsm,
+               struct msm_sync *sync,
+               int node)
+{
+       int dev_num = 3 * node;
+       int rc = msm_setup_cdev(pmsm, node,
+               MKDEV(MAJOR(msm_devno), dev_num),
+               "control", &msm_fops_control);
+       if (rc < 0) {
+               pr_err("error creating control node: %d\n", rc);
+               return rc;
+       }
+
+       rc = msm_setup_cdev(pmsm + 1, node,
+               MKDEV(MAJOR(msm_devno), dev_num + 1),
+               "config", &msm_fops_config);
+       if (rc < 0) {
+               pr_err("error creating config node: %d\n", rc);
+               msm_tear_down_cdev(pmsm, MKDEV(MAJOR(msm_devno),
+                               dev_num));
+               return rc;
+       }
+
+       rc = msm_setup_cdev(pmsm + 2, node,
+               MKDEV(MAJOR(msm_devno), dev_num + 2),
+               "frame", &msm_fops_frame);
+       if (rc < 0) {
+               pr_err("error creating frame node: %d\n", rc);
+               msm_tear_down_cdev(pmsm,
+                       MKDEV(MAJOR(msm_devno), dev_num));
+               msm_tear_down_cdev(pmsm + 1,
+                       MKDEV(MAJOR(msm_devno), dev_num + 1));
+               return rc;
+       }
+
+       atomic_set(&pmsm[0].opened, 0);
+       atomic_set(&pmsm[1].opened, 0);
+       atomic_set(&pmsm[2].opened, 0);
+
+       pmsm[0].sync = sync;
+       pmsm[1].sync = sync;
+       pmsm[2].sync = sync;
+
+       return rc;
+}
+
+int msm_camera_drv_start(struct platform_device *dev,
+               int (*sensor_probe)(const struct msm_camera_sensor_info *,
+                       struct msm_sensor_ctrl *))
+{
+       struct msm_device *pmsm = NULL;
+       struct msm_sync *sync;
+       int rc = -ENODEV;
+       static int camera_node;
+
+       if (camera_node >= MSM_MAX_CAMERA_SENSORS) {
+               pr_err("msm_camera: too many camera sensors\n");
+               return rc;
+       }
+
+       if (!msm_class) {
+               /* There are three device nodes per sensor */
+               rc = alloc_chrdev_region(&msm_devno, 0,
+                               3 * MSM_MAX_CAMERA_SENSORS,
+                               "msm_camera");
+               if (rc < 0) {
+                       pr_err("msm_camera: failed to allocate chrdev: %d\n",
+                               rc);
+                       return rc;
+               }
+
+               msm_class = class_create(THIS_MODULE, "msm_camera");
+               if (IS_ERR(msm_class)) {
+                       rc = PTR_ERR(msm_class);
+                       pr_err("msm_camera: create device class failed: %d\n",
+                               rc);
+                       return rc;
+               }
+       }
+
+       pmsm = kzalloc(sizeof(struct msm_device) * 3 +
+                       sizeof(struct msm_sync), GFP_ATOMIC);
+       if (!pmsm)
+               return -ENOMEM;
+       sync = (struct msm_sync *)(pmsm + 3);
+
+       rc = msm_sync_init(sync, dev, sensor_probe);
+       if (rc < 0) {
+               kfree(pmsm);
+               return rc;
+       }
+
+       CDBG("setting camera node %d\n", camera_node);
+       rc = msm_device_init(pmsm, sync, camera_node);
+       if (rc < 0) {
+               msm_sync_destroy(sync);
+               kfree(pmsm);
+               return rc;
+       }
+
+       camera_node++;
+       list_add(&sync->list, &msm_sensors);
+       return rc;
+}
+EXPORT_SYMBOL(msm_camera_drv_start);
diff --git a/drivers/staging/dream/camera/msm_io7x.c b/drivers/staging/dream/camera/msm_io7x.c
new file mode 100644 (file)
index 0000000..55c020b
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2008-2009 QUALCOMM Incorporated
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+
+#define CAMIF_CFG_RMSK 0x1fffff
+#define CAM_SEL_BMSK 0x2
+#define CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define CAM_PCLK_INVERT_BMSK 0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT 0x1
+#define CAM_PCLK_SRC_SEL_SHFT 0x11
+#define CAM_PCLK_INVERT_SHFT 0x13
+#define CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+#define APPS_RESET_OFFSET 0x00000210
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+extern int clk_set_flags(struct clk *clk, unsigned long flags);
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+       int rc = -1;
+       struct clk *clk = NULL;
+
+       switch (clktype) {
+       case CAMIO_VFE_MDC_CLK:
+               clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk");
+               break;
+
+       case CAMIO_MDC_CLK:
+               clk = camio_mdc_clk = clk_get(NULL, "mdc_clk");
+               break;
+
+       case CAMIO_VFE_CLK:
+               clk = camio_vfe_clk = clk_get(NULL, "vfe_clk");
+               break;
+
+       default:
+               break;
+       }
+
+       if (!IS_ERR(clk)) {
+               clk_enable(clk);
+               rc = 0;
+       }
+
+       return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+       int rc = -1;
+       struct clk *clk = NULL;
+
+       switch (clktype) {
+       case CAMIO_VFE_MDC_CLK:
+               clk = camio_vfe_mdc_clk;
+               break;
+
+       case CAMIO_MDC_CLK:
+               clk = camio_mdc_clk;
+               break;
+
+       case CAMIO_VFE_CLK:
+               clk = camio_vfe_clk;
+               break;
+
+       default:
+               break;
+       }
+
+       if (!IS_ERR(clk)) {
+               clk_disable(clk);
+               clk_put(clk);
+               rc = 0;
+       }
+
+       return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+       struct clk *clk = camio_vfe_clk;
+
+       if (clk != ERR_PTR(-ENOENT))
+               clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+       int rc = 0;
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+       camio_ext = camdev->ioext;
+
+       appio = request_mem_region(camio_ext.appphy,
+               camio_ext.appsz, pdev->name);
+       if (!appio) {
+               rc = -EBUSY;
+               goto enable_fail;
+       }
+
+       appbase = ioremap(camio_ext.appphy,
+               camio_ext.appsz);
+       if (!appbase) {
+               rc = -ENOMEM;
+               goto apps_no_mem;
+       }
+
+       mdcio = request_mem_region(camio_ext.mdcphy,
+               camio_ext.mdcsz, pdev->name);
+       if (!mdcio) {
+               rc = -EBUSY;
+               goto mdc_busy;
+       }
+
+       mdcbase = ioremap(camio_ext.mdcphy,
+               camio_ext.mdcsz);
+       if (!mdcbase) {
+               rc = -ENOMEM;
+               goto mdc_no_mem;
+       }
+
+       camdev->camera_gpio_on();
+
+       msm_camio_clk_enable(CAMIO_VFE_CLK);
+       msm_camio_clk_enable(CAMIO_MDC_CLK);
+       msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+       return 0;
+
+mdc_no_mem:
+       release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+mdc_busy:
+       iounmap(appbase);
+apps_no_mem:
+       release_mem_region(camio_ext.appphy, camio_ext.appsz);
+enable_fail:
+       return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+       iounmap(mdcbase);
+       release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+       iounmap(appbase);
+       release_mem_region(camio_ext.appphy, camio_ext.appsz);
+
+       camdev->camera_gpio_off();
+
+       msm_camio_clk_disable(CAMIO_VFE_CLK);
+       msm_camio_clk_disable(CAMIO_MDC_CLK);
+       msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+       uint32_t reg;
+       uint32_t mask, value;
+
+       /* select CLKRGM_VFE_SRC_CAM_VFE_SRC:  internal source */
+       msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+
+       mask = CAM_SEL_BMSK |
+               CAM_PCLK_SRC_SEL_BMSK |
+               CAM_PCLK_INVERT_BMSK;
+
+       value = 1 << CAM_SEL_SHFT |
+               3 << CAM_PCLK_SRC_SEL_SHFT |
+               0 << CAM_PCLK_INVERT_SHFT;
+
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
+       mdelay(10);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+       uint32_t val;
+
+       val = readl(appbase + 0x00000210);
+       val |= 0x1;
+       writel(val, appbase + 0x00000210);
+       mdelay(10);
+
+       val = readl(appbase + 0x00000210);
+       val &= ~0x1;
+       writel(val, appbase + 0x00000210);
+       mdelay(10);
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+       uint32_t reg;
+       uint32_t mask, value;
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+       struct clk *clk = NULL;
+
+       clk = camio_vfe_clk;
+
+       if (clk != NULL && clk != ERR_PTR(-ENOENT)) {
+               switch (srctype) {
+               case MSM_CAMIO_CLK_SRC_INTERNAL:
+                       clk_set_flags(clk, 0x00000100 << 1);
+                       break;
+
+               case MSM_CAMIO_CLK_SRC_EXTERNAL:
+                       clk_set_flags(clk, 0x00000100);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+       camdev->camera_gpio_on();
+       return msm_camio_clk_enable(CAMIO_VFE_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+       camdev->camera_gpio_off();
+       return msm_camio_clk_disable(CAMIO_VFE_CLK);
+}
diff --git a/drivers/staging/dream/camera/msm_io8x.c b/drivers/staging/dream/camera/msm_io8x.c
new file mode 100644 (file)
index 0000000..895161a
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2008-2009 QUALCOMM Incorporated
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+
+#define CAMIF_CFG_RMSK 0x1fffff
+#define CAM_SEL_BMSK 0x2
+#define CAM_PCLK_SRC_SEL_BMSK 0x60000
+#define CAM_PCLK_INVERT_BMSK 0x80000
+#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
+
+#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
+#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
+#define MDDI_CLK_CHICKEN_BIT_BMSK  0x80
+
+#define CAM_SEL_SHFT 0x1
+#define CAM_PCLK_SRC_SEL_SHFT 0x11
+#define CAM_PCLK_INVERT_SHFT 0x13
+#define CAM_PAD_REG_SW_RESET_SHFT 0x14
+
+#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
+#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
+#define MDDI_CLK_CHICKEN_BIT_SHFT  0x7
+#define APPS_RESET_OFFSET 0x00000210
+
+static struct clk *camio_vfe_mdc_clk;
+static struct clk *camio_mdc_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_vfe_axi_clk;
+static struct msm_camera_io_ext camio_ext;
+static struct resource *appio, *mdcio;
+void __iomem *appbase, *mdcbase;
+
+extern int clk_set_flags(struct clk *clk, unsigned long flags);
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+       int rc = 0;
+       struct clk *clk = NULL;
+
+       switch (clktype) {
+       case CAMIO_VFE_MDC_CLK:
+               camio_vfe_mdc_clk =
+               clk = clk_get(NULL, "vfe_mdc_clk");
+               break;
+
+       case CAMIO_MDC_CLK:
+               camio_mdc_clk =
+               clk = clk_get(NULL, "mdc_clk");
+               break;
+
+       case CAMIO_VFE_CLK:
+               camio_vfe_clk =
+               clk = clk_get(NULL, "vfe_clk");
+               break;
+
+       case CAMIO_VFE_AXI_CLK:
+               camio_vfe_axi_clk =
+               clk = clk_get(NULL, "vfe_axi_clk");
+               break;
+
+       default:
+               break;
+       }
+
+       if (!IS_ERR(clk))
+               clk_enable(clk);
+       else
+               rc = -1;
+
+       return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+       int rc = 0;
+       struct clk *clk = NULL;
+
+       switch (clktype) {
+       case CAMIO_VFE_MDC_CLK:
+               clk = camio_vfe_mdc_clk;
+               break;
+
+       case CAMIO_MDC_CLK:
+               clk = camio_mdc_clk;
+               break;
+
+       case CAMIO_VFE_CLK:
+               clk = camio_vfe_clk;
+               break;
+
+       case CAMIO_VFE_AXI_CLK:
+               clk = camio_vfe_axi_clk;
+               break;
+
+       default:
+               break;
+       }
+
+       if (!IS_ERR(clk)) {
+               clk_disable(clk);
+               clk_put(clk);
+       } else
+               rc = -1;
+
+       return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+       struct clk *clk = camio_vfe_mdc_clk;
+
+       /* TODO: check return */
+       clk_set_rate(clk, rate);
+}
+
+int msm_camio_enable(struct platform_device *pdev)
+{
+       int rc = 0;
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+       camio_ext = camdev->ioext;
+
+       appio = request_mem_region(camio_ext.appphy,
+               camio_ext.appsz, pdev->name);
+       if (!appio) {
+               rc = -EBUSY;
+               goto enable_fail;
+       }
+
+       appbase = ioremap(camio_ext.appphy,
+               camio_ext.appsz);
+       if (!appbase) {
+               rc = -ENOMEM;
+               goto apps_no_mem;
+       }
+
+       mdcio = request_mem_region(camio_ext.mdcphy,
+               camio_ext.mdcsz, pdev->name);
+       if (!mdcio) {
+               rc = -EBUSY;
+               goto mdc_busy;
+       }
+
+       mdcbase = ioremap(camio_ext.mdcphy,
+               camio_ext.mdcsz);
+       if (!mdcbase) {
+               rc = -ENOMEM;
+               goto mdc_no_mem;
+       }
+
+       camdev->camera_gpio_on();
+
+       msm_camio_clk_enable(CAMIO_VFE_CLK);
+       msm_camio_clk_enable(CAMIO_MDC_CLK);
+       msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+       msm_camio_clk_enable(CAMIO_VFE_AXI_CLK);
+       return 0;
+
+mdc_no_mem:
+       release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+mdc_busy:
+       iounmap(appbase);
+apps_no_mem:
+       release_mem_region(camio_ext.appphy, camio_ext.appsz);
+enable_fail:
+       return rc;
+}
+
+void msm_camio_disable(struct platform_device *pdev)
+{
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+       iounmap(mdcbase);
+       release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
+       iounmap(appbase);
+       release_mem_region(camio_ext.appphy, camio_ext.appsz);
+
+       camdev->camera_gpio_off();
+
+       msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+       msm_camio_clk_disable(CAMIO_MDC_CLK);
+       msm_camio_clk_disable(CAMIO_VFE_CLK);
+       msm_camio_clk_disable(CAMIO_VFE_AXI_CLK);
+}
+
+void msm_camio_camif_pad_reg_reset(void)
+{
+       uint32_t reg;
+       uint32_t mask, value;
+
+       /* select CLKRGM_VFE_SRC_CAM_VFE_SRC:  internal source */
+       msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+
+       mask = CAM_SEL_BMSK |
+               CAM_PCLK_SRC_SEL_BMSK |
+               CAM_PCLK_INVERT_BMSK |
+               EXT_CAM_HSYNC_POL_SEL_BMSK |
+               EXT_CAM_VSYNC_POL_SEL_BMSK |
+               MDDI_CLK_CHICKEN_BIT_BMSK;
+
+       value = 1 << CAM_SEL_SHFT |
+               3 << CAM_PCLK_SRC_SEL_SHFT |
+               0 << CAM_PCLK_INVERT_SHFT |
+               0 << EXT_CAM_HSYNC_POL_SEL_SHFT |
+               0 << EXT_CAM_VSYNC_POL_SEL_SHFT |
+               0 << MDDI_CLK_CHICKEN_BIT_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
+
+       mdelay(10);
+
+       /* todo: check return */
+       if (camio_vfe_clk)
+               clk_set_rate(camio_vfe_clk, 96000000);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+       uint32_t val;
+
+       val = readl(appbase + 0x00000210);
+       val |= 0x1;
+       writel(val, appbase + 0x00000210);
+       mdelay(10);
+
+       val = readl(appbase + 0x00000210);
+       val &= ~0x1;
+       writel(val, appbase + 0x00000210);
+       mdelay(10);
+}
+
+void msm_camio_camif_pad_reg_reset_2(void)
+{
+       uint32_t reg;
+       uint32_t mask, value;
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+
+       reg = (readl(mdcbase)) & CAMIF_CFG_RMSK;
+       mask = CAM_PAD_REG_SW_RESET_BMSK;
+       value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
+       writel((reg & (~mask)) | (value & mask), mdcbase);
+       mdelay(10);
+}
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+       struct clk *clk = NULL;
+
+       clk = camio_vfe_clk;
+
+       if (clk != NULL) {
+               switch (srctype) {
+               case MSM_CAMIO_CLK_SRC_INTERNAL:
+                       clk_set_flags(clk, 0x00000100 << 1);
+                       break;
+
+               case MSM_CAMIO_CLK_SRC_EXTERNAL:
+                       clk_set_flags(clk, 0x00000100);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+void msm_camio_clk_axi_rate_set(int rate)
+{
+       struct clk *clk = camio_vfe_axi_clk;
+       /* todo: check return */
+       clk_set_rate(clk, rate);
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+       camdev->camera_gpio_on();
+       return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+       struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+       struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+       camdev->camera_gpio_off();
+       return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
+}
diff --git a/drivers/staging/dream/camera/msm_v4l2.c b/drivers/staging/dream/camera/msm_v4l2.c
new file mode 100644 (file)
index 0000000..46a6eb1
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ *
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ *
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <media/v4l2-dev.h>
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+#include <media/v4l2-ioctl.h>
+/*#include <linux/platform_device.h>*/
+
+#define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \
+      struct v4l2_buffer)
+
+#define MSM_V4L2_GET_PICTURE    _IOWR('V', BASE_VIDIOC_PRIVATE+2, \
+      struct v4l2_buffer)
+
+#define MSM_V4L2_DEVICE_NAME       "msm_v4l2"
+
+#define MSM_V4L2_PROC_NAME         "msm_v4l2"
+
+#define MSM_V4L2_DEVNUM_MPEG2       0
+#define MSM_V4L2_DEVNUM_YUV         20
+
+/* HVGA-P (portrait) and HVGA-L (landscape) */
+#define MSM_V4L2_WIDTH              480
+#define MSM_V4L2_HEIGHT             320
+
+#if 1
+#define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+#define PREVIEW_FRAMES_NUM 4
+
+struct msm_v4l2_device {
+       struct list_head read_queue;
+       struct v4l2_format current_cap_format;
+       struct v4l2_format current_pix_format;
+       struct video_device *pvdev;
+       struct msm_v4l2_driver   *drv;
+       uint8_t opencnt;
+
+       spinlock_t read_queue_lock;
+};
+
+static struct msm_v4l2_device *g_pmsm_v4l2_dev;
+
+
+static DEFINE_MUTEX(msm_v4l2_opencnt_lock);
+
+static int msm_v4l2_open(struct file *f)
+{
+       int rc = 0;
+       D("%s\n", __func__);
+       mutex_lock(&msm_v4l2_opencnt_lock);
+       if (!g_pmsm_v4l2_dev->opencnt) {
+               rc = g_pmsm_v4l2_dev->drv->open(
+                               g_pmsm_v4l2_dev->drv->sync,
+                               MSM_APPS_ID_V4L2);
+       }
+       g_pmsm_v4l2_dev->opencnt++;
+       mutex_unlock(&msm_v4l2_opencnt_lock);
+       return rc;
+}
+
+static int msm_v4l2_release(struct file *f)
+{
+       int rc = 0;
+       D("%s\n", __func__);
+       mutex_lock(&msm_v4l2_opencnt_lock);
+       if (!g_pmsm_v4l2_dev->opencnt) {
+               g_pmsm_v4l2_dev->opencnt--;
+               if (!g_pmsm_v4l2_dev->opencnt) {
+                       rc = g_pmsm_v4l2_dev->drv->release(
+                                       g_pmsm_v4l2_dev->drv->sync);
+               }
+       }
+       mutex_unlock(&msm_v4l2_opencnt_lock);
+       return rc;
+}
+
+static unsigned int msm_v4l2_poll(struct file *f, struct poll_table_struct *w)
+{
+       return g_pmsm_v4l2_dev->drv->drv_poll(g_pmsm_v4l2_dev->drv->sync, f, w);
+}
+
+static long msm_v4l2_ioctl(struct file *filep,
+                          unsigned int cmd, unsigned long arg)
+{
+       struct msm_ctrl_cmd *ctrlcmd;
+
+       D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd, __LINE__);
+
+       switch (cmd) {
+       case MSM_V4L2_START_SNAPSHOT:
+
+               ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+               if (!ctrlcmd) {
+                       CDBG("msm_v4l2_ioctl: cannot allocate buffer\n");
+                       return -ENOMEM;
+               }
+
+               ctrlcmd->length     = 0;
+               ctrlcmd->value      = NULL;
+               ctrlcmd->timeout_ms = 10000;
+
+               D("msm_v4l2_ioctl,  MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n",
+               cmd);
+               ctrlcmd->type = MSM_V4L2_SNAPSHOT;
+               return g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync,
+                                                       ctrlcmd);
+
+       case MSM_V4L2_GET_PICTURE:
+               D("msm_v4l2_ioctl,  MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd);
+               ctrlcmd = (struct msm_ctrl_cmd *)arg;
+               return g_pmsm_v4l2_dev->drv->get_pict(
+                               g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+
+       default:
+               D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd);
+               return video_ioctl2(filep, cmd, arg);
+       }
+}
+
+static void msm_v4l2_release_dev(struct video_device *d)
+{
+       D("%s\n", __func__);
+}
+
+static int msm_v4l2_querycap(struct file *f,
+                            void *pctx, struct v4l2_capability *pcaps)
+{
+       D("%s\n", __func__);
+       strncpy(pcaps->driver, MSM_APPS_ID_V4L2, sizeof(pcaps->driver));
+       strncpy(pcaps->card,
+               MSM_V4L2_DEVICE_NAME, sizeof(pcaps->card));
+       pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int msm_v4l2_s_std(struct file *f, void *pctx, v4l2_std_id *pnorm)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+static int msm_v4l2_queryctrl(struct file *f,
+                               void *pctx, struct v4l2_queryctrl *pqctrl)
+{
+  int rc = 0;
+  struct msm_ctrl_cmd *ctrlcmd;
+
+       D("%s\n", __func__);
+
+       ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+       if (!ctrlcmd) {
+               CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       ctrlcmd->type       = MSM_V4L2_QUERY_CTRL;
+       ctrlcmd->length     = sizeof(struct v4l2_queryctrl);
+       ctrlcmd->value      = pqctrl;
+       ctrlcmd->timeout_ms = 10000;
+
+       rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+       if (rc < 0)
+               return -1;
+
+       return ctrlcmd->status;
+}
+
+static int msm_v4l2_g_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
+{
+       int rc = 0;
+       struct msm_ctrl_cmd *ctrlcmd;
+
+       D("%s\n", __func__);
+
+       ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+       if (!ctrlcmd) {
+               CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       ctrlcmd->type       = MSM_V4L2_GET_CTRL;
+       ctrlcmd->length     = sizeof(struct v4l2_control);
+       ctrlcmd->value      = c;
+       ctrlcmd->timeout_ms = 10000;
+
+       rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+       if (rc < 0)
+               return -1;
+
+       return ctrlcmd->status;
+}
+
+static int msm_v4l2_s_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
+{
+       int rc = 0;
+       struct msm_ctrl_cmd *ctrlcmd;
+
+       ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+       if (!ctrlcmd) {
+               CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       ctrlcmd->type       = MSM_V4L2_SET_CTRL;
+       ctrlcmd->length     = sizeof(struct v4l2_control);
+       ctrlcmd->value      = c;
+       ctrlcmd->timeout_ms = 10000;
+
+       D("%s\n", __func__);
+
+       rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+       if (rc < 0)
+               return -1;
+
+       return ctrlcmd->status;
+}
+
+static int msm_v4l2_reqbufs(struct file *f,
+                           void *pctx, struct v4l2_requestbuffers *b)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+static int msm_v4l2_querybuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
+{
+       struct msm_pmem_info pmem_buf;
+#if 0
+       __u32 width = 0;
+       __u32 height = 0;
+       __u32 y_size = 0;
+       __u32 y_pad = 0;
+
+       /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.width; */
+       width = 640;
+       /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.height; */
+       height = 480;
+
+       D("%s: width = %d, height = %d\n", __func__, width, height);
+
+       y_size = width * height;
+       y_pad = y_size % 4;
+#endif
+
+    __u32 y_pad = pb->bytesused % 4;
+
+       /* V4L2 videodev will do the copy_from_user. */
+
+       memset(&pmem_buf, 0, sizeof(struct msm_pmem_info));
+       pmem_buf.type = MSM_PMEM_OUTPUT2;
+       pmem_buf.vaddr = (void *)pb->m.userptr;
+       pmem_buf.y_off = 0;
+       pmem_buf.fd = (int)pb->reserved;
+       /* pmem_buf.cbcr_off = (y_size + y_pad); */
+    pmem_buf.cbcr_off = (pb->bytesused + y_pad);
+
+       g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, &pmem_buf);
+
+       return 0;
+}
+
+static int msm_v4l2_qbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
+{
+    /*
+       __u32 y_size = 0;
+       __u32 y_pad = 0;
+       __u32 width = 0;
+       __u32 height = 0;
+    */
+
+       __u32 y_pad = 0;
+
+       struct msm_pmem_info meminfo;
+       struct msm_frame frame;
+       static int cnt;
+
+       if ((pb->flags >> 16) & 0x0001) {
+               /* this is for previwe */
+#if 0
+               width = 640;
+               height = 480;
+
+               /* V4L2 videodev will do the copy_from_user. */
+               D("%s: width = %d, height = %d\n", __func__, width, height);
+               y_size = width * height;
+               y_pad = y_size % 4;
+#endif
+
+               y_pad = pb->bytesused % 4;
+
+               if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
+                       /* this qbuf is actually for releasing */
+
+                       frame.buffer           = pb->m.userptr;
+                       frame.y_off            = 0;
+                       /* frame.cbcr_off = (y_size + y_pad); */
+                       frame.cbcr_off         = (pb->bytesused + y_pad);
+                       frame.fd               = pb->reserved;
+
+                       D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n",
+                       pb->bytesused);
+
+                       g_pmsm_v4l2_dev->drv->put_frame(
+                               g_pmsm_v4l2_dev->drv->sync,
+                               &frame);
+
+                       return 0;
+               }
+
+               D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n",
+               pb->bytesused);
+
+               meminfo.type             = MSM_PMEM_OUTPUT2;
+               meminfo.fd               = (int)pb->reserved;
+               meminfo.vaddr            = (void *)pb->m.userptr;
+               meminfo.y_off            = 0;
+               /* meminfo.cbcr_off = (y_size + y_pad); */
+               meminfo.cbcr_off         = (pb->bytesused + y_pad);
+               if (cnt == PREVIEW_FRAMES_NUM - 1)
+                       meminfo.active = 0;
+               else
+                       meminfo.active = 1;
+               cnt++;
+               g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
+                               &meminfo);
+       } else if ((pb->flags) & 0x0001) {
+               /* this is for snapshot */
+
+       __u32 y_size = 0;
+
+       if ((pb->flags >> 8) & 0x01) {
+
+               y_size = pb->bytesused;
+
+               meminfo.type = MSM_PMEM_THUMBAIL;
+       } else if ((pb->flags >> 9) & 0x01) {
+
+               y_size = pb->bytesused;
+
+               meminfo.type = MSM_PMEM_MAINIMG;
+       }
+
+       y_pad = y_size % 4;
+
+       meminfo.fd         = (int)pb->reserved;
+       meminfo.vaddr      = (void *)pb->m.userptr;
+       meminfo.y_off      = 0;
+       /* meminfo.cbcr_off = (y_size + y_pad); */
+       meminfo.cbcr_off   = (y_size + y_pad);
+       meminfo.active     = 1;
+       g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
+                                       &meminfo);
+       }
+
+       return 0;
+}
+
+static int msm_v4l2_dqbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
+{
+       struct msm_frame frame;
+       D("%s\n", __func__);
+
+       /* V4L2 videodev will do the copy_to_user. */
+       if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+
+               D("%s, %d\n", __func__, __LINE__);
+
+               g_pmsm_v4l2_dev->drv->get_frame(
+                       g_pmsm_v4l2_dev->drv->sync,
+                       &frame);
+
+               pb->type       = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               pb->m.userptr  = (unsigned long)frame.buffer;  /* FIXME */
+               pb->reserved   = (int)frame.fd;
+               /* pb->length     = (int)frame.cbcr_off; */
+
+               pb->bytesused  = frame.cbcr_off;
+
+       } else if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
+               __u32 y_pad     = pb->bytesused % 4;
+
+               frame.buffer   = pb->m.userptr;
+               frame.y_off    = 0;
+               /* frame.cbcr_off = (y_size + y_pad); */
+               frame.cbcr_off = (pb->bytesused + y_pad);
+               frame.fd       = pb->reserved;
+
+               g_pmsm_v4l2_dev->drv->put_frame(
+                       g_pmsm_v4l2_dev->drv->sync,
+                       &frame);
+       }
+
+       return 0;
+}
+
+static int msm_v4l2_streamon(struct file *f, void *pctx, enum v4l2_buf_type i)
+{
+  struct msm_ctrl_cmd *ctrlcmd;
+
+       ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+       if (!ctrlcmd) {
+               CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       ctrlcmd->type       = MSM_V4L2_STREAM_ON;
+       ctrlcmd->timeout_ms = 10000;
+       ctrlcmd->length     = 0;
+       ctrlcmd->value      = NULL;
+
+       D("%s\n", __func__);
+
+       g_pmsm_v4l2_dev->drv->ctrl(
+               g_pmsm_v4l2_dev->drv->sync,
+               ctrlcmd);
+
+       D("%s after drv->ctrl \n", __func__);
+
+       return 0;
+}
+
+static int msm_v4l2_streamoff(struct file *f, void *pctx, enum v4l2_buf_type i)
+{
+  struct msm_ctrl_cmd *ctrlcmd;
+
+       ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+       if (!ctrlcmd) {
+               CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
+               return -ENOMEM;
+       }
+
+       ctrlcmd->type       = MSM_V4L2_STREAM_OFF;
+       ctrlcmd->timeout_ms = 10000;
+       ctrlcmd->length     = 0;
+       ctrlcmd->value      = NULL;
+
+
+       D("%s\n", __func__);
+
+       g_pmsm_v4l2_dev->drv->ctrl(
+               g_pmsm_v4l2_dev->drv->sync,
+               ctrlcmd);
+
+       return 0;
+}
+
+static int msm_v4l2_enum_fmt_overlay(struct file *f,
+                                    void *pctx, struct v4l2_fmtdesc *pfmtdesc)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+static int msm_v4l2_enum_fmt_cap(struct file *f,
+                                void *pctx, struct v4l2_fmtdesc *pfmtdesc)
+{
+       D("%s\n", __func__);
+
+       switch (pfmtdesc->index) {
+       case 0:
+               pfmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               pfmtdesc->flags = 0;
+               strncpy(pfmtdesc->description, "YUV 4:2:0",
+                       sizeof(pfmtdesc->description));
+               pfmtdesc->pixelformat = V4L2_PIX_FMT_YVU420;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int msm_v4l2_g_fmt_cap(struct file *f,
+                             void *pctx, struct v4l2_format *pfmt)
+{
+       D("%s\n", __func__);
+       pfmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       pfmt->fmt.pix.width = MSM_V4L2_WIDTH;
+       pfmt->fmt.pix.height = MSM_V4L2_HEIGHT;
+       pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
+       pfmt->fmt.pix.field = V4L2_FIELD_ANY;
+       pfmt->fmt.pix.bytesperline = 0;
+       pfmt->fmt.pix.sizeimage = 0;
+       pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+       pfmt->fmt.pix.priv = 0;
+       return 0;
+}
+
+static int msm_v4l2_s_fmt_cap(struct file *f,
+                             void *pctx, struct v4l2_format *pfmt)
+{
+  struct msm_ctrl_cmd *ctrlcmd;
+
+       D("%s\n", __func__);
+
+       ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
+       if (!ctrlcmd) {
+               CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
+               return -ENOMEM;
+       }
+
+  ctrlcmd->type       = MSM_V4L2_VID_CAP_TYPE;
+  ctrlcmd->length     = sizeof(struct v4l2_format);
+  ctrlcmd->value      = pfmt;
+  ctrlcmd->timeout_ms = 10000;
+
+       if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -1;
+
+#if 0
+       /* FIXEME */
+       if (pfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YVU420)
+               return -EINVAL;
+#endif
+
+       /* Ok, but check other params, too. */
+
+#if 0
+       memcpy(&g_pmsm_v4l2_dev->current_pix_format.fmt.pix, pfmt,
+              sizeof(struct v4l2_format));
+#endif
+
+       g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
+
+       return 0;
+}
+
+static int msm_v4l2_g_fmt_overlay(struct file *f,
+                                 void *pctx, struct v4l2_format *pfmt)
+{
+       D("%s\n", __func__);
+       pfmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+       pfmt->fmt.pix.width = MSM_V4L2_WIDTH;
+       pfmt->fmt.pix.height = MSM_V4L2_HEIGHT;
+       pfmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
+       pfmt->fmt.pix.field = V4L2_FIELD_ANY;
+       pfmt->fmt.pix.bytesperline = 0;
+       pfmt->fmt.pix.sizeimage = 0;
+       pfmt->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+       pfmt->fmt.pix.priv = 0;
+       return 0;
+}
+
+static int msm_v4l2_s_fmt_overlay(struct file *f,
+                                 void *pctx, struct v4l2_format *pfmt)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+static int msm_v4l2_g_jpegcomp(struct file *f,
+                              void *pctx, struct v4l2_jpegcompression *pcomp)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+static int msm_v4l2_s_jpegcomp(struct file *f,
+                              void *pctx, struct v4l2_jpegcompression *pcomp)
+{
+       D("%s\n", __func__);
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+int msm_v4l2_read_proc(char *pbuf, char **start, off_t offset,
+                      int count, int *eof, void *data)
+{
+       int len = 0;
+       len += snprintf(pbuf, strlen("stats\n") + 1, "stats\n");
+
+       if (g_pmsm_v4l2_dev) {
+               len += snprintf(pbuf, strlen("mode: ") + 1, "mode: ");
+
+               if (g_pmsm_v4l2_dev->current_cap_format.type
+                   == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       len += snprintf(pbuf, strlen("capture\n") + 1,
+                                       "capture\n");
+               else
+                       len += snprintf(pbuf, strlen("unknown\n") + 1,
+                                       "unknown\n");
+
+               len += snprintf(pbuf, 21, "resolution: %dx%d\n",
+                               g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
+                               width,
+                               g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
+                               height);
+
+               len += snprintf(pbuf,
+                               strlen("pixel format: ") + 1, "pixel format: ");
+               if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.pixelformat
+                   == V4L2_PIX_FMT_YVU420)
+                       len += snprintf(pbuf, strlen("yvu420\n") + 1,
+                                       "yvu420\n");
+               else
+                       len += snprintf(pbuf, strlen("unknown\n") + 1,
+                                       "unknown\n");
+
+               len += snprintf(pbuf, strlen("colorspace: ") + 1,
+                               "colorspace: ");
+               if (g_pmsm_v4l2_dev->current_cap_format.fmt.pix.colorspace
+                   == V4L2_COLORSPACE_JPEG)
+                       len += snprintf(pbuf, strlen("jpeg\n") + 1, "jpeg\n");
+               else
+                       len += snprintf(pbuf, strlen("unknown\n") + 1,
+                                       "unknown\n");
+       }
+
+       *eof = 1;
+       return len;
+}
+#endif
+
+static const struct v4l2_file_operations msm_v4l2_fops = {
+       .owner = THIS_MODULE,
+       .open = msm_v4l2_open,
+       .poll = msm_v4l2_poll,
+       .release = msm_v4l2_release,
+       .ioctl = msm_v4l2_ioctl,
+};
+
+static void msm_v4l2_dev_init(struct msm_v4l2_device *pmsm_v4l2_dev)
+{
+       pmsm_v4l2_dev->read_queue_lock =
+           __SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev->read_queue_lock);
+       INIT_LIST_HEAD(&pmsm_v4l2_dev->read_queue);
+}
+
+static int msm_v4l2_try_fmt_cap(struct file *file,
+                                void *fh, struct v4l2_format *f)
+{
+       /* FIXME */
+       return 0;
+}
+
+static int mm_v4l2_try_fmt_type_private(struct file *file,
+                                        void *fh, struct v4l2_format *f)
+{
+       /* FIXME */
+       return 0;
+}
+
+/*
+ * should the following structure be used instead of the code in the function?
+ * static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+ *     .vidioc_querycap = ....
+ * }
+ */
+static const struct v4l2_ioctl_ops msm_ioctl_ops = {
+       .vidioc_querycap = msm_v4l2_querycap,
+       .vidioc_s_std = msm_v4l2_s_std,
+
+       .vidioc_queryctrl = msm_v4l2_queryctrl,
+       .vidioc_g_ctrl = msm_v4l2_g_ctrl,
+       .vidioc_s_ctrl = msm_v4l2_s_ctrl,
+
+       .vidioc_reqbufs = msm_v4l2_reqbufs,
+       .vidioc_querybuf = msm_v4l2_querybuf,
+       .vidioc_qbuf = msm_v4l2_qbuf,
+       .vidioc_dqbuf = msm_v4l2_dqbuf,
+
+       .vidioc_streamon = msm_v4l2_streamon,
+       .vidioc_streamoff = msm_v4l2_streamoff,
+
+       .vidioc_enum_fmt_vid_overlay = msm_v4l2_enum_fmt_overlay,
+       .vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt_cap,
+
+       .vidioc_try_fmt_vid_cap = msm_v4l2_try_fmt_cap,
+       .vidioc_try_fmt_type_private = mm_v4l2_try_fmt_type_private,
+
+       .vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt_cap,
+       .vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt_cap,
+       .vidioc_g_fmt_vid_overlay = msm_v4l2_g_fmt_overlay,
+       .vidioc_s_fmt_vid_overlay = msm_v4l2_s_fmt_overlay,
+       .vidioc_overlay = msm_v4l2_overlay,
+
+       .vidioc_g_jpegcomp = msm_v4l2_g_jpegcomp,
+       .vidioc_s_jpegcomp = msm_v4l2_s_jpegcomp,
+};
+
+static int msm_v4l2_video_dev_init(struct video_device *pvd)
+{
+       strncpy(pvd->name, MSM_APPS_ID_V4L2, sizeof(pvd->name));
+       pvd->vfl_type = 1;
+       pvd->fops = &msm_v4l2_fops;
+       pvd->release = msm_v4l2_release_dev;
+       pvd->minor = -1;
+       pvd->ioctl_ops = &msm_ioctl_ops;
+       return msm_v4l2_register(g_pmsm_v4l2_dev->drv);
+}
+
+static int __init msm_v4l2_init(void)
+{
+       int rc = -ENOMEM;
+       struct video_device *pvdev = NULL;
+       struct msm_v4l2_device *pmsm_v4l2_dev = NULL;
+       D("%s\n", __func__);
+
+       pvdev = video_device_alloc();
+       if (pvdev == NULL)
+               return rc;
+
+       pmsm_v4l2_dev =
+               kzalloc(sizeof(struct msm_v4l2_device), GFP_KERNEL);
+       if (pmsm_v4l2_dev == NULL) {
+               video_device_release(pvdev);
+               return rc;
+       }
+
+       msm_v4l2_dev_init(pmsm_v4l2_dev);
+
+       g_pmsm_v4l2_dev = pmsm_v4l2_dev;
+       g_pmsm_v4l2_dev->pvdev = pvdev;
+
+       g_pmsm_v4l2_dev->drv =
+               kzalloc(sizeof(struct msm_v4l2_driver), GFP_KERNEL);
+       if (!g_pmsm_v4l2_dev->drv) {
+               video_device_release(pvdev);
+               kfree(pmsm_v4l2_dev);
+               return rc;
+       }
+
+       rc = msm_v4l2_video_dev_init(pvdev);
+       if (rc < 0) {
+               video_device_release(pvdev);
+               kfree(g_pmsm_v4l2_dev->drv);
+               kfree(pmsm_v4l2_dev);
+               return rc;
+       }
+
+       if (video_register_device(pvdev, VFL_TYPE_GRABBER,
+           MSM_V4L2_DEVNUM_YUV)) {
+               D("failed to register device\n");
+               video_device_release(pvdev);
+               kfree(g_pmsm_v4l2_dev);
+               g_pmsm_v4l2_dev = NULL;
+               return -ENOENT;
+       }
+#ifdef CONFIG_PROC_FS
+       create_proc_read_entry(MSM_V4L2_PROC_NAME,
+                              0, NULL, msm_v4l2_read_proc, NULL);
+#endif
+
+       return 0;
+}
+
+static void __exit msm_v4l2_exit(void)
+{
+       struct video_device *pvdev = g_pmsm_v4l2_dev->pvdev;
+       D("%s\n", __func__);
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry(MSM_V4L2_PROC_NAME, NULL);
+#endif
+       video_unregister_device(pvdev);
+       video_device_release(pvdev);
+
+       msm_v4l2_unregister(g_pmsm_v4l2_dev->drv);
+
+       kfree(g_pmsm_v4l2_dev->drv);
+       g_pmsm_v4l2_dev->drv = NULL;
+
+       kfree(g_pmsm_v4l2_dev);
+       g_pmsm_v4l2_dev = NULL;
+}
+
+module_init(msm_v4l2_init);
+module_exit(msm_v4l2_exit);
+
+MODULE_DESCRIPTION("MSM V4L2 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/dream/camera/msm_vfe7x.c b/drivers/staging/dream/camera/msm_vfe7x.c
new file mode 100644 (file)
index 0000000..5de96c5
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include <linux/msm_adsp.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <mach/msm_adsp.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include "msm_vfe7x.h"
+
+#define QDSP_CMDQUEUE QDSP_vfeCommandQueue
+
+#define VFE_RESET_CMD 0
+#define VFE_START_CMD 1
+#define VFE_STOP_CMD  2
+#define VFE_FRAME_ACK 20
+#define STATS_AF_ACK  21
+#define STATS_WE_ACK  22
+
+#define MSG_STOP_ACK  1
+#define MSG_SNAPSHOT  2
+#define MSG_OUTPUT1   6
+#define MSG_OUTPUT2   7
+#define MSG_STATS_AF  8
+#define MSG_STATS_WE  9
+
+static struct msm_adsp_module *qcam_mod;
+static struct msm_adsp_module *vfe_mod;
+static struct msm_vfe_callback *resp;
+static void *extdata;
+static uint32_t extlen;
+
+struct mutex vfe_lock;
+static void     *vfe_syncdata;
+static uint8_t vfestopped;
+
+static struct stop_event stopevent;
+
+static void vfe_7x_convert(struct msm_vfe_phy_info *pinfo,
+               enum vfe_resp_msg type,
+               void *data, void **ext, int32_t *elen)
+{
+       switch (type) {
+       case VFE_MSG_OUTPUT1:
+       case VFE_MSG_OUTPUT2: {
+               pinfo->y_phy = ((struct vfe_endframe *)data)->y_address;
+               pinfo->cbcr_phy =
+                       ((struct vfe_endframe *)data)->cbcr_address;
+
+               CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+                                pinfo->y_phy, pinfo->cbcr_phy);
+
+               ((struct vfe_frame_extra *)extdata)->bl_evencol =
+               ((struct vfe_endframe *)data)->blacklevelevencolumn;
+
+               ((struct vfe_frame_extra *)extdata)->bl_oddcol =
+               ((struct vfe_endframe *)data)->blackleveloddcolumn;
+
+               ((struct vfe_frame_extra *)extdata)->g_def_p_cnt =
+               ((struct vfe_endframe *)data)->greendefectpixelcount;
+
+               ((struct vfe_frame_extra *)extdata)->r_b_def_p_cnt =
+               ((struct vfe_endframe *)data)->redbluedefectpixelcount;
+
+               *ext  = extdata;
+               *elen = extlen;
+       }
+               break;
+
+       case VFE_MSG_STATS_AF:
+       case VFE_MSG_STATS_WE:
+               pinfo->sbuf_phy = *(uint32_t *)data;
+               break;
+
+       default:
+               break;
+       } /* switch */
+}
+
+static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
+               void (*getevent)(void *ptr, size_t len))
+{
+       uint32_t evt_buf[3];
+       struct msm_vfe_resp *rp;
+       void *data;
+
+       len = (id == (uint16_t)-1) ? 0 : len;
+       data = resp->vfe_alloc(sizeof(struct msm_vfe_resp) + len, vfe_syncdata);
+
+       if (!data) {
+               pr_err("rp: cannot allocate buffer\n");
+               return;
+       }
+       rp = (struct msm_vfe_resp *)data;
+       rp->evt_msg.len = len;
+
+       if (id == ((uint16_t)-1)) {
+               /* event */
+               rp->type           = VFE_EVENT;
+               rp->evt_msg.type   = MSM_CAMERA_EVT;
+               getevent(evt_buf, sizeof(evt_buf));
+               rp->evt_msg.msg_id = evt_buf[0];
+               resp->vfe_resp(rp, MSM_CAM_Q_VFE_EVT, vfe_syncdata);
+       } else {
+               /* messages */
+               rp->evt_msg.type   = MSM_CAMERA_MSG;
+               rp->evt_msg.msg_id = id;
+               rp->evt_msg.data = rp + 1;
+               getevent(rp->evt_msg.data, len);
+
+               switch (rp->evt_msg.msg_id) {
+               case MSG_SNAPSHOT:
+                       rp->type = VFE_MSG_SNAPSHOT;
+                       break;
+
+               case MSG_OUTPUT1:
+                       rp->type = VFE_MSG_OUTPUT1;
+                       vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT1,
+                               rp->evt_msg.data, &(rp->extdata),
+                               &(rp->extlen));
+                       break;
+
+               case MSG_OUTPUT2:
+                       rp->type = VFE_MSG_OUTPUT2;
+                       vfe_7x_convert(&(rp->phy), VFE_MSG_OUTPUT2,
+                                       rp->evt_msg.data, &(rp->extdata),
+                                       &(rp->extlen));
+                       break;
+
+               case MSG_STATS_AF:
+                       rp->type = VFE_MSG_STATS_AF;
+                       vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_AF,
+                                       rp->evt_msg.data, NULL, NULL);
+                       break;
+
+               case MSG_STATS_WE:
+                       rp->type = VFE_MSG_STATS_WE;
+                       vfe_7x_convert(&(rp->phy), VFE_MSG_STATS_WE,
+                                       rp->evt_msg.data, NULL, NULL);
+
+                       CDBG("MSG_STATS_WE: phy = 0x%x\n", rp->phy.sbuf_phy);
+                       break;
+
+               case MSG_STOP_ACK:
+                       rp->type = VFE_MSG_GENERAL;
+                       stopevent.state = 1;
+                       wake_up(&stopevent.wait);
+                       break;
+
+
+               default:
+                       rp->type = VFE_MSG_GENERAL;
+                       break;
+               }
+               resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, vfe_syncdata);
+       }
+}
+
+static struct msm_adsp_ops vfe_7x_sync = {
+       .event = vfe_7x_ops,
+};
+
+static int vfe_7x_enable(struct camera_enable_cmd *enable)
+{
+       int rc = -EFAULT;
+
+       if (!strcmp(enable->name, "QCAMTASK"))
+               rc = msm_adsp_enable(qcam_mod);
+       else if (!strcmp(enable->name, "VFETASK"))
+               rc = msm_adsp_enable(vfe_mod);
+
+       return rc;
+}
+
+static int vfe_7x_disable(struct camera_enable_cmd *enable,
+               struct platform_device *dev __attribute__((unused)))
+{
+       int rc = -EFAULT;
+
+       if (!strcmp(enable->name, "QCAMTASK"))
+               rc = msm_adsp_disable(qcam_mod);
+       else if (!strcmp(enable->name, "VFETASK"))
+               rc = msm_adsp_disable(vfe_mod);
+
+       return rc;
+}
+
+static int vfe_7x_stop(void)
+{
+       int rc = 0;
+       uint32_t stopcmd = VFE_STOP_CMD;
+       rc = msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+                               &stopcmd, sizeof(uint32_t));
+       if (rc < 0) {
+               CDBG("%s:%d: failed rc = %d \n", __func__, __LINE__, rc);
+               return rc;
+       }
+
+       stopevent.state = 0;
+       rc = wait_event_timeout(stopevent.wait,
+               stopevent.state != 0,
+               msecs_to_jiffies(stopevent.timeout));
+
+       return rc;
+}
+
+static void vfe_7x_release(struct platform_device *pdev)
+{
+       mutex_lock(&vfe_lock);
+       vfe_syncdata = NULL;
+       mutex_unlock(&vfe_lock);
+
+       if (!vfestopped) {
+               CDBG("%s:%d:Calling vfe_7x_stop()\n", __func__, __LINE__);
+               vfe_7x_stop();
+       } else
+               vfestopped = 0;
+
+       msm_adsp_disable(qcam_mod);
+       msm_adsp_disable(vfe_mod);
+
+       msm_adsp_put(qcam_mod);
+       msm_adsp_put(vfe_mod);
+
+       msm_camio_disable(pdev);
+
+       kfree(extdata);
+       extlen = 0;
+}
+
+static int vfe_7x_init(struct msm_vfe_callback *presp,
+       struct platform_device *dev)
+{
+       int rc = 0;
+
+       init_waitqueue_head(&stopevent.wait);
+       stopevent.timeout = 200;
+       stopevent.state = 0;
+
+       if (presp && presp->vfe_resp)
+               resp = presp;
+       else
+               return -EFAULT;
+
+       /* Bring up all the required GPIOs and Clocks */
+       rc = msm_camio_enable(dev);
+       if (rc < 0)
+               return rc;
+
+       msm_camio_camif_pad_reg_reset();
+
+       extlen = sizeof(struct vfe_frame_extra);
+
+       extdata =
+               kmalloc(sizeof(extlen), GFP_ATOMIC);
+       if (!extdata) {
+               rc = -ENOMEM;
+               goto init_fail;
+       }
+
+       rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
+       if (rc) {
+               rc = -EBUSY;
+               goto get_qcam_fail;
+       }
+
+       rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
+       if (rc) {
+               rc = -EBUSY;
+               goto get_vfe_fail;
+       }
+
+       return 0;
+
+get_vfe_fail:
+       msm_adsp_put(qcam_mod);
+get_qcam_fail:
+       kfree(extdata);
+init_fail:
+       extlen = 0;
+       return rc;
+}
+
+static int vfe_7x_config_axi(int mode,
+       struct axidata *ad, struct axiout *ao)
+{
+       struct msm_pmem_region *regptr;
+       unsigned long *bptr;
+       int    cnt;
+
+       int rc = 0;
+
+       if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+               regptr = ad->region;
+
+               CDBG("bufnum1 = %d\n", ad->bufnum1);
+               CDBG("config_axi1: O1, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+                       regptr->paddr, regptr->y_off, regptr->cbcr_off);
+
+               bptr = &ao->output1buffer1_y_phy;
+               for (cnt = 0; cnt < ad->bufnum1; cnt++) {
+                       *bptr = regptr->paddr + regptr->y_off;
+                       bptr++;
+                       *bptr = regptr->paddr + regptr->cbcr_off;
+
+                       bptr++;
+                       regptr++;
+               }
+
+               regptr--;
+               for (cnt = 0; cnt < (8 - ad->bufnum1); cnt++) {
+                       *bptr = regptr->paddr + regptr->y_off;
+                       bptr++;
+                       *bptr = regptr->paddr + regptr->cbcr_off;
+                       bptr++;
+               }
+       } /* if OUTPUT1 or Both */
+
+       if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+               regptr = &(ad->region[ad->bufnum1]);
+
+               CDBG("bufnum2 = %d\n", ad->bufnum2);
+               CDBG("config_axi2: O2, phy = 0x%lx, y_off = %d, cbcr_off =%d\n",
+                       regptr->paddr, regptr->y_off, regptr->cbcr_off);
+
+               bptr = &ao->output2buffer1_y_phy;
+               for (cnt = 0; cnt < ad->bufnum2; cnt++) {
+                       *bptr = regptr->paddr + regptr->y_off;
+                       bptr++;
+                       *bptr = regptr->paddr + regptr->cbcr_off;
+
+                       bptr++;
+                       regptr++;
+               }
+
+               regptr--;
+               for (cnt = 0; cnt < (8 - ad->bufnum2); cnt++) {
+                       *bptr = regptr->paddr + regptr->y_off;
+                       bptr++;
+                       *bptr = regptr->paddr + regptr->cbcr_off;
+                       bptr++;
+               }
+       }
+
+       return rc;
+}
+
+static int vfe_7x_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+       struct msm_pmem_region *regptr;
+       unsigned char buf[256];
+
+       struct vfe_stats_ack sack;
+       struct axidata *axid;
+       uint32_t i;
+
+       struct vfe_stats_we_cfg *scfg = NULL;
+       struct vfe_stats_af_cfg *sfcfg = NULL;
+
+       struct axiout *axio = NULL;
+       void   *cmd_data = NULL;
+       void   *cmd_data_alloc = NULL;
+       long rc = 0;
+       struct msm_vfe_command_7k *vfecmd;
+
+       vfecmd =
+                       kmalloc(sizeof(struct msm_vfe_command_7k),
+                               GFP_ATOMIC);
+       if (!vfecmd) {
+               pr_err("vfecmd alloc failed!\n");
+               return -ENOMEM;
+       }
+
+       if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+           cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+           cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+               if (copy_from_user(vfecmd,
+                               (void __user *)(cmd->value),
+                               sizeof(struct msm_vfe_command_7k))) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+       }
+
+       switch (cmd->cmd_type) {
+       case CMD_STATS_ENABLE:
+       case CMD_STATS_AXI_CFG: {
+               axid = data;
+               if (!axid) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               scfg =
+                       kmalloc(sizeof(struct vfe_stats_we_cfg),
+                               GFP_ATOMIC);
+               if (!scfg) {
+                       rc = -ENOMEM;
+                       goto config_failure;
+               }
+
+               if (copy_from_user(scfg,
+                                       (void __user *)(vfecmd->value),
+                                       vfecmd->length)) {
+
+                       rc = -EFAULT;
+                       goto config_done;
+               }
+
+               CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
+                       axid->bufnum1, scfg->wb_expstatsenable);
+
+               if (axid->bufnum1 > 0) {
+                       regptr = axid->region;
+
+                       for (i = 0; i < axid->bufnum1; i++) {
+
+                               CDBG("STATS_ENABLE, phy = 0x%lx\n",
+                                       regptr->paddr);
+
+                               scfg->wb_expstatoutputbuffer[i] =
+                                       (void *)regptr->paddr;
+                               regptr++;
+                       }
+
+                       cmd_data = scfg;
+
+               } else {
+                       rc = -EINVAL;
+                       goto config_done;
+               }
+       }
+               break;
+
+       case CMD_STATS_AF_ENABLE:
+       case CMD_STATS_AF_AXI_CFG: {
+               axid = data;
+               if (!axid) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               sfcfg =
+                       kmalloc(sizeof(struct vfe_stats_af_cfg),
+                               GFP_ATOMIC);
+
+               if (!sfcfg) {
+                       rc = -ENOMEM;
+                       goto config_failure;
+               }
+
+               if (copy_from_user(sfcfg,
+                                       (void __user *)(vfecmd->value),
+                                       vfecmd->length)) {
+
+                       rc = -EFAULT;
+                       goto config_done;
+               }
+
+               CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
+                       axid->bufnum1, sfcfg->af_enable);
+
+               if (axid->bufnum1 > 0) {
+                       regptr = axid->region;
+
+                       for (i = 0; i < axid->bufnum1; i++) {
+
+                               CDBG("STATS_ENABLE, phy = 0x%lx\n",
+                                       regptr->paddr);
+
+                               sfcfg->af_outbuf[i] =
+                                       (void *)regptr->paddr;
+
+                               regptr++;
+                       }
+
+                       cmd_data = sfcfg;
+
+               } else {
+                       rc = -EINVAL;
+                       goto config_done;
+               }
+       }
+               break;
+
+       case CMD_FRAME_BUF_RELEASE: {
+               struct msm_frame *b;
+               unsigned long p;
+               struct vfe_outputack fack;
+               if (!data)  {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               b = (struct msm_frame *)(cmd->value);
+               p = *(unsigned long *)data;
+
+               fack.header = VFE_FRAME_ACK;
+
+               fack.output2newybufferaddress =
+                       (void *)(p + b->y_off);
+
+               fack.output2newcbcrbufferaddress =
+                       (void *)(p + b->cbcr_off);
+
+               vfecmd->queue = QDSP_CMDQUEUE;
+               vfecmd->length = sizeof(struct vfe_outputack);
+               cmd_data = &fack;
+       }
+               break;
+
+       case CMD_SNAP_BUF_RELEASE:
+               break;
+
+       case CMD_STATS_BUF_RELEASE: {
+               CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
+               if (!data) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               sack.header = STATS_WE_ACK;
+               sack.bufaddr = (void *)*(uint32_t *)data;
+
+               vfecmd->queue  = QDSP_CMDQUEUE;
+               vfecmd->length = sizeof(struct vfe_stats_ack);
+               cmd_data = &sack;
+       }
+               break;
+
+       case CMD_STATS_AF_BUF_RELEASE: {
+               CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
+               if (!data) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               sack.header = STATS_AF_ACK;
+               sack.bufaddr = (void *)*(uint32_t *)data;
+
+               vfecmd->queue  = QDSP_CMDQUEUE;
+               vfecmd->length = sizeof(struct vfe_stats_ack);
+               cmd_data = &sack;
+       }
+               break;
+
+       case CMD_GENERAL:
+       case CMD_STATS_DISABLE: {
+               if (vfecmd->length > 256) {
+                       cmd_data_alloc =
+                       cmd_data = kmalloc(vfecmd->length, GFP_ATOMIC);
+                       if (!cmd_data) {
+                               rc = -ENOMEM;
+                               goto config_failure;
+                       }
+               } else
+                       cmd_data = buf;
+
+               if (copy_from_user(cmd_data,
+                                       (void __user *)(vfecmd->value),
+                                       vfecmd->length)) {
+
+                       rc = -EFAULT;
+                       goto config_done;
+               }
+
+               if (vfecmd->queue == QDSP_CMDQUEUE) {
+                       switch (*(uint32_t *)cmd_data) {
+                       case VFE_RESET_CMD:
+                               msm_camio_vfe_blk_reset();
+                               msm_camio_camif_pad_reg_reset_2();
+                               vfestopped = 0;
+                               break;
+
+                       case VFE_START_CMD:
+                               msm_camio_camif_pad_reg_reset_2();
+                               vfestopped = 0;
+                               break;
+
+                       case VFE_STOP_CMD:
+                               vfestopped = 1;
+                               goto config_send;
+
+                       default:
+                               break;
+                       }
+               } /* QDSP_CMDQUEUE */
+       }
+               break;
+
+       case CMD_AXI_CFG_OUT1: {
+               axid = data;
+               if (!axid) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+               if (!axio) {
+                       rc = -ENOMEM;
+                       goto config_failure;
+               }
+
+               if (copy_from_user(axio, (void *)(vfecmd->value),
+                                       sizeof(struct axiout))) {
+                       rc = -EFAULT;
+                       goto config_done;
+               }
+
+               vfe_7x_config_axi(OUTPUT_1, axid, axio);
+
+               cmd_data = axio;
+       }
+               break;
+
+       case CMD_AXI_CFG_OUT2:
+       case CMD_RAW_PICT_AXI_CFG: {
+               axid = data;
+               if (!axid) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+               if (!axio) {
+                       rc = -ENOMEM;
+                       goto config_failure;
+               }
+
+               if (copy_from_user(axio, (void __user *)(vfecmd->value),
+                                       sizeof(struct axiout))) {
+                       rc = -EFAULT;
+                       goto config_done;
+               }
+
+               vfe_7x_config_axi(OUTPUT_2, axid, axio);
+               cmd_data = axio;
+       }
+               break;
+
+       case CMD_AXI_CFG_SNAP_O1_AND_O2: {
+               axid = data;
+               if (!axid) {
+                       rc = -EFAULT;
+                       goto config_failure;
+               }
+
+               axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+               if (!axio) {
+                       rc = -ENOMEM;
+                       goto config_failure;
+               }
+
+               if (copy_from_user(axio, (void __user *)(vfecmd->value),
+                                       sizeof(struct axiout))) {
+                       rc = -EFAULT;
+                       goto config_done;
+               }
+
+               vfe_7x_config_axi(OUTPUT_1_AND_2, axid, axio);
+
+               cmd_data = axio;
+       }
+               break;
+
+       default:
+               break;
+       } /* switch */
+
+       if (vfestopped)
+               goto config_done;
+
+config_send:
+       CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+       rc = msm_adsp_write(vfe_mod, vfecmd->queue,
+                               cmd_data, vfecmd->length);
+
+config_done:
+       if (cmd_data_alloc != NULL)
+               kfree(cmd_data_alloc);
+
+config_failure:
+       kfree(scfg);
+       kfree(axio);
+       kfree(vfecmd);
+       return rc;
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+       mutex_init(&vfe_lock);
+       fptr->vfe_init    = vfe_7x_init;
+       fptr->vfe_enable  = vfe_7x_enable;
+       fptr->vfe_config  = vfe_7x_config;
+       fptr->vfe_disable = vfe_7x_disable;
+       fptr->vfe_release = vfe_7x_release;
+       vfe_syncdata = data;
+}
diff --git a/drivers/staging/dream/camera/msm_vfe7x.h b/drivers/staging/dream/camera/msm_vfe7x.h
new file mode 100644 (file)
index 0000000..be3e9ad
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+#ifndef __MSM_VFE7X_H__
+#define __MSM_VFE7X_H__
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+
+struct vfe_frame_extra {
+       uint32_t  bl_evencol;
+       uint32_t  bl_oddcol;
+       uint16_t  g_def_p_cnt;
+       uint16_t  r_b_def_p_cnt;
+};
+
+struct vfe_endframe {
+       uint32_t      y_address;
+       uint32_t      cbcr_address;
+
+       unsigned int  blacklevelevencolumn:23;
+       uint16_t      reserved1:9;
+       unsigned int  blackleveloddcolumn:23;
+       uint16_t      reserved2:9;
+
+       uint16_t      greendefectpixelcount:8;
+       uint16_t      reserved3:8;
+       uint16_t      redbluedefectpixelcount:8;
+       uint16_t      reserved4:8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_outputack {
+       uint32_t  header;
+       void      *output2newybufferaddress;
+       void      *output2newcbcrbufferaddress;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_stats_ack {
+       uint32_t header;
+       /* MUST BE 64 bit ALIGNED */
+       void     *bufaddr;
+} __attribute__((packed, aligned(4)));
+
+/* AXI Output Config Command sent to DSP */
+struct axiout {
+       uint32_t            cmdheader:32;
+       int                 outputmode:3;
+       uint8_t             format:2;
+       uint32_t            /* reserved */ : 27;
+
+       /* AXI Output 1 Y Configuration, Part 1 */
+       uint32_t            out1yimageheight:12;
+       uint32_t            /* reserved */ : 4;
+       uint32_t            out1yimagewidthin64bitwords:10;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 1 Y Configuration, Part 2 */
+       uint8_t             out1yburstlen:2;
+       uint32_t            out1ynumrows:12;
+       uint32_t            out1yrowincin64bitincs:12;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 1 CbCr Configuration, Part 1 */
+       uint32_t            out1cbcrimageheight:12;
+       uint32_t            /* reserved */ : 4;
+       uint32_t            out1cbcrimagewidthin64bitwords:10;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 1 CbCr Configuration, Part 2 */
+       uint8_t             out1cbcrburstlen:2;
+       uint32_t            out1cbcrnumrows:12;
+       uint32_t            out1cbcrrowincin64bitincs:12;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 2 Y Configuration, Part 1 */
+       uint32_t            out2yimageheight:12;
+       uint32_t            /* reserved */ : 4;
+       uint32_t            out2yimagewidthin64bitwords:10;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 2 Y Configuration, Part 2 */
+       uint8_t             out2yburstlen:2;
+       uint32_t            out2ynumrows:12;
+       uint32_t            out2yrowincin64bitincs:12;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 2 CbCr Configuration, Part 1 */
+       uint32_t            out2cbcrimageheight:12;
+       uint32_t            /* reserved */ : 4;
+       uint32_t            out2cbcrimagewidtein64bitwords:10;
+       uint32_t            /* reserved */ : 6;
+
+       /* AXI Output 2 CbCr Configuration, Part 2 */
+       uint8_t             out2cbcrburstlen:2;
+       uint32_t            out2cbcrnumrows:12;
+       uint32_t            out2cbcrrowincin64bitincs:12;
+       uint32_t            /* reserved */ : 6;
+
+       /* Address configuration:
+        * output1 phisycal address */
+       unsigned long   output1buffer1_y_phy;
+       unsigned long   output1buffer1_cbcr_phy;
+       unsigned long   output1buffer2_y_phy;
+       unsigned long   output1buffer2_cbcr_phy;
+       unsigned long   output1buffer3_y_phy;
+       unsigned long   output1buffer3_cbcr_phy;
+       unsigned long   output1buffer4_y_phy;
+       unsigned long   output1buffer4_cbcr_phy;
+       unsigned long   output1buffer5_y_phy;
+       unsigned long   output1buffer5_cbcr_phy;
+       unsigned long   output1buffer6_y_phy;
+       unsigned long   output1buffer6_cbcr_phy;
+       unsigned long   output1buffer7_y_phy;
+       unsigned long   output1buffer7_cbcr_phy;
+       unsigned long   output1buffer8_y_phy;
+       unsigned long   output1buffer8_cbcr_phy;
+
+       /* output2 phisycal address */
+       unsigned long   output2buffer1_y_phy;
+       unsigned long   output2buffer1_cbcr_phy;
+       unsigned long   output2buffer2_y_phy;
+       unsigned long   output2buffer2_cbcr_phy;
+       unsigned long   output2buffer3_y_phy;
+       unsigned long   output2buffer3_cbcr_phy;
+       unsigned long   output2buffer4_y_phy;
+       unsigned long   output2buffer4_cbcr_phy;
+       unsigned long   output2buffer5_y_phy;
+       unsigned long   output2buffer5_cbcr_phy;
+       unsigned long   output2buffer6_y_phy;
+       unsigned long   output2buffer6_cbcr_phy;
+       unsigned long   output2buffer7_y_phy;
+       unsigned long   output2buffer7_cbcr_phy;
+       unsigned long   output2buffer8_y_phy;
+       unsigned long   output2buffer8_cbcr_phy;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_stats_we_cfg {
+       uint32_t       header;
+
+       /* White Balance/Exposure Statistic Selection */
+       uint8_t        wb_expstatsenable:1;
+       uint8_t        wb_expstatbuspriorityselection:1;
+       unsigned int   wb_expstatbuspriorityvalue:4;
+       unsigned int   /* reserved */ : 26;
+
+       /* White Balance/Exposure Statistic Configuration, Part 1 */
+       uint8_t        exposurestatregions:1;
+       uint8_t        exposurestatsubregions:1;
+       unsigned int   /* reserved */ : 14;
+
+       unsigned int   whitebalanceminimumy:8;
+       unsigned int   whitebalancemaximumy:8;
+
+       /* White Balance/Exposure Statistic Configuration, Part 2 */
+       uint8_t wb_expstatslopeofneutralregionline[
+               NUM_WB_EXP_NEUTRAL_REGION_LINES];
+
+       /* White Balance/Exposure Statistic Configuration, Part 3 */
+       unsigned int   wb_expstatcrinterceptofneutralregionline2:12;
+       unsigned int   /* reserved */ : 4;
+       unsigned int   wb_expstatcbinterceptofneutralreginnline1:12;
+       unsigned int    /* reserved */ : 4;
+
+       /* White Balance/Exposure Statistic Configuration, Part 4 */
+       unsigned int   wb_expstatcrinterceptofneutralregionline4:12;
+       unsigned int   /* reserved */ : 4;
+       unsigned int   wb_expstatcbinterceptofneutralregionline3:12;
+       unsigned int   /* reserved */ : 4;
+
+       /* White Balance/Exposure Statistic Output Buffer Header */
+       unsigned int   wb_expmetricheaderpattern:8;
+       unsigned int   /* reserved */ : 24;
+
+       /* White Balance/Exposure Statistic Output Buffers-MUST
+       * BE 64 bit ALIGNED */
+       void  *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS];
+} __attribute__((packed, aligned(4)));
+
+struct vfe_stats_af_cfg {
+       uint32_t header;
+
+       /* Autofocus Statistic Selection */
+       uint8_t       af_enable:1;
+       uint8_t       af_busprioritysel:1;
+       unsigned int  af_buspriorityval:4;
+       unsigned int  /* reserved */ : 26;
+
+       /* Autofocus Statistic Configuration, Part 1 */
+       unsigned int  af_singlewinvoffset:12;
+       unsigned int  /* reserved */ : 4;
+       unsigned int  af_singlewinhoffset:12;
+       unsigned int  /* reserved */ : 3;
+       uint8_t       af_winmode:1;
+
+       /* Autofocus Statistic Configuration, Part 2 */
+       unsigned int  af_singglewinvh:11;
+       unsigned int  /* reserved */ : 5;
+       unsigned int  af_singlewinhw:11;
+       unsigned int  /* reserved */ : 5;
+
+       /* Autofocus Statistic Configuration, Parts 3-6 */
+       uint8_t       af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS];
+
+       /* Autofocus Statistic Configuration, Part 7 */
+       signed int    af_metrichpfcoefa00:5;
+       signed int    af_metrichpfcoefa04:5;
+       unsigned int  af_metricmaxval:11;
+       uint8_t       af_metricsel:1;
+       unsigned int  /* reserved */ : 10;
+
+       /* Autofocus Statistic Configuration, Part 8 */
+       signed int    af_metrichpfcoefa20:5;
+       signed int    af_metrichpfcoefa21:5;
+       signed int    af_metrichpfcoefa22:5;
+       signed int    af_metrichpfcoefa23:5;
+       signed int    af_metrichpfcoefa24:5;
+       unsigned int  /* reserved */ : 7;
+
+       /* Autofocus Statistic Output Buffer Header */
+       unsigned int  af_metrichp:8;
+       unsigned int  /* reserved */ : 24;
+
+       /* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */
+       void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS];
+} __attribute__((packed, aligned(4))); /* VFE_StatsAutofocusConfigCmdType */
+
+struct msm_camera_frame_msg {
+       unsigned long   output_y_address;
+       unsigned long   output_cbcr_address;
+
+       unsigned int    blacklevelevenColumn:23;
+       uint16_t        reserved1:9;
+       unsigned int    blackleveloddColumn:23;
+       uint16_t        reserved2:9;
+
+       uint16_t        greendefectpixelcount:8;
+       uint16_t        reserved3:8;
+       uint16_t        redbluedefectpixelcount:8;
+       uint16_t        reserved4:8;
+} __attribute__((packed, aligned(4)));
+
+/* New one for 7k */
+struct msm_vfe_command_7k {
+       uint16_t queue;
+       uint16_t length;
+       void     *value;
+};
+
+struct stop_event {
+  wait_queue_head_t wait;
+       int state;
+  int timeout;
+};
+
+
+#endif /* __MSM_VFE7X_H__ */
diff --git a/drivers/staging/dream/camera/msm_vfe8x.c b/drivers/staging/dream/camera/msm_vfe8x.c
new file mode 100644 (file)
index 0000000..03de6ec
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+#include "msm_vfe8x_proc.h"
+
+#define ON  1
+#define OFF 0
+
+struct mutex vfe_lock;
+static void     *vfe_syncdata;
+
+static int vfe_enable(struct camera_enable_cmd *enable)
+{
+       int rc = 0;
+       return rc;
+}
+
+static int vfe_disable(struct camera_enable_cmd *enable,
+       struct platform_device *dev)
+{
+       int rc = 0;
+
+       vfe_stop();
+
+       msm_camio_disable(dev);
+       return rc;
+}
+
+static void vfe_release(struct platform_device *dev)
+{
+       msm_camio_disable(dev);
+       vfe_cmd_release(dev);
+
+       mutex_lock(&vfe_lock);
+       vfe_syncdata = NULL;
+       mutex_unlock(&vfe_lock);
+}
+
+static void vfe_config_axi(int mode,
+       struct axidata *ad, struct vfe_cmd_axi_output_config *ao)
+{
+       struct msm_pmem_region *regptr;
+       int i, j;
+       uint32_t *p1, *p2;
+
+       if (mode == OUTPUT_1 || mode == OUTPUT_1_AND_2) {
+               regptr = ad->region;
+               for (i = 0;
+                       i < ad->bufnum1; i++) {
+
+                       p1 = &(ao->output1.outputY.outFragments[i][0]);
+                       p2 = &(ao->output1.outputCbcr.outFragments[i][0]);
+
+                       for (j = 0;
+                               j < ao->output1.fragmentCount; j++) {
+
+                               *p1 = regptr->paddr + regptr->y_off;
+                               p1++;
+
+                               *p2 = regptr->paddr + regptr->cbcr_off;
+                               p2++;
+                       }
+                       regptr++;
+               }
+       } /* if OUTPUT1 or Both */
+
+       if (mode == OUTPUT_2 || mode == OUTPUT_1_AND_2) {
+
+               regptr = &(ad->region[ad->bufnum1]);
+               CDBG("bufnum2 = %d\n", ad->bufnum2);
+
+               for (i = 0;
+                       i < ad->bufnum2; i++) {
+
+                       p1 = &(ao->output2.outputY.outFragments[i][0]);
+                       p2 = &(ao->output2.outputCbcr.outFragments[i][0]);
+
+               CDBG("config_axi: O2, phy = 0x%lx, y_off = %d, cbcr_off = %d\n",
+                       regptr->paddr, regptr->y_off, regptr->cbcr_off);
+
+                       for (j = 0;
+                               j < ao->output2.fragmentCount; j++) {
+
+                               *p1 = regptr->paddr + regptr->y_off;
+                               CDBG("vfe_config_axi: p1 = 0x%x\n", *p1);
+                               p1++;
+
+                               *p2 = regptr->paddr + regptr->cbcr_off;
+                               CDBG("vfe_config_axi: p2 = 0x%x\n", *p2);
+                               p2++;
+                       }
+                       regptr++;
+               }
+       }
+}
+
+static int vfe_proc_general(struct msm_vfe_command_8k *cmd)
+{
+       int rc = 0;
+
+       CDBG("vfe_proc_general: cmdID = %d\n", cmd->id);
+
+       switch (cmd->id) {
+       case VFE_CMD_ID_RESET:
+               msm_camio_vfe_blk_reset();
+               msm_camio_camif_pad_reg_reset_2();
+               vfe_reset();
+               break;
+
+       case VFE_CMD_ID_START: {
+               struct vfe_cmd_start start;
+               if (copy_from_user(&start,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               /* msm_camio_camif_pad_reg_reset_2(); */
+               msm_camio_camif_pad_reg_reset();
+               vfe_start(&start);
+       }
+               break;
+
+       case VFE_CMD_ID_CAMIF_CONFIG: {
+               struct vfe_cmd_camif_config camif;
+               if (copy_from_user(&camif,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_camif_config(&camif);
+       }
+               break;
+
+       case VFE_CMD_ID_BLACK_LEVEL_CONFIG: {
+               struct vfe_cmd_black_level_config bl;
+               if (copy_from_user(&bl,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_black_level_config(&bl);
+       }
+               break;
+
+       case VFE_CMD_ID_ROLL_OFF_CONFIG: {
+               struct vfe_cmd_roll_off_config rolloff;
+               if (copy_from_user(&rolloff,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_roll_off_config(&rolloff);
+       }
+               break;
+
+       case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG: {
+               struct vfe_cmd_demux_channel_gain_config demuxc;
+               if (copy_from_user(&demuxc,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               /* demux is always enabled.  */
+               vfe_demux_channel_gain_config(&demuxc);
+       }
+               break;
+
+       case VFE_CMD_ID_DEMOSAIC_CONFIG: {
+               struct vfe_cmd_demosaic_config demosaic;
+               if (copy_from_user(&demosaic,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_demosaic_config(&demosaic);
+       }
+               break;
+
+       case VFE_CMD_ID_FOV_CROP_CONFIG:
+       case VFE_CMD_ID_FOV_CROP_UPDATE: {
+               struct vfe_cmd_fov_crop_config fov;
+               if (copy_from_user(&fov,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_fov_crop_config(&fov);
+       }
+               break;
+
+       case VFE_CMD_ID_MAIN_SCALER_CONFIG:
+       case VFE_CMD_ID_MAIN_SCALER_UPDATE: {
+               struct vfe_cmd_main_scaler_config mainds;
+               if (copy_from_user(&mainds,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_main_scaler_config(&mainds);
+       }
+               break;
+
+       case VFE_CMD_ID_WHITE_BALANCE_CONFIG:
+       case VFE_CMD_ID_WHITE_BALANCE_UPDATE: {
+               struct vfe_cmd_white_balance_config wb;
+               if (copy_from_user(&wb,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_white_balance_config(&wb);
+       }
+               break;
+
+       case VFE_CMD_ID_COLOR_CORRECTION_CONFIG:
+       case VFE_CMD_ID_COLOR_CORRECTION_UPDATE: {
+               struct vfe_cmd_color_correction_config cc;
+               if (copy_from_user(&cc,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_color_correction_config(&cc);
+       }
+               break;
+
+       case VFE_CMD_ID_LA_CONFIG: {
+               struct vfe_cmd_la_config la;
+               if (copy_from_user(&la,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_la_config(&la);
+       }
+               break;
+
+       case VFE_CMD_ID_RGB_GAMMA_CONFIG: {
+               struct vfe_cmd_rgb_gamma_config rgb;
+               if (copy_from_user(&rgb,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               rc = vfe_rgb_gamma_config(&rgb);
+       }
+               break;
+
+       case VFE_CMD_ID_CHROMA_ENHAN_CONFIG:
+       case VFE_CMD_ID_CHROMA_ENHAN_UPDATE: {
+               struct vfe_cmd_chroma_enhan_config chrom;
+               if (copy_from_user(&chrom,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_chroma_enhan_config(&chrom);
+       }
+               break;
+
+       case VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG:
+       case VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE: {
+               struct vfe_cmd_chroma_suppression_config chromsup;
+               if (copy_from_user(&chromsup,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_chroma_sup_config(&chromsup);
+       }
+               break;
+
+       case VFE_CMD_ID_ASF_CONFIG: {
+               struct vfe_cmd_asf_config asf;
+               if (copy_from_user(&asf,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_asf_config(&asf);
+       }
+               break;
+
+       case VFE_CMD_ID_SCALER2Y_CONFIG:
+       case VFE_CMD_ID_SCALER2Y_UPDATE: {
+               struct vfe_cmd_scaler2_config ds2y;
+               if (copy_from_user(&ds2y,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_scaler2y_config(&ds2y);
+       }
+               break;
+
+       case VFE_CMD_ID_SCALER2CbCr_CONFIG:
+       case VFE_CMD_ID_SCALER2CbCr_UPDATE: {
+               struct vfe_cmd_scaler2_config ds2cbcr;
+               if (copy_from_user(&ds2cbcr,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_scaler2cbcr_config(&ds2cbcr);
+       }
+               break;
+
+       case VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG: {
+               struct vfe_cmd_chroma_subsample_config sub;
+               if (copy_from_user(&sub,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_chroma_subsample_config(&sub);
+       }
+               break;
+
+       case VFE_CMD_ID_FRAME_SKIP_CONFIG: {
+               struct vfe_cmd_frame_skip_config fskip;
+               if (copy_from_user(&fskip,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_frame_skip_config(&fskip);
+       }
+               break;
+
+       case VFE_CMD_ID_OUTPUT_CLAMP_CONFIG: {
+               struct vfe_cmd_output_clamp_config clamp;
+               if (copy_from_user(&clamp,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_output_clamp_config(&clamp);
+       }
+               break;
+
+       /* module update commands */
+       case VFE_CMD_ID_BLACK_LEVEL_UPDATE: {
+               struct vfe_cmd_black_level_config blk;
+               if (copy_from_user(&blk,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_black_level_update(&blk);
+       }
+               break;
+
+       case VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE: {
+               struct vfe_cmd_demux_channel_gain_config dmu;
+               if (copy_from_user(&dmu,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_demux_channel_gain_update(&dmu);
+       }
+               break;
+
+       case VFE_CMD_ID_DEMOSAIC_BPC_UPDATE: {
+               struct vfe_cmd_demosaic_bpc_update demo_bpc;
+               if (copy_from_user(&demo_bpc,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_demosaic_bpc_update(&demo_bpc);
+       }
+               break;
+
+       case VFE_CMD_ID_DEMOSAIC_ABF_UPDATE: {
+               struct vfe_cmd_demosaic_abf_update demo_abf;
+               if (copy_from_user(&demo_abf,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_demosaic_abf_update(&demo_abf);
+       }
+               break;
+
+       case VFE_CMD_ID_LA_UPDATE: {
+               struct vfe_cmd_la_config la;
+               if (copy_from_user(&la,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_la_update(&la);
+       }
+               break;
+
+       case VFE_CMD_ID_RGB_GAMMA_UPDATE: {
+               struct vfe_cmd_rgb_gamma_config rgb;
+               if (copy_from_user(&rgb,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               rc = vfe_rgb_gamma_update(&rgb);
+       }
+               break;
+
+       case VFE_CMD_ID_ASF_UPDATE: {
+               struct vfe_cmd_asf_update asf;
+               if (copy_from_user(&asf,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_asf_update(&asf);
+       }
+               break;
+
+       case VFE_CMD_ID_FRAME_SKIP_UPDATE: {
+               struct vfe_cmd_frame_skip_update fskip;
+               if (copy_from_user(&fskip,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_frame_skip_update(&fskip);
+       }
+               break;
+
+       case VFE_CMD_ID_CAMIF_FRAME_UPDATE: {
+               struct vfe_cmds_camif_frame fup;
+               if (copy_from_user(&fup,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_camif_frame_update(&fup);
+       }
+               break;
+
+       /* stats update commands */
+       case VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE: {
+               struct vfe_cmd_stats_af_update afup;
+               if (copy_from_user(&afup,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_stats_update_af(&afup);
+       }
+               break;
+
+       case VFE_CMD_ID_STATS_WB_EXP_UPDATE: {
+               struct vfe_cmd_stats_wb_exp_update wbexp;
+               if (copy_from_user(&wbexp,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_stats_update_wb_exp(&wbexp);
+       }
+               break;
+
+       /* control of start, stop, update, etc... */
+       case VFE_CMD_ID_STOP:
+               vfe_stop();
+               break;
+
+       case VFE_CMD_ID_GET_HW_VERSION:
+               break;
+
+       /* stats */
+       case VFE_CMD_ID_STATS_SETTING: {
+               struct vfe_cmd_stats_setting stats;
+               if (copy_from_user(&stats,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_stats_setting(&stats);
+       }
+               break;
+
+       case VFE_CMD_ID_STATS_AUTOFOCUS_START: {
+               struct vfe_cmd_stats_af_start af;
+               if (copy_from_user(&af,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_stats_start_af(&af);
+       }
+               break;
+
+       case VFE_CMD_ID_STATS_AUTOFOCUS_STOP:
+               vfe_stats_af_stop();
+               break;
+
+       case VFE_CMD_ID_STATS_WB_EXP_START: {
+               struct vfe_cmd_stats_wb_exp_start awexp;
+               if (copy_from_user(&awexp,
+                       (void __user *) cmd->value, cmd->length))
+                       rc = -EFAULT;
+
+               vfe_stats_start_wb_exp(&awexp);
+       }
+               break;
+
+       case VFE_CMD_ID_STATS_WB_EXP_STOP:
+               vfe_stats_wb_exp_stop();
+               break;
+
+       case VFE_CMD_ID_ASYNC_TIMER_SETTING:
+               break;
+
+       case VFE_CMD_ID_UPDATE:
+               vfe_update();
+               break;
+
+       /* test gen */
+       case VFE_CMD_ID_TEST_GEN_START:
+               break;
+
+/*
+  acknowledge from upper layer
+       these are not in general command.
+
+       case VFE_CMD_ID_OUTPUT1_ACK:
+               break;
+       case VFE_CMD_ID_OUTPUT2_ACK:
+               break;
+       case VFE_CMD_ID_EPOCH1_ACK:
+               break;
+       case VFE_CMD_ID_EPOCH2_ACK:
+               break;
+       case VFE_CMD_ID_STATS_AUTOFOCUS_ACK:
+               break;
+       case VFE_CMD_ID_STATS_WB_EXP_ACK:
+               break;
+*/
+
+       default:
+               break;
+       } /* switch */
+
+       return rc;
+}
+
+static int vfe_config(struct msm_vfe_cfg_cmd *cmd, void *data)
+{
+       struct msm_pmem_region *regptr;
+       struct msm_vfe_command_8k vfecmd;
+
+       uint32_t i;
+
+       void *cmd_data = NULL;
+       long rc = 0;
+
+       struct vfe_cmd_axi_output_config *axio = NULL;
+       struct vfe_cmd_stats_setting *scfg = NULL;
+
+       if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+           cmd->cmd_type != CMD_STATS_BUF_RELEASE) {
+
+               if (copy_from_user(&vfecmd,
+                               (void __user *)(cmd->value),
+                               sizeof(struct msm_vfe_command_8k)))
+                       return -EFAULT;
+       }
+
+       CDBG("vfe_config: cmdType = %d\n", cmd->cmd_type);
+
+       switch (cmd->cmd_type) {
+       case CMD_GENERAL:
+               rc = vfe_proc_general(&vfecmd);
+               break;
+
+       case CMD_STATS_ENABLE:
+       case CMD_STATS_AXI_CFG: {
+               struct axidata *axid;
+
+               axid = data;
+               if (!axid)
+                       return -EFAULT;
+
+               scfg =
+                       kmalloc(sizeof(struct vfe_cmd_stats_setting),
+                               GFP_ATOMIC);
+               if (!scfg)
+                       return -ENOMEM;
+
+               if (copy_from_user(scfg,
+                                       (void __user *)(vfecmd.value),
+                                       vfecmd.length)) {
+
+                       kfree(scfg);
+                       return -EFAULT;
+               }
+
+               regptr = axid->region;
+               if (axid->bufnum1 > 0) {
+                       for (i = 0; i < axid->bufnum1; i++) {
+                               scfg->awbBuffer[i] =
+                                       (uint32_t)(regptr->paddr);
+                               regptr++;
+                       }
+               }
+
+               if (axid->bufnum2 > 0) {
+                       for (i = 0; i < axid->bufnum2; i++) {
+                               scfg->afBuffer[i] =
+                                       (uint32_t)(regptr->paddr);
+                               regptr++;
+                       }
+               }
+
+               vfe_stats_config(scfg);
+       }
+               break;
+
+       case CMD_STATS_AF_AXI_CFG: {
+       }
+               break;
+
+       case CMD_FRAME_BUF_RELEASE: {
+               /* preview buffer release */
+               struct msm_frame *b;
+               unsigned long p;
+               struct vfe_cmd_output_ack fack;
+
+               if (!data)
+                       return -EFAULT;
+
+               b = (struct msm_frame *)(cmd->value);
+               p = *(unsigned long *)data;
+
+               b->path = MSM_FRAME_ENC;
+
+               fack.ybufaddr[0] =
+                       (uint32_t)(p + b->y_off);
+
+               fack.chromabufaddr[0] =
+                       (uint32_t)(p + b->cbcr_off);
+
+               if (b->path == MSM_FRAME_PREV_1)
+                       vfe_output1_ack(&fack);
+
+               if (b->path == MSM_FRAME_ENC ||
+                   b->path == MSM_FRAME_PREV_2)
+                       vfe_output2_ack(&fack);
+       }
+               break;
+
+       case CMD_SNAP_BUF_RELEASE: {
+       }
+               break;
+
+       case CMD_STATS_BUF_RELEASE: {
+               struct vfe_cmd_stats_wb_exp_ack sack;
+
+               if (!data)
+                       return -EFAULT;
+
+               sack.nextWbExpOutputBufferAddr = *(uint32_t *)data;
+               vfe_stats_wb_exp_ack(&sack);
+       }
+               break;
+
+       case CMD_AXI_CFG_OUT1: {
+               struct axidata *axid;
+
+               axid = data;
+               if (!axid)
+                       return -EFAULT;
+
+               axio =
+                       kmalloc(sizeof(struct vfe_cmd_axi_output_config),
+                               GFP_ATOMIC);
+               if (!axio)
+                       return -ENOMEM;
+
+               if (copy_from_user(axio, (void __user *)(vfecmd.value),
+                       sizeof(struct vfe_cmd_axi_output_config))) {
+                       kfree(axio);
+                       return -EFAULT;
+               }
+
+               vfe_config_axi(OUTPUT_1, axid, axio);
+               vfe_axi_output_config(axio);
+       }
+               break;
+
+       case CMD_AXI_CFG_OUT2:
+       case CMD_RAW_PICT_AXI_CFG: {
+               struct axidata *axid;
+
+               axid = data;
+               if (!axid)
+                       return -EFAULT;
+
+               axio =
+                       kmalloc(sizeof(struct vfe_cmd_axi_output_config),
+                               GFP_ATOMIC);
+               if (!axio)
+                       return -ENOMEM;
+
+               if (copy_from_user(axio, (void __user *)(vfecmd.value),
+                               sizeof(struct vfe_cmd_axi_output_config))) {
+                       kfree(axio);
+                       return -EFAULT;
+               }
+
+               vfe_config_axi(OUTPUT_2, axid, axio);
+
+               axio->outputDataSize = 0;
+               vfe_axi_output_config(axio);
+       }
+               break;
+
+       case CMD_AXI_CFG_SNAP_O1_AND_O2: {
+               struct axidata *axid;
+               axid = data;
+               if (!axid)
+                       return -EFAULT;
+
+               axio =
+                       kmalloc(sizeof(struct vfe_cmd_axi_output_config),
+                               GFP_ATOMIC);
+               if (!axio)
+                       return -ENOMEM;
+
+               if (copy_from_user(axio, (void __user *)(vfecmd.value),
+                       sizeof(struct vfe_cmd_axi_output_config))) {
+                       kfree(axio);
+                       return -EFAULT;
+               }
+
+               vfe_config_axi(OUTPUT_1_AND_2,
+                       axid, axio);
+               vfe_axi_output_config(axio);
+               cmd_data = axio;
+       }
+               break;
+
+       default:
+               break;
+       } /* switch */
+
+       kfree(scfg);
+
+       kfree(axio);
+
+/*
+       if (cmd->length > 256 &&
+                       cmd_data &&
+                       (cmd->cmd_type == CMD_GENERAL ||
+                        cmd->cmd_type == CMD_STATS_DISABLE)) {
+               kfree(cmd_data);
+       }
+*/
+       return rc;
+}
+
+static int vfe_init(struct msm_vfe_callback *presp,
+       struct platform_device *dev)
+{
+       int rc = 0;
+
+       rc = vfe_cmd_init(presp, dev, vfe_syncdata);
+       if (rc < 0)
+               return rc;
+
+       /* Bring up all the required GPIOs and Clocks */
+       return msm_camio_enable(dev);
+}
+
+void msm_camvfe_fn_init(struct msm_camvfe_fn *fptr, void *data)
+{
+       mutex_init(&vfe_lock);
+       fptr->vfe_init    = vfe_init;
+       fptr->vfe_enable  = vfe_enable;
+       fptr->vfe_config  = vfe_config;
+       fptr->vfe_disable = vfe_disable;
+       fptr->vfe_release = vfe_release;
+       vfe_syncdata = data;
+}
diff --git a/drivers/staging/dream/camera/msm_vfe8x.h b/drivers/staging/dream/camera/msm_vfe8x.h
new file mode 100644 (file)
index 0000000..28a70a9
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+#ifndef __MSM_VFE8X_H__
+#define __MSM_VFE8X_H__
+
+#define TRUE  1
+#define FALSE 0
+#define boolean uint8_t
+
+enum  VFE_STATE {
+       VFE_STATE_IDLE,
+       VFE_STATE_ACTIVE
+};
+
+enum vfe_cmd_id {
+       /*
+       *Important! Command_ID are arranged in order.
+       *Don't change!*/
+       VFE_CMD_ID_START,
+       VFE_CMD_ID_RESET,
+
+       /* bus and camif config */
+       VFE_CMD_ID_AXI_INPUT_CONFIG,
+       VFE_CMD_ID_CAMIF_CONFIG,
+       VFE_CMD_ID_AXI_OUTPUT_CONFIG,
+
+       /* module config  */
+       VFE_CMD_ID_BLACK_LEVEL_CONFIG,
+       VFE_CMD_ID_ROLL_OFF_CONFIG,
+       VFE_CMD_ID_DEMUX_CHANNEL_GAIN_CONFIG,
+       VFE_CMD_ID_DEMOSAIC_CONFIG,
+       VFE_CMD_ID_FOV_CROP_CONFIG,
+       VFE_CMD_ID_MAIN_SCALER_CONFIG,
+       VFE_CMD_ID_WHITE_BALANCE_CONFIG,
+       VFE_CMD_ID_COLOR_CORRECTION_CONFIG,
+       VFE_CMD_ID_LA_CONFIG,
+       VFE_CMD_ID_RGB_GAMMA_CONFIG,
+       VFE_CMD_ID_CHROMA_ENHAN_CONFIG,
+       VFE_CMD_ID_CHROMA_SUPPRESSION_CONFIG,
+       VFE_CMD_ID_ASF_CONFIG,
+       VFE_CMD_ID_SCALER2Y_CONFIG,
+       VFE_CMD_ID_SCALER2CbCr_CONFIG,
+       VFE_CMD_ID_CHROMA_SUBSAMPLE_CONFIG,
+       VFE_CMD_ID_FRAME_SKIP_CONFIG,
+       VFE_CMD_ID_OUTPUT_CLAMP_CONFIG,
+
+       /* test gen */
+       VFE_CMD_ID_TEST_GEN_START,
+
+       VFE_CMD_ID_UPDATE,
+
+       /* ackownledge from upper layer */
+       VFE_CMD_ID_OUTPUT1_ACK,
+       VFE_CMD_ID_OUTPUT2_ACK,
+       VFE_CMD_ID_EPOCH1_ACK,
+       VFE_CMD_ID_EPOCH2_ACK,
+       VFE_CMD_ID_STATS_AUTOFOCUS_ACK,
+       VFE_CMD_ID_STATS_WB_EXP_ACK,
+
+       /* module update commands */
+       VFE_CMD_ID_BLACK_LEVEL_UPDATE,
+       VFE_CMD_ID_DEMUX_CHANNEL_GAIN_UPDATE,
+       VFE_CMD_ID_DEMOSAIC_BPC_UPDATE,
+       VFE_CMD_ID_DEMOSAIC_ABF_UPDATE,
+       VFE_CMD_ID_FOV_CROP_UPDATE,
+       VFE_CMD_ID_WHITE_BALANCE_UPDATE,
+       VFE_CMD_ID_COLOR_CORRECTION_UPDATE,
+       VFE_CMD_ID_LA_UPDATE,
+       VFE_CMD_ID_RGB_GAMMA_UPDATE,
+       VFE_CMD_ID_CHROMA_ENHAN_UPDATE,
+       VFE_CMD_ID_CHROMA_SUPPRESSION_UPDATE,
+       VFE_CMD_ID_MAIN_SCALER_UPDATE,
+       VFE_CMD_ID_SCALER2CbCr_UPDATE,
+       VFE_CMD_ID_SCALER2Y_UPDATE,
+       VFE_CMD_ID_ASF_UPDATE,
+       VFE_CMD_ID_FRAME_SKIP_UPDATE,
+       VFE_CMD_ID_CAMIF_FRAME_UPDATE,
+
+       /* stats update commands */
+       VFE_CMD_ID_STATS_AUTOFOCUS_UPDATE,
+       VFE_CMD_ID_STATS_WB_EXP_UPDATE,
+
+       /* control of start, stop, update, etc... */
+  VFE_CMD_ID_STOP,
+       VFE_CMD_ID_GET_HW_VERSION,
+
+       /* stats */
+       VFE_CMD_ID_STATS_SETTING,
+       VFE_CMD_ID_STATS_AUTOFOCUS_START,
+       VFE_CMD_ID_STATS_AUTOFOCUS_STOP,
+       VFE_CMD_ID_STATS_WB_EXP_START,
+       VFE_CMD_ID_STATS_WB_EXP_STOP,
+
+       VFE_CMD_ID_ASYNC_TIMER_SETTING,
+
+       /* max id  */
+       VFE_CMD_ID_MAX
+};
+
+struct vfe_cmd_hw_version {
+       uint32_t minorVersion;
+       uint32_t majorVersion;
+       uint32_t coreVersion;
+};
+
+enum VFE_CAMIF_SYNC_EDGE {
+       VFE_CAMIF_SYNC_EDGE_ActiveHigh,
+       VFE_CAMIF_SYNC_EDGE_ActiveLow
+};
+
+enum VFE_CAMIF_SYNC_MODE {
+       VFE_CAMIF_SYNC_MODE_APS,
+       VFE_CAMIF_SYNC_MODE_EFS,
+       VFE_CAMIF_SYNC_MODE_ELS,
+       VFE_CAMIF_SYNC_MODE_ILLEGAL
+};
+
+struct vfe_cmds_camif_efs {
+       uint8_t efsendofline;
+       uint8_t efsstartofline;
+       uint8_t efsendofframe;
+       uint8_t efsstartofframe;
+};
+
+struct vfe_cmds_camif_frame {
+       uint16_t pixelsPerLine;
+       uint16_t linesPerFrame;
+};
+
+struct vfe_cmds_camif_window {
+       uint16_t firstpixel;
+       uint16_t lastpixel;
+       uint16_t firstline;
+       uint16_t lastline;
+};
+
+enum CAMIF_SUBSAMPLE_FRAME_SKIP {
+       CAMIF_SUBSAMPLE_FRAME_SKIP_0,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_AllFrames,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_2Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_3Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_4Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_5Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_6Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_7Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_8Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_9Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_10Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_11Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_12Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_13Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_14Frame,
+       CAMIF_SUBSAMPLE_FRAME_SKIP_ONE_OUT_OF_EVERY_15Frame
+};
+
+struct vfe_cmds_camif_subsample {
+       uint16_t pixelskipmask;
+       uint16_t lineskipmask;
+       enum CAMIF_SUBSAMPLE_FRAME_SKIP frameskip;
+       uint8_t frameskipmode;
+       uint8_t pixelskipwrap;
+};
+
+struct vfe_cmds_camif_epoch {
+       uint8_t  enable;
+       uint16_t lineindex;
+};
+
+struct vfe_cmds_camif_cfg {
+       enum VFE_CAMIF_SYNC_EDGE  vSyncEdge;
+       enum VFE_CAMIF_SYNC_EDGE  hSyncEdge;
+       enum VFE_CAMIF_SYNC_MODE  syncMode;
+       uint8_t vfeSubSampleEnable;
+       uint8_t busSubSampleEnable;
+       uint8_t irqSubSampleEnable;
+       uint8_t binningEnable;
+       uint8_t misrEnable;
+};
+
+struct vfe_cmd_camif_config {
+       struct vfe_cmds_camif_cfg camifConfig;
+       struct vfe_cmds_camif_efs EFS;
+       struct vfe_cmds_camif_frame     frame;
+       struct vfe_cmds_camif_window    window;
+       struct vfe_cmds_camif_subsample subsample;
+       struct vfe_cmds_camif_epoch     epoch1;
+       struct vfe_cmds_camif_epoch     epoch2;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+       VFE_AXI_OUTPUT_MODE_Output1,
+       VFE_AXI_OUTPUT_MODE_Output2,
+       VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+       VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+       VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+       VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+       VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+       VFE_RAW_OUTPUT_DISABLED,
+       VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+       VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+       VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+enum VFE_RAW_PIXEL_DATA_SIZE {
+       VFE_RAW_PIXEL_DATA_SIZE_8BIT,
+       VFE_RAW_PIXEL_DATA_SIZE_10BIT,
+       VFE_RAW_PIXEL_DATA_SIZE_12BIT,
+};
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_axi_out_per_component {
+       uint16_t imageWidth;
+       uint16_t imageHeight;
+       uint16_t outRowCount;
+       uint16_t outRowIncrement;
+       uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+               [VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+       uint8_t fragmentCount;
+       struct vfe_cmds_axi_out_per_component outputY;
+       struct vfe_cmds_axi_out_per_component outputCbcr;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+       VFE_AXI_BURST_LENGTH_IS_2  = 2,
+       VFE_AXI_BURST_LENGTH_IS_4  = 4,
+       VFE_AXI_BURST_LENGTH_IS_8  = 8,
+       VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+struct vfe_cmd_axi_output_config {
+       enum VFE_AXI_BURST_LENGTH burstLength;
+       enum VFE_AXI_OUTPUT_MODE outputMode;
+       enum VFE_RAW_PIXEL_DATA_SIZE outputDataSize;
+       struct vfe_cmds_axi_per_output_path output1;
+       struct vfe_cmds_axi_per_output_path output2;
+};
+
+struct vfe_cmd_fov_crop_config {
+       uint8_t enable;
+       uint16_t firstPixel;
+       uint16_t lastPixel;
+       uint16_t firstLine;
+       uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+       uint16_t MNCounterInit;
+       uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+       uint8_t  enable;
+       uint16_t inputSize;
+       uint16_t outputSize;
+       uint32_t phaseMultiplicationFactor;
+       uint8_t  interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+       uint8_t enable;
+       struct vfe_cmds_scaler_one_dimension    hconfig;
+       struct vfe_cmds_scaler_one_dimension    vconfig;
+       struct vfe_cmds_main_scaler_stripe_init MNInitH;
+       struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+       uint8_t enable;
+       struct vfe_cmds_scaler_one_dimension hconfig;
+       struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+struct vfe_cmd_frame_skip_config {
+       uint8_t output1Period;
+       uint32_t output1Pattern;
+       uint8_t output2Period;
+       uint32_t output2Pattern;
+};
+
+struct vfe_cmd_frame_skip_update {
+       uint32_t output1Pattern;
+       uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+       uint8_t minCh0;
+       uint8_t minCh1;
+       uint8_t minCh2;
+       uint8_t maxCh0;
+       uint8_t maxCh1;
+       uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+       uint8_t enable;
+       uint8_t cropEnable;
+       uint8_t vsubSampleEnable;
+       uint8_t hsubSampleEnable;
+       uint8_t vCosited;
+       uint8_t hCosited;
+       uint8_t vCositedPhase;
+       uint8_t hCositedPhase;
+       uint16_t cropWidthFirstPixel;
+       uint16_t cropWidthLastPixel;
+       uint16_t cropHeightFirstLine;
+       uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_INPUT_SOURCE {
+       VFE_START_INPUT_SOURCE_CAMIF,
+       VFE_START_INPUT_SOURCE_TESTGEN,
+       VFE_START_INPUT_SOURCE_AXI,
+       VFE_START_INPUT_SOURCE_INVALID
+};
+
+enum VFE_START_OPERATION_MODE {
+       VFE_START_OPERATION_MODE_CONTINUOUS,
+       VFE_START_OPERATION_MODE_SNAPSHOT
+};
+
+enum VFE_START_PIXEL_PATTERN {
+       VFE_BAYER_RGRGRG,
+       VFE_BAYER_GRGRGR,
+       VFE_BAYER_BGBGBG,
+       VFE_BAYER_GBGBGB,
+       VFE_YUV_YCbYCr,
+       VFE_YUV_YCrYCb,
+       VFE_YUV_CbYCrY,
+       VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+       VFE_BAYER_RAW,
+       VFE_YUV_INTERLEAVED,
+       VFE_YUV_PSEUDO_PLANAR_Y,
+       VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+       VFE_YUV_COSITED,
+       VFE_YUV_INTERPOLATED
+};
+
+struct vfe_cmd_start {
+       enum VFE_START_INPUT_SOURCE inputSource;
+       enum VFE_START_OPERATION_MODE operationMode;
+       uint8_t     snapshotCount;
+       enum VFE_START_PIXEL_PATTERN pixel;
+       enum VFE_YUV_INPUT_COSITING_MODE yuvInputCositingMode;
+};
+
+struct vfe_cmd_output_ack {
+       uint32_t ybufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+       uint32_t chromabufaddr[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+#define VFE_STATS_BUFFER_COUNT 3
+
+struct vfe_cmd_stats_setting {
+       uint16_t frameHDimension;
+       uint16_t frameVDimension;
+       uint8_t  afBusPrioritySelection;
+       uint8_t  afBusPriority;
+       uint8_t  awbBusPrioritySelection;
+       uint8_t  awbBusPriority;
+       uint8_t  histBusPrioritySelection;
+       uint8_t  histBusPriority;
+       uint32_t afBuffer[VFE_STATS_BUFFER_COUNT];
+       uint32_t awbBuffer[VFE_STATS_BUFFER_COUNT];
+       uint32_t histBuffer[VFE_STATS_BUFFER_COUNT];
+};
+
+struct vfe_cmd_stats_af_start {
+       uint8_t  enable;
+       uint8_t  windowMode;
+       uint16_t windowHOffset;
+       uint16_t windowVOffset;
+       uint16_t windowWidth;
+       uint16_t windowHeight;
+       uint8_t  gridForMultiWindows[16];
+       uint8_t     metricSelection;
+       int16_t  metricMax;
+       int8_t   highPassCoef[7];
+       int8_t   bufferHeader;
+};
+
+struct vfe_cmd_stats_af_update {
+       uint8_t  windowMode;
+       uint16_t windowHOffset;
+       uint16_t windowVOffset;
+       uint16_t windowWidth;
+       uint16_t windowHeight;
+};
+
+struct vfe_cmd_stats_wb_exp_start {
+       uint8_t   enable;
+       uint8_t   wbExpRegions;
+       uint8_t   wbExpSubRegion;
+       uint8_t   awbYMin;
+       uint8_t   awbYMax;
+       int8_t    awbMCFG[4];
+       int16_t   awbCCFG[4];
+       int8_t    axwHeader;
+};
+
+struct vfe_cmd_stats_wb_exp_update {
+       uint8_t wbExpRegions;
+       uint8_t wbExpSubRegion;
+       int8_t  awbYMin;
+       int8_t  awbYMax;
+       int8_t  awbMCFG[4];
+       int16_t awbCCFG[4];
+};
+
+struct vfe_cmd_stats_af_ack {
+       uint32_t nextAFOutputBufferAddr;
+};
+
+struct vfe_cmd_stats_wb_exp_ack {
+       uint32_t  nextWbExpOutputBufferAddr;
+};
+
+struct vfe_cmd_black_level_config {
+       uint8_t  enable;
+       uint16_t evenEvenAdjustment;
+       uint16_t evenOddAdjustment;
+       uint16_t oddEvenAdjustment;
+       uint16_t oddOddAdjustment;
+};
+
+/* 13*1  */
+#define  VFE_ROLL_OFF_INIT_TABLE_SIZE  13
+/* 13*16 */
+#define  VFE_ROLL_OFF_DELTA_TABLE_SIZE 208
+
+struct vfe_cmd_roll_off_config {
+       uint8_t  enable;
+       uint16_t gridWidth;
+       uint16_t gridHeight;
+       uint16_t  yDelta;
+       uint8_t  gridXIndex;
+       uint8_t  gridYIndex;
+       uint16_t gridPixelXIndex;
+       uint16_t gridPixelYIndex;
+       uint16_t yDeltaAccum;
+       uint16_t initTableR[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+       uint16_t initTableGr[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+       uint16_t initTableB[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+       uint16_t initTableGb[VFE_ROLL_OFF_INIT_TABLE_SIZE];
+       int16_t  deltaTableR[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+       int16_t  deltaTableGr[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+       int16_t  deltaTableB[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+       int16_t  deltaTableGb[VFE_ROLL_OFF_DELTA_TABLE_SIZE];
+};
+
+struct vfe_cmd_demux_channel_gain_config {
+       uint16_t ch0EvenGain;
+       uint16_t ch0OddGain;
+       uint16_t ch1Gain;
+       uint16_t ch2Gain;
+};
+
+struct vfe_cmds_demosaic_abf {
+       uint8_t   enable;
+       uint8_t   forceOn;
+       uint8_t   shift;
+       uint16_t  lpThreshold;
+       uint16_t  max;
+       uint16_t  min;
+       uint8_t   ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+       uint8_t   enable;
+       uint16_t  fmaxThreshold;
+       uint16_t  fminThreshold;
+       uint16_t  redDiffThreshold;
+       uint16_t  blueDiffThreshold;
+       uint16_t  greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+       uint8_t   enable;
+       uint8_t   slopeShift;
+       struct vfe_cmds_demosaic_abf abfConfig;
+       struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+       struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+       struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+       uint8_t  enable;
+       uint16_t ch2Gain;
+       uint16_t ch1Gain;
+       uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+       COEF_IS_Q7_SIGNED,
+       COEF_IS_Q8_SIGNED,
+       COEF_IS_Q9_SIGNED,
+       COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+       uint8_t     enable;
+       enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+       int16_t  C0;
+       int16_t  C1;
+       int16_t  C2;
+       int16_t  C3;
+       int16_t  C4;
+       int16_t  C5;
+       int16_t  C6;
+       int16_t  C7;
+       int16_t  C8;
+       int16_t  K0;
+       int16_t  K1;
+       int16_t  K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 256
+struct vfe_cmd_la_config {
+       uint8_t enable;
+       int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+       RGB_GAMMA_CH0_SELECTED,
+       RGB_GAMMA_CH1_SELECTED,
+       RGB_GAMMA_CH2_SELECTED,
+       RGB_GAMMA_CH0_CH1_SELECTED,
+       RGB_GAMMA_CH0_CH2_SELECTED,
+       RGB_GAMMA_CH1_CH2_SELECTED,
+       RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+       uint8_t enable;
+       enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+       int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+       uint8_t  enable;
+       int16_t am;
+       int16_t ap;
+       int16_t bm;
+       int16_t bp;
+       int16_t cm;
+       int16_t cp;
+       int16_t dm;
+       int16_t dp;
+       int16_t kcr;
+       int16_t kcb;
+       int16_t RGBtoYConversionV0;
+       int16_t RGBtoYConversionV1;
+       int16_t RGBtoYConversionV2;
+       uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+       uint8_t enable;
+       uint8_t m1;
+       uint8_t m3;
+       uint8_t n1;
+       uint8_t n3;
+       uint8_t nn1;
+       uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+       uint8_t enable;
+       uint8_t smoothFilterEnabled;
+       uint8_t sharpMode;
+       uint8_t smoothCoefCenter;
+       uint8_t smoothCoefSurr;
+       uint8_t normalizeFactor;
+       uint8_t sharpK1;
+       uint8_t sharpK2;
+       uint8_t sharpThreshE1;
+       int8_t sharpThreshE2;
+       int8_t sharpThreshE3;
+       int8_t sharpThreshE4;
+       int8_t sharpThreshE5;
+       int8_t filter1Coefficients[9];
+       int8_t filter2Coefficients[9];
+       uint8_t  cropEnable;
+       uint16_t cropFirstPixel;
+       uint16_t cropLastPixel;
+       uint16_t cropFirstLine;
+       uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+       uint8_t enable;
+       uint8_t smoothFilterEnabled;
+       uint8_t sharpMode;
+       uint8_t smoothCoefCenter;
+       uint8_t smoothCoefSurr;
+       uint8_t normalizeFactor;
+       uint8_t sharpK1;
+       uint8_t sharpK2;
+       uint8_t sharpThreshE1;
+       int8_t  sharpThreshE2;
+       int8_t  sharpThreshE3;
+       int8_t  sharpThreshE4;
+       int8_t  sharpThreshE5;
+       int8_t  filter1Coefficients[9];
+       int8_t  filter2Coefficients[9];
+       uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+       VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+       VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+struct vfe_cmd_test_gen_start {
+       uint8_t pixelDataSelect;
+       uint8_t systematicDataSelect;
+       enum VFE_TEST_GEN_SYNC_EDGE  hsyncEdge;
+       enum VFE_TEST_GEN_SYNC_EDGE  vsyncEdge;
+       uint16_t numFrame;
+       enum VFE_RAW_PIXEL_DATA_SIZE pixelDataSize;
+       uint16_t imageWidth;
+       uint16_t imageHeight;
+       uint32_t startOfFrameOffset;
+       uint32_t endOfFrameNOffset;
+       uint16_t startOfLineOffset;
+       uint16_t endOfLineNOffset;
+       uint16_t hbi;
+       uint8_t  vblEnable;
+       uint16_t vbl;
+       uint8_t  startOfFrameDummyLine;
+       uint8_t  endOfFrameDummyLine;
+       uint8_t  unicolorBarEnable;
+       uint8_t  colorBarsSplitEnable;
+       uint8_t  unicolorBarSelect;
+       enum VFE_START_PIXEL_PATTERN  colorBarsPixelPattern;
+       uint8_t  colorBarsRotatePeriod;
+       uint16_t testGenRandomSeed;
+};
+
+struct vfe_cmd_bus_pm_start {
+       uint8_t output2YWrPmEnable;
+       uint8_t output2CbcrWrPmEnable;
+       uint8_t output1YWrPmEnable;
+       uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_cmd_camif_frame_update {
+       struct vfe_cmds_camif_frame camifFrame;
+};
+
+struct vfe_cmd_sync_timer_setting {
+       uint8_t  whichSyncTimer;
+       uint8_t  operation;
+       uint8_t  polarity;
+       uint16_t repeatCount;
+       uint16_t hsyncCount;
+       uint32_t pclkCount;
+       uint32_t outputDuration;
+};
+
+struct vfe_cmd_async_timer_setting {
+       uint8_t  whichAsyncTimer;
+       uint8_t  operation;
+       uint8_t  polarity;
+       uint16_t repeatCount;
+       uint16_t inactiveCount;
+       uint32_t activeCount;
+};
+
+struct  vfe_frame_skip_counts {
+       uint32_t  totalFrameCount;
+       uint32_t  output1Count;
+       uint32_t  output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+       VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+       VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_cmd_axi_input_config {
+       uint32_t  fragAddr[4];
+       uint8_t   totalFragmentCount;
+       uint16_t  ySize;
+       uint16_t  xOffset;
+       uint16_t  xSize;
+       uint16_t  rowIncrement;
+       uint16_t  numOfRows;
+       enum VFE_AXI_BURST_LENGTH burstLength;
+       uint8_t   unpackPhase;
+       enum VFE_AXI_RD_UNPACK_HBI_SEL unpackHbi;
+       enum VFE_RAW_PIXEL_DATA_SIZE   pixelSize;
+       uint8_t   padRepeatCountLeft;
+       uint8_t   padRepeatCountRight;
+       uint8_t   padRepeatCountTop;
+       uint8_t   padRepeatCountBottom;
+       uint8_t   padLeftComponentSelectCycle0;
+       uint8_t   padLeftComponentSelectCycle1;
+       uint8_t   padLeftComponentSelectCycle2;
+       uint8_t   padLeftComponentSelectCycle3;
+       uint8_t   padLeftStopCycle0;
+       uint8_t   padLeftStopCycle1;
+       uint8_t   padLeftStopCycle2;
+       uint8_t   padLeftStopCycle3;
+       uint8_t   padRightComponentSelectCycle0;
+       uint8_t   padRightComponentSelectCycle1;
+       uint8_t   padRightComponentSelectCycle2;
+       uint8_t   padRightComponentSelectCycle3;
+       uint8_t   padRightStopCycle0;
+       uint8_t   padRightStopCycle1;
+       uint8_t   padRightStopCycle2;
+       uint8_t   padRightStopCycle3;
+       uint8_t   padTopLineCount;
+       uint8_t   padBottomLineCount;
+};
+
+struct vfe_interrupt_status {
+       uint8_t camifErrorIrq;
+       uint8_t camifSofIrq;
+       uint8_t camifEolIrq;
+       uint8_t camifEofIrq;
+       uint8_t camifEpoch1Irq;
+       uint8_t camifEpoch2Irq;
+       uint8_t camifOverflowIrq;
+       uint8_t ceIrq;
+       uint8_t regUpdateIrq;
+       uint8_t resetAckIrq;
+       uint8_t encYPingpongIrq;
+       uint8_t encCbcrPingpongIrq;
+       uint8_t viewYPingpongIrq;
+       uint8_t viewCbcrPingpongIrq;
+       uint8_t rdPingpongIrq;
+       uint8_t afPingpongIrq;
+       uint8_t awbPingpongIrq;
+       uint8_t histPingpongIrq;
+       uint8_t encIrq;
+       uint8_t viewIrq;
+       uint8_t busOverflowIrq;
+       uint8_t afOverflowIrq;
+       uint8_t awbOverflowIrq;
+       uint8_t syncTimer0Irq;
+       uint8_t syncTimer1Irq;
+       uint8_t syncTimer2Irq;
+       uint8_t asyncTimer0Irq;
+       uint8_t asyncTimer1Irq;
+       uint8_t asyncTimer2Irq;
+       uint8_t asyncTimer3Irq;
+       uint8_t axiErrorIrq;
+       uint8_t violationIrq;
+       uint8_t anyErrorIrqs;
+       uint8_t anyOutput1PathIrqs;
+       uint8_t anyOutput2PathIrqs;
+       uint8_t anyOutputPathIrqs;
+       uint8_t anyAsyncTimerIrqs;
+       uint8_t anySyncTimerIrqs;
+       uint8_t anyIrqForActiveStatesOnly;
+};
+
+enum VFE_MESSAGE_ID {
+       VFE_MSG_ID_RESET_ACK,
+       VFE_MSG_ID_START_ACK,
+       VFE_MSG_ID_STOP_ACK,
+       VFE_MSG_ID_UPDATE_ACK,
+       VFE_MSG_ID_OUTPUT1,
+       VFE_MSG_ID_OUTPUT2,
+       VFE_MSG_ID_SNAPSHOT_DONE,
+       VFE_MSG_ID_STATS_AUTOFOCUS,
+       VFE_MSG_ID_STATS_WB_EXP,
+       VFE_MSG_ID_EPOCH1,
+       VFE_MSG_ID_EPOCH2,
+       VFE_MSG_ID_SYNC_TIMER0_DONE,
+       VFE_MSG_ID_SYNC_TIMER1_DONE,
+       VFE_MSG_ID_SYNC_TIMER2_DONE,
+       VFE_MSG_ID_ASYNC_TIMER0_DONE,
+       VFE_MSG_ID_ASYNC_TIMER1_DONE,
+       VFE_MSG_ID_ASYNC_TIMER2_DONE,
+       VFE_MSG_ID_ASYNC_TIMER3_DONE,
+       VFE_MSG_ID_AF_OVERFLOW,
+       VFE_MSG_ID_AWB_OVERFLOW,
+       VFE_MSG_ID_AXI_ERROR,
+       VFE_MSG_ID_CAMIF_OVERFLOW,
+       VFE_MSG_ID_VIOLATION,
+       VFE_MSG_ID_CAMIF_ERROR,
+       VFE_MSG_ID_BUS_OVERFLOW,
+};
+
+struct vfe_msg_stats_autofocus {
+       uint32_t    afBuffer;
+       uint32_t    frameCounter;
+};
+
+struct vfe_msg_stats_wb_exp {
+       uint32_t awbBuffer;
+       uint32_t frameCounter;
+};
+
+struct vfe_frame_bpc_info {
+       uint32_t greenDefectPixelCount;
+       uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+       uint32_t  asfMaxEdge;
+       uint32_t  asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+       uint8_t  camifState;
+       uint32_t pixelCount;
+       uint32_t lineCount;
+};
+
+struct vfe_bus_pm_per_path {
+       uint32_t yWrPmStats0;
+       uint32_t yWrPmStats1;
+       uint32_t cbcrWrPmStats0;
+       uint32_t cbcrWrPmStats1;
+};
+
+struct vfe_bus_performance_monitor {
+       struct vfe_bus_pm_per_path encPathPmInfo;
+       struct vfe_bus_pm_per_path viewPathPmInfo;
+};
+
+struct vfe_irq_thread_msg {
+       uint32_t  vfeIrqStatus;
+       uint32_t  camifStatus;
+       uint32_t  demosaicStatus;
+       uint32_t  asfMaxEdge;
+       struct vfe_bus_performance_monitor pmInfo;
+};
+
+struct vfe_msg_output {
+       uint32_t  yBuffer;
+       uint32_t  cbcrBuffer;
+       struct vfe_frame_bpc_info bpcInfo;
+       struct vfe_frame_asf_info asfInfo;
+       uint32_t  frameCounter;
+       struct vfe_bus_pm_per_path pmData;
+};
+
+struct vfe_message {
+       enum VFE_MESSAGE_ID _d;
+       union {
+               struct vfe_msg_output              msgOutput1;
+               struct vfe_msg_output              msgOutput2;
+               struct vfe_msg_stats_autofocus     msgStatsAf;
+               struct vfe_msg_stats_wb_exp        msgStatsWbExp;
+               struct vfe_msg_camif_status        msgCamifError;
+               struct vfe_bus_performance_monitor msgBusOverflow;
+   } _u;
+};
+
+/* New one for 8k */
+struct msm_vfe_command_8k {
+       int32_t  id;
+       uint16_t length;
+       void     *value;
+};
+
+struct vfe_frame_extra {
+       struct vfe_frame_bpc_info bpcInfo;
+       struct vfe_frame_asf_info asfInfo;
+       uint32_t  frameCounter;
+       struct vfe_bus_pm_per_path pmData;
+};
+#endif /* __MSM_VFE8X_H__ */
diff --git a/drivers/staging/dream/camera/msm_vfe8x_proc.c b/drivers/staging/dream/camera/msm_vfe8x_proc.c
new file mode 100644 (file)
index 0000000..bb65013
--- /dev/null
@@ -0,0 +1,3995 @@
+/*
+* Copyright (C) 2008-2009 QUALCOMM Incorporated.
+*/
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include "msm_vfe8x_proc.h"
+#include <media/msm_camera.h>
+
+struct msm_vfe8x_ctrl {
+       /* bit 1:0 ENC_IRQ_MASK = 0x11:
+        * generate IRQ when both y and cbcr frame is ready. */
+
+       /* bit 1:0 VIEW_IRQ_MASK= 0x11:
+        * generate IRQ when both y and cbcr frame is ready. */
+       struct vfe_irq_composite_mask_config vfeIrqCompositeMaskLocal;
+       struct vfe_module_enable vfeModuleEnableLocal;
+       struct vfe_camif_cfg_data   vfeCamifConfigLocal;
+       struct vfe_interrupt_mask   vfeImaskLocal;
+       struct vfe_stats_cmd_data   vfeStatsCmdLocal;
+       struct vfe_bus_cfg_data     vfeBusConfigLocal;
+       struct vfe_cmd_bus_pm_start vfeBusPmConfigLocal;
+       struct vfe_bus_cmd_data     vfeBusCmdLocal;
+       enum vfe_interrupt_name     vfeInterruptNameLocal;
+       uint32_t vfeLaBankSel;
+       struct vfe_gamma_lut_sel  vfeGammaLutSel;
+
+       boolean vfeStartAckPendingFlag;
+       boolean vfeStopAckPending;
+       boolean vfeResetAckPending;
+       boolean vfeUpdateAckPending;
+
+       enum VFE_AXI_OUTPUT_MODE        axiOutputMode;
+       enum VFE_START_OPERATION_MODE   vfeOperationMode;
+
+       uint32_t            vfeSnapShotCount;
+       uint32_t            vfeRequestedSnapShotCount;
+       boolean             vfeStatsPingPongReloadFlag;
+       uint32_t            vfeFrameId;
+
+       struct vfe_cmd_frame_skip_config vfeFrameSkip;
+       uint32_t vfeFrameSkipPattern;
+       uint8_t  vfeFrameSkipCount;
+       uint8_t  vfeFrameSkipPeriod;
+
+       boolean  vfeTestGenStartFlag;
+       uint32_t vfeImaskPacked;
+       uint32_t vfeImaskCompositePacked;
+       enum VFE_RAW_PIXEL_DATA_SIZE       axiInputDataSize;
+       struct vfe_irq_thread_msg          vfeIrqThreadMsgLocal;
+
+       struct vfe_output_path_combo  viewPath;
+       struct vfe_output_path_combo  encPath;
+       struct vfe_frame_skip_counts vfeDroppedFrameCounts;
+       struct vfe_stats_control afStatsControl;
+       struct vfe_stats_control awbStatsControl;
+
+       enum VFE_STATE  vstate;
+
+       spinlock_t  ack_lock;
+       spinlock_t  state_lock;
+       spinlock_t  io_lock;
+
+       struct msm_vfe_callback *resp;
+       uint32_t extlen;
+       void *extdata;
+
+       spinlock_t  tasklet_lock;
+       struct list_head tasklet_q;
+
+       int vfeirq;
+       void __iomem *vfebase;
+
+       void *syncdata;
+};
+static struct msm_vfe8x_ctrl *ctrl;
+static irqreturn_t vfe_parse_irq(int irq_num, void *data);
+
+struct isr_queue_cmd {
+       struct list_head list;
+       struct vfe_interrupt_status        vfeInterruptStatus;
+       struct vfe_frame_asf_info          vfeAsfFrameInfo;
+       struct vfe_frame_bpc_info          vfeBpcFrameInfo;
+       struct vfe_msg_camif_status        vfeCamifStatusLocal;
+       struct vfe_bus_performance_monitor vfePmData;
+};
+
+static void vfe_prog_hw(uint8_t *hwreg,
+       uint32_t *inptr, uint32_t regcnt)
+{
+       /* unsigned long flags; */
+       uint32_t i;
+       uint32_t *p;
+
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->io_lock, flags); */
+
+       p = (uint32_t *)(hwreg);
+       for (i = 0; i < (regcnt >> 2); i++)
+               writel(*inptr++, p++);
+               /* *p++ = *inptr++; */
+
+       /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+}
+
+static void vfe_read_reg_values(uint8_t *hwreg,
+       uint32_t *dest, uint32_t count)
+{
+       /* unsigned long flags; */
+       uint32_t *temp;
+       uint32_t i;
+
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->io_lock, flags); */
+
+       temp = (uint32_t *)(hwreg);
+       for (i = 0; i < count; i++)
+               *dest++ = *temp++;
+
+       /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+}
+
+static struct vfe_irqenable vfe_read_irq_mask(void)
+{
+       /* unsigned long flags; */
+       uint32_t *temp;
+       struct vfe_irqenable rc;
+
+       memset(&rc, 0, sizeof(rc));
+
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->io_lock, flags); */
+       temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_MASK);
+
+       rc = *((struct vfe_irqenable *)temp);
+       /* spin_unlock_irqrestore(&ctrl->io_lock, flags); */
+
+       return rc;
+}
+
+static void
+vfe_set_bus_pipo_addr(struct vfe_output_path_combo *vpath,
+       struct vfe_output_path_combo *epath)
+{
+       vpath->yPath.hwRegPingAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PING_ADDR);
+       vpath->yPath.hwRegPongAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_VIEW_Y_WR_PONG_ADDR);
+       vpath->cbcrPath.hwRegPingAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PING_ADDR);
+       vpath->cbcrPath.hwRegPongAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_VIEW_CBCR_WR_PONG_ADDR);
+
+       epath->yPath.hwRegPingAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR);
+       epath->yPath.hwRegPongAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_ENC_Y_WR_PONG_ADDR);
+       epath->cbcrPath.hwRegPingAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PING_ADDR);
+       epath->cbcrPath.hwRegPongAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PONG_ADDR);
+}
+
+static void vfe_axi_output(struct vfe_cmd_axi_output_config *in,
+       struct vfe_output_path_combo *out1,
+       struct vfe_output_path_combo *out2, uint16_t out)
+{
+       struct vfe_axi_out_cfg cmd;
+
+       uint16_t temp;
+       uint32_t burstLength;
+
+       /* force it to burst length 4, hardware does not support it. */
+       burstLength = 1;
+
+       /* AXI Output 2 Y Configuration*/
+       /* VFE_BUS_ENC_Y_WR_PING_ADDR  */
+       cmd.out2YPingAddr = out2->yPath.addressBuffer[0];
+
+       /* VFE_BUS_ENC_Y_WR_PONG_ADDR  */
+       cmd.out2YPongAddr = out2->yPath.addressBuffer[1];
+
+       /* VFE_BUS_ENC_Y_WR_IMAGE_SIZE */
+       cmd.out2YImageHeight = in->output2.outputY.imageHeight;
+       /* convert the image width and row increment to be in
+        * unit of 64bit (8 bytes) */
+       temp = (in->output2.outputY.imageWidth + (out - 1)) /
+               out;
+       cmd.out2YImageWidthin64bit = temp;
+
+       /* VFE_BUS_ENC_Y_WR_BUFFER_CFG */
+       cmd.out2YBurstLength = burstLength;
+       cmd.out2YNumRows = in->output2.outputY.outRowCount;
+       temp = (in->output2.outputY.outRowIncrement + (out - 1)) /
+               out;
+       cmd.out2YRowIncrementIn64bit = temp;
+
+       /* AXI Output 2 Cbcr Configuration*/
+       /* VFE_BUS_ENC_Cbcr_WR_PING_ADDR  */
+       cmd.out2CbcrPingAddr = out2->cbcrPath.addressBuffer[0];
+
+       /* VFE_BUS_ENC_Cbcr_WR_PONG_ADDR  */
+       cmd.out2CbcrPongAddr = out2->cbcrPath.addressBuffer[1];
+
+       /* VFE_BUS_ENC_Cbcr_WR_IMAGE_SIZE */
+       cmd.out2CbcrImageHeight = in->output2.outputCbcr.imageHeight;
+       temp = (in->output2.outputCbcr.imageWidth + (out - 1)) /
+               out;
+       cmd.out2CbcrImageWidthIn64bit = temp;
+
+       /* VFE_BUS_ENC_Cbcr_WR_BUFFER_CFG */
+       cmd.out2CbcrBurstLength = burstLength;
+       cmd.out2CbcrNumRows = in->output2.outputCbcr.outRowCount;
+       temp = (in->output2.outputCbcr.outRowIncrement + (out - 1)) /
+               out;
+       cmd.out2CbcrRowIncrementIn64bit = temp;
+
+       /* AXI Output 1 Y Configuration */
+       /* VFE_BUS_VIEW_Y_WR_PING_ADDR  */
+       cmd.out1YPingAddr = out1->yPath.addressBuffer[0];
+
+       /* VFE_BUS_VIEW_Y_WR_PONG_ADDR */
+       cmd.out1YPongAddr = out1->yPath.addressBuffer[1];
+
+       /* VFE_BUS_VIEW_Y_WR_IMAGE_SIZE */
+       cmd.out1YImageHeight = in->output1.outputY.imageHeight;
+       temp = (in->output1.outputY.imageWidth + (out - 1)) /
+               out;
+       cmd.out1YImageWidthin64bit = temp;
+
+       /* VFE_BUS_VIEW_Y_WR_BUFFER_CFG     */
+       cmd.out1YBurstLength = burstLength;
+       cmd.out1YNumRows = in->output1.outputY.outRowCount;
+
+       temp =
+               (in->output1.outputY.outRowIncrement +
+                (out - 1)) / out;
+       cmd.out1YRowIncrementIn64bit = temp;
+
+       /* AXI Output 1 Cbcr Configuration*/
+       cmd.out1CbcrPingAddr = out1->cbcrPath.addressBuffer[0];
+
+       /* VFE_BUS_VIEW_Cbcr_WR_PONG_ADDR  */
+       cmd.out1CbcrPongAddr =
+               out1->cbcrPath.addressBuffer[1];
+
+       /* VFE_BUS_VIEW_Cbcr_WR_IMAGE_SIZE */
+       cmd.out1CbcrImageHeight = in->output1.outputCbcr.imageHeight;
+       temp = (in->output1.outputCbcr.imageWidth +
+               (out - 1)) / out;
+       cmd.out1CbcrImageWidthIn64bit = temp;
+
+       cmd.out1CbcrBurstLength = burstLength;
+       cmd.out1CbcrNumRows = in->output1.outputCbcr.outRowCount;
+       temp =
+               (in->output1.outputCbcr.outRowIncrement +
+                (out - 1)) / out;
+
+       cmd.out1CbcrRowIncrementIn64bit = temp;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PING_ADDR,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_reg_bus_cfg(struct vfe_bus_cfg_data *in)
+{
+       struct vfe_axi_bus_cfg cmd;
+
+       cmd.stripeRdPathEn      = in->stripeRdPathEn;
+       cmd.encYWrPathEn        = in->encYWrPathEn;
+       cmd.encCbcrWrPathEn     = in->encCbcrWrPathEn;
+       cmd.viewYWrPathEn       = in->viewYWrPathEn;
+       cmd.viewCbcrWrPathEn    = in->viewCbcrWrPathEn;
+       cmd.rawPixelDataSize    = (uint32_t)in->rawPixelDataSize;
+       cmd.rawWritePathSelect  = (uint32_t)in->rawWritePathSelect;
+
+       /*  program vfe_bus_cfg */
+       writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CFG);
+}
+
+static void vfe_reg_camif_config(struct vfe_camif_cfg_data *in)
+{
+       struct VFE_CAMIFConfigType cfg;
+
+       memset(&cfg, 0, sizeof(cfg));
+
+       cfg.VSyncEdge          =
+               in->camifCfgFromCmd.vSyncEdge;
+
+       cfg.HSyncEdge          =
+               in->camifCfgFromCmd.hSyncEdge;
+
+       cfg.syncMode           =
+               in->camifCfgFromCmd.syncMode;
+
+       cfg.vfeSubsampleEnable =
+               in->camifCfgFromCmd.vfeSubSampleEnable;
+
+       cfg.busSubsampleEnable =
+               in->camifCfgFromCmd.busSubSampleEnable;
+
+       cfg.camif2vfeEnable    =
+               in->camif2OutputEnable;
+
+       cfg.camif2busEnable    =
+               in->camif2BusEnable;
+
+       cfg.irqSubsampleEnable =
+               in->camifCfgFromCmd.irqSubSampleEnable;
+
+       cfg.binningEnable      =
+               in->camifCfgFromCmd.binningEnable;
+
+       cfg.misrEnable         =
+               in->camifCfgFromCmd.misrEnable;
+
+       /*  program camif_config */
+       writel(*((uint32_t *)&cfg), ctrl->vfebase + CAMIF_CONFIG);
+}
+
+static void vfe_reg_bus_cmd(struct vfe_bus_cmd_data *in)
+{
+       struct vfe_buscmd cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.stripeReload        = in->stripeReload;
+       cmd.busPingpongReload   = in->busPingpongReload;
+       cmd.statsPingpongReload = in->statsPingpongReload;
+
+       writel(*((uint32_t *)&cmd), ctrl->vfebase + VFE_BUS_CMD);
+
+       CDBG("bus command = 0x%x\n", (*((uint32_t *)&cmd)));
+
+       /* this is needed, as the control bits are pulse based.
+        * Don't want to reload bus pingpong again. */
+       in->busPingpongReload = 0;
+       in->statsPingpongReload = 0;
+       in->stripeReload = 0;
+}
+
+static void vfe_reg_module_cfg(struct vfe_module_enable *in)
+{
+       struct vfe_mod_enable ena;
+
+       memset(&ena, 0, sizeof(ena));
+
+       ena.blackLevelCorrectionEnable = in->blackLevelCorrectionEnable;
+       ena.lensRollOffEnable          = in->lensRollOffEnable;
+       ena.demuxEnable                = in->demuxEnable;
+       ena.chromaUpsampleEnable       = in->chromaUpsampleEnable;
+       ena.demosaicEnable             = in->demosaicEnable;
+       ena.statsEnable                = in->statsEnable;
+       ena.cropEnable                 = in->cropEnable;
+       ena.mainScalerEnable           = in->mainScalerEnable;
+       ena.whiteBalanceEnable         = in->whiteBalanceEnable;
+       ena.colorCorrectionEnable      = in->colorCorrectionEnable;
+       ena.yHistEnable                = in->yHistEnable;
+       ena.skinToneEnable             = in->skinToneEnable;
+       ena.lumaAdaptationEnable       = in->lumaAdaptationEnable;
+       ena.rgbLUTEnable               = in->rgbLUTEnable;
+       ena.chromaEnhanEnable          = in->chromaEnhanEnable;
+       ena.asfEnable                  = in->asfEnable;
+       ena.chromaSuppressionEnable    = in->chromaSuppressionEnable;
+       ena.chromaSubsampleEnable      = in->chromaSubsampleEnable;
+       ena.scaler2YEnable             = in->scaler2YEnable;
+       ena.scaler2CbcrEnable          = in->scaler2CbcrEnable;
+
+       writel(*((uint32_t *)&ena), ctrl->vfebase + VFE_MODULE_CFG);
+}
+
+static void vfe_program_dmi_cfg(enum VFE_DMI_RAM_SEL bankSel)
+{
+       /* set bit 8 for auto increment. */
+       uint32_t value = (uint32_t) ctrl->vfebase + VFE_DMI_CFG_DEFAULT;
+
+       value += (uint32_t)bankSel;
+       /* CDBG("dmi cfg input bank is  0x%x\n", bankSel); */
+
+       writel(value, ctrl->vfebase + VFE_DMI_CFG);
+       writel(0, ctrl->vfebase + VFE_DMI_ADDR);
+}
+
+static void vfe_write_lens_roll_off_table(
+       struct vfe_cmd_roll_off_config *in)
+{
+       uint16_t i;
+       uint32_t data;
+
+       uint16_t *initGr = in->initTableGr;
+       uint16_t *initGb = in->initTableGb;
+       uint16_t *initB =  in->initTableB;
+       uint16_t *initR =  in->initTableR;
+
+       int16_t *pDeltaGr = in->deltaTableGr;
+       int16_t *pDeltaGb = in->deltaTableGb;
+       int16_t *pDeltaB =  in->deltaTableB;
+       int16_t *pDeltaR =  in->deltaTableR;
+
+       vfe_program_dmi_cfg(ROLLOFF_RAM);
+
+       /* first pack and write init table */
+       for (i = 0; i < VFE_ROLL_OFF_INIT_TABLE_SIZE; i++) {
+               data = (((uint32_t)(*initR)) & 0x0000FFFF) |
+                       (((uint32_t)(*initGr)) << 16);
+               initR++;
+               initGr++;
+
+               writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+               data = (((uint32_t)(*initB)) & 0x0000FFFF) |
+                       (((uint32_t)(*initGr))<<16);
+               initB++;
+               initGb++;
+
+               writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+       }
+
+       /* there are gaps between the init table and delta table,
+        * set the offset for delta table. */
+       writel(LENS_ROLL_OFF_DELTA_TABLE_OFFSET,
+               ctrl->vfebase + VFE_DMI_ADDR);
+
+       /* pack and write delta table */
+       for (i = 0; i < VFE_ROLL_OFF_DELTA_TABLE_SIZE; i++) {
+               data = (((int32_t)(*pDeltaR)) & 0x0000FFFF) |
+                       (((int32_t)(*pDeltaGr))<<16);
+               pDeltaR++;
+               pDeltaGr++;
+
+               writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+
+               data = (((int32_t)(*pDeltaB)) & 0x0000FFFF) |
+                       (((int32_t)(*pDeltaGb))<<16);
+               pDeltaB++;
+               pDeltaGb++;
+
+               writel(data, ctrl->vfebase + VFE_DMI_DATA_LO);
+       }
+
+       /* After DMI transfer, to make it safe, need to set the
+        * DMI_CFG to unselect any SRAM
+        */
+       /* unselect the SRAM Bank. */
+       writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_set_default_reg_values(void)
+{
+       writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_0);
+       writel(0x800080, ctrl->vfebase + VFE_DEMUX_GAIN_1);
+       writel(0xFFFFF, ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+       /* default frame drop period and pattern */
+       writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+       writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+       writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+       writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+       writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_CFG);
+       writel(0x1f, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_CFG);
+       writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+       writel(0xFFFFFFFF, ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+       writel(0, ctrl->vfebase + VFE_CLAMP_MIN_CFG);
+       writel(0xFFFFFF, ctrl->vfebase + VFE_CLAMP_MAX_CFG);
+}
+
+static void vfe_config_demux(uint32_t period, uint32_t even, uint32_t odd)
+{
+       writel(period, ctrl->vfebase + VFE_DEMUX_CFG);
+       writel(even, ctrl->vfebase + VFE_DEMUX_EVEN_CFG);
+       writel(odd, ctrl->vfebase + VFE_DEMUX_ODD_CFG);
+}
+
+static void vfe_pm_stop(void)
+{
+       writel(VFE_PERFORMANCE_MONITOR_STOP, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static void vfe_program_bus_rd_irq_en(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN);
+}
+
+static void vfe_camif_go(void)
+{
+       writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND);
+}
+
+static void vfe_camif_stop_immediately(void)
+{
+       writel(CAMIF_COMMAND_STOP_IMMEDIATELY, ctrl->vfebase + CAMIF_COMMAND);
+       writel(0, ctrl->vfebase + VFE_CGC_OVERRIDE);
+}
+
+static void vfe_program_reg_update_cmd(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static void vfe_program_bus_cmd(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_BUS_CMD);
+}
+
+static void vfe_program_global_reset_cmd(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
+
+static void vfe_program_axi_cmd(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_AXI_CMD);
+}
+
+static void vfe_program_irq_composite_mask(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+}
+
+static inline void vfe_program_irq_mask(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_IRQ_MASK);
+}
+
+static void vfe_program_chroma_upsample_cfg(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG);
+}
+
+static uint32_t vfe_read_axi_status(void)
+{
+       return readl(ctrl->vfebase + VFE_AXI_STATUS);
+}
+
+static uint32_t vfe_read_pm_status_in_raw_capture(void)
+{
+       return readl(ctrl->vfebase + VFE_BUS_ENC_CBCR_WR_PM_STATS_1);
+}
+
+static void
+vfe_set_stats_pingpong_address(struct vfe_stats_control *afControl,
+       struct vfe_stats_control *awbControl)
+{
+       afControl->hwRegPingAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+       afControl->hwRegPongAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+       awbControl->hwRegPingAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+       awbControl->hwRegPongAddress = (uint8_t *)
+               (ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static uint32_t vfe_read_camif_status(void)
+{
+       return readl(ctrl->vfebase + CAMIF_STATUS);
+}
+
+static void vfe_program_lut_bank_sel(struct vfe_gamma_lut_sel *in)
+{
+       struct VFE_GammaLutSelect_ConfigCmdType cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.ch0BankSelect = in->ch0BankSelect;
+       cmd.ch1BankSelect = in->ch1BankSelect;
+       cmd.ch2BankSelect = in->ch2BankSelect;
+       CDBG("VFE gamma lut bank selection is 0x%x\n", *((uint32_t *)&cmd));
+       vfe_prog_hw(ctrl->vfebase + VFE_LUT_BANK_SEL,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_program_stats_cmd(struct vfe_stats_cmd_data *in)
+{
+       struct VFE_StatsCmdType stats;
+       memset(&stats, 0, sizeof(stats));
+
+       stats.autoFocusEnable        = in->autoFocusEnable;
+       stats.axwEnable              = in->axwEnable;
+       stats.histEnable             = in->histEnable;
+       stats.clearHistEnable        = in->clearHistEnable;
+       stats.histAutoClearEnable    = in->histAutoClearEnable;
+       stats.colorConversionEnable  = in->colorConversionEnable;
+
+       writel(*((uint32_t *)&stats), ctrl->vfebase + VFE_STATS_CMD);
+}
+
+static void vfe_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+       struct VFE_Bus_Pm_ConfigCmdType cmd;
+       memset(&cmd, 0, sizeof(struct VFE_Bus_Pm_ConfigCmdType));
+
+       cmd.output2YWrPmEnable     = in->output2YWrPmEnable;
+       cmd.output2CbcrWrPmEnable  = in->output2CbcrWrPmEnable;
+       cmd.output1YWrPmEnable     = in->output1YWrPmEnable;
+       cmd.output1CbcrWrPmEnable  = in->output1CbcrWrPmEnable;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_BUS_PM_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+static void vfe_8k_pm_start(struct vfe_cmd_bus_pm_start *in)
+{
+       in->output1CbcrWrPmEnable = ctrl->vfeBusConfigLocal.viewCbcrWrPathEn;
+       in->output1YWrPmEnable    = ctrl->vfeBusConfigLocal.viewYWrPathEn;
+       in->output2CbcrWrPmEnable = ctrl->vfeBusConfigLocal.encCbcrWrPathEn;
+       in->output2YWrPmEnable    = ctrl->vfeBusConfigLocal.encYWrPathEn;
+
+       if (in->output1CbcrWrPmEnable || in->output1YWrPmEnable)
+               ctrl->viewPath.pmEnabled = TRUE;
+
+       if (in->output2CbcrWrPmEnable || in->output2YWrPmEnable)
+               ctrl->encPath.pmEnabled = TRUE;
+
+       vfe_pm_start(in);
+
+       writel(VFE_PERFORMANCE_MONITOR_GO, ctrl->vfebase + VFE_BUS_PM_CMD);
+}
+
+static uint32_t vfe_irq_pack(struct vfe_interrupt_mask data)
+{
+       struct vfe_irqenable packedData;
+
+       memset(&packedData, 0, sizeof(packedData));
+
+       packedData.camifErrorIrq          = data.camifErrorIrq;
+       packedData.camifSofIrq            = data.camifSofIrq;
+       packedData.camifEolIrq            = data.camifEolIrq;
+       packedData.camifEofIrq            = data.camifEofIrq;
+       packedData.camifEpoch1Irq         = data.camifEpoch1Irq;
+       packedData.camifEpoch2Irq         = data.camifEpoch2Irq;
+       packedData.camifOverflowIrq       = data.camifOverflowIrq;
+       packedData.ceIrq                  = data.ceIrq;
+       packedData.regUpdateIrq           = data.regUpdateIrq;
+       packedData.resetAckIrq            = data.resetAckIrq;
+       packedData.encYPingpongIrq        = data.encYPingpongIrq;
+       packedData.encCbcrPingpongIrq     = data.encCbcrPingpongIrq;
+       packedData.viewYPingpongIrq       = data.viewYPingpongIrq;
+       packedData.viewCbcrPingpongIrq    = data.viewCbcrPingpongIrq;
+       packedData.rdPingpongIrq          = data.rdPingpongIrq;
+       packedData.afPingpongIrq          = data.afPingpongIrq;
+       packedData.awbPingpongIrq         = data.awbPingpongIrq;
+       packedData.histPingpongIrq        = data.histPingpongIrq;
+       packedData.encIrq                 = data.encIrq;
+       packedData.viewIrq                = data.viewIrq;
+       packedData.busOverflowIrq         = data.busOverflowIrq;
+       packedData.afOverflowIrq          = data.afOverflowIrq;
+       packedData.awbOverflowIrq         = data.awbOverflowIrq;
+       packedData.syncTimer0Irq          = data.syncTimer0Irq;
+       packedData.syncTimer1Irq          = data.syncTimer1Irq;
+       packedData.syncTimer2Irq          = data.syncTimer2Irq;
+       packedData.asyncTimer0Irq         = data.asyncTimer0Irq;
+       packedData.asyncTimer1Irq         = data.asyncTimer1Irq;
+       packedData.asyncTimer2Irq         = data.asyncTimer2Irq;
+       packedData.asyncTimer3Irq         = data.asyncTimer3Irq;
+       packedData.axiErrorIrq            = data.axiErrorIrq;
+       packedData.violationIrq           = data.violationIrq;
+
+       return *((uint32_t *)&packedData);
+}
+
+static uint32_t
+vfe_irq_composite_pack(struct vfe_irq_composite_mask_config data)
+{
+       struct VFE_Irq_Composite_MaskType packedData;
+
+       memset(&packedData, 0, sizeof(packedData));
+
+       packedData.encIrqComMaskBits   = data.encIrqComMask;
+       packedData.viewIrqComMaskBits  = data.viewIrqComMask;
+       packedData.ceDoneSelBits       = data.ceDoneSel;
+
+       return *((uint32_t *)&packedData);
+}
+
+static void vfe_addr_convert(struct msm_vfe_phy_info *pinfo,
+       enum vfe_resp_msg type, void *data, void **ext, int32_t *elen)
+{
+       switch (type) {
+       case VFE_MSG_OUTPUT1: {
+               pinfo->y_phy =
+                       ((struct vfe_message *)data)->_u.msgOutput1.yBuffer;
+               pinfo->cbcr_phy =
+                       ((struct vfe_message *)data)->_u.msgOutput1.cbcrBuffer;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->bpcInfo =
+               ((struct vfe_message *)data)->_u.msgOutput1.bpcInfo;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->asfInfo =
+               ((struct vfe_message *)data)->_u.msgOutput1.asfInfo;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->frameCounter =
+               ((struct vfe_message *)data)->_u.msgOutput1.frameCounter;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->pmData =
+               ((struct vfe_message *)data)->_u.msgOutput1.pmData;
+
+               *ext  = ctrl->extdata;
+               *elen = ctrl->extlen;
+       }
+               break;
+
+       case VFE_MSG_OUTPUT2: {
+               pinfo->y_phy =
+                       ((struct vfe_message *)data)->_u.msgOutput2.yBuffer;
+               pinfo->cbcr_phy =
+                       ((struct vfe_message *)data)->_u.msgOutput2.cbcrBuffer;
+
+               CDBG("vfe_addr_convert, pinfo->y_phy = 0x%x\n", pinfo->y_phy);
+               CDBG("vfe_addr_convert, pinfo->cbcr_phy = 0x%x\n",
+                       pinfo->cbcr_phy);
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->bpcInfo =
+               ((struct vfe_message *)data)->_u.msgOutput2.bpcInfo;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->asfInfo =
+               ((struct vfe_message *)data)->_u.msgOutput2.asfInfo;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->frameCounter =
+               ((struct vfe_message *)data)->_u.msgOutput2.frameCounter;
+
+               ((struct vfe_frame_extra *)ctrl->extdata)->pmData =
+               ((struct vfe_message *)data)->_u.msgOutput2.pmData;
+
+               *ext  = ctrl->extdata;
+               *elen = ctrl->extlen;
+       }
+               break;
+
+       case VFE_MSG_STATS_AF:
+               pinfo->sbuf_phy =
+               ((struct vfe_message *)data)->_u.msgStatsAf.afBuffer;
+               break;
+
+       case VFE_MSG_STATS_WE:
+               pinfo->sbuf_phy =
+               ((struct vfe_message *)data)->_u.msgStatsWbExp.awbBuffer;
+               break;
+
+       default:
+               break;
+       } /* switch */
+}
+
+static void
+vfe_proc_ops(enum VFE_MESSAGE_ID id, void *msg, size_t len)
+{
+       struct msm_vfe_resp *rp;
+
+       /* In 8k, OUTPUT1 & OUTPUT2 messages arrive before
+        * SNAPSHOT_DONE. We don't send such messages to user */
+
+       CDBG("ctrl->vfeOperationMode = %d, msgId = %d\n",
+               ctrl->vfeOperationMode, id);
+
+       if ((ctrl->vfeOperationMode == VFE_START_OPERATION_MODE_SNAPSHOT) &&
+               (id == VFE_MSG_ID_OUTPUT1 || id == VFE_MSG_ID_OUTPUT2)) {
+               return;
+       }
+
+       rp = ctrl->resp->vfe_alloc(sizeof(struct msm_vfe_resp), ctrl->syncdata);
+       if (!rp) {
+               CDBG("rp: cannot allocate buffer\n");
+               return;
+       }
+
+       CDBG("vfe_proc_ops, msgId = %d\n", id);
+
+       rp->evt_msg.type   = MSM_CAMERA_MSG;
+       rp->evt_msg.msg_id = id;
+       rp->evt_msg.len    = len;
+       rp->evt_msg.data   = msg;
+
+       switch (rp->evt_msg.msg_id) {
+       case VFE_MSG_ID_SNAPSHOT_DONE:
+               rp->type = VFE_MSG_SNAPSHOT;
+               break;
+
+       case VFE_MSG_ID_OUTPUT1:
+               rp->type = VFE_MSG_OUTPUT1;
+               vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT1,
+                       rp->evt_msg.data, &(rp->extdata),
+                       &(rp->extlen));
+               break;
+
+       case VFE_MSG_ID_OUTPUT2:
+               rp->type = VFE_MSG_OUTPUT2;
+               vfe_addr_convert(&(rp->phy), VFE_MSG_OUTPUT2,
+                               rp->evt_msg.data, &(rp->extdata),
+                               &(rp->extlen));
+               break;
+
+       case VFE_MSG_ID_STATS_AUTOFOCUS:
+               rp->type = VFE_MSG_STATS_AF;
+               vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_AF,
+                               rp->evt_msg.data, NULL, NULL);
+               break;
+
+       case VFE_MSG_ID_STATS_WB_EXP:
+               rp->type = VFE_MSG_STATS_WE;
+               vfe_addr_convert(&(rp->phy), VFE_MSG_STATS_WE,
+                               rp->evt_msg.data, NULL, NULL);
+               break;
+
+       default:
+               rp->type = VFE_MSG_GENERAL;
+               break;
+       }
+
+       ctrl->resp->vfe_resp(rp, MSM_CAM_Q_VFE_MSG, ctrl->syncdata);
+}
+
+static void vfe_send_msg_no_payload(enum VFE_MESSAGE_ID id)
+{
+       struct vfe_message *msg;
+
+       msg = kzalloc(sizeof(msg), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       msg->_d = id;
+       vfe_proc_ops(id, msg, 0);
+}
+
+static void vfe_send_bus_overflow_msg(void)
+{
+       struct vfe_message *msg;
+       msg =
+               kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       msg->_d = VFE_MSG_ID_BUS_OVERFLOW;
+#if 0
+       memcpy(&(msg->_u.msgBusOverflow),
+               &ctrl->vfePmData, sizeof(ctrl->vfePmData));
+#endif
+
+       vfe_proc_ops(VFE_MSG_ID_BUS_OVERFLOW,
+               msg, sizeof(struct vfe_message));
+}
+
+static void vfe_send_camif_error_msg(void)
+{
+#if 0
+       struct vfe_message *msg;
+       msg =
+               kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       msg->_d = VFE_MSG_ID_CAMIF_ERROR;
+       memcpy(&(msg->_u.msgCamifError),
+               &ctrl->vfeCamifStatusLocal, sizeof(ctrl->vfeCamifStatusLocal));
+
+       vfe_proc_ops(VFE_MSG_ID_CAMIF_ERROR,
+               msg, sizeof(struct vfe_message));
+#endif
+}
+
+static void vfe_process_error_irq(
+       struct vfe_interrupt_status *irqstatus)
+{
+       /* all possible error irq.  Note error irqs are not enabled, it is
+        * checked only when other interrupts are present. */
+       if (irqstatus->afOverflowIrq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_AF_OVERFLOW);
+
+       if (irqstatus->awbOverflowIrq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_AWB_OVERFLOW);
+
+       if (irqstatus->axiErrorIrq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_AXI_ERROR);
+
+       if (irqstatus->busOverflowIrq)
+               vfe_send_bus_overflow_msg();
+
+       if (irqstatus->camifErrorIrq)
+               vfe_send_camif_error_msg();
+
+       if (irqstatus->camifOverflowIrq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_CAMIF_OVERFLOW);
+
+       if (irqstatus->violationIrq)
+               ;
+}
+
+static void vfe_process_camif_sof_irq(void)
+{
+       /* increment the frame id number. */
+       ctrl->vfeFrameId++;
+
+       CDBG("camif_sof_irq, frameId = %d\n",
+               ctrl->vfeFrameId);
+
+       /* In snapshot mode, if frame skip is programmed,
+       * need to check it accordingly to stop camif at
+       * correct frame boundary. For the dropped frames,
+       * there won't be any output path irqs, but there is
+       * still SOF irq, which can help us determine when
+       * to stop the camif.
+       */
+       if (ctrl->vfeOperationMode) {
+               if ((1 << ctrl->vfeFrameSkipCount) &
+                               ctrl->vfeFrameSkipPattern) {
+
+                       ctrl->vfeSnapShotCount--;
+                       if (ctrl->vfeSnapShotCount == 0)
+                               /* terminate vfe pipeline at frame boundary. */
+                               writel(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+                                       ctrl->vfebase + CAMIF_COMMAND);
+               }
+
+               /* update frame skip counter for bit checking. */
+               ctrl->vfeFrameSkipCount++;
+               if (ctrl->vfeFrameSkipCount ==
+                               (ctrl->vfeFrameSkipPeriod + 1))
+                       ctrl->vfeFrameSkipCount = 0;
+       }
+}
+
+static int vfe_get_af_pingpong_status(void)
+{
+       uint32_t busPingPongStatus;
+       int rc = 0;
+
+       busPingPongStatus =
+               readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+       if ((busPingPongStatus & VFE_AF_PINGPONG_STATUS_BIT) == 0)
+               return -EFAULT;
+
+       return rc;
+}
+
+static uint32_t vfe_read_af_buf_addr(boolean pipo)
+{
+       if (pipo == FALSE)
+               return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+       else
+               return readl(ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static void
+vfe_update_af_buf_addr(boolean pipo, uint32_t addr)
+{
+       if (pipo == FALSE)
+               writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+       else
+               writel(addr, ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+}
+
+static void
+vfe_send_af_stats_msg(uint32_t afBufAddress)
+{
+       /* unsigned long flags; */
+       struct vfe_message *msg;
+       msg =
+               kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       /* fill message with right content. */
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+       if (ctrl->vstate != VFE_STATE_ACTIVE)
+               goto af_stats_done;
+
+       msg->_d = VFE_MSG_ID_STATS_AUTOFOCUS;
+       msg->_u.msgStatsAf.afBuffer = afBufAddress;
+       msg->_u.msgStatsAf.frameCounter = ctrl->vfeFrameId;
+
+       vfe_proc_ops(VFE_MSG_ID_STATS_AUTOFOCUS,
+               msg, sizeof(struct vfe_message));
+
+       ctrl->afStatsControl.ackPending = TRUE;
+
+af_stats_done:
+       /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+       return;
+}
+
+static void vfe_process_stats_af_irq(void)
+{
+       boolean bufferAvailable;
+
+       if (!(ctrl->afStatsControl.ackPending)) {
+
+               /* read hardware status. */
+               ctrl->afStatsControl.pingPongStatus =
+                       vfe_get_af_pingpong_status();
+
+               bufferAvailable =
+                       (ctrl->afStatsControl.pingPongStatus) ^ 1;
+
+               ctrl->afStatsControl.bufToRender =
+                       vfe_read_af_buf_addr(bufferAvailable);
+
+               /* update the same buffer address (ping or pong) */
+               vfe_update_af_buf_addr(bufferAvailable,
+                       ctrl->afStatsControl.nextFrameAddrBuf);
+
+               vfe_send_af_stats_msg(ctrl->afStatsControl.bufToRender);
+       } else
+               ctrl->afStatsControl.droppedStatsFrameCount++;
+}
+
+static boolean vfe_get_awb_pingpong_status(void)
+{
+       uint32_t busPingPongStatus;
+
+       busPingPongStatus =
+               readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+       if ((busPingPongStatus & VFE_AWB_PINGPONG_STATUS_BIT) == 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+static uint32_t
+vfe_read_awb_buf_addr(boolean pingpong)
+{
+       if (pingpong == FALSE)
+               return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+       else
+               return readl(ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_update_awb_buf_addr(
+       boolean pingpong, uint32_t addr)
+{
+       if (pingpong == FALSE)
+               writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+       else
+               writel(addr, ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+}
+
+static void vfe_send_awb_stats_msg(uint32_t awbBufAddress)
+{
+       /* unsigned long flags; */
+       struct vfe_message   *msg;
+
+       msg =
+               kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       /* fill message with right content. */
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+       if (ctrl->vstate != VFE_STATE_ACTIVE)
+               goto awb_stats_done;
+
+       msg->_d = VFE_MSG_ID_STATS_WB_EXP;
+       msg->_u.msgStatsWbExp.awbBuffer = awbBufAddress;
+       msg->_u.msgStatsWbExp.frameCounter = ctrl->vfeFrameId;
+
+       vfe_proc_ops(VFE_MSG_ID_STATS_WB_EXP,
+               msg, sizeof(struct vfe_message));
+
+       ctrl->awbStatsControl.ackPending = TRUE;
+
+awb_stats_done:
+       /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+       return;
+}
+
+static void vfe_process_stats_awb_irq(void)
+{
+       boolean bufferAvailable;
+
+       if (!(ctrl->awbStatsControl.ackPending)) {
+
+               ctrl->awbStatsControl.pingPongStatus =
+                       vfe_get_awb_pingpong_status();
+
+               bufferAvailable = (ctrl->awbStatsControl.pingPongStatus) ^ 1;
+
+               ctrl->awbStatsControl.bufToRender =
+                       vfe_read_awb_buf_addr(bufferAvailable);
+
+               vfe_update_awb_buf_addr(bufferAvailable,
+                       ctrl->awbStatsControl.nextFrameAddrBuf);
+
+               vfe_send_awb_stats_msg(ctrl->awbStatsControl.bufToRender);
+
+       } else
+               ctrl->awbStatsControl.droppedStatsFrameCount++;
+}
+
+static void vfe_process_sync_timer_irq(
+       struct vfe_interrupt_status *irqstatus)
+{
+       if (irqstatus->syncTimer0Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER0_DONE);
+
+       if (irqstatus->syncTimer1Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER1_DONE);
+
+       if (irqstatus->syncTimer2Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_SYNC_TIMER2_DONE);
+}
+
+static void vfe_process_async_timer_irq(
+       struct vfe_interrupt_status *irqstatus)
+{
+
+       if (irqstatus->asyncTimer0Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER0_DONE);
+
+       if (irqstatus->asyncTimer1Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER1_DONE);
+
+       if (irqstatus->asyncTimer2Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER2_DONE);
+
+       if (irqstatus->asyncTimer3Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER3_DONE);
+}
+
+static void vfe_send_violation_msg(void)
+{
+       vfe_send_msg_no_payload(VFE_MSG_ID_VIOLATION);
+}
+
+static void vfe_send_async_timer_msg(void)
+{
+       vfe_send_msg_no_payload(VFE_MSG_ID_ASYNC_TIMER0_DONE);
+}
+
+static void vfe_write_gamma_table(uint8_t channel,
+       boolean bank, int16_t *pTable)
+{
+       uint16_t i;
+
+       enum VFE_DMI_RAM_SEL dmiRamSel = NO_MEM_SELECTED;
+
+       switch (channel) {
+       case 0:
+               if (bank == 0)
+                       dmiRamSel = RGBLUT_RAM_CH0_BANK0;
+               else
+                       dmiRamSel = RGBLUT_RAM_CH0_BANK1;
+               break;
+
+       case 1:
+               if (bank == 0)
+                       dmiRamSel = RGBLUT_RAM_CH1_BANK0;
+               else
+                       dmiRamSel = RGBLUT_RAM_CH1_BANK1;
+               break;
+
+       case 2:
+               if (bank == 0)
+                       dmiRamSel = RGBLUT_RAM_CH2_BANK0;
+               else
+                       dmiRamSel = RGBLUT_RAM_CH2_BANK1;
+               break;
+
+       default:
+               break;
+       }
+
+       vfe_program_dmi_cfg(dmiRamSel);
+
+       for (i = 0; i < VFE_GAMMA_TABLE_LENGTH; i++) {
+               writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+               pTable++;
+       }
+
+       /* After DMI transfer, need to set the DMI_CFG to unselect any SRAM
+       unselect the SRAM Bank. */
+       writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+}
+
+static void vfe_prog_hw_testgen_cmd(uint32_t value)
+{
+       writel(value, ctrl->vfebase + VFE_HW_TESTGEN_CMD);
+}
+
+static inline void vfe_read_irq_status(struct vfe_irq_thread_msg *out)
+{
+       uint32_t *temp;
+
+       memset(out, 0, sizeof(struct vfe_irq_thread_msg));
+
+       temp = (uint32_t *)(ctrl->vfebase + VFE_IRQ_STATUS);
+       out->vfeIrqStatus = readl(temp);
+
+       temp = (uint32_t *)(ctrl->vfebase + CAMIF_STATUS);
+       out->camifStatus = readl(temp);
+       writel(0x7, ctrl->vfebase + CAMIF_COMMAND);
+       writel(0x3, ctrl->vfebase + CAMIF_COMMAND);
+       CDBG("camifStatus  = 0x%x\n", out->camifStatus);
+
+/*
+       temp = (uint32_t *)(ctrl->vfebase + VFE_DEMOSAIC_STATUS);
+       out->demosaicStatus = readl(temp);
+
+       temp = (uint32_t *)(ctrl->vfebase + VFE_ASF_MAX_EDGE);
+       out->asfMaxEdge = readl(temp);
+
+       temp = (uint32_t *)(ctrl->vfebase + VFE_BUS_ENC_Y_WR_PM_STATS_0);
+*/
+
+#if 0
+       out->pmInfo.encPathPmInfo.yWrPmStats0      = readl(temp++);
+       out->pmInfo.encPathPmInfo.yWrPmStats1      = readl(temp++);
+       out->pmInfo.encPathPmInfo.cbcrWrPmStats0   = readl(temp++);
+       out->pmInfo.encPathPmInfo.cbcrWrPmStats1   = readl(temp++);
+       out->pmInfo.viewPathPmInfo.yWrPmStats0     = readl(temp++);
+       out->pmInfo.viewPathPmInfo.yWrPmStats1     = readl(temp++);
+       out->pmInfo.viewPathPmInfo.cbcrWrPmStats0  = readl(temp++);
+       out->pmInfo.viewPathPmInfo.cbcrWrPmStats1  = readl(temp);
+#endif /* if 0 Jeff */
+}
+
+static struct vfe_interrupt_status
+vfe_parse_interrupt_status(uint32_t irqStatusIn)
+{
+       struct vfe_irqenable hwstat;
+       struct vfe_interrupt_status ret;
+       boolean temp;
+
+       memset(&hwstat, 0, sizeof(hwstat));
+       memset(&ret, 0, sizeof(ret));
+
+       hwstat = *((struct vfe_irqenable *)(&irqStatusIn));
+
+       ret.camifErrorIrq       = hwstat.camifErrorIrq;
+       ret.camifSofIrq         = hwstat.camifSofIrq;
+       ret.camifEolIrq         = hwstat.camifEolIrq;
+       ret.camifEofIrq         = hwstat.camifEofIrq;
+       ret.camifEpoch1Irq      = hwstat.camifEpoch1Irq;
+       ret.camifEpoch2Irq      = hwstat.camifEpoch2Irq;
+       ret.camifOverflowIrq    = hwstat.camifOverflowIrq;
+       ret.ceIrq               = hwstat.ceIrq;
+       ret.regUpdateIrq        = hwstat.regUpdateIrq;
+       ret.resetAckIrq         = hwstat.resetAckIrq;
+       ret.encYPingpongIrq     = hwstat.encYPingpongIrq;
+       ret.encCbcrPingpongIrq  = hwstat.encCbcrPingpongIrq;
+       ret.viewYPingpongIrq    = hwstat.viewYPingpongIrq;
+       ret.viewCbcrPingpongIrq = hwstat.viewCbcrPingpongIrq;
+       ret.rdPingpongIrq       = hwstat.rdPingpongIrq;
+       ret.afPingpongIrq       = hwstat.afPingpongIrq;
+       ret.awbPingpongIrq      = hwstat.awbPingpongIrq;
+       ret.histPingpongIrq     = hwstat.histPingpongIrq;
+       ret.encIrq              = hwstat.encIrq;
+       ret.viewIrq             = hwstat.viewIrq;
+       ret.busOverflowIrq      = hwstat.busOverflowIrq;
+       ret.afOverflowIrq       = hwstat.afOverflowIrq;
+       ret.awbOverflowIrq      = hwstat.awbOverflowIrq;
+       ret.syncTimer0Irq       = hwstat.syncTimer0Irq;
+       ret.syncTimer1Irq       = hwstat.syncTimer1Irq;
+       ret.syncTimer2Irq       = hwstat.syncTimer2Irq;
+       ret.asyncTimer0Irq      = hwstat.asyncTimer0Irq;
+       ret.asyncTimer1Irq      = hwstat.asyncTimer1Irq;
+       ret.asyncTimer2Irq      = hwstat.asyncTimer2Irq;
+       ret.asyncTimer3Irq      = hwstat.asyncTimer3Irq;
+       ret.axiErrorIrq         = hwstat.axiErrorIrq;
+       ret.violationIrq        = hwstat.violationIrq;
+
+       /* logic OR of any error bits
+        * although each irq corresponds to a bit, the data type here is a
+        * boolean already. hence use logic operation.
+        */
+       temp =
+               ret.camifErrorIrq    ||
+               ret.camifOverflowIrq ||
+               ret.afOverflowIrq    ||
+               ret.awbPingpongIrq   ||
+               ret.busOverflowIrq   ||
+               ret.axiErrorIrq      ||
+               ret.violationIrq;
+
+       ret.anyErrorIrqs = temp;
+
+       /* logic OR of any output path bits*/
+       temp =
+               ret.encYPingpongIrq    ||
+               ret.encCbcrPingpongIrq ||
+               ret.encIrq;
+
+       ret.anyOutput2PathIrqs = temp;
+
+       temp =
+               ret.viewYPingpongIrq    ||
+               ret.viewCbcrPingpongIrq ||
+               ret.viewIrq;
+
+       ret.anyOutput1PathIrqs = temp;
+
+       ret.anyOutputPathIrqs =
+               ret.anyOutput1PathIrqs ||
+               ret.anyOutput2PathIrqs;
+
+       /* logic OR of any sync timer bits*/
+       temp =
+               ret.syncTimer0Irq ||
+               ret.syncTimer1Irq ||
+               ret.syncTimer2Irq;
+
+       ret.anySyncTimerIrqs = temp;
+
+       /* logic OR of any async timer bits*/
+       temp =
+               ret.asyncTimer0Irq ||
+               ret.asyncTimer1Irq ||
+               ret.asyncTimer2Irq ||
+               ret.asyncTimer3Irq;
+
+       ret.anyAsyncTimerIrqs = temp;
+
+       /* bool for all interrupts that are not allowed in idle state */
+       temp =
+               ret.anyErrorIrqs      ||
+               ret.anyOutputPathIrqs ||
+               ret.anySyncTimerIrqs  ||
+               ret.regUpdateIrq      ||
+               ret.awbPingpongIrq    ||
+               ret.afPingpongIrq     ||
+               ret.camifSofIrq       ||
+               ret.camifEpoch2Irq    ||
+               ret.camifEpoch1Irq;
+
+       ret.anyIrqForActiveStatesOnly =
+               temp;
+
+       return ret;
+}
+
+static struct vfe_frame_asf_info
+vfe_get_asf_frame_info(struct vfe_irq_thread_msg *in)
+{
+       struct vfe_asf_info     asfInfoTemp;
+       struct vfe_frame_asf_info rc;
+
+       memset(&rc, 0, sizeof(rc));
+       memset(&asfInfoTemp, 0, sizeof(asfInfoTemp));
+
+       asfInfoTemp =
+               *((struct vfe_asf_info *)(&(in->asfMaxEdge)));
+
+       rc.asfHbiCount = asfInfoTemp.HBICount;
+       rc.asfMaxEdge  = asfInfoTemp.maxEdge;
+
+       return rc;
+}
+
+static struct vfe_frame_bpc_info
+vfe_get_demosaic_frame_info(struct vfe_irq_thread_msg *in)
+{
+       struct vfe_bps_info     bpcInfoTemp;
+       struct vfe_frame_bpc_info rc;
+
+       memset(&rc, 0, sizeof(rc));
+       memset(&bpcInfoTemp, 0, sizeof(bpcInfoTemp));
+
+       bpcInfoTemp =
+               *((struct vfe_bps_info *)(&(in->demosaicStatus)));
+
+       rc.greenDefectPixelCount    =
+               bpcInfoTemp.greenBadPixelCount;
+
+       rc.redBlueDefectPixelCount  =
+               bpcInfoTemp.RedBlueBadPixelCount;
+
+       return rc;
+}
+
+static struct vfe_msg_camif_status
+vfe_get_camif_status(struct vfe_irq_thread_msg *in)
+{
+       struct vfe_camif_stats camifStatusTemp;
+       struct vfe_msg_camif_status rc;
+
+       memset(&rc, 0, sizeof(rc));
+       memset(&camifStatusTemp, 0, sizeof(camifStatusTemp));
+
+       camifStatusTemp =
+               *((struct vfe_camif_stats *)(&(in->camifStatus)));
+
+       rc.camifState = (boolean)camifStatusTemp.camifHalt;
+       rc.lineCount  = camifStatusTemp.lineCount;
+       rc.pixelCount = camifStatusTemp.pixelCount;
+
+       return rc;
+}
+
+static struct vfe_bus_performance_monitor
+vfe_get_performance_monitor_data(struct vfe_irq_thread_msg *in)
+{
+       struct vfe_bus_performance_monitor rc;
+       memset(&rc, 0, sizeof(rc));
+
+       rc.encPathPmInfo.yWrPmStats0     =
+               in->pmInfo.encPathPmInfo.yWrPmStats0;
+       rc.encPathPmInfo.yWrPmStats1     =
+               in->pmInfo.encPathPmInfo.yWrPmStats1;
+       rc.encPathPmInfo.cbcrWrPmStats0  =
+               in->pmInfo.encPathPmInfo.cbcrWrPmStats0;
+       rc.encPathPmInfo.cbcrWrPmStats1  =
+               in->pmInfo.encPathPmInfo.cbcrWrPmStats1;
+       rc.viewPathPmInfo.yWrPmStats0    =
+               in->pmInfo.viewPathPmInfo.yWrPmStats0;
+       rc.viewPathPmInfo.yWrPmStats1    =
+               in->pmInfo.viewPathPmInfo.yWrPmStats1;
+       rc.viewPathPmInfo.cbcrWrPmStats0 =
+               in->pmInfo.viewPathPmInfo.cbcrWrPmStats0;
+       rc.viewPathPmInfo.cbcrWrPmStats1 =
+               in->pmInfo.viewPathPmInfo.cbcrWrPmStats1;
+
+       return rc;
+}
+
+static void vfe_process_reg_update_irq(void)
+{
+       CDBG("vfe_process_reg_update_irq: ackPendingFlag is %d\n",
+       ctrl->vfeStartAckPendingFlag);
+       if (ctrl->vfeStartAckPendingFlag == TRUE) {
+               vfe_send_msg_no_payload(VFE_MSG_ID_START_ACK);
+               ctrl->vfeStartAckPendingFlag = FALSE;
+       } else
+               vfe_send_msg_no_payload(VFE_MSG_ID_UPDATE_ACK);
+}
+
+static void vfe_process_reset_irq(void)
+{
+       /* unsigned long flags; */
+
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+       ctrl->vstate = VFE_STATE_IDLE;
+       /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+
+       if (ctrl->vfeStopAckPending == TRUE) {
+               ctrl->vfeStopAckPending = FALSE;
+               vfe_send_msg_no_payload(VFE_MSG_ID_STOP_ACK);
+       } else {
+               vfe_set_default_reg_values();
+               vfe_send_msg_no_payload(VFE_MSG_ID_RESET_ACK);
+       }
+}
+
+static void vfe_process_pingpong_irq(struct vfe_output_path *in,
+       uint8_t fragmentCount)
+{
+       uint16_t circularIndex;
+       uint32_t nextFragmentAddr;
+
+       /* get next fragment address from circular buffer */
+       circularIndex    = (in->fragIndex) % (2 * fragmentCount);
+       nextFragmentAddr = in->addressBuffer[circularIndex];
+
+       in->fragIndex = circularIndex + 1;
+
+       /* use next fragment to program hardware ping/pong address. */
+       if (in->hwCurrentFlag == ping) {
+               writel(nextFragmentAddr, in->hwRegPingAddress);
+               in->hwCurrentFlag = pong;
+
+       } else {
+               writel(nextFragmentAddr, in->hwRegPongAddress);
+               in->hwCurrentFlag = ping;
+       }
+}
+
+static void vfe_send_output2_msg(
+       struct vfe_msg_output *pPayload)
+{
+       /* unsigned long flags; */
+       struct vfe_message *msg;
+
+       msg = kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       /* fill message with right content. */
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+       if (ctrl->vstate != VFE_STATE_ACTIVE)
+               goto output2_msg_done;
+
+       msg->_d = VFE_MSG_ID_OUTPUT2;
+
+       memcpy(&(msg->_u.msgOutput2),
+               (void *)pPayload, sizeof(struct vfe_msg_output));
+
+       vfe_proc_ops(VFE_MSG_ID_OUTPUT2,
+               msg, sizeof(struct vfe_message));
+
+       ctrl->encPath.ackPending = TRUE;
+
+       if (!(ctrl->vfeRequestedSnapShotCount <= 3) &&
+                       (ctrl->vfeOperationMode ==
+                        VFE_START_OPERATION_MODE_SNAPSHOT))
+               ctrl->encPath.ackPending = TRUE;
+
+output2_msg_done:
+       /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+       return;
+}
+
+static void vfe_send_output1_msg(
+       struct vfe_msg_output *pPayload)
+{
+       /* unsigned long flags; */
+       struct vfe_message *msg;
+
+       msg = kzalloc(sizeof(struct vfe_message), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       /* @todo This is causing issues, need further investigate */
+       /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+       if (ctrl->vstate != VFE_STATE_ACTIVE)
+               goto output1_msg_done;
+
+       msg->_d = VFE_MSG_ID_OUTPUT1;
+       memmove(&(msg->_u),
+               (void *)pPayload, sizeof(struct vfe_msg_output));
+
+       vfe_proc_ops(VFE_MSG_ID_OUTPUT1,
+               msg, sizeof(struct vfe_message));
+
+       ctrl->viewPath.ackPending = TRUE;
+
+       if (!(ctrl->vfeRequestedSnapShotCount <= 3) &&
+                       (ctrl->vfeOperationMode ==
+                        VFE_START_OPERATION_MODE_SNAPSHOT))
+               ctrl->viewPath.ackPending = TRUE;
+
+output1_msg_done:
+       /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+       return;
+}
+
+static void vfe_send_output_msg(boolean whichOutputPath,
+       uint32_t yPathAddr, uint32_t cbcrPathAddr)
+{
+       struct vfe_msg_output msgPayload;
+
+       msgPayload.yBuffer = yPathAddr;
+       msgPayload.cbcrBuffer = cbcrPathAddr;
+
+       /* asf info is common for both output1 and output2 */
+#if 0
+       msgPayload.asfInfo.asfHbiCount = ctrl->vfeAsfFrameInfo.asfHbiCount;
+       msgPayload.asfInfo.asfMaxEdge = ctrl->vfeAsfFrameInfo.asfMaxEdge;
+
+       /* demosaic info is common for both output1 and output2 */
+       msgPayload.bpcInfo.greenDefectPixelCount =
+               ctrl->vfeBpcFrameInfo.greenDefectPixelCount;
+       msgPayload.bpcInfo.redBlueDefectPixelCount =
+               ctrl->vfeBpcFrameInfo.redBlueDefectPixelCount;
+#endif /* if 0 */
+
+       /* frame ID is common for both paths. */
+       msgPayload.frameCounter = ctrl->vfeFrameId;
+
+       if (whichOutputPath) {
+               /* msgPayload.pmData = ctrl->vfePmData.encPathPmInfo; */
+               vfe_send_output2_msg(&msgPayload);
+       } else {
+               /* msgPayload.pmData = ctrl->vfePmData.viewPathPmInfo; */
+               vfe_send_output1_msg(&msgPayload);
+       }
+}
+
+static void vfe_process_frame_done_irq_multi_frag(
+       struct vfe_output_path_combo *in)
+{
+       uint32_t yAddress, cbcrAddress;
+       uint16_t idx;
+       uint32_t *ptrY;
+       uint32_t *ptrCbcr;
+       const uint32_t *ptrSrc;
+       uint8_t i;
+
+       if (!in->ackPending) {
+
+               idx = (in->currentFrame) * (in->fragCount);
+
+               /* Send output message. */
+               yAddress = in->yPath.addressBuffer[idx];
+               cbcrAddress = in->cbcrPath.addressBuffer[idx];
+
+               /* copy next frame to current frame. */
+               ptrSrc  = in->nextFrameAddrBuf;
+               ptrY    = (uint32_t *)&(in->yPath.addressBuffer[idx]);
+               ptrCbcr = (uint32_t *)&(in->cbcrPath.addressBuffer[idx]);
+
+               /* Copy Y address */
+               for (i = 0; i < in->fragCount; i++)
+                       *ptrY++ = *ptrSrc++;
+
+               /* Copy Cbcr address */
+               for (i = 0; i < in->fragCount; i++)
+                       *ptrCbcr++ = *ptrSrc++;
+
+               vfe_send_output_msg(in->whichOutputPath, yAddress, cbcrAddress);
+
+       } else {
+               if (in->whichOutputPath == 0)
+                       ctrl->vfeDroppedFrameCounts.output1Count++;
+
+               if (in->whichOutputPath == 1)
+                       ctrl->vfeDroppedFrameCounts.output2Count++;
+       }
+
+       /* toggle current frame. */
+       in->currentFrame = in->currentFrame^1;
+
+       if (ctrl->vfeOperationMode)
+               in->snapshotPendingCount--;
+}
+
+static void vfe_process_frame_done_irq_no_frag_io(
+       struct vfe_output_path_combo *in, uint32_t *pNextAddr,
+       uint32_t *pdestRenderAddr)
+{
+       uint32_t busPingPongStatus;
+       uint32_t tempAddress;
+
+       /* 1. read hw status register. */
+       busPingPongStatus =
+               readl(ctrl->vfebase + VFE_BUS_PINGPONG_STATUS);
+
+       CDBG("hardware status is 0x%x\n", busPingPongStatus);
+
+       /* 2. determine ping or pong */
+       /* use cbcr status */
+       busPingPongStatus = busPingPongStatus & (1<<(in->cbcrStatusBit));
+
+       /* 3. read out address and update address */
+       if (busPingPongStatus == 0) {
+               /* hw is working on ping, render pong buffer */
+               /* a. read out pong address */
+               /* read out y address. */
+               tempAddress = readl(in->yPath.hwRegPongAddress);
+
+               CDBG("pong 1 addr = 0x%x\n", tempAddress);
+               *pdestRenderAddr++ = tempAddress;
+               /* read out cbcr address. */
+               tempAddress = readl(in->cbcrPath.hwRegPongAddress);
+
+               CDBG("pong 2 addr = 0x%x\n", tempAddress);
+               *pdestRenderAddr = tempAddress;
+
+               /* b. update pong address */
+               writel(*pNextAddr++, in->yPath.hwRegPongAddress);
+               writel(*pNextAddr, in->cbcrPath.hwRegPongAddress);
+       } else {
+               /* hw is working on pong, render ping buffer */
+
+               /* a. read out ping address */
+               tempAddress = readl(in->yPath.hwRegPingAddress);
+               CDBG("ping 1 addr = 0x%x\n", tempAddress);
+               *pdestRenderAddr++ = tempAddress;
+               tempAddress = readl(in->cbcrPath.hwRegPingAddress);
+
+               CDBG("ping 2 addr = 0x%x\n", tempAddress);
+               *pdestRenderAddr = tempAddress;
+
+               /* b. update ping address */
+               writel(*pNextAddr++, in->yPath.hwRegPingAddress);
+               CDBG("NextAddress = 0x%x\n", *pNextAddr);
+               writel(*pNextAddr, in->cbcrPath.hwRegPingAddress);
+       }
+}
+
+static void vfe_process_frame_done_irq_no_frag(
+       struct vfe_output_path_combo *in)
+{
+       uint32_t addressToRender[2];
+       static uint32_t fcnt;
+
+       if (fcnt++ < 3)
+               return;
+
+       if (!in->ackPending) {
+               vfe_process_frame_done_irq_no_frag_io(in,
+                       in->nextFrameAddrBuf, addressToRender);
+
+               /* use addressToRender to send out message. */
+               vfe_send_output_msg(in->whichOutputPath,
+                               addressToRender[0], addressToRender[1]);
+
+       } else {
+               /* ackPending is still there, accumulate dropped frame count.
+                * These count can be read through ioctrl command. */
+               CDBG("waiting frame ACK\n");
+
+               if (in->whichOutputPath == 0)
+                       ctrl->vfeDroppedFrameCounts.output1Count++;
+
+               if (in->whichOutputPath == 1)
+                       ctrl->vfeDroppedFrameCounts.output2Count++;
+       }
+
+       /* in case of multishot when upper layer did not ack, there will still
+        * be a snapshot done msg sent out, even though the number of frames
+        * sent out may be less than the desired number of frames.  snapshot
+        * done msg would be helpful to indicate that vfe pipeline has stop,
+        * and in good known state.
+        */
+       if (ctrl->vfeOperationMode)
+               in->snapshotPendingCount--;
+}
+
+static void vfe_process_output_path_irq(
+       struct vfe_interrupt_status *irqstatus)
+{
+       /* unsigned long flags; */
+
+       /* process the view path interrupts */
+       if (irqstatus->anyOutput1PathIrqs) {
+               if (ctrl->viewPath.multiFrag) {
+
+                       if (irqstatus->viewCbcrPingpongIrq)
+                               vfe_process_pingpong_irq(
+                                       &(ctrl->viewPath.cbcrPath),
+                                       ctrl->viewPath.fragCount);
+
+                       if (irqstatus->viewYPingpongIrq)
+                               vfe_process_pingpong_irq(
+                                       &(ctrl->viewPath.yPath),
+                                       ctrl->viewPath.fragCount);
+
+                       if (irqstatus->viewIrq)
+                               vfe_process_frame_done_irq_multi_frag(
+                                       &ctrl->viewPath);
+
+               } else {
+                       /* typical case for no fragment,
+                        only frame done irq is enabled. */
+                       if (irqstatus->viewIrq)
+                               vfe_process_frame_done_irq_no_frag(
+                                       &ctrl->viewPath);
+               }
+       }
+
+       /* process the encoder path interrupts */
+       if (irqstatus->anyOutput2PathIrqs) {
+               if (ctrl->encPath.multiFrag) {
+                       if (irqstatus->encCbcrPingpongIrq)
+                               vfe_process_pingpong_irq(
+                                       &(ctrl->encPath.cbcrPath),
+                                       ctrl->encPath.fragCount);
+
+                       if (irqstatus->encYPingpongIrq)
+                               vfe_process_pingpong_irq(&(ctrl->encPath.yPath),
+                               ctrl->encPath.fragCount);
+
+                       if (irqstatus->encIrq)
+                               vfe_process_frame_done_irq_multi_frag(
+                                       &ctrl->encPath);
+
+               } else {
+                       if (irqstatus->encIrq)
+                               vfe_process_frame_done_irq_no_frag(
+                                       &ctrl->encPath);
+               }
+       }
+
+       if (ctrl->vfeOperationMode) {
+               if ((ctrl->encPath.snapshotPendingCount == 0) &&
+                               (ctrl->viewPath.snapshotPendingCount == 0)) {
+
+                       /* @todo This is causing issues, further investigate */
+                       /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+                       ctrl->vstate = VFE_STATE_IDLE;
+                       /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+
+                       vfe_send_msg_no_payload(VFE_MSG_ID_SNAPSHOT_DONE);
+                       vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+                       vfe_pm_stop();
+               }
+       }
+}
+
+static void vfe_do_tasklet(unsigned long data)
+{
+       unsigned long flags;
+
+       struct isr_queue_cmd *qcmd = NULL;
+
+       CDBG("=== vfe_do_tasklet start === \n");
+
+       spin_lock_irqsave(&ctrl->tasklet_lock, flags);
+       qcmd = list_first_entry(&ctrl->tasklet_q,
+                       struct isr_queue_cmd, list);
+
+       if (!qcmd) {
+               spin_unlock_irqrestore(&ctrl->tasklet_lock, flags);
+               return;
+       }
+
+       list_del(&qcmd->list);
+       spin_unlock_irqrestore(&ctrl->tasklet_lock, flags);
+
+       if (qcmd->vfeInterruptStatus.regUpdateIrq) {
+               CDBG("irq       regUpdateIrq\n");
+               vfe_process_reg_update_irq();
+       }
+
+       if (qcmd->vfeInterruptStatus.resetAckIrq) {
+               CDBG("irq       resetAckIrq\n");
+               vfe_process_reset_irq();
+       }
+
+       spin_lock_irqsave(&ctrl->state_lock, flags);
+       if (ctrl->vstate != VFE_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&ctrl->state_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&ctrl->state_lock, flags);
+
+#if 0
+       if (qcmd->vfeInterruptStatus.camifEpoch1Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_EPOCH1);
+
+       if (qcmd->vfeInterruptStatus.camifEpoch2Irq)
+               vfe_send_msg_no_payload(VFE_MSG_ID_EPOCH2);
+#endif /* Jeff */
+
+       /* next, check output path related interrupts. */
+       if (qcmd->vfeInterruptStatus.anyOutputPathIrqs) {
+               CDBG("irq       anyOutputPathIrqs\n");
+               vfe_process_output_path_irq(&qcmd->vfeInterruptStatus);
+       }
+
+       if (qcmd->vfeInterruptStatus.afPingpongIrq)
+               vfe_process_stats_af_irq();
+
+       if (qcmd->vfeInterruptStatus.awbPingpongIrq)
+               vfe_process_stats_awb_irq();
+
+       /* any error irqs*/
+       if (qcmd->vfeInterruptStatus.anyErrorIrqs)
+               vfe_process_error_irq(&qcmd->vfeInterruptStatus);
+
+#if 0
+       if (qcmd->vfeInterruptStatus.anySyncTimerIrqs)
+               vfe_process_sync_timer_irq();
+
+       if (qcmd->vfeInterruptStatus.anyAsyncTimerIrqs)
+               vfe_process_async_timer_irq();
+#endif /* Jeff */
+
+       if (qcmd->vfeInterruptStatus.camifSofIrq) {
+               CDBG("irq       camifSofIrq\n");
+               vfe_process_camif_sof_irq();
+       }
+
+       kfree(qcmd);
+       CDBG("=== vfe_do_tasklet end === \n");
+}
+
+DECLARE_TASKLET(vfe_tasklet, vfe_do_tasklet, 0);
+
+static irqreturn_t vfe_parse_irq(int irq_num, void *data)
+{
+       unsigned long flags;
+       uint32_t irqStatusLocal;
+       struct vfe_irq_thread_msg irq;
+       struct isr_queue_cmd *qcmd;
+
+       CDBG("vfe_parse_irq\n");
+
+       vfe_read_irq_status(&irq);
+
+       if (irq.vfeIrqStatus == 0) {
+               CDBG("vfe_parse_irq: irq.vfeIrqStatus is 0\n");
+               return IRQ_HANDLED;
+       }
+
+       qcmd = kzalloc(sizeof(struct isr_queue_cmd),
+               GFP_ATOMIC);
+       if (!qcmd) {
+               CDBG("vfe_parse_irq: qcmd malloc failed!\n");
+               return IRQ_HANDLED;
+       }
+
+       spin_lock_irqsave(&ctrl->ack_lock, flags);
+
+       if (ctrl->vfeStopAckPending)
+               irqStatusLocal =
+                       (VFE_IMASK_WHILE_STOPPING & irq.vfeIrqStatus);
+       else
+               irqStatusLocal =
+                       ((ctrl->vfeImaskPacked | VFE_IMASK_ERROR_ONLY) &
+                               irq.vfeIrqStatus);
+
+       spin_unlock_irqrestore(&ctrl->ack_lock, flags);
+
+       /* first parse the interrupt status to local data structures. */
+       qcmd->vfeInterruptStatus = vfe_parse_interrupt_status(irqStatusLocal);
+       qcmd->vfeAsfFrameInfo = vfe_get_asf_frame_info(&irq);
+       qcmd->vfeBpcFrameInfo = vfe_get_demosaic_frame_info(&irq);
+       qcmd->vfeCamifStatusLocal = vfe_get_camif_status(&irq);
+       qcmd->vfePmData = vfe_get_performance_monitor_data(&irq);
+
+       spin_lock_irqsave(&ctrl->tasklet_lock, flags);
+       list_add_tail(&qcmd->list, &ctrl->tasklet_q);
+       spin_unlock_irqrestore(&ctrl->tasklet_lock, flags);
+       tasklet_schedule(&vfe_tasklet);
+
+       /* clear the pending interrupt of the same kind.*/
+       writel(irq.vfeIrqStatus, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+       return IRQ_HANDLED;
+}
+
+int vfe_cmd_init(struct msm_vfe_callback *presp,
+       struct platform_device *pdev, void *sdata)
+{
+       struct resource *vfemem, *vfeirq, *vfeio;
+       int rc;
+
+       vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!vfemem) {
+               CDBG("no mem resource?\n");
+               return -ENODEV;
+       }
+
+       vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!vfeirq) {
+               CDBG("no irq resource?\n");
+               return -ENODEV;
+       }
+
+       vfeio = request_mem_region(vfemem->start,
+               resource_size(vfemem), pdev->name);
+       if (!vfeio) {
+               CDBG("VFE region already claimed\n");
+               return -EBUSY;
+       }
+
+       ctrl =
+       kzalloc(sizeof(struct msm_vfe8x_ctrl), GFP_KERNEL);
+       if (!ctrl) {
+               rc = -ENOMEM;
+               goto cmd_init_failed1;
+       }
+
+       ctrl->vfeirq  = vfeirq->start;
+
+       ctrl->vfebase =
+               ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
+       if (!ctrl->vfebase) {
+               rc = -ENOMEM;
+               goto cmd_init_failed2;
+       }
+
+       rc = request_irq(ctrl->vfeirq, vfe_parse_irq,
+               IRQF_TRIGGER_RISING, "vfe", 0);
+       if (rc < 0)
+               goto cmd_init_failed2;
+
+       if (presp && presp->vfe_resp)
+               ctrl->resp = presp;
+       else {
+               rc = -EINVAL;
+               goto cmd_init_failed3;
+       }
+
+       ctrl->extdata =
+               kmalloc(sizeof(struct vfe_frame_extra), GFP_KERNEL);
+       if (!ctrl->extdata) {
+               rc = -ENOMEM;
+               goto cmd_init_failed3;
+       }
+
+       spin_lock_init(&ctrl->ack_lock);
+       spin_lock_init(&ctrl->state_lock);
+       spin_lock_init(&ctrl->io_lock);
+
+       ctrl->extlen = sizeof(struct vfe_frame_extra);
+
+       spin_lock_init(&ctrl->tasklet_lock);
+       INIT_LIST_HEAD(&ctrl->tasklet_q);
+
+       ctrl->syncdata = sdata;
+       return 0;
+
+cmd_init_failed3:
+       disable_irq(ctrl->vfeirq);
+       free_irq(ctrl->vfeirq, 0);
+       iounmap(ctrl->vfebase);
+cmd_init_failed2:
+       kfree(ctrl);
+cmd_init_failed1:
+       release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
+       return rc;
+}
+
+void vfe_cmd_release(struct platform_device *dev)
+{
+       struct resource *mem;
+
+       disable_irq(ctrl->vfeirq);
+       free_irq(ctrl->vfeirq, 0);
+
+       iounmap(ctrl->vfebase);
+       mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+       ctrl->extlen = 0;
+
+       kfree(ctrl->extdata);
+       kfree(ctrl);
+}
+
+void vfe_stats_af_stop(void)
+{
+       ctrl->vfeStatsCmdLocal.autoFocusEnable = FALSE;
+       ctrl->vfeImaskLocal.afPingpongIrq = FALSE;
+}
+
+void vfe_stop(void)
+{
+       boolean vfeAxiBusy;
+       uint32_t vfeAxiStauts;
+
+       /* for reset hw modules, and send msg when reset_irq comes.*/
+       ctrl->vfeStopAckPending = TRUE;
+
+       ctrl->vfeStatsPingPongReloadFlag = FALSE;
+       vfe_pm_stop();
+
+       /* disable all interrupts.  */
+       vfe_program_irq_mask(VFE_DISABLE_ALL_IRQS);
+
+       /* in either continuous or snapshot mode, stop command can be issued
+        * at any time.
+        */
+       vfe_camif_stop_immediately();
+       vfe_program_axi_cmd(AXI_HALT);
+       vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_STOP);
+
+       vfeAxiBusy = TRUE;
+
+       while (vfeAxiBusy) {
+               vfeAxiStauts = vfe_read_axi_status();
+               if ((vfeAxiStauts & AXI_STATUS_BUSY_MASK) != 0)
+                       vfeAxiBusy = FALSE;
+       }
+
+       vfe_program_axi_cmd(AXI_HALT_CLEAR);
+
+       /* clear all pending interrupts */
+       writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+       /* enable reset_ack and async timer interrupt only while stopping
+        * the pipeline.
+        */
+       vfe_program_irq_mask(VFE_IMASK_WHILE_STOPPING);
+
+       vfe_program_global_reset_cmd(VFE_RESET_UPON_STOP_CMD);
+}
+
+void vfe_update(void)
+{
+       ctrl->vfeModuleEnableLocal.statsEnable =
+               ctrl->vfeStatsCmdLocal.autoFocusEnable |
+               ctrl->vfeStatsCmdLocal.axwEnable;
+
+       vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+       vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+       ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+       vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+       if ((ctrl->vfeModuleEnableLocal.statsEnable == TRUE) &&
+                       (ctrl->vfeStatsPingPongReloadFlag == FALSE)) {
+               ctrl->vfeStatsPingPongReloadFlag = TRUE;
+
+               ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+               vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+       }
+
+       vfe_program_reg_update_cmd(VFE_REG_UPDATE_TRIGGER);
+}
+
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *in)
+{
+       int rc = 0;
+
+       ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+       switch (in->channelSelect) {
+       case RGB_GAMMA_CH0_SELECTED:
+               ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+               vfe_write_gamma_table(0,
+                       ctrl->vfeGammaLutSel.ch0BankSelect, in->table);
+               break;
+
+       case RGB_GAMMA_CH1_SELECTED:
+               ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+               vfe_write_gamma_table(1,
+                       ctrl->vfeGammaLutSel.ch1BankSelect, in->table);
+               break;
+
+       case RGB_GAMMA_CH2_SELECTED:
+               ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+               vfe_write_gamma_table(2,
+                       ctrl->vfeGammaLutSel.ch2BankSelect, in->table);
+               break;
+
+       case RGB_GAMMA_CH0_CH1_SELECTED:
+               ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+               ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+               vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+                       in->table);
+               vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+                       in->table);
+               break;
+
+       case RGB_GAMMA_CH0_CH2_SELECTED:
+               ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+               ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+               vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+                       in->table);
+               vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+                       in->table);
+               break;
+
+       case RGB_GAMMA_CH1_CH2_SELECTED:
+               ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+               ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+               vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+                       in->table);
+               vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+                       in->table);
+               break;
+
+       case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+               ctrl->vfeGammaLutSel.ch0BankSelect ^= 1;
+               ctrl->vfeGammaLutSel.ch1BankSelect ^= 1;
+               ctrl->vfeGammaLutSel.ch2BankSelect ^= 1;
+               vfe_write_gamma_table(0, ctrl->vfeGammaLutSel.ch0BankSelect,
+                       in->table);
+               vfe_write_gamma_table(1, ctrl->vfeGammaLutSel.ch1BankSelect,
+                       in->table);
+               vfe_write_gamma_table(2, ctrl->vfeGammaLutSel.ch2BankSelect,
+                       in->table);
+               break;
+
+       default:
+               return -EINVAL;
+       } /* switch */
+
+       /* update the gammaLutSel register. */
+       vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+       return rc;
+}
+
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *in)
+{
+       int rc = 0;
+
+       ctrl->vfeModuleEnableLocal.rgbLUTEnable = in->enable;
+
+       switch (in->channelSelect) {
+       case RGB_GAMMA_CH0_SELECTED:
+vfe_write_gamma_table(0, 0, in->table);
+break;
+
+       case RGB_GAMMA_CH1_SELECTED:
+               vfe_write_gamma_table(1, 0, in->table);
+               break;
+
+       case RGB_GAMMA_CH2_SELECTED:
+               vfe_write_gamma_table(2, 0, in->table);
+               break;
+
+       case RGB_GAMMA_CH0_CH1_SELECTED:
+               vfe_write_gamma_table(0, 0, in->table);
+               vfe_write_gamma_table(1, 0, in->table);
+               break;
+
+       case RGB_GAMMA_CH0_CH2_SELECTED:
+               vfe_write_gamma_table(0, 0, in->table);
+               vfe_write_gamma_table(2, 0, in->table);
+               break;
+
+       case RGB_GAMMA_CH1_CH2_SELECTED:
+               vfe_write_gamma_table(1, 0, in->table);
+               vfe_write_gamma_table(2, 0, in->table);
+               break;
+
+       case RGB_GAMMA_CH0_CH1_CH2_SELECTED:
+               vfe_write_gamma_table(0, 0, in->table);
+               vfe_write_gamma_table(1, 0, in->table);
+               vfe_write_gamma_table(2, 0, in->table);
+               break;
+
+       default:
+               rc = -EINVAL;
+               break;
+       } /* switch */
+
+       return rc;
+}
+
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *in)
+{
+       ctrl->afStatsControl.nextFrameAddrBuf = in->nextAFOutputBufferAddr;
+       ctrl->afStatsControl.ackPending = FALSE;
+}
+
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *in)
+{
+       ctrl->awbStatsControl.nextFrameAddrBuf = in->nextWbExpOutputBufferAddr;
+       ctrl->awbStatsControl.ackPending = FALSE;
+}
+
+void vfe_output2_ack(struct vfe_cmd_output_ack *in)
+{
+       const uint32_t *psrc;
+       uint32_t *pdest;
+       uint8_t i;
+
+       pdest = ctrl->encPath.nextFrameAddrBuf;
+
+       CDBG("output2_ack: ack addr = 0x%x\n", in->ybufaddr[0]);
+
+       psrc = in->ybufaddr;
+       for (i = 0; i < ctrl->encPath.fragCount; i++)
+               *pdest++ = *psrc++;
+
+       psrc = in->chromabufaddr;
+       for (i = 0; i < ctrl->encPath.fragCount; i++)
+               *pdest++ = *psrc++;
+
+       ctrl->encPath.ackPending = FALSE;
+}
+
+void vfe_output1_ack(struct vfe_cmd_output_ack *in)
+{
+       const uint32_t *psrc;
+       uint32_t *pdest;
+       uint8_t i;
+
+       pdest = ctrl->viewPath.nextFrameAddrBuf;
+
+       psrc = in->ybufaddr;
+       for (i = 0; i < ctrl->viewPath.fragCount; i++)
+               *pdest++ = *psrc++;
+
+       psrc = in->chromabufaddr;
+       for (i = 0; i < ctrl->viewPath.fragCount; i++)
+               *pdest++ = *psrc++;
+
+       ctrl->viewPath.ackPending = FALSE;
+}
+
+void vfe_start(struct vfe_cmd_start *in)
+{
+       unsigned long flags;
+       uint32_t  pmstatus = 0;
+       boolean rawmode;
+       uint32_t  demperiod = 0;
+       uint32_t  demeven = 0;
+       uint32_t  demodd = 0;
+
+       /* derived from other commands.  (camif config, axi output config,
+        * etc)
+       */
+       struct vfe_cfg hwcfg;
+       struct vfe_upsample_cfg chromupcfg;
+
+       CDBG("vfe_start operationMode = %d\n", in->operationMode);
+
+       memset(&hwcfg, 0, sizeof(hwcfg));
+       memset(&chromupcfg, 0, sizeof(chromupcfg));
+
+       switch (in->pixel) {
+       case VFE_BAYER_RGRGRG:
+               demperiod = 1;
+               demeven = 0xC9;
+               demodd = 0xAC;
+               break;
+
+       case VFE_BAYER_GRGRGR:
+               demperiod = 1;
+               demeven = 0x9C;
+               demodd = 0xCA;
+               break;
+
+       case VFE_BAYER_BGBGBG:
+               demperiod = 1;
+               demeven = 0xCA;
+               demodd = 0x9C;
+               break;
+
+       case VFE_BAYER_GBGBGB:
+               demperiod = 1;
+               demeven = 0xAC;
+               demodd = 0xC9;
+               break;
+
+       case VFE_YUV_YCbYCr:
+               demperiod = 3;
+               demeven = 0x9CAC;
+               demodd = 0x9CAC;
+               break;
+
+       case VFE_YUV_YCrYCb:
+               demperiod = 3;
+               demeven = 0xAC9C;
+               demodd = 0xAC9C;
+               break;
+
+       case VFE_YUV_CbYCrY:
+               demperiod = 3;
+               demeven = 0xC9CA;
+               demodd = 0xC9CA;
+               break;
+
+       case VFE_YUV_CrYCbY:
+               demperiod = 3;
+               demeven = 0xCAC9;
+               demodd = 0xCAC9;
+               break;
+
+       default:
+               return;
+       }
+
+       vfe_config_demux(demperiod, demeven, demodd);
+
+       vfe_program_lut_bank_sel(&ctrl->vfeGammaLutSel);
+
+       /* save variables to local. */
+       ctrl->vfeOperationMode = in->operationMode;
+       if (ctrl->vfeOperationMode ==
+                       VFE_START_OPERATION_MODE_SNAPSHOT) {
+               /* in snapshot mode, initialize snapshot count*/
+               ctrl->vfeSnapShotCount = in->snapshotCount;
+
+               /* save the requested count, this is temporarily done, to
+               help with HJR / multishot. */
+               ctrl->vfeRequestedSnapShotCount = ctrl->vfeSnapShotCount;
+
+               CDBG("requested snapshot count = %d\n", ctrl->vfeSnapShotCount);
+
+               /* Assumption is to have the same pattern and period for both
+               paths, if both paths are used. */
+               if (ctrl->viewPath.pathEnabled) {
+                       ctrl->viewPath.snapshotPendingCount =
+                               in->snapshotCount;
+
+                       ctrl->vfeFrameSkipPattern =
+                               ctrl->vfeFrameSkip.output1Pattern;
+                       ctrl->vfeFrameSkipPeriod =
+                               ctrl->vfeFrameSkip.output1Period;
+               }
+
+               if (ctrl->encPath.pathEnabled) {
+                       ctrl->encPath.snapshotPendingCount =
+                               in->snapshotCount;
+
+                       ctrl->vfeFrameSkipPattern =
+                               ctrl->vfeFrameSkip.output2Pattern;
+                       ctrl->vfeFrameSkipPeriod =
+                               ctrl->vfeFrameSkip.output2Period;
+               }
+       }
+
+       /* enable color conversion for bayer sensor
+       if stats enabled, need to do color conversion. */
+       if (in->pixel <= VFE_BAYER_GBGBGB)
+               ctrl->vfeStatsCmdLocal.colorConversionEnable = TRUE;
+
+       vfe_program_stats_cmd(&ctrl->vfeStatsCmdLocal);
+
+       if (in->pixel >= VFE_YUV_YCbYCr)
+               ctrl->vfeModuleEnableLocal.chromaUpsampleEnable = TRUE;
+
+       ctrl->vfeModuleEnableLocal.demuxEnable = TRUE;
+
+       /* if any stats module is enabled, the main bit is enabled. */
+       ctrl->vfeModuleEnableLocal.statsEnable =
+               ctrl->vfeStatsCmdLocal.autoFocusEnable |
+               ctrl->vfeStatsCmdLocal.axwEnable;
+
+       vfe_reg_module_cfg(&ctrl->vfeModuleEnableLocal);
+
+       /* in case of offline processing, do not need to config camif. Having
+        * bus output enabled in camif_config register might confuse the
+        * hardware?
+        */
+       if (in->inputSource != VFE_START_INPUT_SOURCE_AXI) {
+               vfe_reg_camif_config(&ctrl->vfeCamifConfigLocal);
+       } else {
+               /* offline processing, enable axi read */
+               ctrl->vfeBusConfigLocal.stripeRdPathEn = TRUE;
+               ctrl->vfeBusCmdLocal.stripeReload = TRUE;
+               ctrl->vfeBusConfigLocal.rawPixelDataSize =
+                       ctrl->axiInputDataSize;
+       }
+
+       vfe_reg_bus_cfg(&ctrl->vfeBusConfigLocal);
+
+       /* directly from start command */
+       hwcfg.pixelPattern = in->pixel;
+       hwcfg.inputSource = in->inputSource;
+       writel(*(uint32_t *)&hwcfg, ctrl->vfebase + VFE_CFG);
+
+       /* regardless module enabled or not, it does not hurt
+        * to program the cositing mode. */
+       chromupcfg.chromaCositingForYCbCrInputs =
+               in->yuvInputCositingMode;
+
+       writel(*(uint32_t *)&(chromupcfg),
+               ctrl->vfebase + VFE_CHROMA_UPSAMPLE_CFG);
+
+       /* MISR to monitor the axi read. */
+       writel(0xd8, ctrl->vfebase + VFE_BUS_MISR_MAST_CFG_0);
+
+       /* clear all pending interrupts. */
+       writel(VFE_CLEAR_ALL_IRQS, ctrl->vfebase + VFE_IRQ_CLEAR);
+
+       /*  define how composite interrupt work.  */
+       ctrl->vfeImaskCompositePacked =
+               vfe_irq_composite_pack(ctrl->vfeIrqCompositeMaskLocal);
+
+       vfe_program_irq_composite_mask(ctrl->vfeImaskCompositePacked);
+
+       /*  enable all necessary interrupts.      */
+       ctrl->vfeImaskLocal.camifSofIrq  = TRUE;
+       ctrl->vfeImaskLocal.regUpdateIrq = TRUE;
+       ctrl->vfeImaskLocal.resetAckIrq  = TRUE;
+
+       ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+       vfe_program_irq_mask(ctrl->vfeImaskPacked);
+
+       /* enable bus performance monitor */
+       vfe_8k_pm_start(&ctrl->vfeBusPmConfigLocal);
+
+       /* trigger vfe reg update */
+       ctrl->vfeStartAckPendingFlag = TRUE;
+
+       /* write bus command to trigger reload of ping pong buffer. */
+       ctrl->vfeBusCmdLocal.busPingpongReload = TRUE;
+
+       if (ctrl->vfeModuleEnableLocal.statsEnable == TRUE) {
+               ctrl->vfeBusCmdLocal.statsPingpongReload = TRUE;
+               ctrl->vfeStatsPingPongReloadFlag = TRUE;
+       }
+
+       writel(VFE_REG_UPDATE_TRIGGER,
+               ctrl->vfebase + VFE_REG_UPDATE_CMD);
+
+       /* program later than the reg update. */
+       vfe_reg_bus_cmd(&ctrl->vfeBusCmdLocal);
+
+       if ((in->inputSource ==
+                        VFE_START_INPUT_SOURCE_CAMIF) ||
+                       (in->inputSource ==
+                        VFE_START_INPUT_SOURCE_TESTGEN))
+               writel(CAMIF_COMMAND_START, ctrl->vfebase + CAMIF_COMMAND);
+
+       /* start test gen if it is enabled */
+       if (ctrl->vfeTestGenStartFlag == TRUE) {
+               ctrl->vfeTestGenStartFlag = FALSE;
+               vfe_prog_hw_testgen_cmd(VFE_TEST_GEN_GO);
+       }
+
+       CDBG("ctrl->axiOutputMode = %d\n", ctrl->axiOutputMode);
+       if (ctrl->axiOutputMode == VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2) {
+               /* raw dump mode */
+               rawmode = TRUE;
+
+               while (rawmode) {
+                       pmstatus =
+                               readl(ctrl->vfebase +
+                                       VFE_BUS_ENC_CBCR_WR_PM_STATS_1);
+
+                       if ((pmstatus & VFE_PM_BUF_MAX_CNT_MASK) != 0)
+                               rawmode = FALSE;
+               }
+
+               vfe_send_msg_no_payload(VFE_MSG_ID_START_ACK);
+               ctrl->vfeStartAckPendingFlag = FALSE;
+       }
+
+       spin_lock_irqsave(&ctrl->state_lock, flags);
+       ctrl->vstate = VFE_STATE_ACTIVE;
+       spin_unlock_irqrestore(&ctrl->state_lock, flags);
+}
+
+void vfe_la_update(struct vfe_cmd_la_config *in)
+{
+       int16_t *pTable;
+       enum VFE_DMI_RAM_SEL dmiRamSel;
+       int i;
+
+       pTable = in->table;
+       ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+       /* toggle the bank to be used. */
+       ctrl->vfeLaBankSel ^= 1;
+
+       if (ctrl->vfeLaBankSel == 0)
+               dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+       else
+               dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+       /* configure the DMI_CFG to select right sram */
+       vfe_program_dmi_cfg(dmiRamSel);
+
+       for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+               writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+               pTable++;
+       }
+
+       /* After DMI transfer, to make it safe, need to set
+        * the DMI_CFG to unselect any SRAM */
+       writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+       writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+}
+
+void vfe_la_config(struct vfe_cmd_la_config *in)
+{
+       uint16_t i;
+       int16_t  *pTable;
+       enum VFE_DMI_RAM_SEL dmiRamSel;
+
+       pTable = in->table;
+       ctrl->vfeModuleEnableLocal.lumaAdaptationEnable = in->enable;
+
+       if (ctrl->vfeLaBankSel == 0)
+               dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK0;
+       else
+               dmiRamSel = LUMA_ADAPT_LUT_RAM_BANK1;
+
+       /* configure the DMI_CFG to select right sram */
+       vfe_program_dmi_cfg(dmiRamSel);
+
+       for (i = 0; i < VFE_LA_TABLE_LENGTH; i++) {
+               writel((uint32_t)(*pTable), ctrl->vfebase + VFE_DMI_DATA_LO);
+               pTable++;
+       }
+
+       /* After DMI transfer, to make it safe, need to set the
+        * DMI_CFG to unselect any SRAM */
+       writel(VFE_DMI_CFG_DEFAULT, ctrl->vfebase + VFE_DMI_CFG);
+
+       /* can only be bank 0 or bank 1 for now. */
+       writel(ctrl->vfeLaBankSel, ctrl->vfebase + VFE_LA_CFG);
+       CDBG("VFE Luma adaptation bank selection is 0x%x\n",
+                        *(uint32_t *)&ctrl->vfeLaBankSel);
+}
+
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *in)
+{
+       struct VFE_TestGen_ConfigCmdType cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.numFrame              = in->numFrame;
+       cmd.pixelDataSelect       = in->pixelDataSelect;
+       cmd.systematicDataSelect  = in->systematicDataSelect;
+       cmd.pixelDataSize         = (uint32_t)in->pixelDataSize;
+       cmd.hsyncEdge             = (uint32_t)in->hsyncEdge;
+       cmd.vsyncEdge             = (uint32_t)in->vsyncEdge;
+       cmd.imageWidth            = in->imageWidth;
+       cmd.imageHeight           = in->imageHeight;
+       cmd.sofOffset             = in->startOfFrameOffset;
+       cmd.eofNOffset            = in->endOfFrameNOffset;
+       cmd.solOffset             = in->startOfLineOffset;
+       cmd.eolNOffset            = in->endOfLineNOffset;
+       cmd.hBlankInterval        = in->hbi;
+       cmd.vBlankInterval        = in->vbl;
+       cmd.vBlankIntervalEnable  = in->vblEnable;
+       cmd.sofDummy              = in->startOfFrameDummyLine;
+       cmd.eofDummy              = in->endOfFrameDummyLine;
+       cmd.unicolorBarSelect     = in->unicolorBarSelect;
+       cmd.unicolorBarEnable     = in->unicolorBarEnable;
+       cmd.splitEnable           = in->colorBarsSplitEnable;
+       cmd.pixelPattern          = (uint32_t)in->colorBarsPixelPattern;
+       cmd.rotatePeriod          = in->colorBarsRotatePeriod;
+       cmd.randomSeed            = in->testGenRandomSeed;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_HW_TESTGEN_CFG,
+               (uint32_t *) &cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *in)
+{
+       struct VFE_FRAME_SKIP_UpdateCmdType cmd;
+
+       cmd.yPattern    = in->output1Pattern;
+       cmd.cbcrPattern = in->output1Pattern;
+       vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmd.yPattern    = in->output2Pattern;
+       cmd.cbcrPattern = in->output2Pattern;
+       vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *in)
+{
+       struct vfe_frame_skip_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeFrameSkip = *in;
+
+       cmd.output2YPeriod     = in->output2Period;
+       cmd.output2CbCrPeriod  = in->output2Period;
+       cmd.output2YPattern    = in->output2Pattern;
+       cmd.output2CbCrPattern = in->output2Pattern;
+       cmd.output1YPeriod     = in->output1Period;
+       cmd.output1CbCrPeriod  = in->output1Period;
+       cmd.output1YPattern    = in->output1Pattern;
+       cmd.output1CbCrPattern = in->output1Pattern;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *in)
+{
+       struct vfe_output_clamp_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.yChanMax  = in->maxCh0;
+       cmd.cbChanMax = in->maxCh1;
+       cmd.crChanMax = in->maxCh2;
+
+       cmd.yChanMin  = in->minCh0;
+       cmd.cbChanMin = in->minCh1;
+       cmd.crChanMin = in->minCh2;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_CLAMP_MAX_CFG, (uint32_t *)&cmd,
+               sizeof(cmd));
+}
+
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *in)
+{
+       struct vfe_camifframe_update cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.pixelsPerLine = in->pixelsPerLine;
+       cmd.linesPerFrame = in->linesPerFrame;
+
+       vfe_prog_hw(ctrl->vfebase + CAMIF_FRAME_CONFIG, (uint32_t *)&cmd,
+               sizeof(cmd));
+}
+
+void vfe_color_correction_config(
+       struct vfe_cmd_color_correction_config *in)
+{
+       struct vfe_color_correction_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ctrl->vfeModuleEnableLocal.colorCorrectionEnable = in->enable;
+
+       cmd.c0 = in->C0;
+       cmd.c1 = in->C1;
+       cmd.c2 = in->C2;
+       cmd.c3 = in->C3;
+       cmd.c4 = in->C4;
+       cmd.c5 = in->C5;
+       cmd.c6 = in->C6;
+       cmd.c7 = in->C7;
+       cmd.c8 = in->C8;
+
+       cmd.k0 = in->K0;
+       cmd.k1 = in->K1;
+       cmd.k2 = in->K2;
+
+       cmd.coefQFactor = in->coefQFactor;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CORRECT_COEFF_0,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *in)
+{
+struct vfe_demosaic_cfg cmd;
+       struct vfe_demosaic_abf_cfg cmdabf;
+       uint32_t temp;
+
+       memset(&cmd, 0, sizeof(cmd));
+       temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+       cmd = *((struct vfe_demosaic_cfg *)(&temp));
+       cmd.abfEnable       = in->abfUpdate.enable;
+       cmd.forceAbfOn      = in->abfUpdate.forceOn;
+       cmd.abfShift        = in->abfUpdate.shift;
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmdabf.lpThreshold  = in->abfUpdate.lpThreshold;
+       cmdabf.ratio        = in->abfUpdate.ratio;
+       cmdabf.minValue     = in->abfUpdate.min;
+       cmdabf.maxValue     = in->abfUpdate.max;
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+               (uint32_t *)&cmdabf, sizeof(cmdabf));
+}
+
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *in)
+{
+       struct vfe_demosaic_cfg cmd;
+       struct vfe_demosaic_bpc_cfg cmdbpc;
+       uint32_t temp;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       temp = readl(ctrl->vfebase + VFE_DEMOSAIC_CFG);
+
+       cmd = *((struct vfe_demosaic_cfg *)(&temp));
+       cmd.badPixelCorrEnable = in->bpcUpdate.enable;
+       cmd.fminThreshold      = in->bpcUpdate.fminThreshold;
+       cmd.fmaxThreshold      = in->bpcUpdate.fmaxThreshold;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmdbpc.blueDiffThreshold  = in->bpcUpdate.blueDiffThreshold;
+       cmdbpc.redDiffThreshold   = in->bpcUpdate.redDiffThreshold;
+       cmdbpc.greenDiffThreshold = in->bpcUpdate.greenDiffThreshold;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+               (uint32_t *)&cmdbpc, sizeof(cmdbpc));
+}
+
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *in)
+{
+       struct vfe_demosaic_cfg cmd;
+       struct vfe_demosaic_bpc_cfg cmd_bpc;
+       struct vfe_demosaic_abf_cfg cmd_abf;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd_bpc, 0, sizeof(cmd_bpc));
+       memset(&cmd_abf, 0, sizeof(cmd_abf));
+
+       ctrl->vfeModuleEnableLocal.demosaicEnable = in->enable;
+
+       cmd.abfEnable          = in->abfConfig.enable;
+       cmd.badPixelCorrEnable = in->bpcConfig.enable;
+       cmd.forceAbfOn         = in->abfConfig.forceOn;
+       cmd.abfShift           = in->abfConfig.shift;
+       cmd.fminThreshold      = in->bpcConfig.fminThreshold;
+       cmd.fmaxThreshold      = in->bpcConfig.fmaxThreshold;
+       cmd.slopeShift         = in->slopeShift;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmd_abf.lpThreshold = in->abfConfig.lpThreshold;
+       cmd_abf.ratio       = in->abfConfig.ratio;
+       cmd_abf.minValue    = in->abfConfig.min;
+       cmd_abf.maxValue    = in->abfConfig.max;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_ABF_CFG_0,
+               (uint32_t *)&cmd_abf, sizeof(cmd_abf));
+
+       cmd_bpc.blueDiffThreshold   = in->bpcConfig.blueDiffThreshold;
+       cmd_bpc.redDiffThreshold    = in->bpcConfig.redDiffThreshold;
+       cmd_bpc.greenDiffThreshold  = in->bpcConfig.greenDiffThreshold;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMOSAIC_BPC_CFG_0,
+               (uint32_t *)&cmd_bpc, sizeof(cmd_bpc));
+}
+
+void vfe_demux_channel_gain_update(
+       struct vfe_cmd_demux_channel_gain_config *in)
+{
+       struct vfe_demux_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.ch0EvenGain  = in->ch0EvenGain;
+       cmd.ch0OddGain   = in->ch0OddGain;
+       cmd.ch1Gain      = in->ch1Gain;
+       cmd.ch2Gain      = in->ch2Gain;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_demux_channel_gain_config(
+       struct vfe_cmd_demux_channel_gain_config *in)
+{
+       struct vfe_demux_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.ch0EvenGain = in->ch0EvenGain;
+       cmd.ch0OddGain  = in->ch0OddGain;
+       cmd.ch1Gain     = in->ch1Gain;
+       cmd.ch2Gain     = in->ch2Gain;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_DEMUX_GAIN_0,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_update(struct vfe_cmd_black_level_config *in)
+{
+       struct vfe_blacklevel_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+       cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+       cmd.evenOddAdjustment  = in->evenOddAdjustment;
+       cmd.oddEvenAdjustment  = in->oddEvenAdjustment;
+       cmd.oddOddAdjustment   = in->oddOddAdjustment;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_black_level_config(struct vfe_cmd_black_level_config *in)
+{
+       struct vfe_blacklevel_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.blackLevelCorrectionEnable = in->enable;
+
+       cmd.evenEvenAdjustment = in->evenEvenAdjustment;
+       cmd.evenOddAdjustment  = in->evenOddAdjustment;
+       cmd.oddEvenAdjustment  = in->oddEvenAdjustment;
+       cmd.oddOddAdjustment   = in->oddOddAdjustment;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_BLACK_EVEN_EVEN_VALUE,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_update(struct vfe_cmd_asf_update *in)
+{
+       struct vfe_asf_update cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+       cmd.smoothEnable     = in->smoothFilterEnabled;
+       cmd.sharpMode        = in->sharpMode;
+       cmd.smoothCoeff1     = in->smoothCoefCenter;
+       cmd.smoothCoeff0     = in->smoothCoefSurr;
+       cmd.cropEnable       = in->cropEnable;
+       cmd.sharpThresholdE1 = in->sharpThreshE1;
+       cmd.sharpDegreeK1    = in->sharpK1;
+       cmd.sharpDegreeK2    = in->sharpK2;
+       cmd.normalizeFactor  = in->normalizeFactor;
+       cmd.sharpThresholdE2 = in->sharpThreshE2;
+       cmd.sharpThresholdE3 = in->sharpThreshE3;
+       cmd.sharpThresholdE4 = in->sharpThreshE4;
+       cmd.sharpThresholdE5 = in->sharpThreshE5;
+       cmd.F1Coeff0         = in->filter1Coefficients[0];
+       cmd.F1Coeff1         = in->filter1Coefficients[1];
+       cmd.F1Coeff2         = in->filter1Coefficients[2];
+       cmd.F1Coeff3         = in->filter1Coefficients[3];
+       cmd.F1Coeff4         = in->filter1Coefficients[4];
+       cmd.F1Coeff5         = in->filter1Coefficients[5];
+       cmd.F1Coeff6         = in->filter1Coefficients[6];
+       cmd.F1Coeff7         = in->filter1Coefficients[7];
+       cmd.F1Coeff8         = in->filter1Coefficients[8];
+       cmd.F2Coeff0         = in->filter2Coefficients[0];
+       cmd.F2Coeff1         = in->filter2Coefficients[1];
+       cmd.F2Coeff2         = in->filter2Coefficients[2];
+       cmd.F2Coeff3         = in->filter2Coefficients[3];
+       cmd.F2Coeff4         = in->filter2Coefficients[4];
+       cmd.F2Coeff5         = in->filter2Coefficients[5];
+       cmd.F2Coeff6         = in->filter2Coefficients[6];
+       cmd.F2Coeff7         = in->filter2Coefficients[7];
+       cmd.F2Coeff8         = in->filter2Coefficients[8];
+
+       vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_asf_config(struct vfe_cmd_asf_config *in)
+{
+       struct vfe_asf_update     cmd;
+       struct vfe_asfcrop_cfg cmd2;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd2, 0, sizeof(cmd2));
+
+       ctrl->vfeModuleEnableLocal.asfEnable = in->enable;
+
+       cmd.smoothEnable       = in->smoothFilterEnabled;
+       cmd.sharpMode          = in->sharpMode;
+       cmd.smoothCoeff0       = in->smoothCoefCenter;
+       cmd.smoothCoeff1       = in->smoothCoefSurr;
+       cmd.cropEnable         = in->cropEnable;
+       cmd.sharpThresholdE1   = in->sharpThreshE1;
+       cmd.sharpDegreeK1      = in->sharpK1;
+       cmd.sharpDegreeK2      = in->sharpK2;
+       cmd.normalizeFactor    = in->normalizeFactor;
+       cmd.sharpThresholdE2   = in->sharpThreshE2;
+       cmd.sharpThresholdE3   = in->sharpThreshE3;
+       cmd.sharpThresholdE4   = in->sharpThreshE4;
+       cmd.sharpThresholdE5   = in->sharpThreshE5;
+       cmd.F1Coeff0           = in->filter1Coefficients[0];
+       cmd.F1Coeff1           = in->filter1Coefficients[1];
+       cmd.F1Coeff2           = in->filter1Coefficients[2];
+       cmd.F1Coeff3           = in->filter1Coefficients[3];
+       cmd.F1Coeff4           = in->filter1Coefficients[4];
+       cmd.F1Coeff5           = in->filter1Coefficients[5];
+       cmd.F1Coeff6           = in->filter1Coefficients[6];
+       cmd.F1Coeff7           = in->filter1Coefficients[7];
+       cmd.F1Coeff8           = in->filter1Coefficients[8];
+       cmd.F2Coeff0           = in->filter2Coefficients[0];
+       cmd.F2Coeff1           = in->filter2Coefficients[1];
+       cmd.F2Coeff2           = in->filter2Coefficients[2];
+       cmd.F2Coeff3           = in->filter2Coefficients[3];
+       cmd.F2Coeff4           = in->filter2Coefficients[4];
+       cmd.F2Coeff5           = in->filter2Coefficients[5];
+       cmd.F2Coeff6           = in->filter2Coefficients[6];
+       cmd.F2Coeff7           = in->filter2Coefficients[7];
+       cmd.F2Coeff8           = in->filter2Coefficients[8];
+
+       vfe_prog_hw(ctrl->vfebase + VFE_ASF_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmd2.firstLine  = in->cropFirstLine;
+       cmd2.lastLine   = in->cropLastLine;
+       cmd2.firstPixel = in->cropFirstPixel;
+       cmd2.lastPixel  = in->cropLastPixel;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_ASF_CROP_WIDTH_CFG,
+               (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *in)
+{
+       struct vfe_wb_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.whiteBalanceEnable =
+               in->enable;
+
+       cmd.ch0Gain = in->ch0Gain;
+       cmd.ch1Gain = in->ch1Gain;
+       cmd.ch2Gain = in->ch2Gain;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_WB_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *in)
+{
+       struct vfe_chroma_suppress_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.chromaSuppressionEnable = in->enable;
+
+       cmd.m1  = in->m1;
+       cmd.m3  = in->m3;
+       cmd.n1  = in->n1;
+       cmd.n3  = in->n3;
+       cmd.mm1 = in->mm1;
+       cmd.nn1 = in->nn1;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUPPRESS_CFG_0,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *in)
+{
+       struct vfe_rolloff_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.lensRollOffEnable = in->enable;
+
+       cmd.gridWidth   = in->gridWidth;
+       cmd.gridHeight  = in->gridHeight;
+       cmd.yDelta      = in->yDelta;
+       cmd.gridX       = in->gridXIndex;
+       cmd.gridY       = in->gridYIndex;
+       cmd.pixelX      = in->gridPixelXIndex;
+       cmd.pixelY      = in->gridPixelYIndex;
+       cmd.yDeltaAccum = in->yDeltaAccum;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_ROLLOFF_CFG_0,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       vfe_write_lens_roll_off_table(in);
+}
+
+void vfe_chroma_subsample_config(
+       struct vfe_cmd_chroma_subsample_config *in)
+{
+       struct vfe_chromasubsample_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.chromaSubsampleEnable = in->enable;
+
+       cmd.hCositedPhase       = in->hCositedPhase;
+       cmd.vCositedPhase       = in->vCositedPhase;
+       cmd.hCosited            = in->hCosited;
+       cmd.vCosited            = in->vCosited;
+       cmd.hsubSampleEnable    = in->hsubSampleEnable;
+       cmd.vsubSampleEnable    = in->vsubSampleEnable;
+       cmd.cropEnable          = in->cropEnable;
+       cmd.cropWidthLastPixel  = in->cropWidthLastPixel;
+       cmd.cropWidthFirstPixel = in->cropWidthFirstPixel;
+       cmd.cropHeightLastLine  = in->cropHeightLastLine;
+       cmd.cropHeightFirstLine = in->cropHeightFirstLine;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_SUBSAMPLE_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *in)
+{
+       struct vfe_chroma_enhance_cfg cmd;
+       struct vfe_color_convert_cfg cmd2;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd2, 0, sizeof(cmd2));
+
+       ctrl->vfeModuleEnableLocal.chromaEnhanEnable = in->enable;
+
+       cmd.ap             = in->ap;
+       cmd.am             = in->am;
+       cmd.bp             = in->bp;
+       cmd.bm             = in->bm;
+       cmd.cp             = in->cp;
+       cmd.cm             = in->cm;
+       cmd.dp             = in->dp;
+       cmd.dm             = in->dm;
+       cmd.kcb            = in->kcb;
+       cmd.kcr            = in->kcr;
+
+       cmd2.v0            = in->RGBtoYConversionV0;
+       cmd2.v1            = in->RGBtoYConversionV1;
+       cmd2.v2            = in->RGBtoYConversionV2;
+       cmd2.ConvertOffset = in->RGBtoYConversionOffset;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_CHROMA_ENHAN_A,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       vfe_prog_hw(ctrl->vfebase + VFE_COLOR_CONVERT_COEFF_0,
+               (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *in)
+{
+       struct vfe_scaler2_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.scaler2CbcrEnable = in->enable;
+
+       cmd.hEnable              = in->hconfig.enable;
+       cmd.vEnable              = in->vconfig.enable;
+       cmd.inWidth              = in->hconfig.inputSize;
+       cmd.outWidth             = in->hconfig.outputSize;
+       cmd.horizPhaseMult       = in->hconfig.phaseMultiplicationFactor;
+       cmd.horizInterResolution = in->hconfig.interpolationResolution;
+       cmd.inHeight             = in->vconfig.inputSize;
+       cmd.outHeight            = in->vconfig.outputSize;
+       cmd.vertPhaseMult        = in->vconfig.phaseMultiplicationFactor;
+       cmd.vertInterResolution  = in->vconfig.interpolationResolution;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CBCR_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *in)
+{
+       struct vfe_scaler2_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.scaler2YEnable = in->enable;
+
+       cmd.hEnable               = in->hconfig.enable;
+       cmd.vEnable               = in->vconfig.enable;
+       cmd.inWidth               = in->hconfig.inputSize;
+       cmd.outWidth              = in->hconfig.outputSize;
+       cmd.horizPhaseMult        = in->hconfig.phaseMultiplicationFactor;
+       cmd.horizInterResolution  = in->hconfig.interpolationResolution;
+       cmd.inHeight              = in->vconfig.inputSize;
+       cmd.outHeight             = in->vconfig.outputSize;
+       cmd.vertPhaseMult         = in->vconfig.phaseMultiplicationFactor;
+       cmd.vertInterResolution   = in->vconfig.interpolationResolution;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_SCALE_Y_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *in)
+{
+       struct vfe_main_scaler_cfg cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.mainScalerEnable = in->enable;
+
+       cmd.hEnable              = in->hconfig.enable;
+       cmd.vEnable              = in->vconfig.enable;
+       cmd.inWidth              = in->hconfig.inputSize;
+       cmd.outWidth             = in->hconfig.outputSize;
+       cmd.horizPhaseMult       = in->hconfig.phaseMultiplicationFactor;
+       cmd.horizInterResolution = in->hconfig.interpolationResolution;
+       cmd.horizMNInit          = in->MNInitH.MNCounterInit;
+       cmd.horizPhaseInit       = in->MNInitH.phaseInit;
+       cmd.inHeight             = in->vconfig.inputSize;
+       cmd.outHeight            = in->vconfig.outputSize;
+       cmd.vertPhaseMult        = in->vconfig.phaseMultiplicationFactor;
+       cmd.vertInterResolution  = in->vconfig.interpolationResolution;
+       cmd.vertMNInit           = in->MNInitV.MNCounterInit;
+       cmd.vertPhaseInit        = in->MNInitV.phaseInit;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_SCALE_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_wb_exp_stop(void)
+{
+       ctrl->vfeStatsCmdLocal.axwEnable = FALSE;
+       ctrl->vfeImaskLocal.awbPingpongIrq = FALSE;
+}
+
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *in)
+{
+       struct vfe_statsawb_update   cmd;
+       struct vfe_statsawbae_update cmd2;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd2, 0, sizeof(cmd2));
+
+       cmd.m1  = in->awbMCFG[0];
+       cmd.m2  = in->awbMCFG[1];
+       cmd.m3  = in->awbMCFG[2];
+       cmd.m4  = in->awbMCFG[3];
+       cmd.c1  = in->awbCCFG[0];
+       cmd.c2  = in->awbCCFG[1];
+       cmd.c3  = in->awbCCFG[2];
+       cmd.c4  = in->awbCCFG[3];
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmd2.aeRegionCfg    = in->wbExpRegions;
+       cmd2.aeSubregionCfg = in->wbExpSubRegion;
+       cmd2.awbYMin        = in->awbYMin;
+       cmd2.awbYMax        = in->awbYMax;
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+               (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *in)
+{
+       struct vfe_statsaf_update cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.windowVOffset = in->windowVOffset;
+       cmd.windowHOffset = in->windowHOffset;
+       cmd.windowMode    = in->windowMode;
+       cmd.windowHeight  = in->windowHeight;
+       cmd.windowWidth   = in->windowWidth;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *in)
+{
+       struct vfe_statsawb_update   cmd;
+       struct vfe_statsawbae_update cmd2;
+       struct vfe_statsaxw_hdr_cfg  cmd3;
+
+       ctrl->vfeStatsCmdLocal.axwEnable   =  in->enable;
+       ctrl->vfeImaskLocal.awbPingpongIrq = TRUE;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd2, 0, sizeof(cmd2));
+       memset(&cmd3, 0, sizeof(cmd3));
+
+       cmd.m1  = in->awbMCFG[0];
+       cmd.m2  = in->awbMCFG[1];
+       cmd.m3  = in->awbMCFG[2];
+       cmd.m4  = in->awbMCFG[3];
+       cmd.c1  = in->awbCCFG[0];
+       cmd.c2  = in->awbCCFG[1];
+       cmd.c3  = in->awbCCFG[2];
+       cmd.c4  = in->awbCCFG[3];
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWB_MCFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmd2.aeRegionCfg     = in->wbExpRegions;
+       cmd2.aeSubregionCfg  = in->wbExpSubRegion;
+       cmd2.awbYMin         = in->awbYMin;
+       cmd2.awbYMax         = in->awbYMax;
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AWBAE_CFG,
+               (uint32_t *)&cmd2, sizeof(cmd2));
+
+       cmd3.axwHeader       = in->axwHeader;
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AXW_HEADER,
+               (uint32_t *)&cmd3, sizeof(cmd3));
+}
+
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *in)
+{
+       struct vfe_statsaf_update cmd;
+       struct vfe_statsaf_cfg    cmd2;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd2, 0, sizeof(cmd2));
+
+ctrl->vfeStatsCmdLocal.autoFocusEnable = in->enable;
+ctrl->vfeImaskLocal.afPingpongIrq = TRUE;
+
+       cmd.windowVOffset = in->windowVOffset;
+       cmd.windowHOffset = in->windowHOffset;
+       cmd.windowMode    = in->windowMode;
+       cmd.windowHeight  = in->windowHeight;
+       cmd.windowWidth   = in->windowWidth;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       cmd2.a00       = in->highPassCoef[0];
+       cmd2.a04       = in->highPassCoef[1];
+       cmd2.a20       = in->highPassCoef[2];
+       cmd2.a21       = in->highPassCoef[3];
+       cmd2.a22       = in->highPassCoef[4];
+       cmd2.a23       = in->highPassCoef[5];
+       cmd2.a24       = in->highPassCoef[6];
+       cmd2.fvMax     = in->metricMax;
+       cmd2.fvMetric  = in->metricSelection;
+       cmd2.afHeader  = in->bufferHeader;
+       cmd2.entry00   = in->gridForMultiWindows[0];
+       cmd2.entry01   = in->gridForMultiWindows[1];
+       cmd2.entry02   = in->gridForMultiWindows[2];
+       cmd2.entry03   = in->gridForMultiWindows[3];
+       cmd2.entry10   = in->gridForMultiWindows[4];
+       cmd2.entry11   = in->gridForMultiWindows[5];
+       cmd2.entry12   = in->gridForMultiWindows[6];
+       cmd2.entry13   = in->gridForMultiWindows[7];
+       cmd2.entry20   = in->gridForMultiWindows[8];
+       cmd2.entry21   = in->gridForMultiWindows[9];
+       cmd2.entry22   = in->gridForMultiWindows[10];
+       cmd2.entry23   = in->gridForMultiWindows[11];
+       cmd2.entry30   = in->gridForMultiWindows[12];
+       cmd2.entry31   = in->gridForMultiWindows[13];
+       cmd2.entry32   = in->gridForMultiWindows[14];
+       cmd2.entry33   = in->gridForMultiWindows[15];
+
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_AF_GRID_0,
+               (uint32_t *)&cmd2, sizeof(cmd2));
+}
+
+void vfe_stats_setting(struct vfe_cmd_stats_setting *in)
+{
+       struct vfe_statsframe cmd1;
+       struct vfe_busstats_wrprio cmd2;
+
+       memset(&cmd1, 0, sizeof(cmd1));
+       memset(&cmd2, 0, sizeof(cmd2));
+
+       ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0];
+       ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1];
+       ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2];
+
+       ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0];
+       ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1];
+       ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2];
+
+       cmd1.lastPixel = in->frameHDimension;
+       cmd1.lastLine  = in->frameVDimension;
+       vfe_prog_hw(ctrl->vfebase + VFE_STATS_FRAME_SIZE,
+               (uint32_t *)&cmd1, sizeof(cmd1));
+
+       cmd2.afBusPriority    = in->afBusPriority;
+       cmd2.awbBusPriority   = in->awbBusPriority;
+       cmd2.histBusPriority  = in->histBusPriority;
+       cmd2.afBusPriorityEn  = in->afBusPrioritySelection;
+       cmd2.awbBusPriorityEn = in->awbBusPrioritySelection;
+       cmd2.histBusPriorityEn = in->histBusPrioritySelection;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_BUS_STATS_WR_PRIORITY,
+               (uint32_t *)&cmd2, sizeof(cmd2));
+
+       /* Program the bus ping pong address for statistics modules. */
+       writel(in->afBuffer[0], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+       writel(in->afBuffer[1], ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+       writel(in->awbBuffer[0],
+               ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+       writel(in->awbBuffer[1],
+               ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+       writel(in->histBuffer[0],
+               ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+       writel(in->histBuffer[1],
+               ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+}
+
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *in)
+{
+       struct VFE_AxiInputCmdType cmd;
+       uint32_t xSizeWord, axiRdUnpackPattern;
+       uint8_t  axiInputPpw;
+       uint32_t busPingpongRdIrqEnable;
+
+       ctrl->vfeImaskLocal.rdPingpongIrq = TRUE;
+
+       switch (in->pixelSize) {
+       case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+               ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_10BIT;
+               break;
+
+       case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+               ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_12BIT;
+               break;
+
+       case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+       default:
+               ctrl->axiInputDataSize = VFE_RAW_PIXEL_DATA_SIZE_8BIT;
+               break;
+       }
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       switch (in->pixelSize) {
+       case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+               axiInputPpw = 6;
+               axiRdUnpackPattern = 0xD43210;
+               break;
+
+       case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+               axiInputPpw = 5;
+               axiRdUnpackPattern = 0xC3210;
+               break;
+
+       case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+       default:
+               axiInputPpw = 8;
+               axiRdUnpackPattern = 0xF6543210;
+               break;
+       }
+
+       xSizeWord =
+               ((((in->xOffset % axiInputPpw) + in->xSize) +
+                       (axiInputPpw-1)) / axiInputPpw) - 1;
+
+       cmd.stripeStartAddr0  = in->fragAddr[0];
+       cmd.stripeStartAddr1  = in->fragAddr[1];
+       cmd.stripeStartAddr2  = in->fragAddr[2];
+       cmd.stripeStartAddr3  = in->fragAddr[3];
+       cmd.ySize             = in->ySize;
+       cmd.yOffsetDelta      = 0;
+       cmd.xSizeWord         = xSizeWord;
+       cmd.burstLength       = 1;
+       cmd.NumOfRows         = in->numOfRows;
+       cmd.RowIncrement      =
+               (in->rowIncrement + (axiInputPpw-1))/axiInputPpw;
+       cmd.mainUnpackHeight  = in->ySize;
+       cmd.mainUnpackWidth   = in->xSize - 1;
+       cmd.mainUnpackHbiSel  = (uint32_t)in->unpackHbi;
+       cmd.mainUnpackPhase   = in->unpackPhase;
+       cmd.unpackPattern     = axiRdUnpackPattern;
+       cmd.padLeft           = in->padRepeatCountLeft;
+       cmd.padRight          = in->padRepeatCountRight;
+       cmd.padTop            = in->padRepeatCountTop;
+       cmd.padBottom         = in->padRepeatCountBottom;
+       cmd.leftUnpackPattern0   = in->padLeftComponentSelectCycle0;
+       cmd.leftUnpackPattern1   = in->padLeftComponentSelectCycle1;
+       cmd.leftUnpackPattern2   = in->padLeftComponentSelectCycle2;
+       cmd.leftUnpackPattern3   = in->padLeftComponentSelectCycle3;
+       cmd.leftUnpackStop0      = in->padLeftStopCycle0;
+       cmd.leftUnpackStop1      = in->padLeftStopCycle1;
+       cmd.leftUnpackStop2      = in->padLeftStopCycle2;
+       cmd.leftUnpackStop3      = in->padLeftStopCycle3;
+       cmd.rightUnpackPattern0  = in->padRightComponentSelectCycle0;
+       cmd.rightUnpackPattern1  = in->padRightComponentSelectCycle1;
+       cmd.rightUnpackPattern2  = in->padRightComponentSelectCycle2;
+       cmd.rightUnpackPattern3  = in->padRightComponentSelectCycle3;
+       cmd.rightUnpackStop0     = in->padRightStopCycle0;
+       cmd.rightUnpackStop1     = in->padRightStopCycle1;
+       cmd.rightUnpackStop2     = in->padRightStopCycle2;
+       cmd.rightUnpackStop3     = in->padRightStopCycle3;
+       cmd.topUnapckPattern     = in->padTopLineCount;
+       cmd.bottomUnapckPattern  = in->padBottomLineCount;
+
+       /*  program vfe_bus_cfg */
+       vfe_prog_hw(ctrl->vfebase + VFE_BUS_STRIPE_RD_ADDR_0,
+               (uint32_t *)&cmd, sizeof(cmd));
+
+       /* hacking code, put it to default value */
+       busPingpongRdIrqEnable = 0xf;
+
+       writel(busPingpongRdIrqEnable,
+               ctrl->vfebase + VFE_BUS_PINGPONG_IRQ_EN);
+}
+
+void vfe_stats_config(struct vfe_cmd_stats_setting *in)
+{
+       ctrl->afStatsControl.addressBuffer[0] = in->afBuffer[0];
+       ctrl->afStatsControl.addressBuffer[1] = in->afBuffer[1];
+       ctrl->afStatsControl.nextFrameAddrBuf = in->afBuffer[2];
+
+       ctrl->awbStatsControl.addressBuffer[0] = in->awbBuffer[0];
+       ctrl->awbStatsControl.addressBuffer[1] = in->awbBuffer[1];
+       ctrl->awbStatsControl.nextFrameAddrBuf = in->awbBuffer[2];
+
+       vfe_stats_setting(in);
+}
+
+void vfe_axi_output_config(
+       struct vfe_cmd_axi_output_config *in)
+{
+       /* local variable  */
+       uint32_t *pcircle;
+       uint32_t *pdest;
+       uint32_t *psrc;
+       uint8_t  i;
+       uint8_t  fcnt;
+       uint16_t axioutpw = 8;
+
+       /* parameters check, condition and usage mode check */
+       ctrl->encPath.fragCount = in->output2.fragmentCount;
+       if (ctrl->encPath.fragCount > 1)
+               ctrl->encPath.multiFrag = TRUE;
+
+       ctrl->viewPath.fragCount = in->output1.fragmentCount;
+       if (ctrl->viewPath.fragCount > 1)
+               ctrl->viewPath.multiFrag = TRUE;
+
+       /* VFE_BUS_CFG.  raw data size */
+       ctrl->vfeBusConfigLocal.rawPixelDataSize = in->outputDataSize;
+
+       switch (in->outputDataSize) {
+       case VFE_RAW_PIXEL_DATA_SIZE_8BIT:
+               axioutpw = 8;
+               break;
+
+       case VFE_RAW_PIXEL_DATA_SIZE_10BIT:
+               axioutpw = 6;
+               break;
+
+       case VFE_RAW_PIXEL_DATA_SIZE_12BIT:
+               axioutpw = 5;
+               break;
+       }
+
+       ctrl->axiOutputMode = in->outputMode;
+
+       CDBG("axiOutputMode = %d\n", ctrl->axiOutputMode);
+
+       switch (ctrl->axiOutputMode) {
+       case VFE_AXI_OUTPUT_MODE_Output1: {
+               ctrl->vfeCamifConfigLocal.camif2BusEnable   = FALSE;
+               ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+               ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+                       VFE_RAW_OUTPUT_DISABLED;
+
+               ctrl->encPath.pathEnabled                   = FALSE;
+               ctrl->vfeImaskLocal.encIrq                  = FALSE;
+               ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.encYWrPathEn          = FALSE;
+               ctrl->vfeBusConfigLocal.encCbcrWrPathEn       = FALSE;
+               ctrl->viewPath.pathEnabled                    = TRUE;
+               ctrl->vfeImaskLocal.viewIrq                   = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.viewYWrPathEn    = TRUE;
+               ctrl->vfeBusConfigLocal.viewCbcrWrPathEn = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+       } /* VFE_AXI_OUTPUT_MODE_Output1 */
+               break;
+
+       case VFE_AXI_OUTPUT_MODE_Output2: {
+               ctrl->vfeCamifConfigLocal.camif2BusEnable   = FALSE;
+               ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+               ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+                       VFE_RAW_OUTPUT_DISABLED;
+
+               ctrl->encPath.pathEnabled                   = TRUE;
+               ctrl->vfeImaskLocal.encIrq                  = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.encYWrPathEn        = TRUE;
+               ctrl->vfeBusConfigLocal.encCbcrWrPathEn     = TRUE;
+
+               ctrl->viewPath.pathEnabled                   = FALSE;
+               ctrl->vfeImaskLocal.viewIrq                  = FALSE;
+               ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.viewYWrPathEn        = FALSE;
+               ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = FALSE;
+
+               if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+       } /* VFE_AXI_OUTPUT_MODE_Output2 */
+                       break;
+
+       case VFE_AXI_OUTPUT_MODE_Output1AndOutput2: {
+               ctrl->vfeCamifConfigLocal.camif2BusEnable    = FALSE;
+               ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+               ctrl->vfeBusConfigLocal.rawWritePathSelect   =
+                       VFE_RAW_OUTPUT_DISABLED;
+
+               ctrl->encPath.pathEnabled                    = TRUE;
+               ctrl->vfeImaskLocal.encIrq                   = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.encYWrPathEn         = TRUE;
+               ctrl->vfeBusConfigLocal.encCbcrWrPathEn      = TRUE;
+               ctrl->viewPath.pathEnabled                   = TRUE;
+               ctrl->vfeImaskLocal.viewIrq                  = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.viewYWrPathEn        = TRUE;
+               ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+       } /* VFE_AXI_OUTPUT_MODE_Output1AndOutput2 */
+               break;
+
+       case VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2: {
+               /* For raw snapshot, we need both ping and pong buffer
+                * initialized to the same address. Otherwise, if we
+                * leave the pong buffer to NULL, there will be axi_error.
+                * Note that ideally we should deal with this at upper layer,
+                * which is in msm_vfe8x.c */
+               if (!in->output2.outputCbcr.outFragments[1][0]) {
+                       in->output2.outputCbcr.outFragments[1][0] =
+                               in->output2.outputCbcr.outFragments[0][0];
+               }
+
+               ctrl->vfeCamifConfigLocal.camif2BusEnable   = TRUE;
+               ctrl->vfeCamifConfigLocal.camif2OutputEnable = FALSE;
+               ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+                       VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+               ctrl->encPath.pathEnabled                   = TRUE;
+               ctrl->vfeImaskLocal.encIrq                  = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+                       VFE_COMP_IRQ_CBCR_ONLY;
+
+               ctrl->vfeBusConfigLocal.encYWrPathEn        = FALSE;
+               ctrl->vfeBusConfigLocal.encCbcrWrPathEn     = TRUE;
+
+               ctrl->viewPath.pathEnabled                   = FALSE;
+               ctrl->vfeImaskLocal.viewIrq                  = FALSE;
+               ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.viewYWrPathEn        = FALSE;
+               ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = FALSE;
+
+               if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+       } /* VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2 */
+               break;
+
+       case VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1: {
+               ctrl->vfeCamifConfigLocal.camif2BusEnable   = TRUE;
+               ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+               ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+                       VFE_RAW_OUTPUT_VIEW_CBCR_PATH;
+
+               ctrl->encPath.pathEnabled                   = TRUE;
+               ctrl->vfeImaskLocal.encIrq                  = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.encYWrPathEn        = TRUE;
+               ctrl->vfeBusConfigLocal.encCbcrWrPathEn     = TRUE;
+
+               ctrl->viewPath.pathEnabled                   = TRUE;
+               ctrl->vfeImaskLocal.viewIrq                  = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+                       VFE_COMP_IRQ_CBCR_ONLY;
+
+               ctrl->vfeBusConfigLocal.viewYWrPathEn        = FALSE;
+               ctrl->vfeBusConfigLocal.viewCbcrWrPathEn     = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encYPingpongIrq    = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encCbcrPingpongIrq = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewYPingpongIrq   = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewCbcrPingpongIrq = TRUE;
+       } /* VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1 */
+               break;
+
+       case VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2: {
+               ctrl->vfeCamifConfigLocal.camif2BusEnable   = TRUE;
+               ctrl->vfeCamifConfigLocal.camif2OutputEnable = TRUE;
+               ctrl->vfeBusConfigLocal.rawWritePathSelect  =
+                       VFE_RAW_OUTPUT_ENC_CBCR_PATH;
+
+               ctrl->encPath.pathEnabled                     = TRUE;
+               ctrl->vfeImaskLocal.encIrq                    = TRUE;
+               ctrl->vfeIrqCompositeMaskLocal.encIrqComMask  =
+                       VFE_COMP_IRQ_CBCR_ONLY;
+
+               ctrl->vfeBusConfigLocal.encYWrPathEn          = FALSE;
+               ctrl->vfeBusConfigLocal.encCbcrWrPathEn       = TRUE;
+
+               ctrl->viewPath.pathEnabled                    = TRUE;
+               ctrl->vfeImaskLocal.viewIrq                   = TRUE;
+
+               ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+                       VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+               ctrl->vfeBusConfigLocal.viewYWrPathEn         = TRUE;
+               ctrl->vfeBusConfigLocal.viewCbcrWrPathEn      = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encYWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encYPingpongIrq       = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.encCbcrWrPathEn &&
+                               ctrl->encPath.multiFrag)
+                       ctrl->vfeImaskLocal.encCbcrPingpongIrq    = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewYWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewYPingpongIrq      = TRUE;
+
+               if (ctrl->vfeBusConfigLocal.viewCbcrWrPathEn &&
+                               ctrl->viewPath.multiFrag)
+                       ctrl->vfeImaskLocal.viewCbcrPingpongIrq   = TRUE;
+       } /* VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2 */
+               break;
+
+       case VFE_AXI_LAST_OUTPUT_MODE_ENUM:
+               break;
+       } /* switch */
+
+       /* Save the addresses for each path. */
+       /* output2 path */
+       fcnt = ctrl->encPath.fragCount;
+
+       pcircle = ctrl->encPath.yPath.addressBuffer;
+       pdest = ctrl->encPath.nextFrameAddrBuf;
+
+       psrc = &(in->output2.outputY.outFragments[0][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output2.outputY.outFragments[1][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output2.outputY.outFragments[2][0]);
+       for (i = 0; i < fcnt; i++)
+               *pdest++ = *psrc++;
+
+       pcircle = ctrl->encPath.cbcrPath.addressBuffer;
+
+       psrc = &(in->output2.outputCbcr.outFragments[0][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output2.outputCbcr.outFragments[1][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output2.outputCbcr.outFragments[2][0]);
+       for (i = 0; i < fcnt; i++)
+               *pdest++ = *psrc++;
+
+       vfe_set_bus_pipo_addr(&ctrl->viewPath, &ctrl->encPath);
+
+       ctrl->encPath.ackPending = FALSE;
+       ctrl->encPath.currentFrame = ping;
+       ctrl->encPath.whichOutputPath = 1;
+       ctrl->encPath.yPath.fragIndex = 2;
+       ctrl->encPath.cbcrPath.fragIndex = 2;
+       ctrl->encPath.yPath.hwCurrentFlag = ping;
+       ctrl->encPath.cbcrPath.hwCurrentFlag = ping;
+
+       /* output1 path */
+       pcircle = ctrl->viewPath.yPath.addressBuffer;
+       pdest = ctrl->viewPath.nextFrameAddrBuf;
+       fcnt = ctrl->viewPath.fragCount;
+
+       psrc = &(in->output1.outputY.outFragments[0][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output1.outputY.outFragments[1][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output1.outputY.outFragments[2][0]);
+       for (i = 0; i < fcnt; i++)
+               *pdest++ = *psrc++;
+
+       pcircle = ctrl->viewPath.cbcrPath.addressBuffer;
+
+       psrc = &(in->output1.outputCbcr.outFragments[0][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output1.outputCbcr.outFragments[1][0]);
+       for (i = 0; i < fcnt; i++)
+               *pcircle++ = *psrc++;
+
+       psrc = &(in->output1.outputCbcr.outFragments[2][0]);
+       for (i = 0; i < fcnt; i++)
+               *pdest++ = *psrc++;
+
+       ctrl->viewPath.ackPending = FALSE;
+       ctrl->viewPath.currentFrame = ping;
+       ctrl->viewPath.whichOutputPath = 0;
+       ctrl->viewPath.yPath.fragIndex = 2;
+       ctrl->viewPath.cbcrPath.fragIndex = 2;
+       ctrl->viewPath.yPath.hwCurrentFlag = ping;
+       ctrl->viewPath.cbcrPath.hwCurrentFlag = ping;
+
+       /* call to program the registers. */
+       vfe_axi_output(in, &ctrl->viewPath, &ctrl->encPath, axioutpw);
+}
+
+void vfe_camif_config(struct vfe_cmd_camif_config *in)
+{
+       struct vfe_camifcfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       CDBG("camif.frame pixelsPerLine = %d\n", in->frame.pixelsPerLine);
+       CDBG("camif.frame linesPerFrame = %d\n", in->frame.linesPerFrame);
+       CDBG("camif.window firstpixel = %d\n", in->window.firstpixel);
+       CDBG("camif.window lastpixel = %d\n",  in->window.lastpixel);
+       CDBG("camif.window firstline = %d\n",  in->window.firstline);
+       CDBG("camif.window lastline = %d\n",   in->window.lastline);
+
+       /* determine if epoch interrupt needs to be enabled.  */
+       if ((in->epoch1.enable == TRUE) &&
+                       (in->epoch1.lineindex <=
+                        in->frame.linesPerFrame))
+               ctrl->vfeImaskLocal.camifEpoch1Irq = 1;
+
+       if ((in->epoch2.enable == TRUE) &&
+                       (in->epoch2.lineindex <=
+                        in->frame.linesPerFrame)) {
+               ctrl->vfeImaskLocal.camifEpoch2Irq = 1;
+       }
+
+       /*  save the content to program CAMIF_CONFIG seperately. */
+       ctrl->vfeCamifConfigLocal.camifCfgFromCmd = in->camifConfig;
+
+       /* EFS_Config */
+       cmd.efsEndOfLine     = in->EFS.efsendofline;
+       cmd.efsStartOfLine   = in->EFS.efsstartofline;
+       cmd.efsEndOfFrame    = in->EFS.efsendofframe;
+       cmd.efsStartOfFrame  = in->EFS.efsstartofframe;
+
+       /* Frame Config */
+       cmd.frameConfigPixelsPerLine = in->frame.pixelsPerLine;
+       cmd.frameConfigLinesPerFrame = in->frame.linesPerFrame;
+
+       /* Window Width Config */
+       cmd.windowWidthCfgLastPixel  = in->window.lastpixel;
+       cmd.windowWidthCfgFirstPixel = in->window.firstpixel;
+
+       /* Window Height Config */
+       cmd.windowHeightCfglastLine   = in->window.lastline;
+       cmd.windowHeightCfgfirstLine  = in->window.firstline;
+
+       /* Subsample 1 Config */
+       cmd.subsample1CfgPixelSkip = in->subsample.pixelskipmask;
+       cmd.subsample1CfgLineSkip  = in->subsample.lineskipmask;
+
+       /* Subsample 2 Config */
+       cmd.subsample2CfgFrameSkip      = in->subsample.frameskip;
+       cmd.subsample2CfgFrameSkipMode  = in->subsample.frameskipmode;
+       cmd.subsample2CfgPixelSkipWrap  = in->subsample.pixelskipwrap;
+
+       /* Epoch Interrupt */
+       cmd.epoch1Line = in->epoch1.lineindex;
+       cmd.epoch2Line = in->epoch2.lineindex;
+
+       vfe_prog_hw(ctrl->vfebase + CAMIF_EFS_CONFIG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *in)
+{
+       struct vfe_fov_crop_cfg cmd;
+       memset(&cmd, 0, sizeof(cmd));
+
+       ctrl->vfeModuleEnableLocal.cropEnable = in->enable;
+
+       /* FOV Corp, Part 1 */
+       cmd.lastPixel  = in->lastPixel;
+       cmd.firstPixel = in->firstPixel;
+
+       /* FOV Corp, Part 2 */
+       cmd.lastLine   = in->lastLine;
+       cmd.firstLine  = in->firstLine;
+
+       vfe_prog_hw(ctrl->vfebase + VFE_CROP_WIDTH_CFG,
+               (uint32_t *)&cmd, sizeof(cmd));
+}
+
+void vfe_get_hw_version(struct vfe_cmd_hw_version *out)
+{
+       uint32_t vfeHwVersionPacked;
+       struct vfe_hw_ver ver;
+
+       vfeHwVersionPacked = readl(ctrl->vfebase + VFE_HW_VERSION);
+
+       ver = *((struct vfe_hw_ver *)&vfeHwVersionPacked);
+
+       out->coreVersion  = ver.coreVersion;
+       out->minorVersion = ver.minorVersion;
+       out->majorVersion = ver.majorVersion;
+}
+
+static void vfe_reset_internal_variables(void)
+{
+       unsigned long flags;
+
+       /* local variables to program the hardware. */
+       ctrl->vfeImaskPacked = 0;
+       ctrl->vfeImaskCompositePacked = 0;
+
+       /* FALSE = disable,  1 = enable. */
+       memset(&ctrl->vfeModuleEnableLocal, 0,
+               sizeof(ctrl->vfeModuleEnableLocal));
+
+       /* 0 = disable, 1 = enable */
+       memset(&ctrl->vfeCamifConfigLocal, 0,
+               sizeof(ctrl->vfeCamifConfigLocal));
+       /* 0 = disable, 1 = enable */
+       memset(&ctrl->vfeImaskLocal, 0, sizeof(ctrl->vfeImaskLocal));
+       memset(&ctrl->vfeStatsCmdLocal, 0, sizeof(ctrl->vfeStatsCmdLocal));
+       memset(&ctrl->vfeBusConfigLocal, 0, sizeof(ctrl->vfeBusConfigLocal));
+       memset(&ctrl->vfeBusPmConfigLocal, 0,
+               sizeof(ctrl->vfeBusPmConfigLocal));
+       memset(&ctrl->vfeBusCmdLocal, 0, sizeof(ctrl->vfeBusCmdLocal));
+       memset(&ctrl->vfeInterruptNameLocal, 0,
+               sizeof(ctrl->vfeInterruptNameLocal));
+       memset(&ctrl->vfeDroppedFrameCounts, 0,
+               sizeof(ctrl->vfeDroppedFrameCounts));
+       memset(&ctrl->vfeIrqThreadMsgLocal, 0,
+               sizeof(ctrl->vfeIrqThreadMsgLocal));
+
+       /* state control variables */
+       ctrl->vfeStartAckPendingFlag = FALSE;
+       ctrl->vfeStopAckPending = FALSE;
+       ctrl->vfeIrqCompositeMaskLocal.ceDoneSel = 0;
+       ctrl->vfeIrqCompositeMaskLocal.encIrqComMask =
+               VFE_COMP_IRQ_BOTH_Y_CBCR;
+       ctrl->vfeIrqCompositeMaskLocal.viewIrqComMask =
+               VFE_COMP_IRQ_BOTH_Y_CBCR;
+
+       spin_lock_irqsave(&ctrl->state_lock, flags);
+       ctrl->vstate = VFE_STATE_IDLE;
+       spin_unlock_irqrestore(&ctrl->state_lock, flags);
+
+       ctrl->axiOutputMode = VFE_AXI_LAST_OUTPUT_MODE_ENUM;
+       /* 0 for continuous mode, 1 for snapshot mode */
+       ctrl->vfeOperationMode = VFE_START_OPERATION_MODE_CONTINUOUS;
+       ctrl->vfeSnapShotCount = 0;
+       ctrl->vfeStatsPingPongReloadFlag = FALSE;
+       /* this is unsigned 32 bit integer. */
+       ctrl->vfeFrameId = 0;
+       ctrl->vfeFrameSkip.output1Pattern = 0xffffffff;
+       ctrl->vfeFrameSkip.output1Period  = 31;
+       ctrl->vfeFrameSkip.output2Pattern = 0xffffffff;
+       ctrl->vfeFrameSkip.output2Period  = 31;
+       ctrl->vfeFrameSkipPattern = 0xffffffff;
+       ctrl->vfeFrameSkipCount   = 0;
+       ctrl->vfeFrameSkipPeriod  = 31;
+
+       memset((void *)&ctrl->encPath, 0, sizeof(ctrl->encPath));
+       memset((void *)&ctrl->viewPath, 0, sizeof(ctrl->viewPath));
+
+       ctrl->encPath.whichOutputPath  = 1;
+       ctrl->encPath.cbcrStatusBit    = 5;
+       ctrl->viewPath.whichOutputPath = 0;
+       ctrl->viewPath.cbcrStatusBit   = 7;
+
+       ctrl->vfeTestGenStartFlag = FALSE;
+
+       /* default to bank 0. */
+       ctrl->vfeLaBankSel = 0;
+
+       /* default to bank 0 for all channels. */
+       memset(&ctrl->vfeGammaLutSel, 0, sizeof(ctrl->vfeGammaLutSel));
+
+       /* Stats control variables. */
+       memset(&ctrl->afStatsControl, 0, sizeof(ctrl->afStatsControl));
+       memset(&ctrl->awbStatsControl, 0, sizeof(ctrl->awbStatsControl));
+       vfe_set_stats_pingpong_address(&ctrl->afStatsControl,
+               &ctrl->awbStatsControl);
+}
+
+void vfe_reset(void)
+{
+       vfe_reset_internal_variables();
+
+       ctrl->vfeImaskLocal.resetAckIrq = TRUE;
+       ctrl->vfeImaskPacked = vfe_irq_pack(ctrl->vfeImaskLocal);
+
+       /* disable all interrupts. */
+       writel(VFE_DISABLE_ALL_IRQS,
+               ctrl->vfebase + VFE_IRQ_COMPOSITE_MASK);
+
+       /* clear all pending interrupts*/
+       writel(VFE_CLEAR_ALL_IRQS,
+               ctrl->vfebase + VFE_IRQ_CLEAR);
+
+       /* enable reset_ack interrupt.  */
+       writel(ctrl->vfeImaskPacked,
+               ctrl->vfebase + VFE_IRQ_MASK);
+
+       writel(VFE_RESET_UPON_RESET_CMD,
+               ctrl->vfebase + VFE_GLOBAL_RESET_CMD);
+}
diff --git a/drivers/staging/dream/camera/msm_vfe8x_proc.h b/drivers/staging/dream/camera/msm_vfe8x_proc.h
new file mode 100644 (file)
index 0000000..9182856
--- /dev/null
@@ -0,0 +1,1549 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#ifndef __MSM_VFE8X_REG_H__
+#define __MSM_VFE8X_REG_H__
+
+#include <mach/msm_iomap.h>
+#include <mach/camera.h>
+#include "msm_vfe8x.h"
+
+/* at start of camif,  bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START  0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR  0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 =  halted,  0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go;   bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO   0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go;   bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO   0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples.  JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQS   0xffffffff
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq,
+ * bit 29,28,27,26 for async timer, bit 9 for reset */
+#define VFE_IMASK_WHILE_STOPPING  0x3c000200
+
+/* when normal case, don't want to block error status.
+ * bit 0,6,20,21,22,30,31 */
+#define VFE_IMASK_ERROR_ONLY             0xC0700041
+#define VFE_REG_UPDATE_TRIGGER           1
+#define VFE_PM_BUF_MAX_CNT_MASK          0xFF
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+#define LENS_ROLL_OFF_DELTA_TABLE_OFFSET 32
+#define VFE_AF_PINGPONG_STATUS_BIT       0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT      0x200
+
+/* VFE I/O registers */
+enum {
+       VFE_HW_VERSION                    = 0x00000000,
+       VFE_GLOBAL_RESET_CMD              = 0x00000004,
+       VFE_MODULE_RESET                  = 0x00000008,
+       VFE_CGC_OVERRIDE                  = 0x0000000C,
+       VFE_MODULE_CFG                    = 0x00000010,
+       VFE_CFG                           = 0x00000014,
+       VFE_IRQ_MASK                      = 0x00000018,
+       VFE_IRQ_CLEAR                     = 0x0000001C,
+VFE_IRQ_STATUS                    = 0x00000020,
+VFE_IRQ_COMPOSITE_MASK            = 0x00000024,
+VFE_BUS_CMD                       = 0x00000028,
+VFE_BUS_CFG                       = 0x0000002C,
+VFE_BUS_ENC_Y_WR_PING_ADDR        = 0x00000030,
+VFE_BUS_ENC_Y_WR_PONG_ADDR        = 0x00000034,
+VFE_BUS_ENC_Y_WR_IMAGE_SIZE       = 0x00000038,
+VFE_BUS_ENC_Y_WR_BUFFER_CFG       = 0x0000003C,
+VFE_BUS_ENC_CBCR_WR_PING_ADDR     = 0x00000040,
+VFE_BUS_ENC_CBCR_WR_PONG_ADDR     = 0x00000044,
+VFE_BUS_ENC_CBCR_WR_IMAGE_SIZE    = 0x00000048,
+VFE_BUS_ENC_CBCR_WR_BUFFER_CFG    = 0x0000004C,
+VFE_BUS_VIEW_Y_WR_PING_ADDR       = 0x00000050,
+VFE_BUS_VIEW_Y_WR_PONG_ADDR       = 0x00000054,
+VFE_BUS_VIEW_Y_WR_IMAGE_SIZE      = 0x00000058,
+VFE_BUS_VIEW_Y_WR_BUFFER_CFG      = 0x0000005C,
+VFE_BUS_VIEW_CBCR_WR_PING_ADDR    = 0x00000060,
+VFE_BUS_VIEW_CBCR_WR_PONG_ADDR    = 0x00000064,
+VFE_BUS_VIEW_CBCR_WR_IMAGE_SIZE   = 0x00000068,
+VFE_BUS_VIEW_CBCR_WR_BUFFER_CFG   = 0x0000006C,
+VFE_BUS_STATS_AF_WR_PING_ADDR     = 0x00000070,
+VFE_BUS_STATS_AF_WR_PONG_ADDR     = 0x00000074,
+VFE_BUS_STATS_AWB_WR_PING_ADDR    = 0x00000078,
+VFE_BUS_STATS_AWB_WR_PONG_ADDR    = 0x0000007C,
+VFE_BUS_STATS_HIST_WR_PING_ADDR   = 0x00000080,
+VFE_BUS_STATS_HIST_WR_PONG_ADDR   = 0x00000084,
+VFE_BUS_STATS_WR_PRIORITY         = 0x00000088,
+VFE_BUS_STRIPE_RD_ADDR_0          = 0x0000008C,
+VFE_BUS_STRIPE_RD_ADDR_1          = 0x00000090,
+VFE_BUS_STRIPE_RD_ADDR_2          = 0x00000094,
+VFE_BUS_STRIPE_RD_ADDR_3          = 0x00000098,
+VFE_BUS_STRIPE_RD_VSIZE           = 0x0000009C,
+VFE_BUS_STRIPE_RD_HSIZE           = 0x000000A0,
+VFE_BUS_STRIPE_RD_BUFFER_CFG      = 0x000000A4,
+VFE_BUS_STRIPE_RD_UNPACK_CFG      = 0x000000A8,
+VFE_BUS_STRIPE_RD_UNPACK          = 0x000000AC,
+VFE_BUS_STRIPE_RD_PAD_SIZE        = 0x000000B0,
+VFE_BUS_STRIPE_RD_PAD_L_UNPACK    = 0x000000B4,
+VFE_BUS_STRIPE_RD_PAD_R_UNPACK    = 0x000000B8,
+VFE_BUS_STRIPE_RD_PAD_TB_UNPACK   = 0x000000BC,
+VFE_BUS_PINGPONG_IRQ_EN           = 0x000000C0,
+VFE_BUS_PINGPONG_STATUS           = 0x000000C4,
+VFE_BUS_PM_CMD                    = 0x000000C8,
+VFE_BUS_PM_CFG                    = 0x000000CC,
+VFE_BUS_ENC_Y_WR_PM_STATS_0       = 0x000000D0,
+VFE_BUS_ENC_Y_WR_PM_STATS_1       = 0x000000D4,
+VFE_BUS_ENC_CBCR_WR_PM_STATS_0    = 0x000000D8,
+VFE_BUS_ENC_CBCR_WR_PM_STATS_1    = 0x000000DC,
+VFE_BUS_VIEW_Y_WR_PM_STATS_0      = 0x000000E0,
+VFE_BUS_VIEW_Y_WR_PM_STATS_1      = 0x000000E4,
+VFE_BUS_VIEW_CBCR_WR_PM_STATS_0   = 0x000000E8,
+VFE_BUS_VIEW_CBCR_WR_PM_STATS_1   = 0x000000EC,
+VFE_BUS_MISR_CFG                  = 0x000000F4,
+VFE_BUS_MISR_MAST_CFG_0           = 0x000000F8,
+VFE_BUS_MISR_MAST_CFG_1           = 0x000000FC,
+VFE_BUS_MISR_RD_VAL               = 0x00000100,
+VFE_AXI_CMD                       = 0x00000104,
+VFE_AXI_CFG                       = 0x00000108,
+VFE_AXI_STATUS                    = 0x0000010C,
+CAMIF_COMMAND                     = 0x00000110,
+CAMIF_CONFIG                      = 0x00000114,
+CAMIF_EFS_CONFIG                  = 0x00000118,
+CAMIF_FRAME_CONFIG                = 0x0000011C,
+CAMIF_WINDOW_WIDTH_CONFIG         = 0x00000120,
+CAMIF_WINDOW_HEIGHT_CONFIG        = 0x00000124,
+CAMIF_SUBSAMPLE1_CONFIG           = 0x00000128,
+CAMIF_SUBSAMPLE2_CONFIG           = 0x0000012C,
+CAMIF_EPOCH_IRQ                   = 0x00000130,
+CAMIF_STATUS                      = 0x00000134,
+CAMIF_MISR                        = 0x00000138,
+VFE_SYNC_TIMER_CMD                = 0x0000013C,
+VFE_SYNC_TIMER0_LINE_START        = 0x00000140,
+VFE_SYNC_TIMER0_PIXEL_START       = 0x00000144,
+VFE_SYNC_TIMER0_PIXEL_DURATION    = 0x00000148,
+VFE_SYNC_TIMER1_LINE_START        = 0x0000014C,
+VFE_SYNC_TIMER1_PIXEL_START       = 0x00000150,
+VFE_SYNC_TIMER1_PIXEL_DURATION    = 0x00000154,
+VFE_SYNC_TIMER2_LINE_START        = 0x00000158,
+VFE_SYNC_TIMER2_PIXEL_START       = 0x0000015C,
+VFE_SYNC_TIMER2_PIXEL_DURATION    = 0x00000160,
+VFE_SYNC_TIMER_POLARITY           = 0x00000164,
+VFE_ASYNC_TIMER_CMD               = 0x00000168,
+VFE_ASYNC_TIMER0_CFG_0            = 0x0000016C,
+VFE_ASYNC_TIMER0_CFG_1            = 0x00000170,
+VFE_ASYNC_TIMER1_CFG_0            = 0x00000174,
+VFE_ASYNC_TIMER1_CFG_1            = 0x00000178,
+VFE_ASYNC_TIMER2_CFG_0            = 0x0000017C,
+VFE_ASYNC_TIMER2_CFG_1            = 0x00000180,
+VFE_ASYNC_TIMER3_CFG_0            = 0x00000184,
+VFE_ASYNC_TIMER3_CFG_1            = 0x00000188,
+VFE_TIMER_SEL                     = 0x0000018C,
+VFE_REG_UPDATE_CMD                = 0x00000190,
+VFE_BLACK_EVEN_EVEN_VALUE         = 0x00000194,
+VFE_BLACK_EVEN_ODD_VALUE          = 0x00000198,
+VFE_BLACK_ODD_EVEN_VALUE          = 0x0000019C,
+VFE_BLACK_ODD_ODD_VALUE           = 0x000001A0,
+VFE_ROLLOFF_CFG_0                 = 0x000001A4,
+VFE_ROLLOFF_CFG_1                 = 0x000001A8,
+VFE_ROLLOFF_CFG_2                 = 0x000001AC,
+VFE_DEMUX_CFG                     = 0x000001B0,
+VFE_DEMUX_GAIN_0                  = 0x000001B4,
+VFE_DEMUX_GAIN_1                  = 0x000001B8,
+VFE_DEMUX_EVEN_CFG                = 0x000001BC,
+VFE_DEMUX_ODD_CFG                 = 0x000001C0,
+VFE_DEMOSAIC_CFG                  = 0x000001C4,
+VFE_DEMOSAIC_ABF_CFG_0            = 0x000001C8,
+VFE_DEMOSAIC_ABF_CFG_1            = 0x000001CC,
+VFE_DEMOSAIC_BPC_CFG_0            = 0x000001D0,
+VFE_DEMOSAIC_BPC_CFG_1            = 0x000001D4,
+VFE_DEMOSAIC_STATUS               = 0x000001D8,
+VFE_CHROMA_UPSAMPLE_CFG           = 0x000001DC,
+VFE_CROP_WIDTH_CFG                = 0x000001E0,
+VFE_CROP_HEIGHT_CFG               = 0x000001E4,
+VFE_COLOR_CORRECT_COEFF_0         = 0x000001E8,
+VFE_COLOR_CORRECT_COEFF_1         = 0x000001EC,
+VFE_COLOR_CORRECT_COEFF_2         = 0x000001F0,
+VFE_COLOR_CORRECT_COEFF_3         = 0x000001F4,
+VFE_COLOR_CORRECT_COEFF_4         = 0x000001F8,
+VFE_COLOR_CORRECT_COEFF_5         = 0x000001FC,
+VFE_COLOR_CORRECT_COEFF_6         = 0x00000200,
+VFE_COLOR_CORRECT_COEFF_7         = 0x00000204,
+VFE_COLOR_CORRECT_COEFF_8         = 0x00000208,
+VFE_COLOR_CORRECT_OFFSET_0        = 0x0000020C,
+VFE_COLOR_CORRECT_OFFSET_1        = 0x00000210,
+VFE_COLOR_CORRECT_OFFSET_2        = 0x00000214,
+VFE_COLOR_CORRECT_COEFF_Q         = 0x00000218,
+VFE_LA_CFG                        = 0x0000021C,
+VFE_LUT_BANK_SEL                  = 0x00000220,
+VFE_CHROMA_ENHAN_A                = 0x00000224,
+VFE_CHROMA_ENHAN_B                = 0x00000228,
+VFE_CHROMA_ENHAN_C                = 0x0000022C,
+VFE_CHROMA_ENHAN_D                = 0x00000230,
+VFE_CHROMA_ENHAN_K                = 0x00000234,
+VFE_COLOR_CONVERT_COEFF_0         = 0x00000238,
+VFE_COLOR_CONVERT_COEFF_1         = 0x0000023C,
+VFE_COLOR_CONVERT_COEFF_2         = 0x00000240,
+VFE_COLOR_CONVERT_OFFSET          = 0x00000244,
+VFE_ASF_CFG                       = 0x00000248,
+VFE_ASF_SHARP_CFG_0               = 0x0000024C,
+VFE_ASF_SHARP_CFG_1               = 0x00000250,
+VFE_ASF_SHARP_COEFF_0             = 0x00000254,
+VFE_ASF_SHARP_COEFF_1             = 0x00000258,
+VFE_ASF_SHARP_COEFF_2             = 0x0000025C,
+VFE_ASF_SHARP_COEFF_3             = 0x00000260,
+VFE_ASF_MAX_EDGE                  = 0x00000264,
+VFE_ASF_CROP_WIDTH_CFG            = 0x00000268,
+VFE_ASF_CROP_HEIGHT_CFG           = 0x0000026C,
+VFE_SCALE_CFG                     = 0x00000270,
+VFE_SCALE_H_IMAGE_SIZE_CFG        = 0x00000274,
+VFE_SCALE_H_PHASE_CFG             = 0x00000278,
+VFE_SCALE_H_STRIPE_CFG            = 0x0000027C,
+VFE_SCALE_V_IMAGE_SIZE_CFG        = 0x00000280,
+VFE_SCALE_V_PHASE_CFG             = 0x00000284,
+VFE_SCALE_V_STRIPE_CFG            = 0x00000288,
+VFE_SCALE_Y_CFG                   = 0x0000028C,
+VFE_SCALE_Y_H_IMAGE_SIZE_CFG      = 0x00000290,
+VFE_SCALE_Y_H_PHASE_CFG           = 0x00000294,
+VFE_SCALE_Y_V_IMAGE_SIZE_CFG      = 0x00000298,
+VFE_SCALE_Y_V_PHASE_CFG           = 0x0000029C,
+VFE_SCALE_CBCR_CFG                = 0x000002A0,
+VFE_SCALE_CBCR_H_IMAGE_SIZE_CFG   = 0x000002A4,
+VFE_SCALE_CBCR_H_PHASE_CFG        = 0x000002A8,
+VFE_SCALE_CBCR_V_IMAGE_SIZE_CFG   = 0x000002AC,
+VFE_SCALE_CBCR_V_PHASE_CFG        = 0x000002B0,
+VFE_WB_CFG                        = 0x000002B4,
+VFE_CHROMA_SUPPRESS_CFG_0         = 0x000002B8,
+VFE_CHROMA_SUPPRESS_CFG_1         = 0x000002BC,
+VFE_CHROMA_SUBSAMPLE_CFG          = 0x000002C0,
+VFE_CHROMA_SUB_CROP_WIDTH_CFG     = 0x000002C4,
+VFE_CHROMA_SUB_CROP_HEIGHT_CFG    = 0x000002C8,
+VFE_FRAMEDROP_ENC_Y_CFG           = 0x000002CC,
+VFE_FRAMEDROP_ENC_CBCR_CFG        = 0x000002D0,
+VFE_FRAMEDROP_ENC_Y_PATTERN       = 0x000002D4,
+VFE_FRAMEDROP_ENC_CBCR_PATTERN    = 0x000002D8,
+VFE_FRAMEDROP_VIEW_Y_CFG          = 0x000002DC,
+VFE_FRAMEDROP_VIEW_CBCR_CFG       = 0x000002E0,
+VFE_FRAMEDROP_VIEW_Y_PATTERN      = 0x000002E4,
+VFE_FRAMEDROP_VIEW_CBCR_PATTERN   = 0x000002E8,
+VFE_CLAMP_MAX_CFG                 = 0x000002EC,
+VFE_CLAMP_MIN_CFG                 = 0x000002F0,
+VFE_STATS_CMD                     = 0x000002F4,
+VFE_STATS_AF_CFG                  = 0x000002F8,
+VFE_STATS_AF_DIM                  = 0x000002FC,
+VFE_STATS_AF_GRID_0               = 0x00000300,
+VFE_STATS_AF_GRID_1               = 0x00000304,
+VFE_STATS_AF_GRID_2               = 0x00000308,
+VFE_STATS_AF_GRID_3               = 0x0000030C,
+VFE_STATS_AF_HEADER               = 0x00000310,
+VFE_STATS_AF_COEF0                = 0x00000314,
+VFE_STATS_AF_COEF1                = 0x00000318,
+VFE_STATS_AWBAE_CFG               = 0x0000031C,
+VFE_STATS_AXW_HEADER              = 0x00000320,
+VFE_STATS_AWB_MCFG                = 0x00000324,
+VFE_STATS_AWB_CCFG1               = 0x00000328,
+VFE_STATS_AWB_CCFG2               = 0x0000032C,
+VFE_STATS_HIST_HEADER             = 0x00000330,
+VFE_STATS_HIST_INNER_OFFSET       = 0x00000334,
+VFE_STATS_HIST_INNER_DIM          = 0x00000338,
+VFE_STATS_FRAME_SIZE              = 0x0000033C,
+VFE_DMI_CFG                       = 0x00000340,
+VFE_DMI_ADDR                      = 0x00000344,
+VFE_DMI_DATA_HI                   = 0x00000348,
+VFE_DMI_DATA_LO                   = 0x0000034C,
+VFE_DMI_RAM_AUTO_LOAD_CMD         = 0x00000350,
+VFE_DMI_RAM_AUTO_LOAD_STATUS      = 0x00000354,
+VFE_DMI_RAM_AUTO_LOAD_CFG         = 0x00000358,
+VFE_DMI_RAM_AUTO_LOAD_SEED        = 0x0000035C,
+VFE_TESTBUS_SEL                   = 0x00000360,
+VFE_TESTGEN_CFG                   = 0x00000364,
+VFE_SW_TESTGEN_CMD                = 0x00000368,
+VFE_HW_TESTGEN_CMD                = 0x0000036C,
+VFE_HW_TESTGEN_CFG                = 0x00000370,
+VFE_HW_TESTGEN_IMAGE_CFG          = 0x00000374,
+VFE_HW_TESTGEN_SOF_OFFSET_CFG     = 0x00000378,
+VFE_HW_TESTGEN_EOF_NOFFSET_CFG    = 0x0000037C,
+VFE_HW_TESTGEN_SOL_OFFSET_CFG     = 0x00000380,
+VFE_HW_TESTGEN_EOL_NOFFSET_CFG    = 0x00000384,
+VFE_HW_TESTGEN_HBI_CFG            = 0x00000388,
+VFE_HW_TESTGEN_VBL_CFG            = 0x0000038C,
+VFE_HW_TESTGEN_SOF_DUMMY_LINE_CFG2 = 0x00000390,
+VFE_HW_TESTGEN_EOF_DUMMY_LINE_CFG2 = 0x00000394,
+VFE_HW_TESTGEN_COLOR_BARS_CFG     = 0x00000398,
+VFE_HW_TESTGEN_RANDOM_CFG         = 0x0000039C,
+VFE_SPARE                         = 0x000003A0,
+};
+
+#define ping 0x0
+#define pong 0x1
+
+struct vfe_bus_cfg_data {
+       boolean                  stripeRdPathEn;
+       boolean                  encYWrPathEn;
+       boolean                  encCbcrWrPathEn;
+       boolean                  viewYWrPathEn;
+       boolean                  viewCbcrWrPathEn;
+       enum VFE_RAW_PIXEL_DATA_SIZE rawPixelDataSize;
+       enum VFE_RAW_WR_PATH_SEL     rawWritePathSelect;
+};
+
+struct vfe_camif_cfg_data {
+       boolean camif2OutputEnable;
+       boolean camif2BusEnable;
+       struct vfe_cmds_camif_cfg camifCfgFromCmd;
+};
+
+struct vfe_irq_composite_mask_config {
+       uint8_t encIrqComMask;
+       uint8_t viewIrqComMask;
+       uint8_t ceDoneSel;
+};
+
+/* define a structure for each output path.*/
+struct vfe_output_path {
+       uint32_t addressBuffer[8];
+       uint16_t fragIndex;
+       boolean  hwCurrentFlag;
+       uint8_t  *hwRegPingAddress;
+       uint8_t  *hwRegPongAddress;
+};
+
+struct vfe_output_path_combo {
+       boolean           whichOutputPath;
+       boolean           pathEnabled;
+       boolean           multiFrag;
+       uint8_t           fragCount;
+       boolean           ackPending;
+       uint8_t           currentFrame;
+       uint32_t          nextFrameAddrBuf[8];
+       struct vfe_output_path   yPath;
+       struct vfe_output_path   cbcrPath;
+       uint8_t           snapshotPendingCount;
+       boolean           pmEnabled;
+       uint8_t           cbcrStatusBit;
+};
+
+struct vfe_stats_control {
+       boolean  ackPending;
+       uint32_t addressBuffer[2];
+       uint32_t nextFrameAddrBuf;
+       boolean  pingPongStatus;
+       uint8_t  *hwRegPingAddress;
+       uint8_t  *hwRegPongAddress;
+       uint32_t droppedStatsFrameCount;
+       uint32_t bufToRender;
+};
+
+struct vfe_gamma_lut_sel {
+       boolean  ch0BankSelect;
+       boolean  ch1BankSelect;
+       boolean  ch2BankSelect;
+};
+
+struct vfe_interrupt_mask {
+       boolean  camifErrorIrq;
+       boolean  camifSofIrq;
+       boolean  camifEolIrq;
+       boolean  camifEofIrq;
+       boolean  camifEpoch1Irq;
+       boolean  camifEpoch2Irq;
+       boolean  camifOverflowIrq;
+       boolean  ceIrq;
+       boolean  regUpdateIrq;
+       boolean  resetAckIrq;
+       boolean  encYPingpongIrq;
+       boolean  encCbcrPingpongIrq;
+       boolean  viewYPingpongIrq;
+       boolean  viewCbcrPingpongIrq;
+       boolean  rdPingpongIrq;
+       boolean  afPingpongIrq;
+       boolean  awbPingpongIrq;
+       boolean  histPingpongIrq;
+       boolean  encIrq;
+       boolean  viewIrq;
+       boolean  busOverflowIrq;
+       boolean  afOverflowIrq;
+       boolean  awbOverflowIrq;
+       boolean  syncTimer0Irq;
+       boolean  syncTimer1Irq;
+       boolean  syncTimer2Irq;
+       boolean  asyncTimer0Irq;
+       boolean  asyncTimer1Irq;
+       boolean  asyncTimer2Irq;
+       boolean  asyncTimer3Irq;
+       boolean  axiErrorIrq;
+       boolean  violationIrq;
+};
+
+enum vfe_interrupt_name {
+       CAMIF_ERROR_IRQ,
+       CAMIF_SOF_IRQ,
+       CAMIF_EOL_IRQ,
+       CAMIF_EOF_IRQ,
+       CAMIF_EPOCH1_IRQ,
+       CAMIF_EPOCH2_IRQ,
+       CAMIF_OVERFLOW_IRQ,
+       CE_IRQ,
+       REG_UPDATE_IRQ,
+       RESET_ACK_IRQ,
+       ENC_Y_PINGPONG_IRQ,
+       ENC_CBCR_PINGPONG_IRQ,
+       VIEW_Y_PINGPONG_IRQ,
+       VIEW_CBCR_PINGPONG_IRQ,
+       RD_PINGPONG_IRQ,
+       AF_PINGPONG_IRQ,
+       AWB_PINGPONG_IRQ,
+       HIST_PINGPONG_IRQ,
+       ENC_IRQ,
+       VIEW_IRQ,
+       BUS_OVERFLOW_IRQ,
+       AF_OVERFLOW_IRQ,
+       AWB_OVERFLOW_IRQ,
+       SYNC_TIMER0_IRQ,
+       SYNC_TIMER1_IRQ,
+       SYNC_TIMER2_IRQ,
+       ASYNC_TIMER0_IRQ,
+       ASYNC_TIMER1_IRQ,
+       ASYNC_TIMER2_IRQ,
+       ASYNC_TIMER3_IRQ,
+       AXI_ERROR_IRQ,
+       VIOLATION_IRQ
+};
+
+enum VFE_DMI_RAM_SEL {
+       NO_MEM_SELECTED          = 0,
+       ROLLOFF_RAM              = 0x1,
+       RGBLUT_RAM_CH0_BANK0     = 0x2,
+       RGBLUT_RAM_CH0_BANK1     = 0x3,
+       RGBLUT_RAM_CH1_BANK0     = 0x4,
+       RGBLUT_RAM_CH1_BANK1     = 0x5,
+       RGBLUT_RAM_CH2_BANK0     = 0x6,
+       RGBLUT_RAM_CH2_BANK1     = 0x7,
+       STATS_HIST_CB_EVEN_RAM   = 0x8,
+       STATS_HIST_CB_ODD_RAM    = 0x9,
+       STATS_HIST_CR_EVEN_RAM   = 0xa,
+       STATS_HIST_CR_ODD_RAM    = 0xb,
+       RGBLUT_CHX_BANK0         = 0xc,
+       RGBLUT_CHX_BANK1         = 0xd,
+       LUMA_ADAPT_LUT_RAM_BANK0 = 0xe,
+       LUMA_ADAPT_LUT_RAM_BANK1 = 0xf
+};
+
+struct vfe_module_enable {
+       boolean  blackLevelCorrectionEnable;
+       boolean  lensRollOffEnable;
+       boolean  demuxEnable;
+       boolean  chromaUpsampleEnable;
+       boolean  demosaicEnable;
+       boolean  statsEnable;
+       boolean  cropEnable;
+       boolean  mainScalerEnable;
+       boolean  whiteBalanceEnable;
+       boolean  colorCorrectionEnable;
+       boolean  yHistEnable;
+       boolean  skinToneEnable;
+       boolean  lumaAdaptationEnable;
+       boolean  rgbLUTEnable;
+       boolean  chromaEnhanEnable;
+       boolean  asfEnable;
+       boolean  chromaSuppressionEnable;
+       boolean  chromaSubsampleEnable;
+       boolean  scaler2YEnable;
+       boolean  scaler2CbcrEnable;
+};
+
+struct vfe_bus_cmd_data {
+       boolean  stripeReload;
+       boolean  busPingpongReload;
+       boolean  statsPingpongReload;
+};
+
+struct vfe_stats_cmd_data {
+       boolean  autoFocusEnable;
+       boolean  axwEnable;
+       boolean  histEnable;
+       boolean  clearHistEnable;
+       boolean  histAutoClearEnable;
+       boolean  colorConversionEnable;
+};
+
+struct vfe_hw_ver {
+       uint32_t minorVersion:8;
+       uint32_t majorVersion:8;
+       uint32_t coreVersion:4;
+       uint32_t /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_cfg {
+       uint32_t pixelPattern:3;
+       uint32_t /* reserved */ : 13;
+       uint32_t inputSource:2;
+       uint32_t /* reserved */ : 14;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_buscmd {
+       uint32_t  stripeReload:1;
+       uint32_t  /* reserved */ : 3;
+       uint32_t  busPingpongReload:1;
+       uint32_t  statsPingpongReload:1;
+       uint32_t  /* reserved */ : 26;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_Irq_Composite_MaskType {
+       uint32_t  encIrqComMaskBits:2;
+       uint32_t  viewIrqComMaskBits:2;
+       uint32_t  ceDoneSelBits:5;
+       uint32_t  /* reserved */ : 23;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_mod_enable {
+       uint32_t blackLevelCorrectionEnable:1;
+       uint32_t lensRollOffEnable:1;
+       uint32_t demuxEnable:1;
+       uint32_t chromaUpsampleEnable:1;
+       uint32_t demosaicEnable:1;
+       uint32_t statsEnable:1;
+       uint32_t cropEnable:1;
+       uint32_t mainScalerEnable:1;
+       uint32_t whiteBalanceEnable:1;
+       uint32_t colorCorrectionEnable:1;
+       uint32_t yHistEnable:1;
+       uint32_t skinToneEnable:1;
+       uint32_t lumaAdaptationEnable:1;
+       uint32_t rgbLUTEnable:1;
+       uint32_t chromaEnhanEnable:1;
+       uint32_t asfEnable:1;
+       uint32_t chromaSuppressionEnable:1;
+       uint32_t chromaSubsampleEnable:1;
+       uint32_t scaler2YEnable:1;
+       uint32_t scaler2CbcrEnable:1;
+       uint32_t /* reserved */ : 14;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_irqenable {
+       uint32_t camifErrorIrq:1;
+       uint32_t camifSofIrq:1;
+       uint32_t camifEolIrq:1;
+       uint32_t camifEofIrq:1;
+       uint32_t camifEpoch1Irq:1;
+       uint32_t camifEpoch2Irq:1;
+       uint32_t camifOverflowIrq:1;
+       uint32_t ceIrq:1;
+       uint32_t regUpdateIrq:1;
+       uint32_t resetAckIrq:1;
+       uint32_t encYPingpongIrq:1;
+       uint32_t encCbcrPingpongIrq:1;
+       uint32_t viewYPingpongIrq:1;
+       uint32_t viewCbcrPingpongIrq:1;
+       uint32_t rdPingpongIrq:1;
+       uint32_t afPingpongIrq:1;
+       uint32_t awbPingpongIrq:1;
+       uint32_t histPingpongIrq:1;
+       uint32_t encIrq:1;
+       uint32_t viewIrq:1;
+       uint32_t busOverflowIrq:1;
+       uint32_t afOverflowIrq:1;
+       uint32_t awbOverflowIrq:1;
+       uint32_t syncTimer0Irq:1;
+       uint32_t syncTimer1Irq:1;
+       uint32_t syncTimer2Irq:1;
+       uint32_t asyncTimer0Irq:1;
+       uint32_t asyncTimer1Irq:1;
+       uint32_t asyncTimer2Irq:1;
+       uint32_t asyncTimer3Irq:1;
+       uint32_t axiErrorIrq:1;
+       uint32_t violationIrq:1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_upsample_cfg {
+       uint32_t chromaCositingForYCbCrInputs:1;
+       uint32_t /* reserved */ : 31;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_CAMIFConfigType {
+       /* CAMIF Config */
+       uint32_t  /* reserved */ : 1;
+       uint32_t  VSyncEdge:1;
+       uint32_t  HSyncEdge:1;
+       uint32_t  syncMode:2;
+       uint32_t  vfeSubsampleEnable:1;
+       uint32_t  /* reserved */ : 1;
+       uint32_t  busSubsampleEnable:1;
+       uint32_t  camif2vfeEnable:1;
+       uint32_t  /* reserved */ : 1;
+       uint32_t  camif2busEnable:1;
+       uint32_t  irqSubsampleEnable:1;
+       uint32_t  binningEnable:1;
+       uint32_t  /* reserved */ : 18;
+       uint32_t  misrEnable:1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_camifcfg {
+       /* EFS_Config */
+       uint32_t efsEndOfLine:8;
+       uint32_t efsStartOfLine:8;
+       uint32_t efsEndOfFrame:8;
+       uint32_t efsStartOfFrame:8;
+       /* Frame Config */
+       uint32_t frameConfigPixelsPerLine:14;
+       uint32_t /* reserved */ : 2;
+       uint32_t frameConfigLinesPerFrame:14;
+       uint32_t /* reserved */ : 2;
+       /* Window Width Config */
+       uint32_t windowWidthCfgLastPixel:14;
+       uint32_t /* reserved */ : 2;
+       uint32_t windowWidthCfgFirstPixel:14;
+       uint32_t /* reserved */ : 2;
+       /* Window Height Config */
+       uint32_t windowHeightCfglastLine:14;
+       uint32_t /* reserved */ : 2;
+       uint32_t windowHeightCfgfirstLine:14;
+       uint32_t /* reserved */ : 2;
+       /* Subsample 1 Config */
+       uint32_t subsample1CfgPixelSkip:16;
+       uint32_t subsample1CfgLineSkip:16;
+       /* Subsample 2 Config */
+       uint32_t subsample2CfgFrameSkip:4;
+       uint32_t subsample2CfgFrameSkipMode:1;
+       uint32_t subsample2CfgPixelSkipWrap:1;
+       uint32_t /* reserved */ : 26;
+       /* Epoch Interrupt */
+       uint32_t epoch1Line:14;
+       uint32_t /* reserved */ : 2;
+       uint32_t epoch2Line:14;
+       uint32_t /* reserved */ : 2;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_camifframe_update {
+       uint32_t pixelsPerLine:14;
+       uint32_t /* reserved */ : 2;
+       uint32_t linesPerFrame:14;
+       uint32_t /* reserved */ : 2;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_axi_bus_cfg {
+       uint32_t  stripeRdPathEn:1;
+       uint32_t  /* reserved */ : 3;
+       uint32_t  encYWrPathEn:1;
+       uint32_t  encCbcrWrPathEn:1;
+       uint32_t  viewYWrPathEn:1;
+       uint32_t  viewCbcrWrPathEn:1;
+       uint32_t  rawPixelDataSize:2;
+       uint32_t  rawWritePathSelect:2;
+       uint32_t  /* reserved */ : 20;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_axi_out_cfg {
+       uint32_t  out2YPingAddr:32;
+       uint32_t  out2YPongAddr:32;
+       uint32_t  out2YImageHeight:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out2YImageWidthin64bit:10;
+       uint32_t  /* reserved */ : 6;
+       uint32_t  out2YBurstLength:2;
+       uint32_t  /* reserved */ : 2;
+       uint32_t  out2YNumRows:12;
+       uint32_t  out2YRowIncrementIn64bit:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out2CbcrPingAddr:32;
+       uint32_t  out2CbcrPongAddr:32;
+       uint32_t  out2CbcrImageHeight:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out2CbcrImageWidthIn64bit:10;
+       uint32_t  /* reserved */ : 6;
+       uint32_t  out2CbcrBurstLength:2;
+       uint32_t  /* reserved */ : 2;
+       uint32_t  out2CbcrNumRows:12;
+       uint32_t  out2CbcrRowIncrementIn64bit:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out1YPingAddr:32;
+       uint32_t  out1YPongAddr:32;
+       uint32_t  out1YImageHeight:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out1YImageWidthin64bit:10;
+       uint32_t  /* reserved */ : 6;
+       uint32_t  out1YBurstLength:2;
+       uint32_t  /* reserved */ : 2;
+       uint32_t  out1YNumRows:12;
+       uint32_t  out1YRowIncrementIn64bit:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out1CbcrPingAddr:32;
+       uint32_t  out1CbcrPongAddr:32;
+       uint32_t  out1CbcrImageHeight:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  out1CbcrImageWidthIn64bit:10;
+       uint32_t  /* reserved */ : 6;
+       uint32_t  out1CbcrBurstLength:2;
+       uint32_t  /* reserved */ : 2;
+       uint32_t  out1CbcrNumRows:12;
+       uint32_t  out1CbcrRowIncrementIn64bit:12;
+       uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_output_clamp_cfg {
+       /* Output Clamp Maximums */
+       uint32_t yChanMax:8;
+       uint32_t cbChanMax:8;
+       uint32_t crChanMax:8;
+       uint32_t /* reserved */ : 8;
+       /* Output Clamp Minimums */
+       uint32_t yChanMin:8;
+       uint32_t cbChanMin:8;
+       uint32_t crChanMin:8;
+       uint32_t /* reserved */ : 8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_fov_crop_cfg {
+       uint32_t lastPixel:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t firstPixel:12;
+       uint32_t /* reserved */ : 4;
+
+       /* FOV Corp, Part 2 */
+       uint32_t lastLine:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t firstLine:12;
+       uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_FRAME_SKIP_UpdateCmdType {
+       uint32_t  yPattern:32;
+       uint32_t  cbcrPattern:32;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_frame_skip_cfg {
+       /* Frame Drop Enc (output2) */
+       uint32_t output2YPeriod:5;
+       uint32_t /* reserved */ : 27;
+       uint32_t output2CbCrPeriod:5;
+       uint32_t /* reserved */ : 27;
+       uint32_t output2YPattern:32;
+       uint32_t output2CbCrPattern:32;
+       /* Frame Drop View (output1) */
+       uint32_t output1YPeriod:5;
+       uint32_t /* reserved */ : 27;
+       uint32_t output1CbCrPeriod:5;
+       uint32_t /* reserved */ : 27;
+       uint32_t output1YPattern:32;
+       uint32_t output1CbCrPattern:32;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_main_scaler_cfg {
+       /* Scaler Enable Config */
+       uint32_t hEnable:1;
+       uint32_t vEnable:1;
+       uint32_t /* reserved */ : 30;
+       /* Scale H Image Size Config */
+       uint32_t inWidth:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t outWidth:12;
+       uint32_t /* reserved */ : 4;
+       /* Scale H Phase Config */
+       uint32_t horizPhaseMult:18;
+       uint32_t /* reserved */ : 2;
+       uint32_t horizInterResolution:2;
+       uint32_t /* reserved */ : 10;
+       /* Scale H Stripe Config */
+       uint32_t horizMNInit:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t horizPhaseInit:15;
+       uint32_t /* reserved */ : 1;
+       /* Scale V Image Size Config */
+       uint32_t inHeight:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t outHeight:12;
+       uint32_t /* reserved */ : 4;
+       /* Scale V Phase Config */
+       uint32_t vertPhaseMult:18;
+       uint32_t /* reserved */ : 2;
+       uint32_t vertInterResolution:2;
+       uint32_t /* reserved */ : 10;
+       /* Scale V Stripe Config */
+       uint32_t vertMNInit:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t vertPhaseInit:15;
+       uint32_t /* reserved */ : 1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_scaler2_cfg {
+       /* Scaler   Enable Config */
+       uint32_t  hEnable:1;
+       uint32_t  vEnable:1;
+       uint32_t  /* reserved */ : 30;
+       /* Scaler   H Image Size Config */
+       uint32_t  inWidth:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  outWidth:12;
+       uint32_t  /* reserved */ : 4;
+       /* Scaler   H Phase Config */
+       uint32_t  horizPhaseMult:18;
+       uint32_t  /* reserved */ : 2;
+       uint32_t  horizInterResolution:2;
+       uint32_t  /* reserved */ : 10;
+       /* Scaler   V Image Size Config */
+       uint32_t  inHeight:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  outHeight:12;
+       uint32_t  /* reserved */ : 4;
+       /* Scaler   V Phase Config */
+       uint32_t  vertPhaseMult:18;
+       uint32_t  /* reserved */ : 2;
+       uint32_t  vertInterResolution:2;
+       uint32_t  /* reserved */ : 10;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_rolloff_cfg {
+       /* Rolloff 0 Config */
+       uint32_t  gridWidth:9;
+       uint32_t  gridHeight:9;
+       uint32_t  yDelta:9;
+       uint32_t  /* reserved */ : 5;
+       /* Rolloff 1 Config*/
+       uint32_t  gridX:4;
+       uint32_t  gridY:4;
+       uint32_t  pixelX:9;
+       uint32_t  /* reserved */ : 3;
+       uint32_t  pixelY:9;
+       uint32_t  /* reserved */ : 3;
+       /* Rolloff 2 Config */
+       uint32_t  yDeltaAccum:12;
+       uint32_t  /* reserved */ : 20;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_asf_update {
+       /* ASF Config Command */
+       uint32_t smoothEnable:1;
+       uint32_t sharpMode:2;
+       uint32_t /* reserved */ : 1;
+       uint32_t smoothCoeff1:4;
+       uint32_t smoothCoeff0:8;
+       uint32_t pipeFlushCount:12;
+       uint32_t pipeFlushOvd:1;
+       uint32_t flushHaltOvd:1;
+       uint32_t cropEnable:1;
+       uint32_t /* reserved */ : 1;
+       /* Sharpening Config 0 */
+       uint32_t sharpThresholdE1:7;
+       uint32_t /* reserved */ : 1;
+       uint32_t sharpDegreeK1:5;
+       uint32_t /* reserved */ : 3;
+       uint32_t sharpDegreeK2:5;
+       uint32_t /* reserved */ : 3;
+       uint32_t normalizeFactor:7;
+       uint32_t /* reserved */ : 1;
+       /* Sharpening Config 1 */
+       uint32_t sharpThresholdE2:8;
+       uint32_t sharpThresholdE3:8;
+       uint32_t sharpThresholdE4:8;
+       uint32_t sharpThresholdE5:8;
+       /* Sharpening Coefficients 0 */
+       uint32_t F1Coeff0:6;
+       uint32_t F1Coeff1:6;
+       uint32_t F1Coeff2:6;
+       uint32_t F1Coeff3:6;
+       uint32_t F1Coeff4:6;
+       uint32_t /* reserved */ : 2;
+       /* Sharpening Coefficients 1 */
+       uint32_t F1Coeff5:6;
+       uint32_t F1Coeff6:6;
+       uint32_t F1Coeff7:6;
+       uint32_t F1Coeff8:7;
+       uint32_t /* reserved */ : 7;
+       /* Sharpening Coefficients 2 */
+       uint32_t F2Coeff0:6;
+       uint32_t F2Coeff1:6;
+       uint32_t F2Coeff2:6;
+       uint32_t F2Coeff3:6;
+       uint32_t F2Coeff4:6;
+       uint32_t /* reserved */ : 2;
+       /* Sharpening Coefficients 3 */
+       uint32_t F2Coeff5:6;
+       uint32_t F2Coeff6:6;
+       uint32_t F2Coeff7:6;
+       uint32_t F2Coeff8:7;
+       uint32_t /* reserved */ : 7;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_asfcrop_cfg {
+       /* ASF Crop Width Config */
+       uint32_t lastPixel:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t firstPixel:12;
+       uint32_t /* reserved */ : 4;
+       /* ASP Crop Height Config */
+       uint32_t lastLine:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t firstLine:12;
+       uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_chroma_suppress_cfg {
+       /* Chroma Suppress 0 Config */
+       uint32_t m1:8;
+       uint32_t m3:8;
+       uint32_t n1:3;
+       uint32_t /* reserved */ : 1;
+       uint32_t n3:3;
+       uint32_t /* reserved */ : 9;
+       /* Chroma Suppress 1 Config */
+       uint32_t mm1:8;
+       uint32_t nn1:3;
+       uint32_t /* reserved */ : 21;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_chromasubsample_cfg {
+       /* Chroma Subsample Selection */
+       uint32_t  hCositedPhase:1;
+       uint32_t  vCositedPhase:1;
+       uint32_t  hCosited:1;
+       uint32_t  vCosited:1;
+       uint32_t  hsubSampleEnable:1;
+       uint32_t  vsubSampleEnable:1;
+       uint32_t  cropEnable:1;
+       uint32_t  /* reserved */ : 25;
+       uint32_t  cropWidthLastPixel:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  cropWidthFirstPixel:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  cropHeightLastLine:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  cropHeightFirstLine:12;
+       uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_blacklevel_cfg {
+       /* Black Even-Even Value Config */
+       uint32_t    evenEvenAdjustment:9;
+       uint32_t   /* reserved */ : 23;
+       /* Black Even-Odd Value Config */
+       uint32_t    evenOddAdjustment:9;
+       uint32_t   /* reserved */ : 23;
+       /* Black Odd-Even Value Config */
+       uint32_t    oddEvenAdjustment:9;
+       uint32_t   /* reserved */ : 23;
+       /* Black Odd-Odd Value Config */
+       uint32_t    oddOddAdjustment:9;
+       uint32_t   /* reserved */ : 23;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demux_cfg {
+       /* Demux Gain 0 Config */
+       uint32_t  ch0EvenGain:10;
+       uint32_t  /* reserved */ : 6;
+       uint32_t  ch0OddGain:10;
+       uint32_t  /* reserved */ : 6;
+       /* Demux Gain 1 Config */
+       uint32_t  ch1Gain:10;
+       uint32_t  /* reserved */ : 6;
+       uint32_t  ch2Gain:10;
+       uint32_t  /* reserved */ : 6;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_bps_info {
+  uint32_t greenBadPixelCount:8;
+  uint32_t /* reserved */ : 8;
+  uint32_t RedBlueBadPixelCount:8;
+  uint32_t /* reserved */ : 8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demosaic_cfg {
+       /* Demosaic Config */
+       uint32_t abfEnable:1;
+       uint32_t badPixelCorrEnable:1;
+       uint32_t forceAbfOn:1;
+       uint32_t /* reserved */ : 1;
+       uint32_t abfShift:4;
+       uint32_t fminThreshold:7;
+       uint32_t /* reserved */ : 1;
+       uint32_t fmaxThreshold:7;
+       uint32_t /* reserved */ : 5;
+       uint32_t slopeShift:3;
+       uint32_t /* reserved */ : 1;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demosaic_bpc_cfg {
+       /* Demosaic BPC Config 0 */
+       uint32_t blueDiffThreshold:12;
+       uint32_t redDiffThreshold:12;
+       uint32_t /* reserved */ : 8;
+       /* Demosaic BPC Config 1 */
+       uint32_t greenDiffThreshold:12;
+       uint32_t /* reserved */ : 20;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_demosaic_abf_cfg {
+       /* Demosaic ABF Config 0 */
+       uint32_t lpThreshold:10;
+       uint32_t /* reserved */ : 22;
+       /* Demosaic ABF Config 1 */
+       uint32_t ratio:4;
+       uint32_t minValue:10;
+       uint32_t /* reserved */ : 2;
+       uint32_t maxValue:10;
+       uint32_t /* reserved */ : 6;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_color_correction_cfg {
+       /* Color Corr. Coefficient 0 Config */
+       uint32_t   c0:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 1 Config */
+       uint32_t   c1:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 2 Config */
+       uint32_t   c2:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 3 Config */
+       uint32_t   c3:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 4 Config */
+       uint32_t   c4:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 5 Config */
+       uint32_t   c5:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 6 Config */
+       uint32_t   c6:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 7 Config */
+       uint32_t   c7:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Coefficient 8 Config */
+       uint32_t   c8:12;
+       uint32_t   /* reserved */ : 20;
+       /* Color Corr. Offset 0 Config */
+       uint32_t   k0:11;
+       uint32_t   /* reserved */ : 21;
+       /* Color Corr. Offset 1 Config */
+       uint32_t   k1:11;
+       uint32_t   /* reserved */ : 21;
+       /* Color Corr. Offset 2 Config */
+       uint32_t   k2:11;
+       uint32_t   /* reserved */ : 21;
+       /* Color Corr. Coefficient Q Config */
+       uint32_t   coefQFactor:2;
+       uint32_t   /* reserved */ : 30;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_LumaAdaptation_ConfigCmdType {
+       /* LA Config */
+       uint32_t   lutBankSelect:1;
+       uint32_t   /* reserved */ : 31;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_wb_cfg {
+       /* WB Config */
+       uint32_t ch0Gain:9;
+       uint32_t ch1Gain:9;
+       uint32_t ch2Gain:9;
+       uint32_t /* reserved */ : 5;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_GammaLutSelect_ConfigCmdType {
+       /* LUT Bank Select Config */
+       uint32_t   ch0BankSelect:1;
+       uint32_t   ch1BankSelect:1;
+       uint32_t   ch2BankSelect:1;
+       uint32_t   /* reserved */ : 29;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_chroma_enhance_cfg {
+       /* Chroma Enhance A Config */
+       uint32_t ap:11;
+       uint32_t /* reserved */ : 5;
+       uint32_t am:11;
+       uint32_t /* reserved */ : 5;
+       /* Chroma Enhance B Config */
+       uint32_t bp:11;
+       uint32_t /* reserved */ : 5;
+       uint32_t bm:11;
+       uint32_t /* reserved */ : 5;
+       /* Chroma Enhance C Config */
+       uint32_t cp:11;
+       uint32_t /* reserved */ : 5;
+       uint32_t cm:11;
+       uint32_t /* reserved */ : 5;
+       /* Chroma Enhance D Config */
+       uint32_t dp:11;
+       uint32_t /* reserved */ : 5;
+       uint32_t dm:11;
+       uint32_t /* reserved */ : 5;
+       /* Chroma Enhance K Config */
+       uint32_t kcb:11;
+       uint32_t /* reserved */ : 5;
+       uint32_t kcr:11;
+       uint32_t /* reserved */ : 5;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_color_convert_cfg {
+       /* Conversion Coefficient 0 */
+       uint32_t v0:12;
+       uint32_t /* reserved */ : 20;
+       /* Conversion Coefficient 1 */
+       uint32_t v1:12;
+       uint32_t /* reserved */ : 20;
+       /* Conversion Coefficient 2 */
+       uint32_t v2:12;
+       uint32_t /* reserved */ : 20;
+       /* Conversion Offset */
+       uint32_t ConvertOffset:8;
+       uint32_t /* reserved */ : 24;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_SyncTimer_ConfigCmdType {
+       /* Timer Line Start Config */
+       uint32_t       timerLineStart:12;
+       uint32_t       /* reserved */ : 20;
+       /* Timer Pixel Start Config */
+       uint32_t       timerPixelStart:18;
+       uint32_t       /* reserved */ : 14;
+       /* Timer Pixel Duration Config */
+       uint32_t       timerPixelDuration:28;
+       uint32_t       /* reserved */ : 4;
+       /* Sync Timer Polarity Config */
+       uint32_t       timer0Polarity:1;
+       uint32_t       timer1Polarity:1;
+       uint32_t       timer2Polarity:1;
+       uint32_t       /* reserved */ : 29;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AsyncTimer_ConfigCmdType {
+       /* Async Timer Config 0 */
+       uint32_t     inactiveLength:20;
+       uint32_t     numRepetition:10;
+       uint32_t     /* reserved */ : 1;
+       uint32_t     polarity:1;
+       /* Async Timer Config 1 */
+       uint32_t     activeLength:20;
+       uint32_t     /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AWBAEStatistics_ConfigCmdType {
+       /* AWB autoexposure Config */
+       uint32_t    aeRegionConfig:1;
+       uint32_t    aeSubregionConfig:1;
+       uint32_t    /* reserved */ : 14;
+       uint32_t    awbYMin:8;
+       uint32_t    awbYMax:8;
+       /* AXW Header */
+       uint32_t    axwHeader:8;
+       uint32_t    /* reserved */ : 24;
+       /* AWB Mconfig */
+       uint32_t    m4:8;
+       uint32_t    m3:8;
+       uint32_t    m2:8;
+       uint32_t    m1:8;
+       /* AWB Cconfig */
+       uint32_t    c2:12;
+       uint32_t    /* reserved */ : 4;
+       uint32_t    c1:12;
+       uint32_t    /* reserved */ : 4;
+       /* AWB Cconfig 2 */
+       uint32_t    c4:12;
+       uint32_t    /* reserved */ : 4;
+       uint32_t    c3:12;
+       uint32_t    /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_TestGen_ConfigCmdType {
+       /* HW Test Gen Config */
+       uint32_t   numFrame:10;
+       uint32_t   /* reserved */ : 2;
+       uint32_t   pixelDataSelect:1;
+       uint32_t   systematicDataSelect:1;
+       uint32_t   /* reserved */ : 2;
+       uint32_t   pixelDataSize:2;
+       uint32_t   hsyncEdge:1;
+       uint32_t   vsyncEdge:1;
+       uint32_t   /* reserved */ : 12;
+       /* HW Test Gen Image Config */
+       uint32_t   imageWidth:14;
+       uint32_t   /* reserved */ : 2;
+       uint32_t   imageHeight:14;
+       uint32_t   /* reserved */ : 2;
+       /* SOF Offset Config */
+       uint32_t   sofOffset:24;
+       uint32_t   /* reserved */ : 8;
+       /* EOF NOffset Config */
+       uint32_t   eofNOffset:24;
+       uint32_t   /* reserved */ : 8;
+       /* SOL Offset Config */
+       uint32_t   solOffset:9;
+       uint32_t   /* reserved */ : 23;
+       /* EOL NOffset Config */
+       uint32_t   eolNOffset:9;
+       uint32_t   /* reserved */ : 23;
+       /* HBI Config */
+       uint32_t   hBlankInterval:14;
+       uint32_t   /* reserved */ : 18;
+       /* VBL Config */
+       uint32_t   vBlankInterval:14;
+       uint32_t   /* reserved */ : 2;
+       uint32_t   vBlankIntervalEnable:1;
+       uint32_t   /* reserved */ : 15;
+       /* SOF Dummy Line Config */
+       uint32_t   sofDummy:8;
+       uint32_t   /* reserved */ : 24;
+       /* EOF Dummy Line Config */
+       uint32_t   eofDummy:8;
+       uint32_t   /* reserved */ : 24;
+       /* Color Bars Config */
+       uint32_t   unicolorBarSelect:3;
+       uint32_t   /* reserved */ : 1;
+       uint32_t   unicolorBarEnable:1;
+       uint32_t   splitEnable:1;
+       uint32_t   pixelPattern:2;
+       uint32_t   rotatePeriod:6;
+       uint32_t   /* reserved */ : 18;
+       /* Random Config */
+       uint32_t   randomSeed:16;
+       uint32_t   /* reserved */ : 16;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_Bus_Pm_ConfigCmdType {
+       /* VFE Bus Performance Monitor Config */
+       uint32_t  output2YWrPmEnable:1;
+       uint32_t  output2CbcrWrPmEnable:1;
+       uint32_t  output1YWrPmEnable:1;
+       uint32_t  output1CbcrWrPmEnable:1;
+       uint32_t  /* reserved */ : 28;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_asf_info {
+       /* asf max edge  */
+       uint32_t maxEdge:13;
+       uint32_t /* reserved */ : 3;
+       /* HBi count  */
+       uint32_t HBICount:12;
+       uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_camif_stats {
+  uint32_t  pixelCount:14;
+  uint32_t  /* reserved */ : 2;
+  uint32_t  lineCount:14;
+  uint32_t  /* reserved */ : 1;
+  uint32_t  camifHalt:1;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_StatsCmdType {
+       uint32_t  autoFocusEnable:1;
+       uint32_t  axwEnable:1;
+       uint32_t  histEnable:1;
+       uint32_t  clearHistEnable:1;
+       uint32_t  histAutoClearEnable:1;
+       uint32_t  colorConversionEnable:1;
+       uint32_t  /* reserved */ : 26;
+} __attribute__((packed, aligned(4)));
+
+
+struct vfe_statsframe {
+       uint32_t lastPixel:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t lastLine:12;
+       uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_busstats_wrprio {
+       uint32_t afBusPriority:4;
+       uint32_t awbBusPriority:4;
+       uint32_t histBusPriority:4;
+       uint32_t afBusPriorityEn:1;
+       uint32_t awbBusPriorityEn:1;
+       uint32_t histBusPriorityEn:1;
+       uint32_t /* reserved */ : 17;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsaf_update {
+       /* VFE_STATS_AF_CFG */
+       uint32_t windowVOffset:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t windowHOffset:12;
+       uint32_t /* reserved */ : 3;
+       uint32_t windowMode:1;
+
+       /* VFE_STATS_AF_DIM */
+       uint32_t windowHeight:12;
+       uint32_t /* reserved */ : 4;
+       uint32_t windowWidth:12;
+       uint32_t /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsaf_cfg {
+       /* VFE_STATS_AF_GRID_0 */
+       uint32_t  entry00:8;
+       uint32_t  entry01:8;
+       uint32_t  entry02:8;
+       uint32_t  entry03:8;
+
+       /* VFE_STATS_AF_GRID_1 */
+       uint32_t  entry10:8;
+       uint32_t  entry11:8;
+       uint32_t  entry12:8;
+       uint32_t  entry13:8;
+
+       /* VFE_STATS_AF_GRID_2 */
+       uint32_t  entry20:8;
+       uint32_t  entry21:8;
+       uint32_t  entry22:8;
+       uint32_t  entry23:8;
+
+       /* VFE_STATS_AF_GRID_3 */
+       uint32_t  entry30:8;
+       uint32_t  entry31:8;
+       uint32_t  entry32:8;
+       uint32_t  entry33:8;
+
+       /* VFE_STATS_AF_HEADER */
+       uint32_t  afHeader:8;
+       uint32_t  /* reserved */ : 24;
+       /*  VFE_STATS_AF_COEF0 */
+       uint32_t  a00:5;
+       uint32_t  a04:5;
+       uint32_t  fvMax:11;
+       uint32_t  fvMetric:1;
+       uint32_t  /* reserved */ : 10;
+
+       /* VFE_STATS_AF_COEF1 */
+       uint32_t  a20:5;
+       uint32_t  a21:5;
+       uint32_t  a22:5;
+       uint32_t  a23:5;
+       uint32_t  a24:5;
+       uint32_t  /* reserved */ : 7;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsawbae_update {
+       uint32_t  aeRegionCfg:1;
+       uint32_t  aeSubregionCfg:1;
+       uint32_t  /* reserved */ : 14;
+       uint32_t  awbYMin:8;
+       uint32_t  awbYMax:8;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsaxw_hdr_cfg {
+       /* Stats AXW Header Config */
+       uint32_t axwHeader:8;
+       uint32_t /* reserved */ : 24;
+} __attribute__((packed, aligned(4)));
+
+struct vfe_statsawb_update {
+       /* AWB MConfig */
+       uint32_t  m4:8;
+       uint32_t  m3:8;
+       uint32_t  m2:8;
+       uint32_t  m1:8;
+
+       /* AWB CConfig1 */
+       uint32_t  c2:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  c1:12;
+       uint32_t  /* reserved */ : 4;
+
+       /* AWB CConfig2 */
+       uint32_t  c4:12;
+       uint32_t  /* reserved */ : 4;
+       uint32_t  c3:12;
+       uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_SyncTimerCmdType {
+       uint32_t  hsyncCount:12;
+       uint32_t  /* reserved */ : 20;
+       uint32_t  pclkCount:18;
+       uint32_t  /* reserved */ : 14;
+       uint32_t  outputDuration:28;
+       uint32_t  /* reserved */ : 4;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AsyncTimerCmdType {
+       /*  config 0 */
+       uint32_t    inactiveCount:20;
+       uint32_t    repeatCount:10;
+       uint32_t    /* reserved */ : 1;
+       uint32_t    polarity:1;
+       /*  config 1 */
+       uint32_t    activeCount:20;
+       uint32_t    /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AxiInputCmdType {
+       uint32_t   stripeStartAddr0:32;
+       uint32_t   stripeStartAddr1:32;
+       uint32_t   stripeStartAddr2:32;
+       uint32_t   stripeStartAddr3:32;
+
+       uint32_t   ySize:12;
+       uint32_t   yOffsetDelta:12;
+       uint32_t   /* reserved */ : 8;
+
+       /* bus_stripe_rd_hSize */
+       uint32_t   /* reserved */ : 16;
+       uint32_t   xSizeWord:10;
+       uint32_t   /* reserved */ : 6;
+
+       /* bus_stripe_rd_buffer_cfg */
+       uint32_t   burstLength:2;
+       uint32_t   /* reserved */ : 2;
+       uint32_t   NumOfRows:12;
+       uint32_t   RowIncrement:12;
+       uint32_t   /* reserved */ : 4;
+
+       /* bus_stripe_rd_unpack_cfg */
+       uint32_t   mainUnpackHeight:12;
+       uint32_t   mainUnpackWidth:13;
+       uint32_t   mainUnpackHbiSel:3;
+       uint32_t   mainUnpackPhase:3;
+       uint32_t   /* reserved */ : 1;
+
+       /* bus_stripe_rd_unpack */
+       uint32_t   unpackPattern:32;
+
+       /* bus_stripe_rd_pad_size */
+       uint32_t   padLeft:7;
+       uint32_t   /* reserved */ : 1;
+       uint32_t   padRight:7;
+       uint32_t   /* reserved */ : 1;
+       uint32_t   padTop:7;
+       uint32_t   /* reserved */ : 1;
+       uint32_t   padBottom:7;
+       uint32_t   /* reserved */ : 1;
+
+       /* bus_stripe_rd_pad_L_unpack */
+       uint32_t   leftUnpackPattern0:4;
+       uint32_t   leftUnpackPattern1:4;
+       uint32_t   leftUnpackPattern2:4;
+       uint32_t   leftUnpackPattern3:4;
+       uint32_t   leftUnpackStop0:1;
+       uint32_t   leftUnpackStop1:1;
+       uint32_t   leftUnpackStop2:1;
+       uint32_t   leftUnpackStop3:1;
+       uint32_t   /* reserved */ : 12;
+
+       /* bus_stripe_rd_pad_R_unpack */
+       uint32_t   rightUnpackPattern0:4;
+       uint32_t   rightUnpackPattern1:4;
+       uint32_t   rightUnpackPattern2:4;
+       uint32_t   rightUnpackPattern3:4;
+       uint32_t   rightUnpackStop0:1;
+       uint32_t   rightUnpackStop1:1;
+       uint32_t   rightUnpackStop2:1;
+       uint32_t   rightUnpackStop3:1;
+       uint32_t   /* reserved */ : 12;
+
+       /* bus_stripe_rd_pad_tb_unpack */
+       uint32_t   topUnapckPattern:4;
+       uint32_t   /* reserved */ : 12;
+       uint32_t   bottomUnapckPattern:4;
+       uint32_t   /* reserved */ : 12;
+} __attribute__((packed, aligned(4)));
+
+struct VFE_AxiRdFragIrqEnable {
+       uint32_t stripeRdFragirq0Enable:1;
+       uint32_t stripeRdFragirq1Enable:1;
+       uint32_t stripeRdFragirq2Enable:1;
+       uint32_t stripeRdFragirq3Enable:1;
+       uint32_t   /* reserved */ : 28;
+} __attribute__((packed, aligned(4)));
+
+int vfe_cmd_init(struct msm_vfe_callback *, struct platform_device *, void *);
+void vfe_stats_af_stop(void);
+void vfe_stop(void);
+void vfe_update(void);
+int vfe_rgb_gamma_update(struct vfe_cmd_rgb_gamma_config *);
+int vfe_rgb_gamma_config(struct vfe_cmd_rgb_gamma_config *);
+void vfe_stats_wb_exp_ack(struct vfe_cmd_stats_wb_exp_ack *);
+void vfe_stats_af_ack(struct vfe_cmd_stats_af_ack *);
+void vfe_start(struct vfe_cmd_start *);
+void vfe_la_update(struct vfe_cmd_la_config *);
+void vfe_la_config(struct vfe_cmd_la_config *);
+void vfe_test_gen_start(struct vfe_cmd_test_gen_start *);
+void vfe_frame_skip_update(struct vfe_cmd_frame_skip_update *);
+void vfe_frame_skip_config(struct vfe_cmd_frame_skip_config *);
+void vfe_output_clamp_config(struct vfe_cmd_output_clamp_config *);
+void vfe_camif_frame_update(struct vfe_cmds_camif_frame *);
+void vfe_color_correction_config(struct vfe_cmd_color_correction_config *);
+void vfe_demosaic_abf_update(struct vfe_cmd_demosaic_abf_update *);
+void vfe_demosaic_bpc_update(struct vfe_cmd_demosaic_bpc_update *);
+void vfe_demosaic_config(struct vfe_cmd_demosaic_config *);
+void vfe_demux_channel_gain_update(struct vfe_cmd_demux_channel_gain_config *);
+void vfe_demux_channel_gain_config(struct vfe_cmd_demux_channel_gain_config *);
+void vfe_black_level_update(struct vfe_cmd_black_level_config *);
+void vfe_black_level_config(struct vfe_cmd_black_level_config *);
+void vfe_asf_update(struct vfe_cmd_asf_update *);
+void vfe_asf_config(struct vfe_cmd_asf_config *);
+void vfe_white_balance_config(struct vfe_cmd_white_balance_config *);
+void vfe_chroma_sup_config(struct vfe_cmd_chroma_suppression_config *);
+void vfe_roll_off_config(struct vfe_cmd_roll_off_config *);
+void vfe_chroma_subsample_config(struct vfe_cmd_chroma_subsample_config *);
+void vfe_chroma_enhan_config(struct vfe_cmd_chroma_enhan_config *);
+void vfe_scaler2cbcr_config(struct vfe_cmd_scaler2_config *);
+void vfe_scaler2y_config(struct vfe_cmd_scaler2_config *);
+void vfe_main_scaler_config(struct vfe_cmd_main_scaler_config *);
+void vfe_stats_wb_exp_stop(void);
+void vfe_stats_update_wb_exp(struct vfe_cmd_stats_wb_exp_update *);
+void vfe_stats_update_af(struct vfe_cmd_stats_af_update *);
+void vfe_stats_start_wb_exp(struct vfe_cmd_stats_wb_exp_start *);
+void vfe_stats_start_af(struct vfe_cmd_stats_af_start *);
+void vfe_stats_setting(struct vfe_cmd_stats_setting *);
+void vfe_axi_input_config(struct vfe_cmd_axi_input_config *);
+void vfe_stats_config(struct vfe_cmd_stats_setting *);
+void vfe_axi_output_config(struct vfe_cmd_axi_output_config *);
+void vfe_camif_config(struct vfe_cmd_camif_config *);
+void vfe_fov_crop_config(struct vfe_cmd_fov_crop_config *);
+void vfe_get_hw_version(struct vfe_cmd_hw_version *);
+void vfe_reset(void);
+void vfe_cmd_release(struct platform_device *);
+void vfe_output1_ack(struct vfe_cmd_output_ack *);
+void vfe_output2_ack(struct vfe_cmd_output_ack *);
+#endif /* __MSM_VFE8X_REG_H__ */
diff --git a/drivers/staging/dream/camera/mt9d112.c b/drivers/staging/dream/camera/mt9d112.c
new file mode 100644 (file)
index 0000000..4f938f9
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include "mt9d112.h"
+
+/* Micron MT9D112 Registers and their values */
+/* Sensor Core Registers */
+#define  REG_MT9D112_MODEL_ID 0x3000
+#define  MT9D112_MODEL_ID     0x1580
+
+/*  SOC Registers Page 1  */
+#define  REG_MT9D112_SENSOR_RESET     0x301A
+#define  REG_MT9D112_STANDBY_CONTROL  0x3202
+#define  REG_MT9D112_MCU_BOOT         0x3386
+
+struct mt9d112_work {
+       struct work_struct work;
+};
+
+static struct  mt9d112_work *mt9d112_sensorw;
+static struct  i2c_client *mt9d112_client;
+
+struct mt9d112_ctrl {
+       const struct msm_camera_sensor_info *sensordata;
+};
+
+
+static struct mt9d112_ctrl *mt9d112_ctrl;
+
+static DECLARE_WAIT_QUEUE_HEAD(mt9d112_wait_queue);
+DECLARE_MUTEX(mt9d112_sem);
+
+
+/*=============================================================
+       EXTERNAL DECLARATIONS
+==============================================================*/
+extern struct mt9d112_reg mt9d112_regs;
+
+
+/*=============================================================*/
+
+static int mt9d112_reset(const struct msm_camera_sensor_info *dev)
+{
+       int rc = 0;
+
+       rc = gpio_request(dev->sensor_reset, "mt9d112");
+
+       if (!rc) {
+               rc = gpio_direction_output(dev->sensor_reset, 0);
+               mdelay(20);
+               rc = gpio_direction_output(dev->sensor_reset, 1);
+       }
+
+       gpio_free(dev->sensor_reset);
+       return rc;
+}
+
+static int32_t mt9d112_i2c_txdata(unsigned short saddr,
+       unsigned char *txdata, int length)
+{
+       struct i2c_msg msg[] = {
+               {
+                       .addr = saddr,
+                       .flags = 0,
+                       .len = length,
+                       .buf = txdata,
+               },
+       };
+
+       if (i2c_transfer(mt9d112_client->adapter, msg, 1) < 0) {
+               CDBG("mt9d112_i2c_txdata failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t mt9d112_i2c_write(unsigned short saddr,
+       unsigned short waddr, unsigned short wdata, enum mt9d112_width width)
+{
+       int32_t rc = -EIO;
+       unsigned char buf[4];
+
+       memset(buf, 0, sizeof(buf));
+       switch (width) {
+       case WORD_LEN: {
+               buf[0] = (waddr & 0xFF00)>>8;
+               buf[1] = (waddr & 0x00FF);
+               buf[2] = (wdata & 0xFF00)>>8;
+               buf[3] = (wdata & 0x00FF);
+
+               rc = mt9d112_i2c_txdata(saddr, buf, 4);
+       }
+               break;
+
+       case BYTE_LEN: {
+               buf[0] = waddr;
+               buf[1] = wdata;
+               rc = mt9d112_i2c_txdata(saddr, buf, 2);
+       }
+               break;
+
+       default:
+               break;
+       }
+
+       if (rc < 0)
+               CDBG(
+               "i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+               waddr, wdata);
+
+       return rc;
+}
+
+static int32_t mt9d112_i2c_write_table(
+       struct mt9d112_i2c_reg_conf const *reg_conf_tbl,
+       int num_of_items_in_table)
+{
+       int i;
+       int32_t rc = -EIO;
+
+       for (i = 0; i < num_of_items_in_table; i++) {
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       reg_conf_tbl->waddr, reg_conf_tbl->wdata,
+                       reg_conf_tbl->width);
+               if (rc < 0)
+                       break;
+               if (reg_conf_tbl->mdelay_time != 0)
+                       mdelay(reg_conf_tbl->mdelay_time);
+               reg_conf_tbl++;
+       }
+
+       return rc;
+}
+
+static int mt9d112_i2c_rxdata(unsigned short saddr,
+       unsigned char *rxdata, int length)
+{
+       struct i2c_msg msgs[] = {
+       {
+               .addr   = saddr,
+               .flags = 0,
+               .len   = 2,
+               .buf   = rxdata,
+       },
+       {
+               .addr   = saddr,
+               .flags = I2C_M_RD,
+               .len   = length,
+               .buf   = rxdata,
+       },
+       };
+
+       if (i2c_transfer(mt9d112_client->adapter, msgs, 2) < 0) {
+               CDBG("mt9d112_i2c_rxdata failed!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t mt9d112_i2c_read(unsigned short   saddr,
+       unsigned short raddr, unsigned short *rdata, enum mt9d112_width width)
+{
+       int32_t rc = 0;
+       unsigned char buf[4];
+
+       if (!rdata)
+               return -EIO;
+
+       memset(buf, 0, sizeof(buf));
+
+       switch (width) {
+       case WORD_LEN: {
+               buf[0] = (raddr & 0xFF00)>>8;
+               buf[1] = (raddr & 0x00FF);
+
+               rc = mt9d112_i2c_rxdata(saddr, buf, 2);
+               if (rc < 0)
+                       return rc;
+
+               *rdata = buf[0] << 8 | buf[1];
+       }
+               break;
+
+       default:
+               break;
+       }
+
+       if (rc < 0)
+               CDBG("mt9d112_i2c_read failed!\n");
+
+       return rc;
+}
+
+static int32_t mt9d112_set_lens_roll_off(void)
+{
+       int32_t rc = 0;
+       rc = mt9d112_i2c_write_table(&mt9d112_regs.rftbl[0],
+                                                                mt9d112_regs.rftbl_size);
+       return rc;
+}
+
+static long mt9d112_reg_init(void)
+{
+       int32_t array_length;
+       int32_t i;
+       long rc;
+
+       /* PLL Setup Start */
+       rc = mt9d112_i2c_write_table(&mt9d112_regs.plltbl[0],
+                                       mt9d112_regs.plltbl_size);
+
+       if (rc < 0)
+               return rc;
+       /* PLL Setup End   */
+
+       array_length = mt9d112_regs.prev_snap_reg_settings_size;
+
+       /* Configure sensor for Preview mode and Snapshot mode */
+       for (i = 0; i < array_length; i++) {
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                 mt9d112_regs.prev_snap_reg_settings[i].register_address,
+                 mt9d112_regs.prev_snap_reg_settings[i].register_value,
+                 WORD_LEN);
+
+               if (rc < 0)
+                       return rc;
+       }
+
+       /* Configure for Noise Reduction, Saturation and Aperture Correction */
+       array_length = mt9d112_regs.noise_reduction_reg_settings_size;
+
+       for (i = 0; i < array_length; i++) {
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       mt9d112_regs.noise_reduction_reg_settings[i].register_address,
+                       mt9d112_regs.noise_reduction_reg_settings[i].register_value,
+                       WORD_LEN);
+
+               if (rc < 0)
+                       return rc;
+       }
+
+       /* Set Color Kill Saturation point to optimum value */
+       rc =
+       mt9d112_i2c_write(mt9d112_client->addr,
+       0x35A4,
+       0x0593,
+       WORD_LEN);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9d112_i2c_write_table(&mt9d112_regs.stbl[0],
+                                       mt9d112_regs.stbl_size);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9d112_set_lens_roll_off();
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static long mt9d112_set_sensor_mode(int mode)
+{
+       uint16_t clock;
+       long rc = 0;
+
+       switch (mode) {
+       case SENSOR_PREVIEW_MODE:
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x338C, 0xA20C, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x3390, 0x0004, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x338C, 0xA215, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x3390, 0x0004, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x338C, 0xA20B, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x3390, 0x0000, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               clock = 0x0250;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x341C, clock, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x338C, 0xA103, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x3390, 0x0001, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+               break;
+
+       case SENSOR_SNAPSHOT_MODE:
+               /* Switch to lower fps for Snapshot */
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x341C, 0x0120, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x338C, 0xA120, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x3390, 0x0002, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x338C, 0xA103, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9d112_i2c_write(mt9d112_client->addr,
+                               0x3390, 0x0002, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static long mt9d112_set_effect(int mode, int effect)
+{
+       uint16_t reg_addr;
+       uint16_t reg_val;
+       long rc = 0;
+
+       switch (mode) {
+       case SENSOR_PREVIEW_MODE:
+               /* Context A Special Effects */
+               reg_addr = 0x2799;
+               break;
+
+       case SENSOR_SNAPSHOT_MODE:
+               /* Context B Special Effects */
+               reg_addr = 0x279B;
+               break;
+
+       default:
+               reg_addr = 0x2799;
+               break;
+       }
+
+       switch (effect) {
+       case CAMERA_EFFECT_OFF: {
+               reg_val = 0x6440;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x338C, reg_addr, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x3390, reg_val, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+       }
+                       break;
+
+       case CAMERA_EFFECT_MONO: {
+               reg_val = 0x6441;
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x338C, reg_addr, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x3390, reg_val, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+       }
+               break;
+
+       case CAMERA_EFFECT_NEGATIVE: {
+               reg_val = 0x6443;
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x338C, reg_addr, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x3390, reg_val, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+       }
+               break;
+
+       case CAMERA_EFFECT_SOLARIZE: {
+               reg_val = 0x6445;
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x338C, reg_addr, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x3390, reg_val, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+       }
+               break;
+
+       case CAMERA_EFFECT_SEPIA: {
+               reg_val = 0x6442;
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x338C, reg_addr, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x3390, reg_val, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+       }
+               break;
+
+       case CAMERA_EFFECT_PASTEL:
+       case CAMERA_EFFECT_MOSAIC:
+       case CAMERA_EFFECT_RESIZE:
+               return -EINVAL;
+
+       default: {
+               reg_val = 0x6440;
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x338C, reg_addr, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9d112_i2c_write(mt9d112_client->addr,
+                       0x3390, reg_val, WORD_LEN);
+               if (rc < 0)
+                       return rc;
+
+               return -EINVAL;
+       }
+       }
+
+       /* Refresh Sequencer */
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               0x338C, 0xA103, WORD_LEN);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               0x3390, 0x0005, WORD_LEN);
+
+       return rc;
+}
+
+static int mt9d112_sensor_init_probe(const struct msm_camera_sensor_info *data)
+{
+       uint16_t model_id = 0;
+       int rc = 0;
+
+       CDBG("init entry \n");
+       rc = mt9d112_reset(data);
+       if (rc < 0) {
+               CDBG("reset failed!\n");
+               goto init_probe_fail;
+       }
+
+       mdelay(5);
+
+       /* Micron suggested Power up block Start:
+       * Put MCU into Reset - Stop MCU */
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               REG_MT9D112_MCU_BOOT, 0x0501, WORD_LEN);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       /* Pull MCU from Reset - Start MCU */
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               REG_MT9D112_MCU_BOOT, 0x0500, WORD_LEN);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       mdelay(5);
+
+       /* Micron Suggested - Power up block */
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               REG_MT9D112_SENSOR_RESET, 0x0ACC, WORD_LEN);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               REG_MT9D112_STANDBY_CONTROL, 0x0008, WORD_LEN);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       /* FUSED_DEFECT_CORRECTION */
+       rc = mt9d112_i2c_write(mt9d112_client->addr,
+               0x33F4, 0x031D, WORD_LEN);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       mdelay(5);
+
+       /* Micron suggested Power up block End */
+       /* Read the Model ID of the sensor */
+       rc = mt9d112_i2c_read(mt9d112_client->addr,
+               REG_MT9D112_MODEL_ID, &model_id, WORD_LEN);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       CDBG("mt9d112 model_id = 0x%x\n", model_id);
+
+       /* Check if it matches it with the value in Datasheet */
+       if (model_id != MT9D112_MODEL_ID) {
+               rc = -EINVAL;
+               goto init_probe_fail;
+       }
+
+       rc = mt9d112_reg_init();
+       if (rc < 0)
+               goto init_probe_fail;
+
+       return rc;
+
+init_probe_fail:
+       return rc;
+}
+
+int mt9d112_sensor_init(const struct msm_camera_sensor_info *data)
+{
+       int rc = 0;
+
+       mt9d112_ctrl = kzalloc(sizeof(struct mt9d112_ctrl), GFP_KERNEL);
+       if (!mt9d112_ctrl) {
+               CDBG("mt9d112_init failed!\n");
+               rc = -ENOMEM;
+               goto init_done;
+       }
+
+       if (data)
+               mt9d112_ctrl->sensordata = data;
+
+       /* Input MCLK = 24MHz */
+       msm_camio_clk_rate_set(24000000);
+       mdelay(5);
+
+       msm_camio_camif_pad_reg_reset();
+
+       rc = mt9d112_sensor_init_probe(data);
+       if (rc < 0) {
+               CDBG("mt9d112_sensor_init failed!\n");
+               goto init_fail;
+       }
+
+init_done:
+       return rc;
+
+init_fail:
+       kfree(mt9d112_ctrl);
+       return rc;
+}
+
+static int mt9d112_init_client(struct i2c_client *client)
+{
+       /* Initialize the MSM_CAMI2C Chip */
+       init_waitqueue_head(&mt9d112_wait_queue);
+       return 0;
+}
+
+int mt9d112_sensor_config(void __user *argp)
+{
+       struct sensor_cfg_data cfg_data;
+       long   rc = 0;
+
+       if (copy_from_user(&cfg_data,
+                       (void *)argp,
+                       sizeof(struct sensor_cfg_data)))
+               return -EFAULT;
+
+       /* down(&mt9d112_sem); */
+
+       CDBG("mt9d112_ioctl, cfgtype = %d, mode = %d\n",
+               cfg_data.cfgtype, cfg_data.mode);
+
+               switch (cfg_data.cfgtype) {
+               case CFG_SET_MODE:
+                       rc = mt9d112_set_sensor_mode(
+                                               cfg_data.mode);
+                       break;
+
+               case CFG_SET_EFFECT:
+                       rc = mt9d112_set_effect(cfg_data.mode,
+                                               cfg_data.cfg.effect);
+                       break;
+
+               case CFG_GET_AF_MAX_STEPS:
+               default:
+                       rc = -EINVAL;
+                       break;
+               }
+
+       /* up(&mt9d112_sem); */
+
+       return rc;
+}
+
+int mt9d112_sensor_release(void)
+{
+       int rc = 0;
+
+       /* down(&mt9d112_sem); */
+
+       kfree(mt9d112_ctrl);
+       /* up(&mt9d112_sem); */
+
+       return rc;
+}
+
+static int mt9d112_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       int rc = 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               rc = -ENOTSUPP;
+               goto probe_failure;
+       }
+
+       mt9d112_sensorw =
+               kzalloc(sizeof(struct mt9d112_work), GFP_KERNEL);
+
+       if (!mt9d112_sensorw) {
+               rc = -ENOMEM;
+               goto probe_failure;
+       }
+
+       i2c_set_clientdata(client, mt9d112_sensorw);
+       mt9d112_init_client(client);
+       mt9d112_client = client;
+
+       CDBG("mt9d112_probe succeeded!\n");
+
+       return 0;
+
+probe_failure:
+       kfree(mt9d112_sensorw);
+       mt9d112_sensorw = NULL;
+       CDBG("mt9d112_probe failed!\n");
+       return rc;
+}
+
+static const struct i2c_device_id mt9d112_i2c_id[] = {
+       { "mt9d112", 0},
+       { },
+};
+
+static struct i2c_driver mt9d112_i2c_driver = {
+       .id_table = mt9d112_i2c_id,
+       .probe  = mt9d112_i2c_probe,
+       .remove = __exit_p(mt9d112_i2c_remove),
+       .driver = {
+               .name = "mt9d112",
+       },
+};
+
+static int mt9d112_sensor_probe(const struct msm_camera_sensor_info *info,
+                               struct msm_sensor_ctrl *s)
+{
+       int rc = i2c_add_driver(&mt9d112_i2c_driver);
+       if (rc < 0 || mt9d112_client == NULL) {
+               rc = -ENOTSUPP;
+               goto probe_done;
+       }
+
+       /* Input MCLK = 24MHz */
+       msm_camio_clk_rate_set(24000000);
+       mdelay(5);
+
+       rc = mt9d112_sensor_init_probe(info);
+       if (rc < 0)
+               goto probe_done;
+
+       s->s_init = mt9d112_sensor_init;
+       s->s_release = mt9d112_sensor_release;
+       s->s_config  = mt9d112_sensor_config;
+
+probe_done:
+       CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+       return rc;
+}
+
+static int __mt9d112_probe(struct platform_device *pdev)
+{
+       return msm_camera_drv_start(pdev, mt9d112_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+       .probe = __mt9d112_probe,
+       .driver = {
+               .name = "msm_camera_mt9d112",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mt9d112_init(void)
+{
+       return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9d112_init);
diff --git a/drivers/staging/dream/camera/mt9d112.h b/drivers/staging/dream/camera/mt9d112.h
new file mode 100644 (file)
index 0000000..c678996
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#ifndef MT9D112_H
+#define MT9D112_H
+
+#include <linux/types.h>
+#include <mach/camera.h>
+
+enum mt9d112_width {
+       WORD_LEN,
+       BYTE_LEN
+};
+
+struct mt9d112_i2c_reg_conf {
+       unsigned short waddr;
+       unsigned short wdata;
+       enum mt9d112_width width;
+       unsigned short mdelay_time;
+};
+
+struct mt9d112_reg {
+       const struct register_address_value_pair *prev_snap_reg_settings;
+       uint16_t prev_snap_reg_settings_size;
+       const struct register_address_value_pair *noise_reduction_reg_settings;
+       uint16_t noise_reduction_reg_settings_size;
+       const struct mt9d112_i2c_reg_conf *plltbl;
+       uint16_t plltbl_size;
+       const struct mt9d112_i2c_reg_conf *stbl;
+       uint16_t stbl_size;
+       const struct mt9d112_i2c_reg_conf *rftbl;
+       uint16_t rftbl_size;
+};
+
+#endif /* MT9D112_H */
diff --git a/drivers/staging/dream/camera/mt9d112_reg.c b/drivers/staging/dream/camera/mt9d112_reg.c
new file mode 100644 (file)
index 0000000..c52e96f
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include "mt9d112.h"
+
+struct register_address_value_pair
+preview_snapshot_mode_reg_settings_array[] = {
+       {0x338C, 0x2703},
+       {0x3390, 800},    /* Output Width (P) = 640 */
+       {0x338C, 0x2705},
+       {0x3390, 600},    /* Output Height (P) = 480 */
+       {0x338C, 0x2707},
+       {0x3390, 0x0640}, /* Output Width (S) = 1600 */
+       {0x338C, 0x2709},
+       {0x3390, 0x04B0}, /* Output Height (S) = 1200 */
+       {0x338C, 0x270D},
+       {0x3390, 0x0000}, /* Row Start (P) = 0 */
+       {0x338C, 0x270F},
+       {0x3390, 0x0000}, /* Column Start (P) = 0 */
+       {0x338C, 0x2711},
+       {0x3390, 0x04BD}, /* Row End (P) = 1213 */
+       {0x338C, 0x2713},
+       {0x3390, 0x064D}, /* Column End (P) = 1613 */
+       {0x338C, 0x2715},
+       {0x3390, 0x0000}, /* Extra Delay (P) = 0 */
+       {0x338C, 0x2717},
+       {0x3390, 0x2111}, /* Row Speed (P) = 8465 */
+       {0x338C, 0x2719},
+       {0x3390, 0x046C}, /* Read Mode (P) = 1132 */
+       {0x338C, 0x271B},
+       {0x3390, 0x024F}, /* Sensor_Sample_Time_pck(P) = 591 */
+       {0x338C, 0x271D},
+       {0x3390, 0x0102}, /* Sensor_Fine_Correction(P) = 258 */
+       {0x338C, 0x271F},
+       {0x3390, 0x0279}, /* Sensor_Fine_IT_min(P) = 633 */
+       {0x338C, 0x2721},
+       {0x3390, 0x0155}, /* Sensor_Fine_IT_max_margin(P) = 341 */
+       {0x338C, 0x2723},
+       {0x3390, 659},    /* Frame Lines (P) = 679 */
+       {0x338C, 0x2725},
+       {0x3390, 0x0824}, /* Line Length (P) = 2084 */
+       {0x338C, 0x2727},
+       {0x3390, 0x2020},
+       {0x338C, 0x2729},
+       {0x3390, 0x2020},
+       {0x338C, 0x272B},
+       {0x3390, 0x1020},
+       {0x338C, 0x272D},
+       {0x3390, 0x2007},
+       {0x338C, 0x272F},
+       {0x3390, 0x0004}, /* Row Start(S) = 4 */
+       {0x338C, 0x2731},
+       {0x3390, 0x0004}, /* Column Start(S) = 4 */
+       {0x338C, 0x2733},
+       {0x3390, 0x04BB}, /* Row End(S) = 1211 */
+       {0x338C, 0x2735},
+       {0x3390, 0x064B}, /* Column End(S) = 1611 */
+       {0x338C, 0x2737},
+       {0x3390, 0x04CE}, /* Extra Delay(S) = 1230 */
+       {0x338C, 0x2739},
+       {0x3390, 0x2111}, /* Row Speed(S) = 8465 */
+       {0x338C, 0x273B},
+       {0x3390, 0x0024}, /* Read Mode(S) = 36 */
+       {0x338C, 0x273D},
+       {0x3390, 0x0120}, /* Sensor sample time pck(S) = 288 */
+       {0x338C, 0x2741},
+       {0x3390, 0x0169}, /* Sensor_Fine_IT_min(P) = 361 */
+       {0x338C, 0x2745},
+       {0x3390, 0x04FF}, /* Frame Lines(S) = 1279 */
+       {0x338C, 0x2747},
+       {0x3390, 0x0824}, /* Line Length(S) = 2084 */
+       {0x338C, 0x2751},
+       {0x3390, 0x0000}, /* Crop_X0(P) = 0 */
+       {0x338C, 0x2753},
+       {0x3390, 0x0320}, /* Crop_X1(P) = 800 */
+       {0x338C, 0x2755},
+       {0x3390, 0x0000}, /* Crop_Y0(P) = 0 */
+       {0x338C, 0x2757},
+       {0x3390, 0x0258}, /* Crop_Y1(P) = 600 */
+       {0x338C, 0x275F},
+       {0x3390, 0x0000}, /* Crop_X0(S) = 0 */
+       {0x338C, 0x2761},
+       {0x3390, 0x0640}, /* Crop_X1(S) = 1600 */
+       {0x338C, 0x2763},
+       {0x3390, 0x0000}, /* Crop_Y0(S) = 0 */
+       {0x338C, 0x2765},
+       {0x3390, 0x04B0}, /* Crop_Y1(S) = 1200 */
+       {0x338C, 0x222E},
+       {0x3390, 0x00A0}, /* R9 Step = 160 */
+       {0x338C, 0xA408},
+       {0x3390, 0x001F},
+       {0x338C, 0xA409},
+       {0x3390, 0x0021},
+       {0x338C, 0xA40A},
+       {0x3390, 0x0025},
+       {0x338C, 0xA40B},
+       {0x3390, 0x0027},
+       {0x338C, 0x2411},
+       {0x3390, 0x00A0},
+       {0x338C, 0x2413},
+       {0x3390, 0x00C0},
+       {0x338C, 0x2415},
+       {0x3390, 0x00A0},
+       {0x338C, 0x2417},
+       {0x3390, 0x00C0},
+       {0x338C, 0x2799},
+       {0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(P) */
+       {0x338C, 0x279B},
+       {0x3390, 0x6408}, /* MODE_SPEC_EFFECTS(S) */
+};
+
+static struct register_address_value_pair
+noise_reduction_reg_settings_array[] = {
+       {0x338C, 0xA76D},
+       {0x3390, 0x0003},
+       {0x338C, 0xA76E},
+       {0x3390, 0x0003},
+       {0x338C, 0xA76F},
+       {0x3390, 0},
+       {0x338C, 0xA770},
+       {0x3390, 21},
+       {0x338C, 0xA771},
+       {0x3390, 37},
+       {0x338C, 0xA772},
+       {0x3390, 63},
+       {0x338C, 0xA773},
+       {0x3390, 100},
+       {0x338C, 0xA774},
+       {0x3390, 128},
+       {0x338C, 0xA775},
+       {0x3390, 151},
+       {0x338C, 0xA776},
+       {0x3390, 169},
+       {0x338C, 0xA777},
+       {0x3390, 186},
+       {0x338C, 0xA778},
+       {0x3390, 199},
+       {0x338C, 0xA779},
+       {0x3390, 210},
+       {0x338C, 0xA77A},
+       {0x3390, 220},
+       {0x338C, 0xA77B},
+       {0x3390, 228},
+       {0x338C, 0xA77C},
+       {0x3390, 234},
+       {0x338C, 0xA77D},
+       {0x3390, 240},
+       {0x338C, 0xA77E},
+       {0x3390, 244},
+       {0x338C, 0xA77F},
+       {0x3390, 248},
+       {0x338C, 0xA780},
+       {0x3390, 252},
+       {0x338C, 0xA781},
+       {0x3390, 255},
+       {0x338C, 0xA782},
+       {0x3390, 0},
+       {0x338C, 0xA783},
+       {0x3390, 21},
+       {0x338C, 0xA784},
+       {0x3390, 37},
+       {0x338C, 0xA785},
+       {0x3390, 63},
+       {0x338C, 0xA786},
+       {0x3390, 100},
+       {0x338C, 0xA787},
+       {0x3390, 128},
+       {0x338C, 0xA788},
+       {0x3390, 151},
+       {0x338C, 0xA789},
+       {0x3390, 169},
+       {0x338C, 0xA78A},
+       {0x3390, 186},
+       {0x338C, 0xA78B},
+       {0x3390, 199},
+       {0x338C, 0xA78C},
+       {0x3390, 210},
+       {0x338C, 0xA78D},
+       {0x3390, 220},
+       {0x338C, 0xA78E},
+       {0x3390, 228},
+       {0x338C, 0xA78F},
+       {0x3390, 234},
+       {0x338C, 0xA790},
+       {0x3390, 240},
+       {0x338C, 0xA791},
+       {0x3390, 244},
+       {0x338C, 0xA793},
+       {0x3390, 252},
+       {0x338C, 0xA794},
+       {0x3390, 255},
+       {0x338C, 0xA103},
+       {0x3390, 6},
+};
+
+static const struct mt9d112_i2c_reg_conf const lens_roll_off_tbl[] = {
+       { 0x34CE, 0x81A0, WORD_LEN, 0 },
+       { 0x34D0, 0x6331, WORD_LEN, 0 },
+       { 0x34D2, 0x3394, WORD_LEN, 0 },
+       { 0x34D4, 0x9966, WORD_LEN, 0 },
+       { 0x34D6, 0x4B25, WORD_LEN, 0 },
+       { 0x34D8, 0x2670, WORD_LEN, 0 },
+       { 0x34DA, 0x724C, WORD_LEN, 0 },
+       { 0x34DC, 0xFFFD, WORD_LEN, 0 },
+       { 0x34DE, 0x00CA, WORD_LEN, 0 },
+       { 0x34E6, 0x00AC, WORD_LEN, 0 },
+       { 0x34EE, 0x0EE1, WORD_LEN, 0 },
+       { 0x34F6, 0x0D87, WORD_LEN, 0 },
+       { 0x3500, 0xE1F7, WORD_LEN, 0 },
+       { 0x3508, 0x1CF4, WORD_LEN, 0 },
+       { 0x3510, 0x1D28, WORD_LEN, 0 },
+       { 0x3518, 0x1F26, WORD_LEN, 0 },
+       { 0x3520, 0x2220, WORD_LEN, 0 },
+       { 0x3528, 0x333D, WORD_LEN, 0 },
+       { 0x3530, 0x15D9, WORD_LEN, 0 },
+       { 0x3538, 0xCFB8, WORD_LEN, 0 },
+       { 0x354C, 0x05FE, WORD_LEN, 0 },
+       { 0x3544, 0x05F8, WORD_LEN, 0 },
+       { 0x355C, 0x0596, WORD_LEN, 0 },
+       { 0x3554, 0x0611, WORD_LEN, 0 },
+       { 0x34E0, 0x00F2, WORD_LEN, 0 },
+       { 0x34E8, 0x00A8, WORD_LEN, 0 },
+       { 0x34F0, 0x0F7B, WORD_LEN, 0 },
+       { 0x34F8, 0x0CD7, WORD_LEN, 0 },
+       { 0x3502, 0xFEDB, WORD_LEN, 0 },
+       { 0x350A, 0x13E4, WORD_LEN, 0 },
+       { 0x3512, 0x1F2C, WORD_LEN, 0 },
+       { 0x351A, 0x1D20, WORD_LEN, 0 },
+       { 0x3522, 0x2422, WORD_LEN, 0 },
+       { 0x352A, 0x2925, WORD_LEN, 0 },
+       { 0x3532, 0x1D04, WORD_LEN, 0 },
+       { 0x353A, 0xFBF2, WORD_LEN, 0 },
+       { 0x354E, 0x0616, WORD_LEN, 0 },
+       { 0x3546, 0x0597, WORD_LEN, 0 },
+       { 0x355E, 0x05CD, WORD_LEN, 0 },
+       { 0x3556, 0x0529, WORD_LEN, 0 },
+       { 0x34E4, 0x00B2, WORD_LEN, 0 },
+       { 0x34EC, 0x005E, WORD_LEN, 0 },
+       { 0x34F4, 0x0F43, WORD_LEN, 0 },
+       { 0x34FC, 0x0E2F, WORD_LEN, 0 },
+       { 0x3506, 0xF9FC, WORD_LEN, 0 },
+       { 0x350E, 0x0CE4, WORD_LEN, 0 },
+       { 0x3516, 0x1E1E, WORD_LEN, 0 },
+       { 0x351E, 0x1B19, WORD_LEN, 0 },
+       { 0x3526, 0x151B, WORD_LEN, 0 },
+       { 0x352E, 0x1416, WORD_LEN, 0 },
+       { 0x3536, 0x10FC, WORD_LEN, 0 },
+       { 0x353E, 0xC018, WORD_LEN, 0 },
+       { 0x3552, 0x06B4, WORD_LEN, 0 },
+       { 0x354A, 0x0506, WORD_LEN, 0 },
+       { 0x3562, 0x06AB, WORD_LEN, 0 },
+       { 0x355A, 0x063A, WORD_LEN, 0 },
+       { 0x34E2, 0x00E5, WORD_LEN, 0 },
+       { 0x34EA, 0x008B, WORD_LEN, 0 },
+       { 0x34F2, 0x0E4C, WORD_LEN, 0 },
+       { 0x34FA, 0x0CA3, WORD_LEN, 0 },
+       { 0x3504, 0x0907, WORD_LEN, 0 },
+       { 0x350C, 0x1DFD, WORD_LEN, 0 },
+       { 0x3514, 0x1E24, WORD_LEN, 0 },
+       { 0x351C, 0x2529, WORD_LEN, 0 },
+       { 0x3524, 0x1D20, WORD_LEN, 0 },
+       { 0x352C, 0x2332, WORD_LEN, 0 },
+       { 0x3534, 0x10E9, WORD_LEN, 0 },
+       { 0x353C, 0x0BCB, WORD_LEN, 0 },
+       { 0x3550, 0x04EF, WORD_LEN, 0 },
+       { 0x3548, 0x0609, WORD_LEN, 0 },
+       { 0x3560, 0x0580, WORD_LEN, 0 },
+       { 0x3558, 0x05DD, WORD_LEN, 0 },
+       { 0x3540, 0x0000, WORD_LEN, 0 },
+       { 0x3542, 0x0000, WORD_LEN, 0 }
+};
+
+static const struct mt9d112_i2c_reg_conf const pll_setup_tbl[] = {
+       { 0x341E, 0x8F09, WORD_LEN, 0 },
+       { 0x341C, 0x0250, WORD_LEN, 0 },
+       { 0x341E, 0x8F09, WORD_LEN, 5 },
+       { 0x341E, 0x8F08, WORD_LEN, 0 }
+};
+
+/* Refresh Sequencer */
+static const struct mt9d112_i2c_reg_conf const sequencer_tbl[] = {
+       { 0x338C, 0x2799, WORD_LEN, 0},
+       { 0x3390, 0x6440, WORD_LEN, 5},
+       { 0x338C, 0x279B, WORD_LEN, 0},
+       { 0x3390, 0x6440, WORD_LEN, 5},
+       { 0x338C, 0xA103, WORD_LEN, 0},
+       { 0x3390, 0x0005, WORD_LEN, 5},
+       { 0x338C, 0xA103, WORD_LEN, 0},
+       { 0x3390, 0x0006, WORD_LEN, 5}
+};
+
+struct mt9d112_reg mt9d112_regs = {
+       .prev_snap_reg_settings = &preview_snapshot_mode_reg_settings_array[0],
+       .prev_snap_reg_settings_size = ARRAY_SIZE(preview_snapshot_mode_reg_settings_array),
+       .noise_reduction_reg_settings = &noise_reduction_reg_settings_array[0],
+       .noise_reduction_reg_settings_size = ARRAY_SIZE(noise_reduction_reg_settings_array),
+       .plltbl = pll_setup_tbl,
+       .plltbl_size = ARRAY_SIZE(pll_setup_tbl),
+       .stbl = sequencer_tbl,
+       .stbl_size = ARRAY_SIZE(sequencer_tbl),
+       .rftbl = lens_roll_off_tbl,
+       .rftbl_size = ARRAY_SIZE(lens_roll_off_tbl)
+};
+
+
+
diff --git a/drivers/staging/dream/camera/mt9p012.h b/drivers/staging/dream/camera/mt9p012.h
new file mode 100644 (file)
index 0000000..678a002
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+
+#ifndef MT9T012_H
+#define MT9T012_H
+
+#include <linux/types.h>
+
+struct reg_struct {
+       uint16_t vt_pix_clk_div;     /* 0x0300 */
+       uint16_t vt_sys_clk_div;     /* 0x0302 */
+       uint16_t pre_pll_clk_div;    /* 0x0304 */
+       uint16_t pll_multiplier;     /* 0x0306 */
+       uint16_t op_pix_clk_div;     /* 0x0308 */
+       uint16_t op_sys_clk_div;     /* 0x030A */
+       uint16_t scale_m;            /* 0x0404 */
+       uint16_t row_speed;          /* 0x3016 */
+       uint16_t x_addr_start;       /* 0x3004 */
+       uint16_t x_addr_end;         /* 0x3008 */
+       uint16_t y_addr_start;       /* 0x3002 */
+       uint16_t y_addr_end;         /* 0x3006 */
+       uint16_t read_mode;          /* 0x3040 */
+       uint16_t x_output_size ;     /* 0x034C */
+       uint16_t y_output_size;      /* 0x034E */
+       uint16_t line_length_pck;    /* 0x300C */
+       uint16_t frame_length_lines; /* 0x300A */
+       uint16_t coarse_int_time;    /* 0x3012 */
+       uint16_t fine_int_time;      /* 0x3014 */
+};
+
+
+struct mt9p012_i2c_reg_conf {
+       unsigned short waddr;
+       unsigned short wdata;
+};
+
+
+struct mt9p012_reg {
+       struct reg_struct *reg_pat;
+       uint16_t reg_pat_size;
+       struct mt9p012_i2c_reg_conf *ttbl;
+       uint16_t ttbl_size;
+       struct mt9p012_i2c_reg_conf *lctbl;
+       uint16_t lctbl_size;
+       struct mt9p012_i2c_reg_conf *rftbl;
+       uint16_t rftbl_size;
+};
+
+#endif /* MT9T012_H */
diff --git a/drivers/staging/dream/camera/mt9p012_fox.c b/drivers/staging/dream/camera/mt9p012_fox.c
new file mode 100644 (file)
index 0000000..70119d5
--- /dev/null
@@ -0,0 +1,1305 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "mt9p012.h"
+
+/*=============================================================
+    SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9P012_REG_MODEL_ID         0x0000
+#define MT9P012_MODEL_ID             0x2801
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INTEGRATION_TIME    0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9P012_REG_RESET_REGISTER   0x301A
+#define MT9P012_RESET_REGISTER_PWON  0x10CC
+#define MT9P012_RESET_REGISTER_PWOFF 0x10C8
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+#define MT9P012_REV_7
+
+
+enum mt9p012_test_mode {
+       TEST_OFF,
+       TEST_1,
+       TEST_2,
+       TEST_3
+};
+
+enum mt9p012_resolution {
+       QTR_SIZE,
+       FULL_SIZE,
+       INVALID_SIZE
+};
+
+enum mt9p012_reg_update {
+       /* Sensor egisters that need to be updated during initialization */
+       REG_INIT,
+       /* Sensor egisters that needs periodic I2C writes */
+       UPDATE_PERIODIC,
+       /* All the sensor Registers will be updated */
+       UPDATE_ALL,
+       /* Not valid update */
+       UPDATE_INVALID
+};
+
+enum mt9p012_setting {
+       RES_PREVIEW,
+       RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9P012_AF_I2C_ADDR   0x18
+
+/* AF Total steps parameters */
+#define MT9P012_STEPS_NEAR_TO_CLOSEST_INF  32
+#define MT9P012_TOTAL_STEPS_NEAR_TO_FAR    32
+
+#define MT9P012_MU5M0_PREVIEW_DUMMY_PIXELS 0
+#define MT9P012_MU5M0_PREVIEW_DUMMY_LINES  0
+
+/* Time in milisecs for waiting for the sensor to reset.*/
+#define MT9P012_RESET_DELAY_MSECS   66
+
+/* for 20 fps preview */
+#define MT9P012_DEFAULT_CLOCK_RATE  24000000
+#define MT9P012_DEFAULT_MAX_FPS     26 /* ???? */
+
+struct mt9p012_work {
+       struct work_struct work;
+};
+static struct mt9p012_work *mt9p012_sensorw;
+static struct i2c_client *mt9p012_client;
+
+struct mt9p012_ctrl {
+       const struct msm_camera_sensor_info *sensordata;
+
+       int sensormode;
+       uint32_t fps_divider; /* init to 1 * 0x00000400 */
+       uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */
+
+       uint16_t curr_lens_pos;
+       uint16_t init_curr_lens_pos;
+       uint16_t my_reg_gain;
+       uint32_t my_reg_line_count;
+
+       enum mt9p012_resolution prev_res;
+       enum mt9p012_resolution pict_res;
+       enum mt9p012_resolution curr_res;
+       enum mt9p012_test_mode  set_test;
+};
+
+
+static struct mt9p012_ctrl *mt9p012_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9p012_wait_queue);
+DECLARE_MUTEX(mt9p012_sem);
+
+/*=============================================================
+       EXTERNAL DECLARATIONS
+==============================================================*/
+extern struct mt9p012_reg mt9p012_regs;        /* from mt9p012_reg.c */
+
+
+
+/*=============================================================*/
+
+static int mt9p012_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+       int length)
+{
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = saddr,
+                       .flags = 0,
+                       .len   = 2,
+                       .buf   = rxdata,
+               },
+               {
+                       .addr   = saddr,
+                       .flags = I2C_M_RD,
+                       .len   = length,
+                       .buf   = rxdata,
+               },
+       };
+
+       if (i2c_transfer(mt9p012_client->adapter, msgs, 2) < 0) {
+               CDBG("mt9p012_i2c_rxdata failed!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t mt9p012_i2c_read_w(unsigned short saddr, unsigned short raddr,
+       unsigned short *rdata)
+{
+       int32_t rc = 0;
+       unsigned char buf[4];
+
+       if (!rdata)
+               return -EIO;
+
+       memset(buf, 0, sizeof(buf));
+
+       buf[0] = (raddr & 0xFF00)>>8;
+       buf[1] = (raddr & 0x00FF);
+
+       rc = mt9p012_i2c_rxdata(saddr, buf, 2);
+       if (rc < 0)
+               return rc;
+
+       *rdata = buf[0] << 8 | buf[1];
+
+       if (rc < 0)
+               CDBG("mt9p012_i2c_read failed!\n");
+
+       return rc;
+}
+
+static int32_t mt9p012_i2c_txdata(unsigned short saddr, unsigned char *txdata,
+       int length)
+{
+       struct i2c_msg msg[] = {
+               {
+               .addr  = saddr,
+               .flags = 0,
+               .len = length,
+               .buf = txdata,
+               },
+       };
+
+       if (i2c_transfer(mt9p012_client->adapter, msg, 1) < 0) {
+               CDBG("mt9p012_i2c_txdata failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t mt9p012_i2c_write_b(unsigned short saddr, unsigned short baddr,
+       unsigned short bdata)
+{
+       int32_t rc = -EIO;
+       unsigned char buf[2];
+
+       memset(buf, 0, sizeof(buf));
+       buf[0] = baddr;
+       buf[1] = bdata;
+       rc = mt9p012_i2c_txdata(saddr, buf, 2);
+
+       if (rc < 0)
+               CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!\n",
+               saddr, baddr, bdata);
+
+       return rc;
+}
+
+static int32_t mt9p012_i2c_write_w(unsigned short saddr, unsigned short waddr,
+       unsigned short wdata)
+{
+       int32_t rc = -EIO;
+       unsigned char buf[4];
+
+       memset(buf, 0, sizeof(buf));
+       buf[0] = (waddr & 0xFF00)>>8;
+       buf[1] = (waddr & 0x00FF);
+       buf[2] = (wdata & 0xFF00)>>8;
+       buf[3] = (wdata & 0x00FF);
+
+       rc = mt9p012_i2c_txdata(saddr, buf, 4);
+
+       if (rc < 0)
+               CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+                       waddr, wdata);
+
+       return rc;
+}
+
+static int32_t mt9p012_i2c_write_w_table(
+       struct mt9p012_i2c_reg_conf *reg_conf_tbl, int num)
+{
+       int i;
+       int32_t rc = -EIO;
+
+       for (i = 0; i < num; i++) {
+               rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+                       reg_conf_tbl->waddr, reg_conf_tbl->wdata);
+               if (rc < 0)
+                       break;
+               reg_conf_tbl++;
+       }
+
+       return rc;
+}
+
+static int32_t mt9p012_test(enum mt9p012_test_mode mo)
+{
+       int32_t rc = 0;
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               REG_GROUPED_PARAMETER_HOLD,
+               GROUPED_PARAMETER_HOLD);
+       if (rc < 0)
+               return rc;
+
+       if (mo == TEST_OFF)
+               return 0;
+       else {
+               rc = mt9p012_i2c_write_w_table(mt9p012_regs.ttbl, mt9p012_regs.ttbl_size);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+                               REG_TEST_PATTERN_MODE, (uint16_t)mo);
+               if (rc < 0)
+                       return rc;
+       }
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               REG_GROUPED_PARAMETER_HOLD,
+               GROUPED_PARAMETER_UPDATE);
+       if (rc < 0)
+               return rc;
+
+       return rc;
+}
+
+static int32_t mt9p012_lens_shading_enable(uint8_t is_enable)
+{
+       int32_t rc = 0;
+
+       CDBG("%s: entered. enable = %d\n", __func__, is_enable);
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x3780,
+               ((uint16_t) is_enable) << 15);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE);
+
+       CDBG("%s: exiting. rc = %d\n", __func__, rc);
+       return rc;
+}
+
+static int32_t mt9p012_set_lc(void)
+{
+       int32_t rc;
+
+       rc = mt9p012_i2c_write_w_table(mt9p012_regs.lctbl, mt9p012_regs.lctbl_size);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9p012_i2c_write_w_table(mt9p012_regs.rftbl, mt9p012_regs.rftbl_size);
+
+       return rc;
+}
+
+static void mt9p012_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+       /* input fps is preview fps in Q8 format */
+       uint32_t divider;   /*Q10 */
+       uint32_t pclk_mult; /*Q10 */
+
+       if (mt9p012_ctrl->prev_res == QTR_SIZE) {
+               divider = (uint32_t)
+               (((mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+               mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck) * 0x00000400) /
+               (mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines *
+               mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck));
+
+               pclk_mult =
+               (uint32_t) ((mt9p012_regs.reg_pat[RES_CAPTURE].pll_multiplier *
+               0x00000400) / (mt9p012_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+       } else {
+               /* full size resolution used for preview. */
+               divider   = 0x00000400;  /*1.0 */
+               pclk_mult = 0x00000400;  /*1.0 */
+       }
+
+       /* Verify PCLK settings and frame sizes. */
+       *pfps = (uint16_t) (fps * divider * pclk_mult / 0x00000400 /
+               0x00000400);
+}
+
+static uint16_t mt9p012_get_prev_lines_pf(void)
+{
+       if (mt9p012_ctrl->prev_res == QTR_SIZE)
+               return mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+       else
+               return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_prev_pixels_pl(void)
+{
+       if (mt9p012_ctrl->prev_res == QTR_SIZE)
+               return mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck;
+       else
+               return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9p012_get_pict_lines_pf(void)
+{
+       return mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9p012_get_pict_pixels_pl(void)
+{
+       return mt9p012_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9p012_get_pict_max_exp_lc(void)
+{
+       uint16_t snapshot_lines_per_frame;
+
+       if (mt9p012_ctrl->pict_res == QTR_SIZE)
+               snapshot_lines_per_frame =
+               mt9p012_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+       else
+               snapshot_lines_per_frame =
+               mt9p012_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+
+       return snapshot_lines_per_frame * 24;
+}
+
+static int32_t mt9p012_set_fps(struct fps_cfg *fps)
+{
+       /* input is new fps in Q10 format */
+       int32_t rc = 0;
+
+       mt9p012_ctrl->fps_divider = fps->fps_div;
+       mt9p012_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_HOLD);
+       if (rc < 0)
+               return -EBUSY;
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_LINE_LENGTH_PCK,
+                       (mt9p012_regs.reg_pat[RES_PREVIEW].line_length_pck *
+                       fps->f_mult / 0x00000400));
+       if (rc < 0)
+               return rc;
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_UPDATE);
+
+       return rc;
+}
+
+static int32_t mt9p012_write_exp_gain(uint16_t gain, uint32_t line)
+{
+       uint16_t max_legal_gain = 0x01FF;
+       uint32_t line_length_ratio = 0x00000400;
+       enum mt9p012_setting setting;
+       int32_t rc = 0;
+
+       CDBG("Line:%d mt9p012_write_exp_gain \n", __LINE__);
+
+       if (mt9p012_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+               mt9p012_ctrl->my_reg_gain = gain;
+               mt9p012_ctrl->my_reg_line_count = (uint16_t)line;
+       }
+
+       if (gain > max_legal_gain) {
+               CDBG("Max legal gain Line:%d \n", __LINE__);
+               gain = max_legal_gain;
+       }
+
+       /* Verify no overflow */
+       if (mt9p012_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+               line = (uint32_t)(line * mt9p012_ctrl->fps_divider /
+                       0x00000400);
+               setting = RES_PREVIEW;
+       } else {
+               line = (uint32_t)(line * mt9p012_ctrl->pict_fps_divider /
+                       0x00000400);
+               setting = RES_CAPTURE;
+       }
+
+       /* Set digital gain to 1 */
+#ifdef MT9P012_REV_7
+       gain |= 0x1000;
+#else
+       gain |= 0x0200;
+#endif
+
+       if ((mt9p012_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+               line_length_ratio = (uint32_t) (line * 0x00000400) /
+               (mt9p012_regs.reg_pat[setting].frame_length_lines - 1);
+       } else
+               line_length_ratio = 0x00000400;
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_HOLD);
+       if (rc < 0) {
+               CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+               return rc;
+       }
+
+       rc =
+               mt9p012_i2c_write_w(
+                       mt9p012_client->addr,
+                       REG_GLOBAL_GAIN, gain);
+       if (rc < 0) {
+               CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+               return rc;
+       }
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_COARSE_INT_TIME,
+                       line);
+       if (rc < 0) {
+               CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+               return rc;
+       }
+
+       CDBG("mt9p012_write_exp_gain: gain = %d, line = %d\n", gain, line);
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_UPDATE);
+       if (rc < 0)
+               CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+
+       return rc;
+}
+
+static int32_t mt9p012_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+       int32_t rc = 0;
+
+       CDBG("Line:%d mt9p012_set_pict_exp_gain \n", __LINE__);
+
+       rc =
+               mt9p012_write_exp_gain(gain, line);
+       if (rc < 0) {
+               CDBG("Line:%d mt9p012_set_pict_exp_gain failed... \n",
+                       __LINE__);
+               return rc;
+       }
+
+       rc =
+       mt9p012_i2c_write_w(mt9p012_client->addr,
+               MT9P012_REG_RESET_REGISTER,
+               0x10CC | 0x0002);
+       if (rc < 0) {
+               CDBG("mt9p012_i2c_write_w failed... Line:%d \n", __LINE__);
+               return rc;
+       }
+
+       mdelay(5);
+
+       /* camera_timed_wait(snapshot_wait*exposure_ratio); */
+       return rc;
+}
+
+static int32_t mt9p012_setting(enum mt9p012_reg_update rupdate,
+       enum mt9p012_setting rt)
+{
+       int32_t rc = 0;
+
+       switch (rupdate) {
+       case UPDATE_PERIODIC:
+       if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+
+               struct mt9p012_i2c_reg_conf ppc_tbl[] = {
+               {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD},
+               {REG_ROW_SPEED, mt9p012_regs.reg_pat[rt].row_speed},
+               {REG_X_ADDR_START, mt9p012_regs.reg_pat[rt].x_addr_start},
+               {REG_X_ADDR_END, mt9p012_regs.reg_pat[rt].x_addr_end},
+               {REG_Y_ADDR_START, mt9p012_regs.reg_pat[rt].y_addr_start},
+               {REG_Y_ADDR_END, mt9p012_regs.reg_pat[rt].y_addr_end},
+               {REG_READ_MODE, mt9p012_regs.reg_pat[rt].read_mode},
+               {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+               {REG_X_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].x_output_size},
+               {REG_Y_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].y_output_size},
+
+               {REG_LINE_LENGTH_PCK, mt9p012_regs.reg_pat[rt].line_length_pck},
+               {REG_FRAME_LENGTH_LINES,
+                       (mt9p012_regs.reg_pat[rt].frame_length_lines *
+                       mt9p012_ctrl->fps_divider / 0x00000400)},
+               {REG_COARSE_INT_TIME, mt9p012_regs.reg_pat[rt].coarse_int_time},
+               {REG_FINE_INTEGRATION_TIME, mt9p012_regs.reg_pat[rt].fine_int_time},
+               {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE},
+               };
+
+               rc = mt9p012_i2c_write_w_table(&ppc_tbl[0],
+                       ARRAY_SIZE(ppc_tbl));
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9p012_test(mt9p012_ctrl->set_test);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9p012_i2c_write_w(mt9p012_client->addr,
+                       MT9P012_REG_RESET_REGISTER,
+                       MT9P012_RESET_REGISTER_PWON | 0x0002);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5); /* 15? wait for sensor to transition*/
+
+               return rc;
+       }
+       break; /* UPDATE_PERIODIC */
+
+       case REG_INIT:
+       if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+               struct mt9p012_i2c_reg_conf ipc_tbl1[] = {
+               {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWOFF},
+               {REG_VT_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+               {REG_VT_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+               {REG_PRE_PLL_CLK_DIV, mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+               {REG_PLL_MULTIPLIER, mt9p012_regs.reg_pat[rt].pll_multiplier},
+               {REG_OP_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+               {REG_OP_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+               {0x30B0, 0x0001},
+               {0x308E, 0xE060},
+               {0x3092, 0x0A52},
+               {0x3094, 0x4656},
+               {0x3096, 0x5652},
+               {0x30CA, 0x8006},
+               {0x312A, 0xDD02},
+               {0x312C, 0x00E4},
+               {0x3170, 0x299A},
+#endif
+               /* optimized settings for noise */
+               {0x3088, 0x6FF6},
+               {0x3154, 0x0282},
+               {0x3156, 0x0381},
+               {0x3162, 0x04CE},
+               {0x0204, 0x0010},
+               {0x0206, 0x0010},
+               {0x0208, 0x0010},
+               {0x020A, 0x0010},
+               {0x020C, 0x0010},
+               {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWON},
+               };
+
+               struct mt9p012_i2c_reg_conf ipc_tbl2[] = {
+               {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWOFF},
+               {REG_VT_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_pix_clk_div},
+               {REG_VT_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].vt_sys_clk_div},
+               {REG_PRE_PLL_CLK_DIV, mt9p012_regs.reg_pat[rt].pre_pll_clk_div},
+               {REG_PLL_MULTIPLIER, mt9p012_regs.reg_pat[rt].pll_multiplier},
+               {REG_OP_PIX_CLK_DIV, mt9p012_regs.reg_pat[rt].op_pix_clk_div},
+               {REG_OP_SYS_CLK_DIV, mt9p012_regs.reg_pat[rt].op_sys_clk_div},
+#ifdef MT9P012_REV_7
+               {0x30B0, 0x0001},
+               {0x308E, 0xE060},
+               {0x3092, 0x0A52},
+               {0x3094, 0x4656},
+               {0x3096, 0x5652},
+               {0x30CA, 0x8006},
+               {0x312A, 0xDD02},
+               {0x312C, 0x00E4},
+               {0x3170, 0x299A},
+#endif
+               /* optimized settings for noise */
+               {0x3088, 0x6FF6},
+               {0x3154, 0x0282},
+               {0x3156, 0x0381},
+               {0x3162, 0x04CE},
+               {0x0204, 0x0010},
+               {0x0206, 0x0010},
+               {0x0208, 0x0010},
+               {0x020A, 0x0010},
+               {0x020C, 0x0010},
+               {MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWON},
+               };
+
+               struct mt9p012_i2c_reg_conf ipc_tbl3[] = {
+               {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD},
+               /* Set preview or snapshot mode */
+               {REG_ROW_SPEED, mt9p012_regs.reg_pat[rt].row_speed},
+               {REG_X_ADDR_START, mt9p012_regs.reg_pat[rt].x_addr_start},
+               {REG_X_ADDR_END, mt9p012_regs.reg_pat[rt].x_addr_end},
+               {REG_Y_ADDR_START, mt9p012_regs.reg_pat[rt].y_addr_start},
+               {REG_Y_ADDR_END, mt9p012_regs.reg_pat[rt].y_addr_end},
+               {REG_READ_MODE, mt9p012_regs.reg_pat[rt].read_mode},
+               {REG_SCALE_M, mt9p012_regs.reg_pat[rt].scale_m},
+               {REG_X_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].x_output_size},
+               {REG_Y_OUTPUT_SIZE, mt9p012_regs.reg_pat[rt].y_output_size},
+               {REG_LINE_LENGTH_PCK, mt9p012_regs.reg_pat[rt].line_length_pck},
+               {REG_FRAME_LENGTH_LINES,
+                       mt9p012_regs.reg_pat[rt].frame_length_lines},
+               {REG_COARSE_INT_TIME, mt9p012_regs.reg_pat[rt].coarse_int_time},
+               {REG_FINE_INTEGRATION_TIME, mt9p012_regs.reg_pat[rt].fine_int_time},
+               {REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE},
+               };
+
+               /* reset fps_divider */
+               mt9p012_ctrl->fps_divider = 1 * 0x0400;
+
+               rc = mt9p012_i2c_write_w_table(&ipc_tbl1[0],
+                       ARRAY_SIZE(ipc_tbl1));
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9p012_i2c_write_w_table(&ipc_tbl2[0],
+                       ARRAY_SIZE(ipc_tbl2));
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               rc = mt9p012_i2c_write_w_table(&ipc_tbl3[0],
+                       ARRAY_SIZE(ipc_tbl3));
+               if (rc < 0)
+                       return rc;
+
+               /* load lens shading */
+               rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_HOLD);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9p012_set_lc();
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD, GROUPED_PARAMETER_UPDATE);
+
+               if (rc < 0)
+                       return rc;
+       }
+       break; /* case REG_INIT: */
+
+       default:
+               rc = -EINVAL;
+               break;
+       } /* switch (rupdate) */
+
+       return rc;
+}
+
+static int32_t mt9p012_video_config(int mode, int res)
+{
+       int32_t rc;
+
+       switch (res) {
+       case QTR_SIZE:
+               rc = mt9p012_setting(UPDATE_PERIODIC, RES_PREVIEW);
+               if (rc < 0)
+                       return rc;
+
+               CDBG("mt9p012 sensor configuration done!\n");
+               break;
+
+       case FULL_SIZE:
+               rc =
+               mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+               if (rc < 0)
+                       return rc;
+
+               break;
+
+       default:
+               return 0;
+       } /* switch */
+
+       mt9p012_ctrl->prev_res = res;
+       mt9p012_ctrl->curr_res = res;
+       mt9p012_ctrl->sensormode = mode;
+
+       rc =
+               mt9p012_write_exp_gain(mt9p012_ctrl->my_reg_gain,
+                       mt9p012_ctrl->my_reg_line_count);
+
+       rc =
+               mt9p012_i2c_write_w(mt9p012_client->addr,
+                       MT9P012_REG_RESET_REGISTER,
+                       0x10cc|0x0002);
+
+       return rc;
+}
+
+static int32_t mt9p012_snapshot_config(int mode)
+{
+       int32_t rc = 0;
+
+       rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+       if (rc < 0)
+               return rc;
+
+       mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+       mt9p012_ctrl->sensormode = mode;
+
+       return rc;
+}
+
+static int32_t mt9p012_raw_snapshot_config(int mode)
+{
+       int32_t rc = 0;
+
+       rc = mt9p012_setting(UPDATE_PERIODIC, RES_CAPTURE);
+       if (rc < 0)
+               return rc;
+
+       mt9p012_ctrl->curr_res = mt9p012_ctrl->pict_res;
+
+       mt9p012_ctrl->sensormode = mode;
+
+       return rc;
+}
+
+static int32_t mt9p012_power_down(void)
+{
+       int32_t rc = 0;
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               MT9P012_REG_RESET_REGISTER,
+               MT9P012_RESET_REGISTER_PWOFF);
+
+       mdelay(5);
+       return rc;
+}
+
+static int32_t mt9p012_move_focus(int direction, int32_t num_steps)
+{
+       int16_t step_direction;
+       int16_t actual_step;
+       int16_t next_position;
+       uint8_t code_val_msb, code_val_lsb;
+
+       if (num_steps > MT9P012_TOTAL_STEPS_NEAR_TO_FAR)
+               num_steps = MT9P012_TOTAL_STEPS_NEAR_TO_FAR;
+       else if (num_steps == 0) {
+               CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+               return -EINVAL;
+       }
+
+       if (direction == MOVE_NEAR)
+               step_direction = 16; /* 10bit */
+       else if (direction == MOVE_FAR)
+               step_direction = -16; /* 10 bit */
+       else {
+               CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+               return -EINVAL;
+       }
+
+       if (mt9p012_ctrl->curr_lens_pos < mt9p012_ctrl->init_curr_lens_pos)
+               mt9p012_ctrl->curr_lens_pos =
+                       mt9p012_ctrl->init_curr_lens_pos;
+
+       actual_step = (int16_t)(step_direction * (int16_t)num_steps);
+       next_position = (int16_t)(mt9p012_ctrl->curr_lens_pos + actual_step);
+
+       if (next_position > 1023)
+               next_position = 1023;
+       else if (next_position < 0)
+               next_position = 0;
+
+       code_val_msb = next_position >> 4;
+       code_val_lsb = (next_position & 0x000F) << 4;
+       /* code_val_lsb |= mode_mask; */
+
+       /* Writing the digital code for current to the actuator */
+       if (mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1,
+               code_val_msb, code_val_lsb) < 0) {
+               CDBG("mt9p012_move_focus failed at line %d ...\n", __LINE__);
+               return -EBUSY;
+       }
+
+       /* Storing the current lens Position */
+       mt9p012_ctrl->curr_lens_pos = next_position;
+
+       return 0;
+}
+
+static int32_t mt9p012_set_default_focus(void)
+{
+       int32_t rc = 0;
+       uint8_t code_val_msb, code_val_lsb;
+
+       code_val_msb = 0x00;
+       code_val_lsb = 0x00;
+
+       /* Write the digital code for current to the actuator */
+       rc = mt9p012_i2c_write_b(MT9P012_AF_I2C_ADDR >> 1,
+               code_val_msb, code_val_lsb);
+
+       mt9p012_ctrl->curr_lens_pos = 0;
+       mt9p012_ctrl->init_curr_lens_pos = 0;
+
+       return rc;
+}
+
+static int mt9p012_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+       gpio_direction_output(data->sensor_reset, 0);
+       gpio_free(data->sensor_reset);
+       return 0;
+}
+
+static int mt9p012_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+       int32_t  rc;
+       uint16_t chipid;
+
+       rc = gpio_request(data->sensor_reset, "mt9p012");
+       if (!rc)
+               gpio_direction_output(data->sensor_reset, 1);
+       else
+               goto init_probe_done;
+
+       mdelay(20);
+
+       /* RESET the sensor image part via I2C command */
+       CDBG("mt9p012_sensor_init(): reseting sensor.\n");
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               MT9P012_REG_RESET_REGISTER, 0x10CC|0x0001);
+       if (rc < 0) {
+               CDBG("sensor reset failed. rc = %d\n", rc);
+               goto init_probe_fail;
+       }
+
+       mdelay(MT9P012_RESET_DELAY_MSECS);
+
+       /* 3. Read sensor Model ID: */
+       rc = mt9p012_i2c_read_w(mt9p012_client->addr,
+               MT9P012_REG_MODEL_ID, &chipid);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       /* 4. Compare sensor ID to MT9T012VC ID: */
+       if (chipid != MT9P012_MODEL_ID) {
+               CDBG("mt9p012 wrong model_id = 0x%x\n", chipid);
+               rc = -ENODEV;
+               goto init_probe_fail;
+       }
+
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x306E, 0x9000);
+       if (rc < 0) {
+               CDBG("REV_7 write failed. rc = %d\n", rc);
+               goto init_probe_fail;
+       }
+
+       /* RESET_REGISTER, enable parallel interface and disable serialiser */
+       CDBG("mt9p012_sensor_init(): enabling parallel interface.\n");
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr, 0x301A, 0x10CC);
+       if (rc < 0) {
+               CDBG("enable parallel interface failed. rc = %d\n", rc);
+               goto init_probe_fail;
+       }
+
+       /* To disable the 2 extra lines */
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               0x3064, 0x0805);
+
+       if (rc < 0) {
+               CDBG("disable the 2 extra lines failed. rc = %d\n", rc);
+               goto init_probe_fail;
+       }
+
+       mdelay(MT9P012_RESET_DELAY_MSECS);
+       goto init_probe_done;
+
+init_probe_fail:
+       mt9p012_probe_init_done(data);
+init_probe_done:
+       return rc;
+}
+
+static int mt9p012_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+       int32_t  rc;
+
+       mt9p012_ctrl = kzalloc(sizeof(struct mt9p012_ctrl), GFP_KERNEL);
+       if (!mt9p012_ctrl) {
+               CDBG("mt9p012_init failed!\n");
+               rc = -ENOMEM;
+               goto init_done;
+       }
+
+       mt9p012_ctrl->fps_divider = 1 * 0x00000400;
+       mt9p012_ctrl->pict_fps_divider = 1 * 0x00000400;
+       mt9p012_ctrl->set_test = TEST_OFF;
+       mt9p012_ctrl->prev_res = QTR_SIZE;
+       mt9p012_ctrl->pict_res = FULL_SIZE;
+
+       if (data)
+               mt9p012_ctrl->sensordata = data;
+
+       /* enable mclk first */
+       msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE);
+       mdelay(20);
+
+       msm_camio_camif_pad_reg_reset();
+       mdelay(20);
+
+       rc = mt9p012_probe_init_sensor(data);
+       if (rc < 0)
+               goto init_fail1;
+
+       if (mt9p012_ctrl->prev_res == QTR_SIZE)
+               rc = mt9p012_setting(REG_INIT, RES_PREVIEW);
+       else
+               rc = mt9p012_setting(REG_INIT, RES_CAPTURE);
+
+       if (rc < 0) {
+               CDBG("mt9p012_setting failed. rc = %d\n", rc);
+               goto init_fail1;
+       }
+
+       /* sensor : output enable */
+       CDBG("mt9p012_sensor_open_init(): enabling output.\n");
+       rc = mt9p012_i2c_write_w(mt9p012_client->addr,
+               MT9P012_REG_RESET_REGISTER, MT9P012_RESET_REGISTER_PWON);
+       if (rc < 0) {
+               CDBG("sensor output enable failed. rc = %d\n", rc);
+               goto init_fail1;
+       }
+
+       /* TODO: enable AF actuator */
+#if 0
+       CDBG("enable AF actuator, gpio = %d\n",
+               mt9p012_ctrl->sensordata->vcm_pwd);
+       rc = gpio_request(mt9p012_ctrl->sensordata->vcm_pwd, "mt9p012");
+       if (!rc)
+               gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 1);
+       else {
+               CDBG("mt9p012_ctrl gpio request failed!\n");
+               goto init_fail1;
+       }
+       mdelay(20);
+
+       rc = mt9p012_set_default_focus();
+#endif
+       if (rc >= 0)
+               goto init_done;
+
+       /* TODO:
+        * gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0);
+        * gpio_free(mt9p012_ctrl->sensordata->vcm_pwd); */
+init_fail1:
+       mt9p012_probe_init_done(data);
+       kfree(mt9p012_ctrl);
+init_done:
+       return rc;
+}
+
+static int mt9p012_init_client(struct i2c_client *client)
+{
+       /* Initialize the MSM_CAMI2C Chip */
+       init_waitqueue_head(&mt9p012_wait_queue);
+       return 0;
+}
+
+static int32_t mt9p012_set_sensor_mode(int mode, int res)
+{
+       int32_t rc = 0;
+
+       switch (mode) {
+       case SENSOR_PREVIEW_MODE:
+               rc = mt9p012_video_config(mode, res);
+               break;
+
+       case SENSOR_SNAPSHOT_MODE:
+               rc = mt9p012_snapshot_config(mode);
+               break;
+
+       case SENSOR_RAW_SNAPSHOT_MODE:
+               rc = mt9p012_raw_snapshot_config(mode);
+               break;
+
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
+
+int mt9p012_sensor_config(void __user *argp)
+{
+       struct sensor_cfg_data cdata;
+       int rc = 0;
+
+       if (copy_from_user(&cdata,
+                       (void *)argp,
+                       sizeof(struct sensor_cfg_data)))
+               return -EFAULT;
+
+       down(&mt9p012_sem);
+
+               CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+       switch (cdata.cfgtype) {
+       case CFG_GET_PICT_FPS:
+               mt9p012_get_pict_fps(cdata.cfg.gfps.prevfps,
+                               &(cdata.cfg.gfps.pictfps));
+
+               if (copy_to_user((void *)argp, &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PREV_L_PF:
+               cdata.cfg.prevl_pf = mt9p012_get_prev_lines_pf();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PREV_P_PL:
+               cdata.cfg.prevp_pl = mt9p012_get_prev_pixels_pl();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_L_PF:
+               cdata.cfg.pictl_pf = mt9p012_get_pict_lines_pf();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_P_PL:
+               cdata.cfg.pictp_pl = mt9p012_get_pict_pixels_pl();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_MAX_EXP_LC:
+               cdata.cfg.pict_max_exp_lc =
+                       mt9p012_get_pict_max_exp_lc();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_SET_FPS:
+       case CFG_SET_PICT_FPS:
+               rc = mt9p012_set_fps(&(cdata.cfg.fps));
+               break;
+
+       case CFG_SET_EXP_GAIN:
+               rc = mt9p012_write_exp_gain(cdata.cfg.exp_gain.gain,
+                               cdata.cfg.exp_gain.line);
+               break;
+
+       case CFG_SET_PICT_EXP_GAIN:
+               CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+               rc = mt9p012_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+                               cdata.cfg.exp_gain.line);
+               break;
+
+       case CFG_SET_MODE:
+               rc = mt9p012_set_sensor_mode(cdata.mode, cdata.rs);
+               break;
+
+       case CFG_PWR_DOWN:
+               rc = mt9p012_power_down();
+               break;
+
+       case CFG_MOVE_FOCUS:
+               CDBG("mt9p012_ioctl: CFG_MOVE_FOCUS: cdata.cfg.focus.dir=%d cdata.cfg.focus.steps=%d\n",
+                               cdata.cfg.focus.dir, cdata.cfg.focus.steps);
+               rc = mt9p012_move_focus(cdata.cfg.focus.dir,
+                                       cdata.cfg.focus.steps);
+               break;
+
+       case CFG_SET_DEFAULT_FOCUS:
+               rc = mt9p012_set_default_focus();
+               break;
+
+       case CFG_SET_LENS_SHADING:
+               CDBG("%s: CFG_SET_LENS_SHADING\n", __func__);
+               rc = mt9p012_lens_shading_enable(cdata.cfg.lens_shading);
+               break;
+
+       case CFG_GET_AF_MAX_STEPS:
+               cdata.max_steps = MT9P012_STEPS_NEAR_TO_CLOSEST_INF;
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_SET_EFFECT:
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       up(&mt9p012_sem);
+       return rc;
+}
+
+int mt9p012_sensor_release(void)
+{
+       int rc = -EBADF;
+
+       down(&mt9p012_sem);
+
+       mt9p012_power_down();
+
+       gpio_direction_output(mt9p012_ctrl->sensordata->sensor_reset,
+               0);
+       gpio_free(mt9p012_ctrl->sensordata->sensor_reset);
+
+       gpio_direction_output(mt9p012_ctrl->sensordata->vcm_pwd, 0);
+       gpio_free(mt9p012_ctrl->sensordata->vcm_pwd);
+
+       kfree(mt9p012_ctrl);
+       mt9p012_ctrl = NULL;
+
+       CDBG("mt9p012_release completed\n");
+
+       up(&mt9p012_sem);
+       return rc;
+}
+
+static int mt9p012_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       int rc = 0;
+       CDBG("mt9p012_probe called!\n");
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               CDBG("i2c_check_functionality failed\n");
+               goto probe_failure;
+       }
+
+       mt9p012_sensorw = kzalloc(sizeof(struct mt9p012_work), GFP_KERNEL);
+       if (!mt9p012_sensorw) {
+               CDBG("kzalloc failed.\n");
+               rc = -ENOMEM;
+               goto probe_failure;
+       }
+
+       i2c_set_clientdata(client, mt9p012_sensorw);
+       mt9p012_init_client(client);
+       mt9p012_client = client;
+
+       mdelay(50);
+
+       CDBG("mt9p012_probe successed! rc = %d\n", rc);
+       return 0;
+
+probe_failure:
+       CDBG("mt9p012_probe failed! rc = %d\n", rc);
+       return rc;
+}
+
+static const struct i2c_device_id mt9p012_i2c_id[] = {
+       { "mt9p012", 0},
+       { }
+};
+
+static struct i2c_driver mt9p012_i2c_driver = {
+       .id_table = mt9p012_i2c_id,
+       .probe  = mt9p012_i2c_probe,
+       .remove = __exit_p(mt9p012_i2c_remove),
+       .driver = {
+               .name = "mt9p012",
+       },
+};
+
+static int mt9p012_sensor_probe(const struct msm_camera_sensor_info *info,
+                               struct msm_sensor_ctrl *s)
+{
+       int rc = i2c_add_driver(&mt9p012_i2c_driver);
+       if (rc < 0 || mt9p012_client == NULL) {
+               rc = -ENOTSUPP;
+               goto probe_done;
+       }
+
+       msm_camio_clk_rate_set(MT9P012_DEFAULT_CLOCK_RATE);
+       mdelay(20);
+
+       rc = mt9p012_probe_init_sensor(info);
+       if (rc < 0)
+               goto probe_done;
+
+       s->s_init = mt9p012_sensor_open_init;
+       s->s_release = mt9p012_sensor_release;
+       s->s_config  = mt9p012_sensor_config;
+       mt9p012_probe_init_done(info);
+
+probe_done:
+       CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
+       return rc;
+}
+
+static int __mt9p012_probe(struct platform_device *pdev)
+{
+       return msm_camera_drv_start(pdev, mt9p012_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+       .probe = __mt9p012_probe,
+       .driver = {
+               .name = "msm_camera_mt9p012",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mt9p012_init(void)
+{
+       return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9p012_init);
diff --git a/drivers/staging/dream/camera/mt9p012_reg.c b/drivers/staging/dream/camera/mt9p012_reg.c
new file mode 100644 (file)
index 0000000..e5223d6
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2009 QUALCOMM Incorporated.
+ */
+
+#include "mt9p012.h"
+#include <linux/kernel.h>
+
+/*Micron settings from Applications for lower power consumption.*/
+struct reg_struct mt9p012_reg_pat[2] = {
+       { /* Preview */
+               /* vt_pix_clk_div          REG=0x0300 */
+               6,  /* 5 */
+
+               /* vt_sys_clk_div          REG=0x0302 */
+               1,
+
+               /* pre_pll_clk_div         REG=0x0304 */
+               2,
+
+               /* pll_multiplier          REG=0x0306 */
+               60,
+
+               /* op_pix_clk_div          REG=0x0308 */
+               8,  /* 10 */
+
+               /* op_sys_clk_div          REG=0x030A */
+               1,
+
+               /* scale_m                 REG=0x0404 */
+               16,
+
+               /* row_speed               REG=0x3016 */
+               0x0111,
+
+               /* x_addr_start            REG=0x3004 */
+               8,
+
+               /* x_addr_end              REG=0x3008 */
+               2597,
+
+               /* y_addr_start            REG=0x3002 */
+               8,
+
+               /* y_addr_end              REG=0x3006 */
+               1949,
+
+               /* read_mode               REG=0x3040
+                * Preview 2x2 skipping */
+               0x00C3,
+
+               /* x_output_size           REG=0x034C */
+               1296,
+
+               /* y_output_size           REG=0x034E */
+               972,
+
+               /* line_length_pck         REG=0x300C */
+               3784,
+
+               /* frame_length_lines      REG=0x300A */
+               1057,
+
+               /* coarse_integration_time REG=0x3012 */
+               16,
+
+               /* fine_integration_time   REG=0x3014 */
+               1764
+       },
+       { /*Snapshot*/
+               /* vt_pix_clk_div          REG=0x0300 */
+               6,
+
+               /* vt_sys_clk_div          REG=0x0302 */
+               1,
+
+               /* pre_pll_clk_div         REG=0x0304 */
+               2,
+
+               /* pll_multiplier          REG=0x0306
+                * 60 for 10fps snapshot */
+               60,
+
+               /* op_pix_clk_div          REG=0x0308 */
+               8,
+
+               /* op_sys_clk_div          REG=0x030A */
+               1,
+
+               /* scale_m                 REG=0x0404 */
+               16,
+
+               /* row_speed               REG=0x3016 */
+               0x0111,
+
+               /* x_addr_start            REG=0x3004 */
+               8,
+
+               /* x_addr_end              REG=0x3008 */
+               2615,
+
+               /* y_addr_start            REG=0x3002 */
+               8,
+
+               /* y_addr_end              REG=0x3006 */
+               1967,
+
+               /* read_mode               REG=0x3040 */
+               0x0041,
+
+               /* x_output_size           REG=0x034C */
+               2608,
+
+               /* y_output_size           REG=0x034E */
+               1960,
+
+               /* line_length_pck         REG=0x300C */
+               3911,
+
+               /* frame_length_lines      REG=0x300A //10 fps snapshot */
+               2045,
+
+               /* coarse_integration_time REG=0x3012 */
+               16,
+
+               /* fine_integration_time   REG=0x3014 */
+               882
+       }
+};
+
+
+struct mt9p012_i2c_reg_conf mt9p012_test_tbl[] = {
+       {0x3044, 0x0544 & 0xFBFF},
+       {0x30CA, 0x0004 | 0x0001},
+       {0x30D4, 0x9020 & 0x7FFF},
+       {0x31E0, 0x0003 & 0xFFFE},
+       {0x3180, 0x91FF & 0x7FFF},
+       {0x301A, (0x10CC | 0x8000) & 0xFFF7},
+       {0x301E, 0x0000},
+       {0x3780, 0x0000},
+};
+
+
+struct mt9p012_i2c_reg_conf mt9p012_lc_tbl[] = {
+       /* [Lens shading 85 Percent TL84] */
+       /* P_RD_P0Q0 */
+       {0x360A, 0x7FEF},
+       /* P_RD_P0Q1 */
+       {0x360C, 0x232C},
+       /* P_RD_P0Q2 */
+       {0x360E, 0x7050},
+       /* P_RD_P0Q3 */
+       {0x3610, 0xF3CC},
+       /* P_RD_P0Q4 */
+       {0x3612, 0x89D1},
+       /* P_RD_P1Q0 */
+       {0x364A, 0xBE0D},
+       /* P_RD_P1Q1 */
+       {0x364C, 0x9ACB},
+       /* P_RD_P1Q2 */
+       {0x364E, 0x2150},
+       /* P_RD_P1Q3 */
+       {0x3650, 0xB26B},
+       /* P_RD_P1Q4 */
+       {0x3652, 0x9511},
+       /* P_RD_P2Q0 */
+       {0x368A, 0x2151},
+       /* P_RD_P2Q1 */
+       {0x368C, 0x00AD},
+       /* P_RD_P2Q2 */
+       {0x368E, 0x8334},
+       /* P_RD_P2Q3 */
+       {0x3690, 0x478E},
+       /* P_RD_P2Q4 */
+       {0x3692, 0x0515},
+       /* P_RD_P3Q0 */
+       {0x36CA, 0x0710},
+       /* P_RD_P3Q1 */
+       {0x36CC, 0x452D},
+       /* P_RD_P3Q2 */
+       {0x36CE, 0xF352},
+       /* P_RD_P3Q3 */
+       {0x36D0, 0x190F},
+       /* P_RD_P3Q4 */
+       {0x36D2, 0x4413},
+       /* P_RD_P4Q0 */
+       {0x370A, 0xD112},
+       /* P_RD_P4Q1 */
+       {0x370C, 0xF50F},
+       /* P_RD_P4Q2 */
+       {0x370C, 0xF50F},
+       /* P_RD_P4Q3 */
+       {0x3710, 0xDC11},
+       /* P_RD_P4Q4 */
+       {0x3712, 0xD776},
+       /* P_GR_P0Q0 */
+       {0x3600, 0x1750},
+       /* P_GR_P0Q1 */
+       {0x3602, 0xF0AC},
+       /* P_GR_P0Q2 */
+       {0x3604, 0x4711},
+       /* P_GR_P0Q3 */
+       {0x3606, 0x07CE},
+       /* P_GR_P0Q4 */
+       {0x3608, 0x96B2},
+       /* P_GR_P1Q0 */
+       {0x3640, 0xA9AE},
+       /* P_GR_P1Q1 */
+       {0x3642, 0xF9AC},
+       /* P_GR_P1Q2 */
+       {0x3644, 0x39F1},
+       /* P_GR_P1Q3 */
+       {0x3646, 0x016F},
+       /* P_GR_P1Q4 */
+       {0x3648, 0x8AB2},
+       /* P_GR_P2Q0 */
+       {0x3680, 0x1752},
+       /* P_GR_P2Q1 */
+       {0x3682, 0x70F0},
+       /* P_GR_P2Q2 */
+       {0x3684, 0x83F5},
+       /* P_GR_P2Q3 */
+       {0x3686, 0x8392},
+       /* P_GR_P2Q4 */
+       {0x3688, 0x1FD6},
+       /* P_GR_P3Q0 */
+       {0x36C0, 0x1131},
+       /* P_GR_P3Q1 */
+       {0x36C2, 0x3DAF},
+       /* P_GR_P3Q2 */
+       {0x36C4, 0x89B4},
+       /* P_GR_P3Q3 */
+       {0x36C6, 0xA391},
+       /* P_GR_P3Q4 */
+       {0x36C8, 0x1334},
+       /* P_GR_P4Q0 */
+       {0x3700, 0xDC13},
+       /* P_GR_P4Q1 */
+       {0x3702, 0xD052},
+       /* P_GR_P4Q2 */
+       {0x3704, 0x5156},
+       /* P_GR_P4Q3 */
+       {0x3706, 0x1F13},
+       /* P_GR_P4Q4 */
+       {0x3708, 0x8C38},
+       /* P_BL_P0Q0 */
+       {0x3614, 0x0050},
+       /* P_BL_P0Q1 */
+       {0x3616, 0xBD4C},
+       /* P_BL_P0Q2 */
+       {0x3618, 0x41B0},
+       /* P_BL_P0Q3 */
+       {0x361A, 0x660D},
+       /* P_BL_P0Q4 */
+       {0x361C, 0xC590},
+       /* P_BL_P1Q0 */
+       {0x3654, 0x87EC},
+       /* P_BL_P1Q1 */
+       {0x3656, 0xE44C},
+       /* P_BL_P1Q2 */
+       {0x3658, 0x302E},
+       /* P_BL_P1Q3 */
+       {0x365A, 0x106E},
+       /* P_BL_P1Q4 */
+       {0x365C, 0xB58E},
+       /* P_BL_P2Q0 */
+       {0x3694, 0x0DD1},
+       /* P_BL_P2Q1 */
+       {0x3696, 0x2A50},
+       /* P_BL_P2Q2 */
+       {0x3698, 0xC793},
+       /* P_BL_P2Q3 */
+       {0x369A, 0xE8F1},
+       /* P_BL_P2Q4 */
+       {0x369C, 0x4174},
+       /* P_BL_P3Q0 */
+       {0x36D4, 0x01EF},
+       /* P_BL_P3Q1 */
+       {0x36D6, 0x06CF},
+       /* P_BL_P3Q2 */
+       {0x36D8, 0x8D91},
+       /* P_BL_P3Q3 */
+       {0x36DA, 0x91F0},
+       /* P_BL_P3Q4 */
+       {0x36DC, 0x52EF},
+       /* P_BL_P4Q0 */
+       {0x3714, 0xA6D2},
+       /* P_BL_P4Q1 */
+       {0x3716, 0xA312},
+       /* P_BL_P4Q2 */
+       {0x3718, 0x2695},
+       /* P_BL_P4Q3 */
+       {0x371A, 0x3953},
+       /* P_BL_P4Q4 */
+       {0x371C, 0x9356},
+       /* P_GB_P0Q0 */
+       {0x361E, 0x7EAF},
+       /* P_GB_P0Q1 */
+       {0x3620, 0x2A4C},
+       /* P_GB_P0Q2 */
+       {0x3622, 0x49F0},
+       {0x3624, 0xF1EC},
+       /* P_GB_P0Q4 */
+       {0x3626, 0xC670},
+       /* P_GB_P1Q0 */
+       {0x365E, 0x8E0C},
+       /* P_GB_P1Q1 */
+       {0x3660, 0xC2A9},
+       /* P_GB_P1Q2 */
+       {0x3662, 0x274F},
+       /* P_GB_P1Q3 */
+       {0x3664, 0xADAB},
+       /* P_GB_P1Q4 */
+       {0x3666, 0x8EF0},
+       /* P_GB_P2Q0 */
+       {0x369E, 0x09B1},
+       /* P_GB_P2Q1 */
+       {0x36A0, 0xAA2E},
+       /* P_GB_P2Q2 */
+       {0x36A2, 0xC3D3},
+       /* P_GB_P2Q3 */
+       {0x36A4, 0x7FAF},
+       /* P_GB_P2Q4 */
+       {0x36A6, 0x3F34},
+       /* P_GB_P3Q0 */
+       {0x36DE, 0x4C8F},
+       /* P_GB_P3Q1 */
+       {0x36E0, 0x886E},
+       /* P_GB_P3Q2 */
+       {0x36E2, 0xE831},
+       /* P_GB_P3Q3 */
+       {0x36E4, 0x1FD0},
+       /* P_GB_P3Q4 */
+       {0x36E6, 0x1192},
+       /* P_GB_P4Q0 */
+       {0x371E, 0xB952},
+       /* P_GB_P4Q1 */
+       {0x3720, 0x6DCF},
+       /* P_GB_P4Q2 */
+       {0x3722, 0x1B55},
+       /* P_GB_P4Q3 */
+       {0x3724, 0xA112},
+       /* P_GB_P4Q4 */
+       {0x3726, 0x82F6},
+       /* POLY_ORIGIN_C */
+       {0x3782, 0x0510},
+       /* POLY_ORIGIN_R  */
+       {0x3784, 0x0390},
+       /* POLY_SC_ENABLE */
+       {0x3780, 0x8000},
+};
+
+/* rolloff table for illuminant A */
+struct mt9p012_i2c_reg_conf mt9p012_rolloff_tbl[] = {
+       /* P_RD_P0Q0 */
+       {0x360A, 0x7FEF},
+       /* P_RD_P0Q1 */
+       {0x360C, 0x232C},
+       /* P_RD_P0Q2 */
+       {0x360E, 0x7050},
+       /* P_RD_P0Q3 */
+       {0x3610, 0xF3CC},
+       /* P_RD_P0Q4 */
+       {0x3612, 0x89D1},
+       /* P_RD_P1Q0 */
+       {0x364A, 0xBE0D},
+       /* P_RD_P1Q1 */
+       {0x364C, 0x9ACB},
+       /* P_RD_P1Q2 */
+       {0x364E, 0x2150},
+       /* P_RD_P1Q3 */
+       {0x3650, 0xB26B},
+       /* P_RD_P1Q4 */
+       {0x3652, 0x9511},
+       /* P_RD_P2Q0 */
+       {0x368A, 0x2151},
+       /* P_RD_P2Q1 */
+       {0x368C, 0x00AD},
+       /* P_RD_P2Q2 */
+       {0x368E, 0x8334},
+       /* P_RD_P2Q3 */
+       {0x3690, 0x478E},
+       /* P_RD_P2Q4 */
+       {0x3692, 0x0515},
+       /* P_RD_P3Q0 */
+       {0x36CA, 0x0710},
+       /* P_RD_P3Q1 */
+       {0x36CC, 0x452D},
+       /* P_RD_P3Q2 */
+       {0x36CE, 0xF352},
+       /* P_RD_P3Q3 */
+       {0x36D0, 0x190F},
+       /* P_RD_P3Q4 */
+       {0x36D2, 0x4413},
+       /* P_RD_P4Q0 */
+       {0x370A, 0xD112},
+       /* P_RD_P4Q1 */
+       {0x370C, 0xF50F},
+       /* P_RD_P4Q2 */
+       {0x370E, 0x6375},
+       /* P_RD_P4Q3 */
+       {0x3710, 0xDC11},
+       /* P_RD_P4Q4 */
+       {0x3712, 0xD776},
+       /* P_GR_P0Q0 */
+       {0x3600, 0x1750},
+       /* P_GR_P0Q1 */
+       {0x3602, 0xF0AC},
+       /* P_GR_P0Q2 */
+       {0x3604, 0x4711},
+       /* P_GR_P0Q3 */
+       {0x3606, 0x07CE},
+       /* P_GR_P0Q4 */
+       {0x3608, 0x96B2},
+       /* P_GR_P1Q0 */
+       {0x3640, 0xA9AE},
+       /* P_GR_P1Q1 */
+       {0x3642, 0xF9AC},
+       /* P_GR_P1Q2 */
+       {0x3644, 0x39F1},
+       /* P_GR_P1Q3 */
+       {0x3646, 0x016F},
+       /* P_GR_P1Q4 */
+       {0x3648, 0x8AB2},
+       /* P_GR_P2Q0 */
+       {0x3680, 0x1752},
+       /* P_GR_P2Q1 */
+       {0x3682, 0x70F0},
+       /* P_GR_P2Q2 */
+       {0x3684, 0x83F5},
+       /* P_GR_P2Q3 */
+       {0x3686, 0x8392},
+       /* P_GR_P2Q4 */
+       {0x3688, 0x1FD6},
+       /* P_GR_P3Q0 */
+       {0x36C0, 0x1131},
+       /* P_GR_P3Q1 */
+       {0x36C2, 0x3DAF},
+       /* P_GR_P3Q2 */
+       {0x36C4, 0x89B4},
+       /* P_GR_P3Q3 */
+       {0x36C6, 0xA391},
+       /* P_GR_P3Q4 */
+       {0x36C8, 0x1334},
+       /* P_GR_P4Q0 */
+       {0x3700, 0xDC13},
+       /* P_GR_P4Q1 */
+       {0x3702, 0xD052},
+       /* P_GR_P4Q2 */
+       {0x3704, 0x5156},
+       /* P_GR_P4Q3 */
+       {0x3706, 0x1F13},
+       /* P_GR_P4Q4 */
+       {0x3708, 0x8C38},
+       /* P_BL_P0Q0 */
+       {0x3614, 0x0050},
+       /* P_BL_P0Q1 */
+       {0x3616, 0xBD4C},
+       /* P_BL_P0Q2 */
+       {0x3618, 0x41B0},
+       /* P_BL_P0Q3 */
+       {0x361A, 0x660D},
+       /* P_BL_P0Q4 */
+       {0x361C, 0xC590},
+       /* P_BL_P1Q0 */
+       {0x3654, 0x87EC},
+       /* P_BL_P1Q1 */
+       {0x3656, 0xE44C},
+       /* P_BL_P1Q2 */
+       {0x3658, 0x302E},
+       /* P_BL_P1Q3 */
+       {0x365A, 0x106E},
+       /* P_BL_P1Q4 */
+       {0x365C, 0xB58E},
+       /* P_BL_P2Q0 */
+       {0x3694, 0x0DD1},
+       /* P_BL_P2Q1 */
+       {0x3696, 0x2A50},
+       /* P_BL_P2Q2 */
+       {0x3698, 0xC793},
+       /* P_BL_P2Q3 */
+       {0x369A, 0xE8F1},
+       /* P_BL_P2Q4 */
+       {0x369C, 0x4174},
+       /* P_BL_P3Q0 */
+       {0x36D4, 0x01EF},
+       /* P_BL_P3Q1 */
+       {0x36D6, 0x06CF},
+       /* P_BL_P3Q2 */
+       {0x36D8, 0x8D91},
+       /* P_BL_P3Q3 */
+       {0x36DA, 0x91F0},
+       /* P_BL_P3Q4 */
+       {0x36DC, 0x52EF},
+       /* P_BL_P4Q0 */
+       {0x3714, 0xA6D2},
+       /* P_BL_P4Q1 */
+       {0x3716, 0xA312},
+       /* P_BL_P4Q2 */
+       {0x3718, 0x2695},
+       /* P_BL_P4Q3 */
+       {0x371A, 0x3953},
+       /* P_BL_P4Q4 */
+       {0x371C, 0x9356},
+       /* P_GB_P0Q0 */
+       {0x361E, 0x7EAF},
+       /* P_GB_P0Q1 */
+       {0x3620, 0x2A4C},
+       /* P_GB_P0Q2 */
+       {0x3622, 0x49F0},
+       {0x3624, 0xF1EC},
+       /* P_GB_P0Q4 */
+       {0x3626, 0xC670},
+       /* P_GB_P1Q0 */
+       {0x365E, 0x8E0C},
+       /* P_GB_P1Q1 */
+       {0x3660, 0xC2A9},
+       /* P_GB_P1Q2 */
+       {0x3662, 0x274F},
+       /* P_GB_P1Q3 */
+       {0x3664, 0xADAB},
+       /* P_GB_P1Q4 */
+       {0x3666, 0x8EF0},
+       /* P_GB_P2Q0 */
+       {0x369E, 0x09B1},
+       /* P_GB_P2Q1 */
+       {0x36A0, 0xAA2E},
+       /* P_GB_P2Q2 */
+       {0x36A2, 0xC3D3},
+       /* P_GB_P2Q3 */
+       {0x36A4, 0x7FAF},
+       /* P_GB_P2Q4 */
+       {0x36A6, 0x3F34},
+       /* P_GB_P3Q0 */
+       {0x36DE, 0x4C8F},
+       /* P_GB_P3Q1 */
+       {0x36E0, 0x886E},
+       /* P_GB_P3Q2 */
+       {0x36E2, 0xE831},
+       /* P_GB_P3Q3 */
+       {0x36E4, 0x1FD0},
+       /* P_GB_P3Q4 */
+       {0x36E6, 0x1192},
+       /* P_GB_P4Q0 */
+       {0x371E, 0xB952},
+       /* P_GB_P4Q1 */
+       {0x3720, 0x6DCF},
+       /* P_GB_P4Q2 */
+       {0x3722, 0x1B55},
+       /* P_GB_P4Q3 */
+       {0x3724, 0xA112},
+       /* P_GB_P4Q4 */
+       {0x3726, 0x82F6},
+       /* POLY_ORIGIN_C */
+       {0x3782, 0x0510},
+       /* POLY_ORIGIN_R  */
+       {0x3784, 0x0390},
+       /* POLY_SC_ENABLE */
+       {0x3780, 0x8000},
+};
+
+
+struct mt9p012_reg mt9p012_regs = {
+       .reg_pat = &mt9p012_reg_pat[0],
+       .reg_pat_size = ARRAY_SIZE(mt9p012_reg_pat),
+       .ttbl = &mt9p012_test_tbl[0],
+       .ttbl_size = ARRAY_SIZE(mt9p012_test_tbl),
+       .lctbl = &mt9p012_lc_tbl[0],
+       .lctbl_size = ARRAY_SIZE(mt9p012_lc_tbl),
+       .rftbl = &mt9p012_rolloff_tbl[0],
+       .rftbl_size = ARRAY_SIZE(mt9p012_rolloff_tbl)
+};
+
+
diff --git a/drivers/staging/dream/camera/mt9t013.c b/drivers/staging/dream/camera/mt9t013.c
new file mode 100644 (file)
index 0000000..88229f2
--- /dev/null
@@ -0,0 +1,1496 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include <asm/mach-types.h>
+#include "mt9t013.h"
+
+/*=============================================================
+       SENSOR REGISTER DEFINES
+==============================================================*/
+#define MT9T013_REG_MODEL_ID            0x0000
+#define MT9T013_MODEL_ID                0x2600
+#define REG_GROUPED_PARAMETER_HOLD   0x0104
+#define GROUPED_PARAMETER_HOLD       0x0100
+#define GROUPED_PARAMETER_UPDATE     0x0000
+#define REG_COARSE_INT_TIME          0x3012
+#define REG_VT_PIX_CLK_DIV           0x0300
+#define REG_VT_SYS_CLK_DIV           0x0302
+#define REG_PRE_PLL_CLK_DIV          0x0304
+#define REG_PLL_MULTIPLIER           0x0306
+#define REG_OP_PIX_CLK_DIV           0x0308
+#define REG_OP_SYS_CLK_DIV           0x030A
+#define REG_SCALE_M                  0x0404
+#define REG_FRAME_LENGTH_LINES       0x300A
+#define REG_LINE_LENGTH_PCK          0x300C
+#define REG_X_ADDR_START             0x3004
+#define REG_Y_ADDR_START             0x3002
+#define REG_X_ADDR_END               0x3008
+#define REG_Y_ADDR_END               0x3006
+#define REG_X_OUTPUT_SIZE            0x034C
+#define REG_Y_OUTPUT_SIZE            0x034E
+#define REG_FINE_INT_TIME            0x3014
+#define REG_ROW_SPEED                0x3016
+#define MT9T013_REG_RESET_REGISTER   0x301A
+#define MT9T013_RESET_REGISTER_PWON  0x10CC
+#define MT9T013_RESET_REGISTER_PWOFF 0x1008 /* 0x10C8 stop streaming*/
+#define REG_READ_MODE                0x3040
+#define REG_GLOBAL_GAIN              0x305E
+#define REG_TEST_PATTERN_MODE        0x3070
+
+
+enum mt9t013_test_mode {
+       TEST_OFF,
+       TEST_1,
+       TEST_2,
+       TEST_3
+};
+
+enum mt9t013_resolution {
+       QTR_SIZE,
+       FULL_SIZE,
+       INVALID_SIZE
+};
+
+enum mt9t013_reg_update {
+       REG_INIT, /* registers that need to be updated during initialization */
+       UPDATE_PERIODIC, /* registers that needs periodic I2C writes */
+       UPDATE_ALL, /* all registers will be updated */
+       UPDATE_INVALID
+};
+
+enum mt9t013_setting {
+       RES_PREVIEW,
+       RES_CAPTURE
+};
+
+/* actuator's Slave Address */
+#define MT9T013_AF_I2C_ADDR   0x18
+
+/*
+* AF Total steps parameters
+*/
+#define MT9T013_TOTAL_STEPS_NEAR_TO_FAR    30
+
+/*
+ * Time in milisecs for waiting for the sensor to reset.
+ */
+#define MT9T013_RESET_DELAY_MSECS   66
+
+/* for 30 fps preview */
+#define MT9T013_DEFAULT_CLOCK_RATE  24000000
+#define MT9T013_DEFAULT_MAX_FPS     26
+
+
+/* FIXME: Changes from here */
+struct mt9t013_work {
+       struct work_struct work;
+};
+
+static struct  mt9t013_work *mt9t013_sensorw;
+static struct  i2c_client *mt9t013_client;
+
+struct mt9t013_ctrl {
+       const struct msm_camera_sensor_info *sensordata;
+
+       int sensormode;
+       uint32_t fps_divider;           /* init to 1 * 0x00000400 */
+       uint32_t pict_fps_divider;      /* init to 1 * 0x00000400 */
+
+       uint16_t curr_lens_pos;
+       uint16_t init_curr_lens_pos;
+       uint16_t my_reg_gain;
+       uint32_t my_reg_line_count;
+
+       enum mt9t013_resolution prev_res;
+       enum mt9t013_resolution pict_res;
+       enum mt9t013_resolution curr_res;
+       enum mt9t013_test_mode  set_test;
+
+       unsigned short imgaddr;
+};
+
+
+static struct mt9t013_ctrl *mt9t013_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(mt9t013_wait_queue);
+DECLARE_MUTEX(mt9t013_sem);
+
+extern struct mt9t013_reg mt9t013_regs; /* from mt9t013_reg.c */
+
+static int mt9t013_i2c_rxdata(unsigned short saddr,
+       unsigned char *rxdata, int length)
+{
+       struct i2c_msg msgs[] = {
+       {
+               .addr   = saddr,
+               .flags = 0,
+               .len   = 2,
+               .buf   = rxdata,
+       },
+       {
+               .addr  = saddr,
+               .flags = I2C_M_RD,
+               .len   = length,
+               .buf   = rxdata,
+       },
+       };
+
+       if (i2c_transfer(mt9t013_client->adapter, msgs, 2) < 0) {
+               pr_err("mt9t013_i2c_rxdata failed!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t mt9t013_i2c_read_w(unsigned short saddr,
+       unsigned short raddr, unsigned short *rdata)
+{
+       int32_t rc = 0;
+       unsigned char buf[4];
+
+       if (!rdata)
+               return -EIO;
+
+       memset(buf, 0, sizeof(buf));
+
+       buf[0] = (raddr & 0xFF00)>>8;
+       buf[1] = (raddr & 0x00FF);
+
+       rc = mt9t013_i2c_rxdata(saddr, buf, 2);
+       if (rc < 0)
+               return rc;
+
+       *rdata = buf[0] << 8 | buf[1];
+
+       if (rc < 0)
+               pr_err("mt9t013_i2c_read failed!\n");
+
+       return rc;
+}
+
+static int32_t mt9t013_i2c_txdata(unsigned short saddr,
+       unsigned char *txdata, int length)
+{
+       struct i2c_msg msg[] = {
+       {
+               .addr = saddr,
+               .flags = 0,
+               .len = length,
+               .buf = txdata,
+       },
+       };
+
+       if (i2c_transfer(mt9t013_client->adapter, msg, 1) < 0) {
+               pr_err("mt9t013_i2c_txdata failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t mt9t013_i2c_write_b(unsigned short saddr,
+       unsigned short waddr, unsigned short wdata)
+{
+       int32_t rc = -EIO;
+       unsigned char buf[2];
+
+       memset(buf, 0, sizeof(buf));
+       buf[0] = waddr;
+       buf[1] = wdata;
+       rc = mt9t013_i2c_txdata(saddr, buf, 2);
+
+       if (rc < 0)
+               pr_err("i2c_write failed, addr = 0x%x, val = 0x%x!\n",
+               waddr, wdata);
+
+       return rc;
+}
+
+static int32_t mt9t013_i2c_write_w(unsigned short saddr,
+       unsigned short waddr, unsigned short wdata)
+{
+       int32_t rc = -EIO;
+       unsigned char buf[4];
+
+       memset(buf, 0, sizeof(buf));
+       buf[0] = (waddr & 0xFF00)>>8;
+       buf[1] = (waddr & 0x00FF);
+       buf[2] = (wdata & 0xFF00)>>8;
+       buf[3] = (wdata & 0x00FF);
+
+       rc = mt9t013_i2c_txdata(saddr, buf, 4);
+
+       if (rc < 0)
+               pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+               waddr, wdata);
+
+       return rc;
+}
+
+static int32_t mt9t013_i2c_write_w_table(
+       struct mt9t013_i2c_reg_conf *reg_conf_tbl, int num_of_items_in_table)
+{
+       int i;
+       int32_t rc = -EIO;
+
+       for (i = 0; i < num_of_items_in_table; i++) {
+               rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       reg_conf_tbl->waddr, reg_conf_tbl->wdata);
+               if (rc < 0)
+                       break;
+               reg_conf_tbl++;
+       }
+
+       return rc;
+}
+
+static int32_t mt9t013_test(enum mt9t013_test_mode mo)
+{
+       int32_t rc = 0;
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_HOLD);
+       if (rc < 0)
+               return rc;
+
+       if (mo == TEST_OFF)
+               return 0;
+       else {
+               rc = mt9t013_i2c_write_w_table(mt9t013_regs.ttbl,
+                               mt9t013_regs.ttbl_size);
+               if (rc < 0)
+                       return rc;
+               rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_TEST_PATTERN_MODE, (uint16_t)mo);
+               if (rc < 0)
+                       return rc;
+       }
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_UPDATE);
+       if (rc < 0)
+               return rc;
+
+       return rc;
+}
+
+static int32_t mt9t013_set_lc(void)
+{
+       int32_t rc;
+
+       rc = mt9t013_i2c_write_w_table(mt9t013_regs.lctbl, mt9t013_regs.lctbl_size);
+       if (rc < 0)
+               return rc;
+
+       return rc;
+}
+
+static int32_t mt9t013_set_default_focus(uint8_t af_step)
+{
+       int32_t rc = 0;
+       uint8_t code_val_msb, code_val_lsb;
+       code_val_msb = 0x01;
+       code_val_lsb = af_step;
+
+       /* Write the digital code for current to the actuator */
+       rc = mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1,
+                       code_val_msb, code_val_lsb);
+
+       mt9t013_ctrl->curr_lens_pos = 0;
+       mt9t013_ctrl->init_curr_lens_pos = 0;
+       return rc;
+}
+
+static void mt9t013_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+       /* input fps is preview fps in Q8 format */
+       uint32_t divider;   /*Q10 */
+       uint32_t pclk_mult; /*Q10 */
+
+       if (mt9t013_ctrl->prev_res == QTR_SIZE) {
+               divider =
+                       (uint32_t)(
+               ((mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines *
+               mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck) *
+               0x00000400) /
+               (mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines *
+               mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck));
+
+               pclk_mult =
+               (uint32_t) ((mt9t013_regs.reg_pat[RES_CAPTURE].pll_multiplier *
+               0x00000400) /
+               (mt9t013_regs.reg_pat[RES_PREVIEW].pll_multiplier));
+
+       } else {
+               /* full size resolution used for preview. */
+               divider   = 0x00000400;  /*1.0 */
+               pclk_mult = 0x00000400;  /*1.0 */
+       }
+
+       /* Verify PCLK settings and frame sizes. */
+       *pfps =
+               (uint16_t) (fps * divider * pclk_mult /
+               0x00000400 / 0x00000400);
+}
+
+static uint16_t mt9t013_get_prev_lines_pf(void)
+{
+       if (mt9t013_ctrl->prev_res == QTR_SIZE)
+               return mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines;
+       else
+               return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9t013_get_prev_pixels_pl(void)
+{
+       if (mt9t013_ctrl->prev_res == QTR_SIZE)
+               return mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck;
+       else
+               return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint16_t mt9t013_get_pict_lines_pf(void)
+{
+       return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
+}
+
+static uint16_t mt9t013_get_pict_pixels_pl(void)
+{
+       return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
+}
+
+static uint32_t mt9t013_get_pict_max_exp_lc(void)
+{
+       uint16_t snapshot_lines_per_frame;
+
+       if (mt9t013_ctrl->pict_res == QTR_SIZE) {
+               snapshot_lines_per_frame =
+               mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
+       } else  {
+               snapshot_lines_per_frame =
+               mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
+       }
+
+       return snapshot_lines_per_frame * 24;
+}
+
+static int32_t mt9t013_set_fps(struct fps_cfg *fps)
+{
+       /* input is new fps in Q8 format */
+       int32_t rc = 0;
+
+       mt9t013_ctrl->fps_divider = fps->fps_div;
+       mt9t013_ctrl->pict_fps_divider = fps->pict_fps_div;
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_HOLD);
+       if (rc < 0)
+               return -EBUSY;
+
+       CDBG("mt9t013_set_fps: fps_div is %d, frame_rate is %d\n",
+                       fps->fps_div,
+                       (uint16_t) (mt9t013_regs.reg_pat[RES_PREVIEW].
+                                               frame_length_lines *
+                                       fps->fps_div/0x00000400));
+
+       CDBG("mt9t013_set_fps: fps_mult is %d, frame_rate is %d\n",
+                       fps->f_mult,
+                       (uint16_t)(mt9t013_regs.reg_pat[RES_PREVIEW].
+                                       line_length_pck *
+                                       fps->f_mult / 0x00000400));
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_LINE_LENGTH_PCK,
+                       (uint16_t) (
+                       mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck *
+                       fps->f_mult / 0x00000400));
+       if (rc < 0)
+               return rc;
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_UPDATE);
+       if (rc < 0)
+               return rc;
+
+       return rc;
+}
+
+static int32_t mt9t013_write_exp_gain(uint16_t gain, uint32_t line)
+{
+       const uint16_t max_legal_gain = 0x01FF;
+       uint32_t line_length_ratio = 0x00000400;
+       enum mt9t013_setting setting;
+       int32_t rc = 0;
+
+       if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+               mt9t013_ctrl->my_reg_gain = gain;
+               mt9t013_ctrl->my_reg_line_count = (uint16_t) line;
+       }
+
+       if (gain > max_legal_gain)
+               gain = max_legal_gain;
+
+       /* Verify no overflow */
+       if (mt9t013_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
+               line = (uint32_t) (line * mt9t013_ctrl->fps_divider /
+                       0x00000400);
+
+               setting = RES_PREVIEW;
+
+       } else {
+               line = (uint32_t) (line * mt9t013_ctrl->pict_fps_divider /
+                       0x00000400);
+
+               setting = RES_CAPTURE;
+       }
+
+       /*Set digital gain to 1 */
+       gain |= 0x0200;
+
+       if ((mt9t013_regs.reg_pat[setting].frame_length_lines - 1) < line) {
+
+               line_length_ratio =
+               (uint32_t) (line * 0x00000400) /
+               (mt9t013_regs.reg_pat[setting].frame_length_lines - 1);
+       } else
+               line_length_ratio = 0x00000400;
+
+       /* There used to be PARAMETER_HOLD register write before and
+        * after REG_GLOBAL_GAIN & REG_COARSE_INIT_TIME. This causes
+        * aec oscillation. Hence removed. */
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr, REG_GLOBAL_GAIN, gain);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_COARSE_INT_TIME,
+                       (uint16_t)((uint32_t) line * 0x00000400 /
+                       line_length_ratio));
+       if (rc < 0)
+               return rc;
+
+       return rc;
+}
+
+static int32_t mt9t013_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+       int32_t rc = 0;
+
+       rc = mt9t013_write_exp_gain(gain, line);
+       if (rc < 0)
+               return rc;
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       MT9T013_REG_RESET_REGISTER,
+                       0x10CC | 0x0002);
+
+       mdelay(5);
+
+       /* camera_timed_wait(snapshot_wait*exposure_ratio); */
+       return rc;
+}
+
+static int32_t mt9t013_setting(enum mt9t013_reg_update rupdate,
+       enum mt9t013_setting rt)
+{
+       int32_t rc = 0;
+
+       switch (rupdate) {
+       case UPDATE_PERIODIC: {
+
+       if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+#if 0
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               MT9T013_REG_RESET_REGISTER,
+                               MT9T013_RESET_REGISTER_PWOFF);
+               if (rc < 0)
+                       return rc;
+#endif
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_VT_PIX_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].vt_pix_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_VT_SYS_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].vt_sys_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_PRE_PLL_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].pre_pll_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_PLL_MULTIPLIER,
+                               mt9t013_regs.reg_pat[rt].pll_multiplier);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_OP_PIX_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].op_pix_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_OP_SYS_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].op_sys_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_GROUPED_PARAMETER_HOLD,
+                               GROUPED_PARAMETER_HOLD);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_ROW_SPEED,
+                               mt9t013_regs.reg_pat[rt].row_speed);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_X_ADDR_START,
+                               mt9t013_regs.reg_pat[rt].x_addr_start);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_X_ADDR_END,
+                               mt9t013_regs.reg_pat[rt].x_addr_end);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_Y_ADDR_START,
+                               mt9t013_regs.reg_pat[rt].y_addr_start);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_Y_ADDR_END,
+                               mt9t013_regs.reg_pat[rt].y_addr_end);
+               if (rc < 0)
+                       return rc;
+
+               if (machine_is_sapphire()) {
+                       if (rt == 0)
+                               rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                                       REG_READ_MODE,
+                                       0x046F);
+                       else
+                               rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                                       REG_READ_MODE,
+                                       0x0027);
+               } else
+                       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                                       REG_READ_MODE,
+                                       mt9t013_regs.reg_pat[rt].read_mode);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_SCALE_M,
+                               mt9t013_regs.reg_pat[rt].scale_m);
+               if (rc < 0)
+                       return rc;
+
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_X_OUTPUT_SIZE,
+                               mt9t013_regs.reg_pat[rt].x_output_size);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_Y_OUTPUT_SIZE,
+                               mt9t013_regs.reg_pat[rt].y_output_size);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_LINE_LENGTH_PCK,
+                               mt9t013_regs.reg_pat[rt].line_length_pck);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_FRAME_LENGTH_LINES,
+                       (mt9t013_regs.reg_pat[rt].frame_length_lines *
+                       mt9t013_ctrl->fps_divider / 0x00000400));
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_COARSE_INT_TIME,
+                       mt9t013_regs.reg_pat[rt].coarse_int_time);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_FINE_INT_TIME,
+                       mt9t013_regs.reg_pat[rt].fine_int_time);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_UPDATE);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9t013_test(mt9t013_ctrl->set_test);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                       MT9T013_REG_RESET_REGISTER,
+                       MT9T013_RESET_REGISTER_PWON);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               return rc;
+       }
+       }
+               break;
+
+       /*CAMSENSOR_REG_UPDATE_PERIODIC */
+       case REG_INIT: {
+       if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               MT9T013_REG_RESET_REGISTER,
+                               MT9T013_RESET_REGISTER_PWOFF);
+               if (rc < 0)
+                       /* MODE_SELECT, stop streaming */
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_VT_PIX_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].vt_pix_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_VT_SYS_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].vt_sys_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_PRE_PLL_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].pre_pll_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_PLL_MULTIPLIER,
+                               mt9t013_regs.reg_pat[rt].pll_multiplier);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_OP_PIX_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].op_pix_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_OP_SYS_CLK_DIV,
+                               mt9t013_regs.reg_pat[rt].op_sys_clk_div);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_GROUPED_PARAMETER_HOLD,
+                               GROUPED_PARAMETER_HOLD);
+               if (rc < 0)
+                       return rc;
+
+               /* additional power saving mode ok around 38.2MHz */
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               0x3084, 0x2409);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               0x3092, 0x0A49);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               0x3094, 0x4949);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               0x3096, 0x4949);
+               if (rc < 0)
+                       return rc;
+
+               /* Set preview or snapshot mode */
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_ROW_SPEED,
+                               mt9t013_regs.reg_pat[rt].row_speed);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_X_ADDR_START,
+                               mt9t013_regs.reg_pat[rt].x_addr_start);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_X_ADDR_END,
+                               mt9t013_regs.reg_pat[rt].x_addr_end);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_Y_ADDR_START,
+                               mt9t013_regs.reg_pat[rt].y_addr_start);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_Y_ADDR_END,
+                               mt9t013_regs.reg_pat[rt].y_addr_end);
+               if (rc < 0)
+                       return rc;
+
+               if (machine_is_sapphire()) {
+                       if (rt == 0)
+                               rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                                       REG_READ_MODE,
+                                       0x046F);
+                       else
+                               rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                                       REG_READ_MODE,
+                                       0x0027);
+               } else
+                       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                                       REG_READ_MODE,
+                                       mt9t013_regs.reg_pat[rt].read_mode);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_SCALE_M,
+                               mt9t013_regs.reg_pat[rt].scale_m);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_X_OUTPUT_SIZE,
+                               mt9t013_regs.reg_pat[rt].x_output_size);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_Y_OUTPUT_SIZE,
+                               mt9t013_regs.reg_pat[rt].y_output_size);
+               if (rc < 0)
+                       return 0;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_LINE_LENGTH_PCK,
+                               mt9t013_regs.reg_pat[rt].line_length_pck);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_FRAME_LENGTH_LINES,
+                               mt9t013_regs.reg_pat[rt].frame_length_lines);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_COARSE_INT_TIME,
+                               mt9t013_regs.reg_pat[rt].coarse_int_time);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_FINE_INT_TIME,
+                               mt9t013_regs.reg_pat[rt].fine_int_time);
+               if (rc < 0)
+                       return rc;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_GROUPED_PARAMETER_HOLD,
+                               GROUPED_PARAMETER_UPDATE);
+                       if (rc < 0)
+                               return rc;
+
+               /* load lens shading */
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_GROUPED_PARAMETER_HOLD,
+                               GROUPED_PARAMETER_HOLD);
+               if (rc < 0)
+                       return rc;
+
+               /* most likely needs to be written only once. */
+               rc = mt9t013_set_lc();
+               if (rc < 0)
+                       return -EBUSY;
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_GROUPED_PARAMETER_HOLD,
+                               GROUPED_PARAMETER_UPDATE);
+               if (rc < 0)
+                       return rc;
+
+               rc = mt9t013_test(mt9t013_ctrl->set_test);
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               rc =
+                       mt9t013_i2c_write_w(mt9t013_client->addr,
+                               MT9T013_REG_RESET_REGISTER,
+                               MT9T013_RESET_REGISTER_PWON);
+               if (rc < 0)
+                       /* MODE_SELECT, stop streaming */
+                       return rc;
+
+               CDBG("!!! mt9t013 !!! PowerOn is done!\n");
+               mdelay(5);
+               return rc;
+               }
+       } /* case CAMSENSOR_REG_INIT: */
+       break;
+
+       /*CAMSENSOR_REG_INIT */
+       default:
+               rc = -EINVAL;
+               break;
+       } /* switch (rupdate) */
+
+       return rc;
+}
+
+static int32_t mt9t013_video_config(int mode, int res)
+{
+       int32_t rc;
+
+       switch (res) {
+       case QTR_SIZE:
+               rc = mt9t013_setting(UPDATE_PERIODIC, RES_PREVIEW);
+               if (rc < 0)
+                       return rc;
+               CDBG("sensor configuration done!\n");
+               break;
+
+       case FULL_SIZE:
+               rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+               if (rc < 0)
+                       return rc;
+               break;
+
+       default:
+               return -EINVAL;
+       } /* switch */
+
+       mt9t013_ctrl->prev_res = res;
+       mt9t013_ctrl->curr_res = res;
+       mt9t013_ctrl->sensormode = mode;
+
+       return mt9t013_write_exp_gain(mt9t013_ctrl->my_reg_gain,
+                       mt9t013_ctrl->my_reg_line_count);
+}
+
+static int32_t mt9t013_snapshot_config(int mode)
+{
+       int32_t rc = 0;
+
+       rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+       if (rc < 0)
+               return rc;
+
+       mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
+       mt9t013_ctrl->sensormode = mode;
+       return rc;
+}
+
+static int32_t mt9t013_raw_snapshot_config(int mode)
+{
+       int32_t rc = 0;
+
+       rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
+       if (rc < 0)
+               return rc;
+
+       mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
+       mt9t013_ctrl->sensormode = mode;
+       return rc;
+}
+
+static int32_t mt9t013_power_down(void)
+{
+       int32_t rc = 0;
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       MT9T013_REG_RESET_REGISTER,
+                       MT9T013_RESET_REGISTER_PWOFF);
+       if (rc >= 0)
+               mdelay(5);
+       return rc;
+}
+
+static int32_t mt9t013_move_focus(int direction, int32_t num_steps)
+{
+       int16_t step_direction;
+       int16_t actual_step;
+       int16_t next_position;
+       int16_t break_steps[4];
+       uint8_t code_val_msb, code_val_lsb;
+       int16_t i;
+
+       if (num_steps > MT9T013_TOTAL_STEPS_NEAR_TO_FAR)
+               num_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
+       else if (num_steps == 0)
+               return -EINVAL;
+
+       if (direction == MOVE_NEAR)
+               step_direction = 4;
+       else if (direction == MOVE_FAR)
+               step_direction = -4;
+       else
+               return -EINVAL;
+
+       if (mt9t013_ctrl->curr_lens_pos < mt9t013_ctrl->init_curr_lens_pos)
+               mt9t013_ctrl->curr_lens_pos = mt9t013_ctrl->init_curr_lens_pos;
+
+       actual_step =
+               (int16_t) (step_direction *
+               (int16_t) num_steps);
+
+       for (i = 0; i < 4; i++)
+               break_steps[i] =
+                       actual_step / 4 * (i + 1) - actual_step / 4 * i;
+
+       for (i = 0; i < 4; i++) {
+               next_position =
+               (int16_t)
+               (mt9t013_ctrl->curr_lens_pos + break_steps[i]);
+
+               if (next_position > 255)
+                       next_position = 255;
+               else if (next_position < 0)
+                       next_position = 0;
+
+               code_val_msb =
+               ((next_position >> 4) << 2) |
+               ((next_position << 4) >> 6);
+
+               code_val_lsb =
+               ((next_position & 0x03) << 6);
+
+               /* Writing the digital code for current to the actuator */
+               if (mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1,
+                               code_val_msb, code_val_lsb) < 0)
+                       return -EBUSY;
+
+               /* Storing the current lens Position */
+               mt9t013_ctrl->curr_lens_pos = next_position;
+
+               if (i < 3)
+                       mdelay(1);
+       } /* for */
+
+       return 0;
+}
+
+static int mt9t013_sensor_init_done(const struct msm_camera_sensor_info *data)
+{
+       gpio_direction_output(data->sensor_reset, 0);
+       gpio_free(data->sensor_reset);
+       return 0;
+}
+
+static int mt9t013_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+       int rc;
+       uint16_t chipid;
+
+       rc = gpio_request(data->sensor_reset, "mt9t013");
+       if (!rc)
+               gpio_direction_output(data->sensor_reset, 1);
+       else
+               goto init_probe_done;
+
+       mdelay(20);
+
+       /* RESET the sensor image part via I2C command */
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+               MT9T013_REG_RESET_REGISTER, 0x1009);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       /* 3. Read sensor Model ID: */
+       rc = mt9t013_i2c_read_w(mt9t013_client->addr,
+               MT9T013_REG_MODEL_ID, &chipid);
+
+       if (rc < 0)
+               goto init_probe_fail;
+
+       CDBG("mt9t013 model_id = 0x%x\n", chipid);
+
+       /* 4. Compare sensor ID to MT9T012VC ID: */
+       if (chipid != MT9T013_MODEL_ID) {
+               rc = -ENODEV;
+               goto init_probe_fail;
+       }
+
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+               0x3064, 0x0805);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       mdelay(MT9T013_RESET_DELAY_MSECS);
+
+       goto init_probe_done;
+
+       /* sensor: output enable */
+#if 0
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+               MT9T013_REG_RESET_REGISTER,
+               MT9T013_RESET_REGISTER_PWON);
+
+       /* if this fails, the sensor is not the MT9T013 */
+       rc = mt9t013_set_default_focus(0);
+#endif
+
+init_probe_fail:
+       gpio_direction_output(data->sensor_reset, 0);
+       gpio_free(data->sensor_reset);
+init_probe_done:
+       return rc;
+}
+
+static int32_t mt9t013_poweron_af(void)
+{
+       int32_t rc = 0;
+
+       /* enable AF actuator */
+       CDBG("enable AF actuator, gpio = %d\n",
+                       mt9t013_ctrl->sensordata->vcm_pwd);
+       rc = gpio_request(mt9t013_ctrl->sensordata->vcm_pwd, "mt9t013");
+       if (!rc) {
+               gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 0);
+               mdelay(20);
+               rc = mt9t013_set_default_focus(0);
+       } else
+               pr_err("%s, gpio_request failed (%d)!\n", __func__, rc);
+       return rc;
+}
+
+static void mt9t013_poweroff_af(void)
+{
+       gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 1);
+       gpio_free(mt9t013_ctrl->sensordata->vcm_pwd);
+}
+
+int mt9t013_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+       int32_t  rc;
+
+       mt9t013_ctrl = kzalloc(sizeof(struct mt9t013_ctrl), GFP_KERNEL);
+       if (!mt9t013_ctrl) {
+               pr_err("mt9t013_init failed!\n");
+               rc = -ENOMEM;
+               goto init_done;
+       }
+
+       mt9t013_ctrl->fps_divider = 1 * 0x00000400;
+       mt9t013_ctrl->pict_fps_divider = 1 * 0x00000400;
+       mt9t013_ctrl->set_test = TEST_OFF;
+       mt9t013_ctrl->prev_res = QTR_SIZE;
+       mt9t013_ctrl->pict_res = FULL_SIZE;
+
+       if (data)
+               mt9t013_ctrl->sensordata = data;
+
+       /* enable mclk first */
+       msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
+       mdelay(20);
+
+       msm_camio_camif_pad_reg_reset();
+       mdelay(20);
+
+       rc = mt9t013_probe_init_sensor(data);
+       if (rc < 0)
+               goto init_fail;
+
+       if (mt9t013_ctrl->prev_res == QTR_SIZE)
+               rc = mt9t013_setting(REG_INIT, RES_PREVIEW);
+       else
+               rc = mt9t013_setting(REG_INIT, RES_CAPTURE);
+
+       if (rc >= 0)
+               rc = mt9t013_poweron_af();
+
+       if (rc < 0)
+               goto init_fail;
+       else
+               goto init_done;
+
+init_fail:
+       kfree(mt9t013_ctrl);
+init_done:
+       return rc;
+}
+
+static int mt9t013_init_client(struct i2c_client *client)
+{
+       /* Initialize the MSM_CAMI2C Chip */
+       init_waitqueue_head(&mt9t013_wait_queue);
+       return 0;
+}
+
+
+static int32_t mt9t013_set_sensor_mode(int mode, int res)
+{
+       int32_t rc = 0;
+       rc = mt9t013_i2c_write_w(mt9t013_client->addr,
+                       REG_GROUPED_PARAMETER_HOLD,
+                       GROUPED_PARAMETER_HOLD);
+       if (rc < 0)
+               return rc;
+
+       switch (mode) {
+       case SENSOR_PREVIEW_MODE:
+               rc = mt9t013_video_config(mode, res);
+               break;
+
+       case SENSOR_SNAPSHOT_MODE:
+               rc = mt9t013_snapshot_config(mode);
+               break;
+
+       case SENSOR_RAW_SNAPSHOT_MODE:
+               rc = mt9t013_raw_snapshot_config(mode);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* FIXME: what should we do if rc < 0? */
+       if (rc >= 0)
+               return mt9t013_i2c_write_w(mt9t013_client->addr,
+                               REG_GROUPED_PARAMETER_HOLD,
+                               GROUPED_PARAMETER_UPDATE);
+       return rc;
+}
+
+int mt9t013_sensor_config(void __user *argp)
+{
+       struct sensor_cfg_data cdata;
+       long   rc = 0;
+
+       if (copy_from_user(&cdata, (void *)argp,
+                       sizeof(struct sensor_cfg_data)))
+               return -EFAULT;
+
+       down(&mt9t013_sem);
+
+       CDBG("mt9t013_sensor_config: cfgtype = %d\n", cdata.cfgtype);
+       switch (cdata.cfgtype) {
+       case CFG_GET_PICT_FPS:
+               mt9t013_get_pict_fps(cdata.cfg.gfps.prevfps,
+                               &(cdata.cfg.gfps.pictfps));
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PREV_L_PF:
+               cdata.cfg.prevl_pf = mt9t013_get_prev_lines_pf();
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PREV_P_PL:
+               cdata.cfg.prevp_pl = mt9t013_get_prev_pixels_pl();
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_L_PF:
+               cdata.cfg.pictl_pf = mt9t013_get_pict_lines_pf();
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_P_PL:
+               cdata.cfg.pictp_pl =
+                       mt9t013_get_pict_pixels_pl();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_MAX_EXP_LC:
+               cdata.cfg.pict_max_exp_lc =
+                       mt9t013_get_pict_max_exp_lc();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_SET_FPS:
+       case CFG_SET_PICT_FPS:
+               rc = mt9t013_set_fps(&(cdata.cfg.fps));
+               break;
+
+       case CFG_SET_EXP_GAIN:
+               rc = mt9t013_write_exp_gain(cdata.cfg.exp_gain.gain,
+                               cdata.cfg.exp_gain.line);
+               break;
+
+       case CFG_SET_PICT_EXP_GAIN:
+               rc = mt9t013_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
+                               cdata.cfg.exp_gain.line);
+               break;
+
+       case CFG_SET_MODE:
+               rc = mt9t013_set_sensor_mode(cdata.mode, cdata.rs);
+               break;
+
+       case CFG_PWR_DOWN:
+               rc = mt9t013_power_down();
+               break;
+
+       case CFG_MOVE_FOCUS:
+               rc = mt9t013_move_focus(cdata.cfg.focus.dir,
+                               cdata.cfg.focus.steps);
+               break;
+
+       case CFG_SET_DEFAULT_FOCUS:
+               rc = mt9t013_set_default_focus(cdata.cfg.focus.steps);
+               break;
+
+       case CFG_GET_AF_MAX_STEPS:
+               cdata.max_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_SET_EFFECT:
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       up(&mt9t013_sem);
+       return rc;
+}
+
+int mt9t013_sensor_release(void)
+{
+       int rc = -EBADF;
+
+       down(&mt9t013_sem);
+
+       mt9t013_poweroff_af();
+       mt9t013_power_down();
+
+       gpio_direction_output(mt9t013_ctrl->sensordata->sensor_reset,
+                       0);
+       gpio_free(mt9t013_ctrl->sensordata->sensor_reset);
+
+       kfree(mt9t013_ctrl);
+
+       up(&mt9t013_sem);
+       CDBG("mt9t013_release completed!\n");
+       return rc;
+}
+
+static int mt9t013_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       int rc = 0;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               rc = -ENOTSUPP;
+               goto probe_failure;
+       }
+
+       mt9t013_sensorw =
+               kzalloc(sizeof(struct mt9t013_work), GFP_KERNEL);
+
+       if (!mt9t013_sensorw) {
+               rc = -ENOMEM;
+               goto probe_failure;
+       }
+
+       i2c_set_clientdata(client, mt9t013_sensorw);
+       mt9t013_init_client(client);
+       mt9t013_client = client;
+       mt9t013_client->addr = mt9t013_client->addr >> 1;
+       mdelay(50);
+
+       CDBG("i2c probe ok\n");
+       return 0;
+
+probe_failure:
+       kfree(mt9t013_sensorw);
+       mt9t013_sensorw = NULL;
+       pr_err("i2c probe failure %d\n", rc);
+       return rc;
+}
+
+static const struct i2c_device_id mt9t013_i2c_id[] = {
+       { "mt9t013", 0},
+       { }
+};
+
+static struct i2c_driver mt9t013_i2c_driver = {
+       .id_table = mt9t013_i2c_id,
+       .probe  = mt9t013_i2c_probe,
+       .remove = __exit_p(mt9t013_i2c_remove),
+       .driver = {
+               .name = "mt9t013",
+       },
+};
+
+static int mt9t013_sensor_probe(
+               const struct msm_camera_sensor_info *info,
+               struct msm_sensor_ctrl *s)
+{
+       /* We expect this driver to match with the i2c device registered
+        * in the board file immediately. */
+       int rc = i2c_add_driver(&mt9t013_i2c_driver);
+       if (rc < 0 || mt9t013_client == NULL) {
+               rc = -ENOTSUPP;
+               goto probe_done;
+       }
+
+       /* enable mclk first */
+       msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
+       mdelay(20);
+
+       rc = mt9t013_probe_init_sensor(info);
+       if (rc < 0) {
+               i2c_del_driver(&mt9t013_i2c_driver);
+               goto probe_done;
+       }
+
+       s->s_init = mt9t013_sensor_open_init;
+       s->s_release = mt9t013_sensor_release;
+       s->s_config  = mt9t013_sensor_config;
+       mt9t013_sensor_init_done(info);
+
+probe_done:
+       return rc;
+}
+
+static int __mt9t013_probe(struct platform_device *pdev)
+{
+       return msm_camera_drv_start(pdev, mt9t013_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+       .probe = __mt9t013_probe,
+       .driver = {
+               .name = "msm_camera_mt9t013",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mt9t013_init(void)
+{
+       return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(mt9t013_init);
diff --git a/drivers/staging/dream/camera/mt9t013.h b/drivers/staging/dream/camera/mt9t013.h
new file mode 100644 (file)
index 0000000..9bce203
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#ifndef MT9T013_H
+#define MT9T013_H
+
+#include <linux/types.h>
+
+struct reg_struct {
+       uint16_t vt_pix_clk_div;        /*  0x0300 */
+       uint16_t vt_sys_clk_div;        /*  0x0302 */
+       uint16_t pre_pll_clk_div;       /*  0x0304 */
+       uint16_t pll_multiplier;        /*  0x0306 */
+       uint16_t op_pix_clk_div;        /*  0x0308 */
+       uint16_t op_sys_clk_div;        /*  0x030A */
+       uint16_t scale_m;               /*  0x0404 */
+       uint16_t row_speed;             /*  0x3016 */
+       uint16_t x_addr_start;          /*  0x3004 */
+       uint16_t x_addr_end;            /*  0x3008 */
+       uint16_t y_addr_start;          /*  0x3002 */
+       uint16_t y_addr_end;            /*  0x3006 */
+       uint16_t read_mode;             /*  0x3040 */
+       uint16_t x_output_size;         /*  0x034C */
+       uint16_t y_output_size;         /*  0x034E */
+       uint16_t line_length_pck;       /*  0x300C */
+       uint16_t frame_length_lines;    /*  0x300A */
+       uint16_t coarse_int_time;               /*  0x3012 */
+       uint16_t fine_int_time;                 /*  0x3014 */
+};
+
+struct mt9t013_i2c_reg_conf {
+       unsigned short waddr;
+       unsigned short wdata;
+};
+
+struct mt9t013_reg {
+       struct reg_struct *reg_pat;
+       uint16_t reg_pat_size;
+       struct mt9t013_i2c_reg_conf *ttbl;
+       uint16_t ttbl_size;
+       struct mt9t013_i2c_reg_conf *lctbl;
+       uint16_t lctbl_size;
+       struct mt9t013_i2c_reg_conf *rftbl;
+       uint16_t rftbl_size;
+};
+
+#endif /* #define MT9T013_H */
diff --git a/drivers/staging/dream/camera/mt9t013_reg.c b/drivers/staging/dream/camera/mt9t013_reg.c
new file mode 100644 (file)
index 0000000..ba0a1d4
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2009 QUALCOMM Incorporated.
+ */
+
+#include "mt9t013.h"
+#include <linux/kernel.h>
+
+struct reg_struct const mt9t013_reg_pat[2] = {
+       { /* Preview 2x2 binning 20fps, pclk MHz, MCLK 24MHz */
+       /* vt_pix_clk_div:REG=0x0300 update get_snapshot_fps
+       * if this change */
+       8,
+
+       /* vt_sys_clk_div: REG=0x0302  update get_snapshot_fps
+       * if this change */
+       1,
+
+       /* pre_pll_clk_div REG=0x0304  update get_snapshot_fps
+       * if this change */
+       2,
+
+       /* pll_multiplier  REG=0x0306 60 for 30fps preview, 40
+        * for 20fps preview
+        * 46 for 30fps preview, try 47/48 to increase further */
+       46,
+
+       /* op_pix_clk_div        REG=0x0308 */
+       8,
+
+       /* op_sys_clk_div        REG=0x030A */
+       1,
+
+       /* scale_m       REG=0x0404 */
+       16,
+
+       /* row_speed     REG=0x3016 */
+       0x0111,
+
+       /* x_addr_start  REG=0x3004 */
+       8,
+
+       /* x_addr_end    REG=0x3008 */
+       2053,
+
+       /* y_addr_start  REG=0x3002 */
+       8,
+
+       /* y_addr_end    REG=0x3006 */
+       1541,
+
+       /* read_mode     REG=0x3040 */
+       0x046C,
+
+       /* x_output_size REG=0x034C */
+       1024,
+
+       /* y_output_size REG=0x034E */
+       768,
+
+       /* line_length_pck    REG=0x300C */
+       2616,
+
+       /* frame_length_lines REG=0x300A */
+       916,
+
+       /* coarse_int_time REG=0x3012 */
+       16,
+
+       /* fine_int_time   REG=0x3014 */
+       1461
+       },
+       { /*Snapshot */
+       /* vt_pix_clk_div  REG=0x0300 update get_snapshot_fps
+       * if this change */
+       8,
+
+       /* vt_sys_clk_div  REG=0x0302 update get_snapshot_fps
+       * if this change */
+       1,
+
+       /* pre_pll_clk_div REG=0x0304 update get_snapshot_fps
+        * if this change */
+       2,
+
+       /* pll_multiplier REG=0x0306 50 for 15fps snapshot,
+        * 40 for 10fps snapshot
+        * 46 for 30fps snapshot, try 47/48 to increase further */
+       46,
+
+       /* op_pix_clk_div        REG=0x0308 */
+       8,
+
+       /* op_sys_clk_div        REG=0x030A */
+       1,
+
+       /* scale_m       REG=0x0404 */
+       16,
+
+       /* row_speed     REG=0x3016 */
+       0x0111,
+
+       /* x_addr_start  REG=0x3004 */
+       8,
+
+       /* x_addr_end    REG=0x3008 */
+       2071,
+
+       /* y_addr_start  REG=0x3002 */
+       8,
+
+       /* y_addr_end    REG=0x3006 */
+       1551,
+
+       /* read_mode     REG=0x3040 */
+       0x0024,
+
+       /* x_output_size REG=0x034C */
+       2064,
+
+       /* y_output_size REG=0x034E */
+       1544,
+
+       /* line_length_pck REG=0x300C */
+       2952,
+
+       /* frame_length_lines    REG=0x300A */
+       1629,
+
+       /* coarse_int_time REG=0x3012 */
+       16,
+
+       /* fine_int_time REG=0x3014   */
+       733
+       }
+};
+
+struct mt9t013_i2c_reg_conf mt9t013_test_tbl[] = {
+       { 0x3044, 0x0544 & 0xFBFF },
+       { 0x30CA, 0x0004 | 0x0001 },
+       { 0x30D4, 0x9020 & 0x7FFF },
+       { 0x31E0, 0x0003 & 0xFFFE },
+       { 0x3180, 0x91FF & 0x7FFF },
+       { 0x301A, (0x10CC | 0x8000) & 0xFFF7 },
+       { 0x301E, 0x0000 },
+       { 0x3780, 0x0000 },
+};
+
+/* [Lens shading 85 Percent TL84] */
+struct mt9t013_i2c_reg_conf mt9t013_lc_tbl[] = {
+       { 0x360A, 0x0290 }, /* P_RD_P0Q0 */
+       { 0x360C, 0xC92D }, /* P_RD_P0Q1 */
+       { 0x360E, 0x0771 }, /* P_RD_P0Q2 */
+       { 0x3610, 0xE38C }, /* P_RD_P0Q3 */
+       { 0x3612, 0xD74F }, /* P_RD_P0Q4 */
+       { 0x364A, 0x168C }, /* P_RD_P1Q0 */
+       { 0x364C, 0xCACB }, /* P_RD_P1Q1 */
+       { 0x364E, 0x8C4C }, /* P_RD_P1Q2 */
+       { 0x3650, 0x0BEA }, /* P_RD_P1Q3 */
+       { 0x3652, 0xDC0F }, /* P_RD_P1Q4 */
+       { 0x368A, 0x70B0 }, /* P_RD_P2Q0 */
+       { 0x368C, 0x200B }, /* P_RD_P2Q1 */
+       { 0x368E, 0x30B2 }, /* P_RD_P2Q2 */
+       { 0x3690, 0xD04F }, /* P_RD_P2Q3 */
+       { 0x3692, 0xACF5 }, /* P_RD_P2Q4 */
+       { 0x36CA, 0xF7C9 }, /* P_RD_P3Q0 */
+       { 0x36CC, 0x2AED }, /* P_RD_P3Q1 */
+       { 0x36CE, 0xA652 }, /* P_RD_P3Q2 */
+       { 0x36D0, 0x8192 }, /* P_RD_P3Q3 */
+       { 0x36D2, 0x3A15 }, /* P_RD_P3Q4 */
+       { 0x370A, 0xDA30 }, /* P_RD_P4Q0 */
+       { 0x370C, 0x2E2F }, /* P_RD_P4Q1 */
+       { 0x370E, 0xBB56 }, /* P_RD_P4Q2 */
+       { 0x3710, 0x8195 }, /* P_RD_P4Q3 */
+       { 0x3712, 0x02F9 }, /* P_RD_P4Q4 */
+       { 0x3600, 0x0230 }, /* P_GR_P0Q0 */
+       { 0x3602, 0x58AD }, /* P_GR_P0Q1 */
+       { 0x3604, 0x18D1 }, /* P_GR_P0Q2 */
+       { 0x3606, 0x260D }, /* P_GR_P0Q3 */
+       { 0x3608, 0xF530 }, /* P_GR_P0Q4 */
+       { 0x3640, 0x17EB }, /* P_GR_P1Q0 */
+       { 0x3642, 0x3CAB }, /* P_GR_P1Q1 */
+       { 0x3644, 0x87CE }, /* P_GR_P1Q2 */
+       { 0x3646, 0xC02E }, /* P_GR_P1Q3 */
+       { 0x3648, 0xF48F }, /* P_GR_P1Q4 */
+       { 0x3680, 0x5350 }, /* P_GR_P2Q0 */
+       { 0x3682, 0x7EAF }, /* P_GR_P2Q1 */
+       { 0x3684, 0x4312 }, /* P_GR_P2Q2 */
+       { 0x3686, 0xC652 }, /* P_GR_P2Q3 */
+       { 0x3688, 0xBC15 }, /* P_GR_P2Q4 */
+       { 0x36C0, 0xB8AD }, /* P_GR_P3Q0 */
+       { 0x36C2, 0xBDCD }, /* P_GR_P3Q1 */
+       { 0x36C4, 0xE4B2 }, /* P_GR_P3Q2 */
+       { 0x36C6, 0xB50F }, /* P_GR_P3Q3 */
+       { 0x36C8, 0x5B95 }, /* P_GR_P3Q4 */
+       { 0x3700, 0xFC90 }, /* P_GR_P4Q0 */
+       { 0x3702, 0x8C51 }, /* P_GR_P4Q1 */
+       { 0x3704, 0xCED6 }, /* P_GR_P4Q2 */
+       { 0x3706, 0xB594 }, /* P_GR_P4Q3 */
+       { 0x3708, 0x0A39 }, /* P_GR_P4Q4 */
+       { 0x3614, 0x0230 }, /* P_BL_P0Q0 */
+       { 0x3616, 0x160D }, /* P_BL_P0Q1 */
+       { 0x3618, 0x08D1 }, /* P_BL_P0Q2 */
+       { 0x361A, 0x98AB }, /* P_BL_P0Q3 */
+       { 0x361C, 0xEA50 }, /* P_BL_P0Q4 */
+       { 0x3654, 0xB4EA }, /* P_BL_P1Q0 */
+       { 0x3656, 0xEA6C }, /* P_BL_P1Q1 */
+       { 0x3658, 0xFE08 }, /* P_BL_P1Q2 */
+       { 0x365A, 0x2C6E }, /* P_BL_P1Q3 */
+       { 0x365C, 0xEB0E }, /* P_BL_P1Q4 */
+       { 0x3694, 0x6DF0 }, /* P_BL_P2Q0 */
+       { 0x3696, 0x3ACF }, /* P_BL_P2Q1 */
+       { 0x3698, 0x3E0F }, /* P_BL_P2Q2 */
+       { 0x369A, 0xB2B1 }, /* P_BL_P2Q3 */
+       { 0x369C, 0xC374 }, /* P_BL_P2Q4 */
+       { 0x36D4, 0xF2AA }, /* P_BL_P3Q0 */
+       { 0x36D6, 0x8CCC }, /* P_BL_P3Q1 */
+       { 0x36D8, 0xDEF2 }, /* P_BL_P3Q2 */
+       { 0x36DA, 0xFA11 }, /* P_BL_P3Q3 */
+       { 0x36DC, 0x42F5 }, /* P_BL_P3Q4 */
+       { 0x3714, 0xF4F1 }, /* P_BL_P4Q0 */
+       { 0x3716, 0xF6F0 }, /* P_BL_P4Q1 */
+       { 0x3718, 0x8FD6 }, /* P_BL_P4Q2 */
+       { 0x371A, 0xEA14 }, /* P_BL_P4Q3 */
+       { 0x371C, 0x6338 }, /* P_BL_P4Q4 */
+       { 0x361E, 0x0350 }, /* P_GB_P0Q0 */
+       { 0x3620, 0x91AE }, /* P_GB_P0Q1 */
+       { 0x3622, 0x0571 }, /* P_GB_P0Q2 */
+       { 0x3624, 0x100D }, /* P_GB_P0Q3 */
+       { 0x3626, 0xCA70 }, /* P_GB_P0Q4 */
+       { 0x365E, 0xE6CB }, /* P_GB_P1Q0 */
+       { 0x3660, 0x50ED }, /* P_GB_P1Q1 */
+       { 0x3662, 0x3DAE }, /* P_GB_P1Q2 */
+       { 0x3664, 0xAA4F }, /* P_GB_P1Q3 */
+       { 0x3666, 0xDC50 }, /* P_GB_P1Q4 */
+       { 0x369E, 0x5470 }, /* P_GB_P2Q0 */
+       { 0x36A0, 0x1F6E }, /* P_GB_P2Q1 */
+       { 0x36A2, 0x6671 }, /* P_GB_P2Q2 */
+       { 0x36A4, 0xC010 }, /* P_GB_P2Q3 */
+       { 0x36A6, 0x8DF5 }, /* P_GB_P2Q4 */
+       { 0x36DE, 0x0B0C }, /* P_GB_P3Q0 */
+       { 0x36E0, 0x84CE }, /* P_GB_P3Q1 */
+       { 0x36E2, 0x8493 }, /* P_GB_P3Q2 */
+       { 0x36E4, 0xA610 }, /* P_GB_P3Q3 */
+       { 0x36E6, 0x50B5 }, /* P_GB_P3Q4 */
+       { 0x371E, 0x9651 }, /* P_GB_P4Q0 */
+       { 0x3720, 0x1EAB }, /* P_GB_P4Q1 */
+       { 0x3722, 0xAF76 }, /* P_GB_P4Q2 */
+       { 0x3724, 0xE4F4 }, /* P_GB_P4Q3 */
+       { 0x3726, 0x79F8 }, /* P_GB_P4Q4 */
+       { 0x3782, 0x0410 }, /* POLY_ORIGIN_C */
+       { 0x3784, 0x0320 }, /* POLY_ORIGIN_R  */
+       { 0x3780, 0x8000 } /* POLY_SC_ENABLE */
+};
+
+struct mt9t013_reg mt9t013_regs = {
+       .reg_pat = &mt9t013_reg_pat[0],
+       .reg_pat_size = ARRAY_SIZE(mt9t013_reg_pat),
+       .ttbl = &mt9t013_test_tbl[0],
+       .ttbl_size = ARRAY_SIZE(mt9t013_test_tbl),
+       .lctbl = &mt9t013_lc_tbl[0],
+       .lctbl_size = ARRAY_SIZE(mt9t013_lc_tbl),
+       .rftbl = &mt9t013_lc_tbl[0],    /* &mt9t013_rolloff_tbl[0], */
+       .rftbl_size = ARRAY_SIZE(mt9t013_lc_tbl)
+};
+
+
diff --git a/drivers/staging/dream/camera/s5k3e2fx.c b/drivers/staging/dream/camera/s5k3e2fx.c
new file mode 100644 (file)
index 0000000..edba198
--- /dev/null
@@ -0,0 +1,1310 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <media/msm_camera.h>
+#include <mach/gpio.h>
+#include <mach/camera.h>
+#include "s5k3e2fx.h"
+
+#define S5K3E2FX_REG_MODEL_ID   0x0000
+#define S5K3E2FX_MODEL_ID              0x3E2F
+
+/* PLL Registers */
+#define REG_PRE_PLL_CLK_DIV                    0x0305
+#define REG_PLL_MULTIPLIER_MSB                 0x0306
+#define REG_PLL_MULTIPLIER_LSB                 0x0307
+#define REG_VT_PIX_CLK_DIV                     0x0301
+#define REG_VT_SYS_CLK_DIV                     0x0303
+#define REG_OP_PIX_CLK_DIV                     0x0309
+#define REG_OP_SYS_CLK_DIV                     0x030B
+
+/* Data Format Registers */
+#define REG_CCP_DATA_FORMAT_MSB                0x0112
+#define REG_CCP_DATA_FORMAT_LSB                0x0113
+
+/* Output Size */
+#define REG_X_OUTPUT_SIZE_MSB                  0x034C
+#define REG_X_OUTPUT_SIZE_LSB                  0x034D
+#define REG_Y_OUTPUT_SIZE_MSB                  0x034E
+#define REG_Y_OUTPUT_SIZE_LSB                  0x034F
+
+/* Binning */
+#define REG_X_EVEN_INC                         0x0381
+#define REG_X_ODD_INC                          0x0383
+#define REG_Y_EVEN_INC                         0x0385
+#define REG_Y_ODD_INC                          0x0387
+/*Reserved register */
+#define REG_BINNING_ENABLE                     0x3014
+
+/* Frame Fotmat */
+#define REG_FRAME_LENGTH_LINES_MSB             0x0340
+#define REG_FRAME_LENGTH_LINES_LSB             0x0341
+#define REG_LINE_LENGTH_PCK_MSB                0x0342
+#define REG_LINE_LENGTH_PCK_LSB                0x0343
+
+/* MSR setting */
+/* Reserved registers */
+#define REG_SHADE_CLK_ENABLE                   0x30AC
+#define REG_SEL_CCP                            0x30C4
+#define REG_VPIX                               0x3024
+#define REG_CLAMP_ON                           0x3015
+#define REG_OFFSET                             0x307E
+
+/* CDS timing settings */
+/* Reserved registers */
+#define REG_LD_START                           0x3000
+#define REG_LD_END                             0x3001
+#define REG_SL_START                           0x3002
+#define REG_SL_END                             0x3003
+#define REG_RX_START                           0x3004
+#define REG_S1_START                           0x3005
+#define REG_S1_END                             0x3006
+#define REG_S1S_START                          0x3007
+#define REG_S1S_END                            0x3008
+#define REG_S3_START                           0x3009
+#define REG_S3_END                             0x300A
+#define REG_CMP_EN_START                       0x300B
+#define REG_CLP_SL_START                       0x300C
+#define REG_CLP_SL_END                         0x300D
+#define REG_OFF_START                          0x300E
+#define REG_RMP_EN_START                       0x300F
+#define REG_TX_START                           0x3010
+#define REG_TX_END                             0x3011
+#define REG_STX_WIDTH                          0x3012
+#define REG_TYPE1_AF_ENABLE                    0x3130
+#define DRIVER_ENABLED                         0x0001
+#define AUTO_START_ENABLED                     0x0010
+#define REG_NEW_POSITION                       0x3131
+#define REG_3152_RESERVED                      0x3152
+#define REG_315A_RESERVED                      0x315A
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204
+#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205
+#define REG_FINE_INTEGRATION_TIME              0x0200
+#define REG_COARSE_INTEGRATION_TIME            0x0202
+#define REG_COARSE_INTEGRATION_TIME_LSB   0x0203
+
+/* Mode select register */
+#define S5K3E2FX_REG_MODE_SELECT               0x0100
+#define S5K3E2FX_MODE_SELECT_STREAM            0x01   /* start streaming */
+#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00   /* software standby */
+#define S5K3E2FX_REG_SOFTWARE_RESET   0x0103
+#define S5K3E2FX_SOFTWARE_RESET                0x01
+#define REG_TEST_PATTERN_MODE                  0x0601
+
+struct reg_struct {
+       uint8_t pre_pll_clk_div;               /* 0x0305 */
+       uint8_t pll_multiplier_msb;            /* 0x0306 */
+       uint8_t pll_multiplier_lsb;            /* 0x0307 */
+       uint8_t vt_pix_clk_div;                /* 0x0301 */
+       uint8_t vt_sys_clk_div;                /* 0x0303 */
+       uint8_t op_pix_clk_div;                /* 0x0309 */
+       uint8_t op_sys_clk_div;                /* 0x030B */
+       uint8_t ccp_data_format_msb;           /* 0x0112 */
+       uint8_t ccp_data_format_lsb;           /* 0x0113 */
+       uint8_t x_output_size_msb;             /* 0x034C */
+       uint8_t x_output_size_lsb;             /* 0x034D */
+       uint8_t y_output_size_msb;             /* 0x034E */
+       uint8_t y_output_size_lsb;             /* 0x034F */
+       uint8_t x_even_inc;                    /* 0x0381 */
+       uint8_t x_odd_inc;                     /* 0x0383 */
+       uint8_t y_even_inc;                    /* 0x0385 */
+       uint8_t y_odd_inc;                     /* 0x0387 */
+       uint8_t binning_enable;                /* 0x3014 */
+       uint8_t frame_length_lines_msb;        /* 0x0340 */
+       uint8_t frame_length_lines_lsb;        /* 0x0341 */
+       uint8_t line_length_pck_msb;           /* 0x0342 */
+       uint8_t line_length_pck_lsb;           /* 0x0343 */
+       uint8_t shade_clk_enable ;             /* 0x30AC */
+       uint8_t sel_ccp;                       /* 0x30C4 */
+       uint8_t vpix;                          /* 0x3024 */
+       uint8_t clamp_on;                      /* 0x3015 */
+       uint8_t offset;                        /* 0x307E */
+       uint8_t ld_start;                      /* 0x3000 */
+       uint8_t ld_end;                        /* 0x3001 */
+       uint8_t sl_start;                      /* 0x3002 */
+       uint8_t sl_end;                        /* 0x3003 */
+       uint8_t rx_start;                      /* 0x3004 */
+       uint8_t s1_start;                      /* 0x3005 */
+       uint8_t s1_end;                        /* 0x3006 */
+       uint8_t s1s_start;                     /* 0x3007 */
+       uint8_t s1s_end;                       /* 0x3008 */
+       uint8_t s3_start;                      /* 0x3009 */
+       uint8_t s3_end;                        /* 0x300A */
+       uint8_t cmp_en_start;                  /* 0x300B */
+       uint8_t clp_sl_start;                  /* 0x300C */
+       uint8_t clp_sl_end;                    /* 0x300D */
+       uint8_t off_start;                     /* 0x300E */
+       uint8_t rmp_en_start;                  /* 0x300F */
+       uint8_t tx_start;                      /* 0x3010 */
+       uint8_t tx_end;                        /* 0x3011 */
+       uint8_t stx_width;                     /* 0x3012 */
+       uint8_t reg_3152_reserved;             /* 0x3152 */
+       uint8_t reg_315A_reserved;             /* 0x315A */
+       uint8_t analogue_gain_code_global_msb; /* 0x0204 */
+       uint8_t analogue_gain_code_global_lsb; /* 0x0205 */
+       uint8_t fine_integration_time;         /* 0x0200 */
+       uint8_t coarse_integration_time;       /* 0x0202 */
+       uint32_t size_h;
+       uint32_t blk_l;
+       uint32_t size_w;
+       uint32_t blk_p;
+};
+
+struct reg_struct s5k3e2fx_reg_pat[2] = {
+       { /* Preview */
+               0x06,  /* pre_pll_clk_div       REG=0x0305 */
+               0x00,  /* pll_multiplier_msb    REG=0x0306 */
+               0x88,  /* pll_multiplier_lsb    REG=0x0307 */
+               0x0a,  /* vt_pix_clk_div        REG=0x0301 */
+               0x01,  /* vt_sys_clk_div        REG=0x0303 */
+               0x0a,  /* op_pix_clk_div        REG=0x0309 */
+               0x01,  /* op_sys_clk_div        REG=0x030B */
+               0x0a,  /* ccp_data_format_msb   REG=0x0112 */
+               0x0a,  /* ccp_data_format_lsb   REG=0x0113 */
+               0x05,  /* x_output_size_msb     REG=0x034C */
+               0x10,  /* x_output_size_lsb     REG=0x034D */
+               0x03,  /* y_output_size_msb     REG=0x034E */
+               0xcc,  /* y_output_size_lsb     REG=0x034F */
+
+       /* enable binning for preview */
+               0x01,  /* x_even_inc             REG=0x0381 */
+               0x01,  /* x_odd_inc              REG=0x0383 */
+               0x01,  /* y_even_inc             REG=0x0385 */
+               0x03,  /* y_odd_inc              REG=0x0387 */
+               0x06,  /* binning_enable         REG=0x3014 */
+
+               0x03,  /* frame_length_lines_msb        REG=0x0340 */
+               0xde,  /* frame_length_lines_lsb        REG=0x0341 */
+               0x0a,  /* line_length_pck_msb           REG=0x0342 */
+               0xac,  /* line_length_pck_lsb           REG=0x0343 */
+               0x81,  /* shade_clk_enable              REG=0x30AC */
+               0x01,  /* sel_ccp                       REG=0x30C4 */
+               0x04,  /* vpix                          REG=0x3024 */
+               0x00,  /* clamp_on                      REG=0x3015 */
+               0x02,  /* offset                        REG=0x307E */
+               0x03,  /* ld_start                      REG=0x3000 */
+               0x9c,  /* ld_end                        REG=0x3001 */
+               0x02,  /* sl_start                      REG=0x3002 */
+               0x9e,  /* sl_end                        REG=0x3003 */
+               0x05,  /* rx_start                      REG=0x3004 */
+               0x0f,  /* s1_start                      REG=0x3005 */
+               0x24,  /* s1_end                        REG=0x3006 */
+               0x7c,  /* s1s_start                     REG=0x3007 */
+               0x9a,  /* s1s_end                       REG=0x3008 */
+               0x10,  /* s3_start                      REG=0x3009 */
+               0x14,  /* s3_end                        REG=0x300A */
+               0x10,  /* cmp_en_start                  REG=0x300B */
+               0x04,  /* clp_sl_start                  REG=0x300C */
+               0x26,  /* clp_sl_end                    REG=0x300D */
+               0x02,  /* off_start                     REG=0x300E */
+               0x0e,  /* rmp_en_start                  REG=0x300F */
+               0x30,  /* tx_start                      REG=0x3010 */
+               0x4e,  /* tx_end                        REG=0x3011 */
+               0x1E,  /* stx_width                     REG=0x3012 */
+               0x08,  /* reg_3152_reserved             REG=0x3152 */
+               0x10,  /* reg_315A_reserved             REG=0x315A */
+               0x00,  /* analogue_gain_code_global_msb REG=0x0204 */
+               0x80,  /* analogue_gain_code_global_lsb REG=0x0205 */
+               0x02,  /* fine_integration_time         REG=0x0200 */
+               0x03,  /* coarse_integration_time       REG=0x0202 */
+               972,
+               18,
+               1296,
+               1436
+       },
+       { /* Snapshot */
+               0x06,  /* pre_pll_clk_div               REG=0x0305 */
+               0x00,  /* pll_multiplier_msb            REG=0x0306 */
+               0x88,  /* pll_multiplier_lsb            REG=0x0307 */
+               0x0a,  /* vt_pix_clk_div                REG=0x0301 */
+               0x01,  /* vt_sys_clk_div                REG=0x0303 */
+               0x0a,  /* op_pix_clk_div                REG=0x0309 */
+               0x01,  /* op_sys_clk_div                REG=0x030B */
+               0x0a,  /* ccp_data_format_msb           REG=0x0112 */
+               0x0a,  /* ccp_data_format_lsb           REG=0x0113 */
+               0x0a,  /* x_output_size_msb             REG=0x034C */
+               0x30,  /* x_output_size_lsb             REG=0x034D */
+               0x07,  /* y_output_size_msb             REG=0x034E */
+               0xa8,  /* y_output_size_lsb             REG=0x034F */
+
+       /* disable binning for snapshot */
+               0x01,  /* x_even_inc                    REG=0x0381 */
+               0x01,  /* x_odd_inc                     REG=0x0383 */
+               0x01,  /* y_even_inc                    REG=0x0385 */
+               0x01,  /* y_odd_inc                     REG=0x0387 */
+               0x00,  /* binning_enable                REG=0x3014 */
+
+               0x07,  /* frame_length_lines_msb        REG=0x0340 */
+               0xb6,  /* frame_length_lines_lsb        REG=0x0341 */
+               0x0a,  /* line_length_pck_msb           REG=0x0342 */
+               0xac,  /* line_length_pck_lsb           REG=0x0343 */
+               0x81,  /* shade_clk_enable              REG=0x30AC */
+               0x01,  /* sel_ccp                       REG=0x30C4 */
+               0x04,  /* vpix                          REG=0x3024 */
+               0x00,  /* clamp_on                      REG=0x3015 */
+               0x02,  /* offset                        REG=0x307E */
+               0x03,  /* ld_start                      REG=0x3000 */
+               0x9c,  /* ld_end                        REG=0x3001 */
+               0x02,  /* sl_start                      REG=0x3002 */
+               0x9e,  /* sl_end                        REG=0x3003 */
+               0x05,  /* rx_start                      REG=0x3004 */
+               0x0f,  /* s1_start                      REG=0x3005 */
+               0x24,  /* s1_end                        REG=0x3006 */
+               0x7c,  /* s1s_start                     REG=0x3007 */
+               0x9a,  /* s1s_end                       REG=0x3008 */
+               0x10,  /* s3_start                      REG=0x3009 */
+               0x14,  /* s3_end                        REG=0x300A */
+               0x10,  /* cmp_en_start                  REG=0x300B */
+               0x04,  /* clp_sl_start                  REG=0x300C */
+               0x26,  /* clp_sl_end                    REG=0x300D */
+               0x02,  /* off_start                     REG=0x300E */
+               0x0e,  /* rmp_en_start                  REG=0x300F */
+               0x30,  /* tx_start                      REG=0x3010 */
+               0x4e,  /* tx_end                        REG=0x3011 */
+               0x1E,  /* stx_width                     REG=0x3012 */
+               0x08,  /* reg_3152_reserved             REG=0x3152 */
+               0x10,  /* reg_315A_reserved             REG=0x315A */
+               0x00,  /* analogue_gain_code_global_msb REG=0x0204 */
+               0x80,  /* analogue_gain_code_global_lsb REG=0x0205 */
+               0x02,  /* fine_integration_time         REG=0x0200 */
+               0x03,  /* coarse_integration_time       REG=0x0202 */
+               1960,
+               14,
+               2608,
+               124
+       }
+};
+
+struct s5k3e2fx_work {
+       struct work_struct work;
+};
+static struct s5k3e2fx_work *s5k3e2fx_sensorw;
+static struct i2c_client *s5k3e2fx_client;
+
+struct s5k3e2fx_ctrl {
+       const struct msm_camera_sensor_info *sensordata;
+
+       int sensormode;
+       uint32_t fps_divider; /* init to 1 * 0x00000400 */
+       uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */
+
+       uint16_t curr_lens_pos;
+       uint16_t init_curr_lens_pos;
+       uint16_t my_reg_gain;
+       uint32_t my_reg_line_count;
+
+       enum msm_s_resolution prev_res;
+       enum msm_s_resolution pict_res;
+       enum msm_s_resolution curr_res;
+       enum msm_s_test_mode  set_test;
+};
+
+struct s5k3e2fx_i2c_reg_conf {
+       unsigned short waddr;
+       unsigned char  bdata;
+};
+
+static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl;
+static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue);
+DECLARE_MUTEX(s5k3e2fx_sem);
+
+static int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
+       int length)
+{
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = saddr,
+                       .flags = 0,
+                       .len   = 2,
+                       .buf   = rxdata,
+               },
+               {
+                       .addr   = saddr,
+                       .flags = I2C_M_RD,
+                       .len   = length,
+                       .buf   = rxdata,
+               },
+       };
+
+       if (i2c_transfer(s5k3e2fx_client->adapter, msgs, 2) < 0) {
+               CDBG("s5k3e2fx_i2c_rxdata failed!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t s5k3e2fx_i2c_txdata(unsigned short saddr,
+       unsigned char *txdata, int length)
+{
+       struct i2c_msg msg[] = {
+               {
+               .addr  = saddr,
+               .flags = 0,
+               .len = length,
+               .buf = txdata,
+               },
+       };
+
+       if (i2c_transfer(s5k3e2fx_client->adapter, msg, 1) < 0) {
+               CDBG("s5k3e2fx_i2c_txdata failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int32_t s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr,
+       unsigned char bdata)
+{
+       int32_t rc = -EIO;
+       unsigned char buf[4];
+
+       memset(buf, 0, sizeof(buf));
+       buf[0] = (waddr & 0xFF00)>>8;
+       buf[1] = (waddr & 0x00FF);
+       buf[2] = bdata;
+
+       rc = s5k3e2fx_i2c_txdata(saddr, buf, 3);
+
+       if (rc < 0)
+               CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
+                       waddr, bdata);
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_i2c_write_table(
+       struct s5k3e2fx_i2c_reg_conf *reg_cfg_tbl, int num)
+{
+       int i;
+       int32_t rc = -EIO;
+       for (i = 0; i < num; i++) {
+               if (rc < 0)
+                       break;
+               reg_cfg_tbl++;
+       }
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr,
+       unsigned short *rdata)
+{
+       int32_t rc = 0;
+       unsigned char buf[4];
+
+       if (!rdata)
+               return -EIO;
+
+       memset(buf, 0, sizeof(buf));
+
+       buf[0] = (raddr & 0xFF00)>>8;
+       buf[1] = (raddr & 0x00FF);
+
+       rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2);
+       if (rc < 0)
+               return rc;
+
+       *rdata = buf[0] << 8 | buf[1];
+
+       if (rc < 0)
+               CDBG("s5k3e2fx_i2c_read failed!\n");
+
+       return rc;
+}
+
+static int s5k3e2fx_probe_init_done(const struct msm_camera_sensor_info *data)
+{
+       gpio_direction_output(data->sensor_reset, 0);
+       gpio_free(data->sensor_reset);
+       return 0;
+}
+
+static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data)
+{
+       int32_t  rc;
+       uint16_t chipid = 0;
+
+       rc = gpio_request(data->sensor_reset, "s5k3e2fx");
+       if (!rc)
+               gpio_direction_output(data->sensor_reset, 1);
+       else
+               goto init_probe_done;
+
+       mdelay(20);
+
+       CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n");
+
+       rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr,
+               S5K3E2FX_REG_MODEL_ID, &chipid);
+       if (rc < 0)
+               goto init_probe_fail;
+
+       if (chipid != S5K3E2FX_MODEL_ID) {
+               CDBG("S5K3E2FX wrong model_id = 0x%x\n", chipid);
+               rc = -ENODEV;
+               goto init_probe_fail;
+       }
+
+       goto init_probe_done;
+
+init_probe_fail:
+       s5k3e2fx_probe_init_done(data);
+init_probe_done:
+       return rc;
+}
+
+static int s5k3e2fx_init_client(struct i2c_client *client)
+{
+       /* Initialize the MSM_CAMI2C Chip */
+       init_waitqueue_head(&s5k3e2fx_wait_queue);
+       return 0;
+}
+
+static const struct i2c_device_id s5k3e2fx_i2c_id[] = {
+       { "s5k3e2fx", 0},
+       { }
+};
+
+static int s5k3e2fx_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       int rc = 0;
+       CDBG("s5k3e2fx_probe called!\n");
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               CDBG("i2c_check_functionality failed\n");
+               goto probe_failure;
+       }
+
+       s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL);
+       if (!s5k3e2fx_sensorw) {
+               CDBG("kzalloc failed.\n");
+               rc = -ENOMEM;
+               goto probe_failure;
+       }
+
+       i2c_set_clientdata(client, s5k3e2fx_sensorw);
+       s5k3e2fx_init_client(client);
+       s5k3e2fx_client = client;
+
+       mdelay(50);
+
+       CDBG("s5k3e2fx_probe successed! rc = %d\n", rc);
+       return 0;
+
+probe_failure:
+       CDBG("s5k3e2fx_probe failed! rc = %d\n", rc);
+       return rc;
+}
+
+static struct i2c_driver s5k3e2fx_i2c_driver = {
+       .id_table = s5k3e2fx_i2c_id,
+       .probe  = s5k3e2fx_i2c_probe,
+       .remove = __exit_p(s5k3e2fx_i2c_remove),
+       .driver = {
+               .name = "s5k3e2fx",
+       },
+};
+
+static int32_t s5k3e2fx_test(enum msm_s_test_mode mo)
+{
+       int32_t rc = 0;
+
+       if (mo == S_TEST_OFF)
+               rc = 0;
+       else
+               rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+                       REG_TEST_PATTERN_MODE, (uint16_t)mo);
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_setting(enum msm_s_reg_update rupdate,
+       enum msm_s_setting rt)
+{
+       int32_t rc = 0;
+       uint16_t num_lperf;
+
+       switch (rupdate) {
+       case S_UPDATE_PERIODIC:
+       if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
+
+               struct s5k3e2fx_i2c_reg_conf tbl_1[] = {
+               {REG_CCP_DATA_FORMAT_MSB, s5k3e2fx_reg_pat[rt].ccp_data_format_msb},
+               {REG_CCP_DATA_FORMAT_LSB, s5k3e2fx_reg_pat[rt].ccp_data_format_lsb},
+               {REG_X_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].x_output_size_msb},
+               {REG_X_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].x_output_size_lsb},
+               {REG_Y_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].y_output_size_msb},
+               {REG_Y_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].y_output_size_lsb},
+               {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc},
+               {REG_X_ODD_INC,  s5k3e2fx_reg_pat[rt].x_odd_inc},
+               {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc},
+               {REG_Y_ODD_INC,  s5k3e2fx_reg_pat[rt].y_odd_inc},
+               {REG_BINNING_ENABLE, s5k3e2fx_reg_pat[rt].binning_enable},
+               };
+
+               struct s5k3e2fx_i2c_reg_conf tbl_2[] = {
+                       {REG_FRAME_LENGTH_LINES_MSB, 0},
+                       {REG_FRAME_LENGTH_LINES_LSB, 0},
+                       {REG_LINE_LENGTH_PCK_MSB, s5k3e2fx_reg_pat[rt].line_length_pck_msb},
+                       {REG_LINE_LENGTH_PCK_LSB, s5k3e2fx_reg_pat[rt].line_length_pck_lsb},
+                       {REG_SHADE_CLK_ENABLE, s5k3e2fx_reg_pat[rt].shade_clk_enable},
+                       {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp},
+                       {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix},
+                       {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on},
+                       {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset},
+                       {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start},
+                       {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end},
+                       {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start},
+                       {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end},
+                       {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start},
+                       {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start},
+                       {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end},
+                       {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start},
+                       {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end},
+                       {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start},
+                       {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end},
+                       {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start},
+                       {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start},
+                       {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end},
+                       {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start},
+                       {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start},
+                       {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start},
+                       {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end},
+                       {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width},
+                       {REG_3152_RESERVED, s5k3e2fx_reg_pat[rt].reg_3152_reserved},
+                       {REG_315A_RESERVED, s5k3e2fx_reg_pat[rt].reg_315A_reserved},
+                       {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_msb},
+                       {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_lsb},
+                       {REG_FINE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].fine_integration_time},
+                       {REG_COARSE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].coarse_integration_time},
+                       {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM},
+               };
+
+               rc = s5k3e2fx_i2c_write_table(&tbl_1[0],
+                       ARRAY_SIZE(tbl_1));
+               if (rc < 0)
+                       return rc;
+
+               num_lperf =
+                       (uint16_t)((s5k3e2fx_reg_pat[rt].frame_length_lines_msb << 8) & 0xFF00) +
+                               s5k3e2fx_reg_pat[rt].frame_length_lines_lsb;
+
+               num_lperf = num_lperf * s5k3e2fx_ctrl->fps_divider / 0x0400;
+
+               tbl_2[0] = (struct s5k3e2fx_i2c_reg_conf) {REG_FRAME_LENGTH_LINES_MSB, (num_lperf & 0xFF00) >> 8};
+               tbl_2[1] = (struct s5k3e2fx_i2c_reg_conf) {REG_FRAME_LENGTH_LINES_LSB, (num_lperf & 0x00FF)};
+
+               rc = s5k3e2fx_i2c_write_table(&tbl_2[0],
+                       ARRAY_SIZE(tbl_2));
+               if (rc < 0)
+                       return rc;
+
+               mdelay(5);
+
+               rc = s5k3e2fx_test(s5k3e2fx_ctrl->set_test);
+               if (rc < 0)
+                       return rc;
+       }
+       break; /* UPDATE_PERIODIC */
+
+       case S_REG_INIT:
+       if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
+
+               struct s5k3e2fx_i2c_reg_conf tbl_3[] = {
+                       {S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET},
+                       {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_SW_STANDBY},
+                       /* PLL setting */
+                       {REG_PRE_PLL_CLK_DIV, s5k3e2fx_reg_pat[rt].pre_pll_clk_div},
+                       {REG_PLL_MULTIPLIER_MSB, s5k3e2fx_reg_pat[rt].pll_multiplier_msb},
+                       {REG_PLL_MULTIPLIER_LSB, s5k3e2fx_reg_pat[rt].pll_multiplier_lsb},
+                       {REG_VT_PIX_CLK_DIV, s5k3e2fx_reg_pat[rt].vt_pix_clk_div},
+                       {REG_VT_SYS_CLK_DIV, s5k3e2fx_reg_pat[rt].vt_sys_clk_div},
+                       {REG_OP_PIX_CLK_DIV, s5k3e2fx_reg_pat[rt].op_pix_clk_div},
+                       {REG_OP_SYS_CLK_DIV, s5k3e2fx_reg_pat[rt].op_sys_clk_div},
+                       /*Data Format */
+                       {REG_CCP_DATA_FORMAT_MSB, s5k3e2fx_reg_pat[rt].ccp_data_format_msb},
+                       {REG_CCP_DATA_FORMAT_LSB, s5k3e2fx_reg_pat[rt].ccp_data_format_lsb},
+                       /*Output Size */
+                       {REG_X_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].x_output_size_msb},
+                       {REG_X_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].x_output_size_lsb},
+                       {REG_Y_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].y_output_size_msb},
+                       {REG_Y_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].y_output_size_lsb},
+                       /* Binning */
+                       {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc},
+                       {REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc },
+                       {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc},
+                       {REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc},
+                       {REG_BINNING_ENABLE, s5k3e2fx_reg_pat[rt].binning_enable},
+                       /* Frame format */
+                       {REG_FRAME_LENGTH_LINES_MSB, s5k3e2fx_reg_pat[rt].frame_length_lines_msb},
+                       {REG_FRAME_LENGTH_LINES_LSB, s5k3e2fx_reg_pat[rt].frame_length_lines_lsb},
+                       {REG_LINE_LENGTH_PCK_MSB, s5k3e2fx_reg_pat[rt].line_length_pck_msb},
+                       {REG_LINE_LENGTH_PCK_LSB, s5k3e2fx_reg_pat[rt].line_length_pck_lsb},
+                       /* MSR setting */
+                       {REG_SHADE_CLK_ENABLE, s5k3e2fx_reg_pat[rt].shade_clk_enable},
+                       {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp},
+                       {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix},
+                       {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on},
+                       {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset},
+                       /* CDS timing setting */
+                       {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start},
+                       {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end},
+                       {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start},
+                       {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end},
+                       {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start},
+                       {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start},
+                       {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end},
+                       {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start},
+                       {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end},
+                       {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start},
+                       {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end},
+                       {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start},
+                       {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start},
+                       {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end},
+                       {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start},
+                       {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start},
+                       {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start},
+                       {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end},
+                       {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width},
+                       {REG_3152_RESERVED, s5k3e2fx_reg_pat[rt].reg_3152_reserved},
+                       {REG_315A_RESERVED, s5k3e2fx_reg_pat[rt].reg_315A_reserved},
+                       {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_msb},
+                       {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_lsb},
+                       {REG_FINE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].fine_integration_time},
+                       {REG_COARSE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].coarse_integration_time},
+                       {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM},
+               };
+
+               /* reset fps_divider */
+               s5k3e2fx_ctrl->fps_divider = 1 * 0x0400;
+               rc = s5k3e2fx_i2c_write_table(&tbl_3[0],
+                       ARRAY_SIZE(tbl_3));
+               if (rc < 0)
+                       return rc;
+       }
+       break; /* case REG_INIT: */
+
+       default:
+               rc = -EINVAL;
+               break;
+       } /* switch (rupdate) */
+
+       return rc;
+}
+
+static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data)
+{
+       int32_t  rc;
+
+       s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL);
+       if (!s5k3e2fx_ctrl) {
+               CDBG("s5k3e2fx_init failed!\n");
+               rc = -ENOMEM;
+               goto init_done;
+       }
+
+       s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400;
+       s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400;
+       s5k3e2fx_ctrl->set_test = S_TEST_OFF;
+       s5k3e2fx_ctrl->prev_res = S_QTR_SIZE;
+       s5k3e2fx_ctrl->pict_res = S_FULL_SIZE;
+
+       if (data)
+               s5k3e2fx_ctrl->sensordata = data;
+
+       /* enable mclk first */
+       msm_camio_clk_rate_set(24000000);
+       mdelay(20);
+
+       msm_camio_camif_pad_reg_reset();
+       mdelay(20);
+
+       rc = s5k3e2fx_probe_init_sensor(data);
+       if (rc < 0)
+               goto init_fail1;
+
+       if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE)
+               rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW);
+       else
+               rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE);
+
+       if (rc < 0) {
+               CDBG("s5k3e2fx_setting failed. rc = %d\n", rc);
+               goto init_fail1;
+       }
+
+       /* initialize AF */
+       if ((rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+                       0x3146, 0x3A)) < 0)
+               goto init_fail1;
+
+       if ((rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+                       0x3130, 0x03)) < 0)
+               goto init_fail1;
+
+       goto init_done;
+
+init_fail1:
+       s5k3e2fx_probe_init_done(data);
+       kfree(s5k3e2fx_ctrl);
+init_done:
+       return rc;
+}
+
+static int32_t s5k3e2fx_power_down(void)
+{
+       int32_t rc = 0;
+       return rc;
+}
+
+static int s5k3e2fx_sensor_release(void)
+{
+       int rc = -EBADF;
+
+       down(&s5k3e2fx_sem);
+
+       s5k3e2fx_power_down();
+
+       gpio_direction_output(s5k3e2fx_ctrl->sensordata->sensor_reset,
+               0);
+       gpio_free(s5k3e2fx_ctrl->sensordata->sensor_reset);
+
+       kfree(s5k3e2fx_ctrl);
+       s5k3e2fx_ctrl = NULL;
+
+       CDBG("s5k3e2fx_release completed\n");
+
+       up(&s5k3e2fx_sem);
+       return rc;
+}
+
+static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps)
+{
+       /* input fps is preview fps in Q8 format */
+       uint32_t divider;   /* Q10 */
+
+       divider = (uint32_t)
+               ((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+                       s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+                (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+                       s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 /
+               ((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+                       s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) *
+                (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+                       s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p));
+
+       /* Verify PCLK settings and frame sizes. */
+       *pfps = (uint16_t)(fps * divider / 0x00000400);
+}
+
+static uint16_t s5k3e2fx_get_prev_lines_pf(void)
+{
+       return (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+               s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l);
+}
+
+static uint16_t s5k3e2fx_get_prev_pixels_pl(void)
+{
+       return (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+               s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p);
+}
+
+static uint16_t s5k3e2fx_get_pict_lines_pf(void)
+{
+       return (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+               s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l);
+}
+
+static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
+{
+       return (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+               s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p);
+}
+
+static uint32_t s5k3e2fx_get_pict_max_exp_lc(void)
+{
+       uint32_t snapshot_lines_per_frame;
+
+       if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE)
+               snapshot_lines_per_frame =
+               s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+               s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
+       else
+               snapshot_lines_per_frame = 3961 * 3;
+
+       return snapshot_lines_per_frame;
+}
+
+static int32_t s5k3e2fx_set_fps(struct fps_cfg *fps)
+{
+       /* input is new fps in Q10 format */
+       int32_t rc = 0;
+
+       s5k3e2fx_ctrl->fps_divider = fps->fps_div;
+
+       rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+               REG_FRAME_LENGTH_LINES_MSB,
+               (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+                       s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+                       s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00) >> 8);
+       if (rc < 0)
+               goto set_fps_done;
+
+       rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+               REG_FRAME_LENGTH_LINES_LSB,
+               (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+                       s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
+                       s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00));
+
+set_fps_done:
+       return rc;
+}
+
+static int32_t s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line)
+{
+       int32_t rc = 0;
+
+       uint16_t max_legal_gain = 0x0200;
+       uint32_t ll_ratio; /* Q10 */
+       uint16_t ll_pck, fl_lines;
+       uint16_t offset = 4;
+       uint8_t  gain_msb, gain_lsb;
+       uint8_t  intg_t_msb, intg_t_lsb;
+       uint8_t  ll_pck_msb, ll_pck_lsb, tmp;
+
+       struct s5k3e2fx_i2c_reg_conf tbl[2];
+
+       CDBG("Line:%d s5k3e2fx_write_exp_gain \n", __LINE__);
+
+       if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
+
+               s5k3e2fx_ctrl->my_reg_gain = gain;
+               s5k3e2fx_ctrl->my_reg_line_count = (uint16_t)line;
+
+               fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
+                       s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
+
+               ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
+                       s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
+
+       } else {
+
+               fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
+                       s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
+
+               ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
+                       s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
+       }
+
+       if (gain > max_legal_gain)
+               gain = max_legal_gain;
+
+       /* in Q10 */
+       line = (line * s5k3e2fx_ctrl->fps_divider);
+
+       if (fl_lines < (line / 0x400))
+               ll_ratio = (line / (fl_lines - offset));
+       else
+               ll_ratio = 0x400;
+
+       /* update gain registers */
+       gain_msb = (gain & 0xFF00) >> 8;
+       gain_lsb = gain & 0x00FF;
+       tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB;
+       tbl[0].bdata = gain_msb;
+       tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB;
+       tbl[1].bdata = gain_lsb;
+       rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+       if (rc < 0)
+               goto write_gain_done;
+
+       ll_pck = ll_pck * ll_ratio;
+       ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8;
+       ll_pck_lsb = (ll_pck / 0x400) & 0x00FF;
+       tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB;
+       tbl[0].bdata = s5k3e2fx_reg_pat[S_RES_PREVIEW].line_length_pck_msb;
+       tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB;
+       tbl[1].bdata = s5k3e2fx_reg_pat[S_RES_PREVIEW].line_length_pck_lsb;
+       rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+       if (rc < 0)
+               goto write_gain_done;
+
+       tmp = (ll_pck * 0x400) / ll_ratio;
+       intg_t_msb = (tmp & 0xFF00) >> 8;
+       intg_t_lsb = (tmp & 0x00FF);
+       tbl[0].waddr = REG_COARSE_INTEGRATION_TIME;
+       tbl[0].bdata = intg_t_msb;
+       tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB;
+       tbl[1].bdata = intg_t_lsb;
+       rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
+
+write_gain_done:
+       return rc;
+}
+
+static int32_t s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line)
+{
+       int32_t rc = 0;
+
+       CDBG("Line:%d s5k3e2fx_set_pict_exp_gain \n", __LINE__);
+
+       rc =
+               s5k3e2fx_write_exp_gain(gain, line);
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_video_config(int mode, int res)
+{
+       int32_t rc;
+
+       switch (res) {
+       case S_QTR_SIZE:
+               rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW);
+               if (rc < 0)
+                       return rc;
+
+               CDBG("s5k3e2fx sensor configuration done!\n");
+               break;
+
+       case S_FULL_SIZE:
+               rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+               if (rc < 0)
+                       return rc;
+
+               break;
+
+       default:
+               return 0;
+       } /* switch */
+
+       s5k3e2fx_ctrl->prev_res = res;
+       s5k3e2fx_ctrl->curr_res = res;
+       s5k3e2fx_ctrl->sensormode = mode;
+
+       rc =
+               s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain,
+                       s5k3e2fx_ctrl->my_reg_line_count);
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_snapshot_config(int mode)
+{
+       int32_t rc = 0;
+
+       rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+       if (rc < 0)
+               return rc;
+
+       s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res;
+       s5k3e2fx_ctrl->sensormode = mode;
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_raw_snapshot_config(int mode)
+{
+       int32_t rc = 0;
+
+       rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
+       if (rc < 0)
+               return rc;
+
+       s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res;
+       s5k3e2fx_ctrl->sensormode = mode;
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_set_sensor_mode(int mode, int res)
+{
+       int32_t rc = 0;
+
+       switch (mode) {
+       case SENSOR_PREVIEW_MODE:
+               rc = s5k3e2fx_video_config(mode, res);
+               break;
+
+       case SENSOR_SNAPSHOT_MODE:
+               rc = s5k3e2fx_snapshot_config(mode);
+               break;
+
+       case SENSOR_RAW_SNAPSHOT_MODE:
+               rc = s5k3e2fx_raw_snapshot_config(mode);
+               break;
+
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_set_default_focus(void)
+{
+       int32_t rc = 0;
+
+       rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+                       0x3131, 0);
+       if (rc < 0)
+               return rc;
+
+       rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
+                       0x3132, 0);
+       if (rc < 0)
+               return rc;
+
+       s5k3e2fx_ctrl->curr_lens_pos = 0;
+
+       return rc;
+}
+
+static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps)
+{
+       int32_t rc = 0;
+       int32_t i;
+       int16_t step_direction;
+       int16_t actual_step;
+       int16_t next_pos, pos_offset;
+       int16_t init_code = 50;
+       uint8_t next_pos_msb, next_pos_lsb;
+       int16_t s_move[5];
+       uint32_t gain; /* Q10 format */
+
+       if (direction == MOVE_NEAR)
+               step_direction = 20;
+       else if (direction == MOVE_FAR)
+               step_direction = -20;
+       else {
+               CDBG("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__);
+               return -EINVAL;
+       }
+
+       actual_step = step_direction * (int16_t)num_steps;
+       pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos;
+       gain = actual_step * 0x400 / 5;
+
+       for (i = 0; i <= 4; i++) {
+               if (actual_step >= 0)
+                       s_move[i] = ((((i+1)*gain+0x200) - (i*gain+0x200))/0x400);
+               else
+                       s_move[i] = ((((i+1)*gain-0x200) - (i*gain-0x200))/0x400);
+       }
+
+       /* Ring Damping Code */
+       for (i = 0; i <= 4; i++) {
+               next_pos = (int16_t)(pos_offset + s_move[i]);
+
+               if (next_pos > (738 + init_code))
+                       next_pos = 738 + init_code;
+               else if (next_pos < 0)
+                       next_pos = 0;
+
+               CDBG("next_position in damping mode = %d\n", next_pos);
+               /* Writing the Values to the actuator */
+               if (next_pos == init_code)
+                       next_pos = 0x00;
+
+               next_pos_msb = next_pos >> 8;
+               next_pos_lsb = next_pos & 0x00FF;
+
+               rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131, next_pos_msb);
+               if (rc < 0)
+                       break;
+
+               rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132, next_pos_lsb);
+               if (rc < 0)
+                       break;
+
+               pos_offset = next_pos;
+               s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code;
+               if (i < 4)
+                       mdelay(3);
+       }
+
+       return rc;
+}
+
+static int s5k3e2fx_sensor_config(void __user *argp)
+{
+       struct sensor_cfg_data cdata;
+       long   rc = 0;
+
+       if (copy_from_user(&cdata,
+                       (void *)argp,
+                       sizeof(struct sensor_cfg_data)))
+               return -EFAULT;
+
+       down(&s5k3e2fx_sem);
+
+       CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
+       switch (cdata.cfgtype) {
+       case CFG_GET_PICT_FPS:
+               s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps,
+                       &(cdata.cfg.gfps.pictfps));
+
+               if (copy_to_user((void *)argp, &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PREV_L_PF:
+               cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PREV_P_PL:
+               cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_L_PF:
+               cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_P_PL:
+               cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_GET_PICT_MAX_EXP_LC:
+               cdata.cfg.pict_max_exp_lc =
+                       s5k3e2fx_get_pict_max_exp_lc();
+
+               if (copy_to_user((void *)argp,
+                               &cdata,
+                               sizeof(struct sensor_cfg_data)))
+                       rc = -EFAULT;
+               break;
+
+       case CFG_SET_FPS:
+       case CFG_SET_PICT_FPS:
+               rc = s5k3e2fx_set_fps(&(cdata.cfg.fps));
+               break;
+
+       case CFG_SET_EXP_GAIN:
+               rc =
+                       s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain,
+                               cdata.cfg.exp_gain.line);
+               break;
+
+       case CFG_SET_PICT_EXP_GAIN:
+               CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__);
+               rc =
+                       s5k3e2fx_set_pict_exp_gain(
+                               cdata.cfg.exp_gain.gain,
+                               cdata.cfg.exp_gain.line);
+               break;
+
+       case CFG_SET_MODE:
+               rc =
+                       s5k3e2fx_set_sensor_mode(
+                       cdata.mode, cdata.rs);
+               break;
+
+       case CFG_PWR_DOWN:
+               rc = s5k3e2fx_power_down();
+               break;
+
+       case CFG_MOVE_FOCUS:
+               rc =
+                       s5k3e2fx_move_focus(
+                       cdata.cfg.focus.dir,
+                       cdata.cfg.focus.steps);
+               break;
+
+       case CFG_SET_DEFAULT_FOCUS:
+               rc =
+                       s5k3e2fx_set_default_focus();
+               break;
+
+       case CFG_GET_AF_MAX_STEPS:
+       case CFG_SET_EFFECT:
+       case CFG_SET_LENS_SHADING:
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       up(&s5k3e2fx_sem);
+       return rc;
+}
+
+static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info,
+               struct msm_sensor_ctrl *s)
+{
+       int rc = 0;
+
+       rc = i2c_add_driver(&s5k3e2fx_i2c_driver);
+       if (rc < 0 || s5k3e2fx_client == NULL) {
+               rc = -ENOTSUPP;
+               goto probe_fail;
+       }
+
+       msm_camio_clk_rate_set(24000000);
+       mdelay(20);
+
+       rc = s5k3e2fx_probe_init_sensor(info);
+       if (rc < 0)
+               goto probe_fail;
+
+       s->s_init = s5k3e2fx_sensor_open_init;
+       s->s_release = s5k3e2fx_sensor_release;
+       s->s_config  = s5k3e2fx_sensor_config;
+       s5k3e2fx_probe_init_done(info);
+
+       return rc;
+
+probe_fail:
+       CDBG("SENSOR PROBE FAILS!\n");
+       return rc;
+}
+
+static int __s5k3e2fx_probe(struct platform_device *pdev)
+{
+       return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe);
+}
+
+static struct platform_driver msm_camera_driver = {
+       .probe = __s5k3e2fx_probe,
+       .driver = {
+               .name = "msm_camera_s5k3e2fx",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s5k3e2fx_init(void)
+{
+       return platform_driver_register(&msm_camera_driver);
+}
+
+module_init(s5k3e2fx_init);
+
diff --git a/drivers/staging/dream/camera/s5k3e2fx.h b/drivers/staging/dream/camera/s5k3e2fx.h
new file mode 100644 (file)
index 0000000..69bc750
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#ifndef CAMSENSOR_S5K3E2FX
+#define CAMSENSOR_S5K3E2FX
+
+#include <mach/board.h>
+#endif /* CAMSENSOR_S5K3E2FX */