--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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(®ion->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,
+ ®ion, 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,
+ ®ion, 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, ®ion[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 = ®ion[0];
+ data = &axi_data;
+ break;
+ case CMD_STATS_AF_ENABLE:
+ axi_data.bufnum1 =
+ msm_pmem_region_lookup(&sync->stats,
+ MSM_PMEM_AF, ®ion[0],
+ NUM_AF_STAT_OUTPUT_BUFFERS);
+ if (!axi_data.bufnum1) {
+ pr_err("%s: pmem region lookup error\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ axi_data.region = ®ion[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,
+ ®ion[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,
+ ®ion[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,
+ ®ion[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,
+ ®ion[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,
+ ®ion[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 = ®ion[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,
+ ®ion[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 = ®ion[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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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");
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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)
+};
+
+
+
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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)
+};
+
+
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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)
+};
+
+
--- /dev/null
+/*
+ * 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);
+
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 QUALCOMM Incorporated.
+ */
+
+#ifndef CAMSENSOR_S5K3E2FX
+#define CAMSENSOR_S5K3E2FX
+
+#include <mach/board.h>
+#endif /* CAMSENSOR_S5K3E2FX */