]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
CCI: Add QC MSM CCI driver
authorTodor Tomov <todor.tomov@linaro.org>
Thu, 31 Mar 2016 09:16:57 +0000 (12:16 +0300)
committerTodor Tomov <todor.tomov@linaro.org>
Tue, 7 Jun 2016 15:38:13 +0000 (18:38 +0300)
Add driver for QC MSM Camera Control Interface cotroller.
This is only temporary version to allow controlling the
camera sensor. Proper implementation will follow.

Signed-off-by: Todor Tomov <todor.tomov@linaro.org>
drivers/media/platform/msm/Kconfig
drivers/media/platform/msm/Makefile
drivers/media/platform/msm/cci/Kconfig [new file with mode: 0644]
drivers/media/platform/msm/cci/Makefile [new file with mode: 0644]
drivers/media/platform/msm/cci/msm_cam_cci_hwreg.h [new file with mode: 0644]
drivers/media/platform/msm/cci/msm_camsensor_sdk.h [new file with mode: 0644]
drivers/media/platform/msm/cci/msm_cci.c [new file with mode: 0644]
drivers/media/platform/msm/cci/msm_cci.h [new file with mode: 0644]

index 4b4a899ff51cd825042acf501f4582737720e46c..7a24e7a636473bdf11acebed2be7517efea2e170 100644 (file)
@@ -1,8 +1,9 @@
-#
+
 # MSM camera configuration
 #
 
 comment "Qualcomm MSM Camera And Video"
 
 source "drivers/media/platform/msm/camss-8x16/Kconfig"
+source "drivers/media/platform/msm/cci/Kconfig"
 source "drivers/media/platform/msm/vidc/Kconfig"
index ef6fd4bd795fe61381c0aee4a742fe5c81504a82..b2572e5c815ef86459a056ec851252537c5b1d59 100644 (file)
@@ -4,4 +4,5 @@
 #
 
 obj-$(CONFIG_MSM_CAMSS_V4L2)    += camss-8x16/
+obj-$(CONFIG_MSM_CCI)           += cci/
 obj-$(CONFIG_MSM_VIDC_V4L2)     += vidc/
diff --git a/drivers/media/platform/msm/cci/Kconfig b/drivers/media/platform/msm/cci/Kconfig
new file mode 100644 (file)
index 0000000..df6b954
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# CAMERA CONTROL INTERFACE
+#
+
+menuconfig MSM_CCI
+       tristate "Qualcomm MSM camera control interface driver"
+       depends on ARCH_QCOM
diff --git a/drivers/media/platform/msm/cci/Makefile b/drivers/media/platform/msm/cci/Makefile
new file mode 100644 (file)
index 0000000..833f00e
--- /dev/null
@@ -0,0 +1,7 @@
+# Makefile for Qualcomm cci driver
+
+ccflags-y += -Idrivers/media/platform/msm/cci
+msm-cci-objs += \
+               cci.o \
+
+obj-$(CONFIG_MSM_CCI) += msm_cci.o
diff --git a/drivers/media/platform/msm/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/cci/msm_cam_cci_hwreg.h
new file mode 100644 (file)
index 0000000..059633b
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+   *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CAM_CCI_HWREG__
+#define __MSM_CAM_CCI_HWREG__
+
+#define CCI_HW_VERSION_ADDR                                         0x00000000
+#define CCI_RESET_CMD_ADDR                                          0x00000004
+#define CCI_RESET_CMD_RMSK                                          0x0f73f3f7
+#define CCI_M0_RESET_RMSK                                                0x3F1
+#define CCI_M1_RESET_RMSK                                              0x3F001
+#define CCI_QUEUE_START_ADDR                                        0x00000008
+#define CCI_SET_CID_SYNC_TIMER_0_ADDR                               0x00000010
+#define CCI_I2C_M0_SCL_CTL_ADDR                                     0x00000100
+#define CCI_I2C_M0_SDA_CTL_0_ADDR                                   0x00000104
+#define CCI_I2C_M0_SDA_CTL_1_ADDR                                   0x00000108
+#define CCI_I2C_M0_SDA_CTL_2_ADDR                                   0x0000010c
+#define CCI_I2C_M0_READ_DATA_ADDR                                   0x00000118
+#define CCI_I2C_M0_MISC_CTL_ADDR                                    0x00000110
+#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR                              0x0000011C
+#define CCI_HALT_REQ_ADDR                                           0x00000034
+#define CCI_M0_HALT_REQ_RMSK                                               0x1
+#define CCI_M1_HALT_REQ_RMSK                                               0x2
+#define CCI_I2C_M1_SCL_CTL_ADDR                                     0x00000200
+#define CCI_I2C_M1_SDA_CTL_0_ADDR                                   0x00000204
+#define CCI_I2C_M1_SDA_CTL_1_ADDR                                   0x00000208
+#define CCI_I2C_M1_SDA_CTL_2_ADDR                                   0x0000020c
+#define CCI_I2C_M1_MISC_CTL_ADDR                                    0x00000210
+#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR                             0x00000304
+#define CCI_I2C_M0_Q0_CUR_CMD_ADDR                                  0x00000308
+#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR                            0x00000300
+#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR                                0x00000310
+#define CCI_IRQ_MASK_0_ADDR                                         0x00000c04
+#define CCI_IRQ_MASK_0_RMSK                                         0x7fff7ff7
+#define CCI_IRQ_CLEAR_0_ADDR                                        0x00000c08
+#define CCI_IRQ_STATUS_0_ADDR                                       0x00000c0c
+#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK                   0x4000000
+#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK                   0x2000000
+#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK                           0x1000000
+#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK                        0x100000
+#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK                         0x10000
+#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK                            0x1000
+#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK                           0x100
+#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK                            0x10
+#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK                          0x18000EE6
+#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK                          0x60EE6000
+#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK                               0x1
+#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR                               0x00000c00
+#endif /* __MSM_CAM_CCI_HWREG__ */
diff --git a/drivers/media/platform/msm/cci/msm_camsensor_sdk.h b/drivers/media/platform/msm/cci/msm_camsensor_sdk.h
new file mode 100644 (file)
index 0000000..d10617a
--- /dev/null
@@ -0,0 +1,335 @@
+#ifndef __LINUX_MSM_CAMSENSOR_SDK_H
+#define __LINUX_MSM_CAMSENSOR_SDK_H
+
+#include <linux/v4l2-mediabus.h>
+
+#define KVERSION 0x1
+
+#define MAX_POWER_CONFIG      12
+#define GPIO_OUT_LOW          (0 << 1)
+#define GPIO_OUT_HIGH         (1 << 1)
+#define CSI_EMBED_DATA        0x12
+#define CSI_RESERVED_DATA_0   0x13
+#define CSI_YUV422_8          0x1E
+#define CSI_RAW8              0x2A
+#define CSI_RAW10             0x2B
+#define CSI_RAW12             0x2C
+#define CSI_DECODE_6BIT         0
+#define CSI_DECODE_8BIT         1
+#define CSI_DECODE_10BIT        2
+#define CSI_DECODE_DPCM_10_8_10 5
+#define MAX_CID                 16
+#define I2C_SEQ_REG_DATA_MAX    256
+#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */
+
+#define MAX_ACTUATOR_REG_TBL_SIZE 8
+#define MAX_ACTUATOR_REGION       5
+#define NUM_ACTUATOR_DIR          2
+#define MAX_ACTUATOR_SCENARIO     8
+#define MAX_ACT_MOD_NAME_SIZE     32
+#define MAX_ACT_NAME_SIZE         32
+#define MAX_ACTUATOR_INIT_SET     12
+#define MAX_I2C_REG_SET           12
+
+#define MAX_NAME_SIZE             32
+#define MAX_FLASH_NUM             8
+
+enum msm_sensor_camera_id_t {
+       CAMERA_0,
+       CAMERA_1,
+       CAMERA_2,
+       CAMERA_3,
+       MAX_CAMERAS,
+};
+
+enum i2c_freq_mode_t {
+       I2C_STANDARD_MODE,
+       I2C_FAST_MODE,
+       I2C_CUSTOM_MODE,
+       I2C_MAX_MODES,
+};
+
+enum camb_position_t {
+       BACK_CAMERA_B,
+       FRONT_CAMERA_B,
+       INVALID_CAMERA_B,
+};
+
+enum msm_sensor_power_seq_type_t {
+       SENSOR_CLK,
+       SENSOR_GPIO,
+       SENSOR_VREG,
+       SENSOR_I2C_MUX,
+       SENSOR_I2C,
+};
+
+enum msm_camera_qup_i2c_write_batch_size_t {
+       MSM_CAMERA_I2C_BATCH_SIZE_1 = 1,
+       MSM_CAMERA_I2C_BATCH_SIZE_2,
+       MSM_CAMERA_I2C_BATCH_SIZE_3,
+       MSM_CAMERA_I2C_BATCH_SIZE_4,
+       MSM_CAMERA_I2C_BATCH_SIZE_5,
+       MSM_CAMERA_I2C_BATCH_SIZE_MAX,
+};
+
+enum msm_camera_qup_i2c_write_batch_t {
+       MSM_CAMREA_I2C_BATCH_DISABLE = 0,
+       MSM_CAMERA_I2C_BATCH_ENABLE,
+};
+
+enum msm_camera_i2c_reg_addr_type {
+       MSM_CAMERA_I2C_BYTE_ADDR = 1,
+       MSM_CAMERA_I2C_WORD_ADDR,
+       MSM_CAMERA_I2C_3B_ADDR,
+       MSM_CAMERA_I2C_ADDR_TYPE_MAX,
+};
+
+enum msm_camera_i2c_data_type {
+       MSM_CAMERA_I2C_BYTE_DATA = 1,
+       MSM_CAMERA_I2C_WORD_DATA,
+       MSM_CAMERA_I2C_DWORD_DATA,
+       MSM_CAMERA_I2C_SET_BYTE_MASK,
+       MSM_CAMERA_I2C_UNSET_BYTE_MASK,
+       MSM_CAMERA_I2C_SET_WORD_MASK,
+       MSM_CAMERA_I2C_UNSET_WORD_MASK,
+       MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+       MSM_CAMERA_I2C_DATA_TYPE_MAX,
+};
+
+enum msm_sensor_power_seq_gpio_t {
+       SENSOR_GPIO_RESET,
+       SENSOR_GPIO_STANDBY,
+       SENSOR_GPIO_AF_PWDM,
+       SENSOR_GPIO_VIO,
+       SENSOR_GPIO_VANA,
+       SENSOR_GPIO_VDIG,
+       SENSOR_GPIO_VAF,
+       SENSOR_GPIO_FL_EN,
+       SENSOR_GPIO_FL_NOW,
+       SENSOR_GPIO_FL_RESET,
+       SENSOR_GPIO_CUSTOM1,
+       SENSOR_GPIO_CUSTOM2,
+       SENSOR_GPIO_MAX,
+};
+
+enum msm_camera_vreg_name_t {
+       CAM_VDIG,
+       CAM_VIO,
+       CAM_VANA,
+       CAM_VAF,
+       CAM_V_CUSTOM1,
+       CAM_V_CUSTOM2,
+       CAM_VREG_MAX,
+};
+
+enum msm_sensor_clk_type_t {
+       SENSOR_CAM_MCLK,
+       SENSOR_CAM_CLK,
+       SENSOR_CAM_CLK_MAX,
+};
+
+enum camerab_mode_t {
+       CAMERA_MODE_2D_B = (1<<0),
+       CAMERA_MODE_3D_B = (1<<1),
+       CAMERA_MODE_INVALID = (1<<2),
+};
+
+enum sensor_stats_type {
+       YRGB,
+       YYYY,
+};
+
+enum msm_actuator_data_type {
+       MSM_ACTUATOR_BYTE_DATA = 1,
+       MSM_ACTUATOR_WORD_DATA,
+};
+
+enum msm_actuator_addr_type {
+       MSM_ACTUATOR_BYTE_ADDR = 1,
+       MSM_ACTUATOR_WORD_ADDR,
+};
+
+enum msm_actuator_write_type {
+       MSM_ACTUATOR_WRITE_HW_DAMP,
+       MSM_ACTUATOR_WRITE_DAC,
+};
+
+enum msm_actuator_i2c_operation {
+       MSM_ACT_WRITE = 0,
+       MSM_ACT_POLL,
+};
+
+enum actuator_type {
+       ACTUATOR_VCM,
+       ACTUATOR_PIEZO,
+       ACTUATOR_HVCM,
+};
+
+enum msm_flash_driver_type {
+       FLASH_DRIVER_PMIC,
+       FLASH_DRIVER_I2C,
+       FLASH_DRIVER_GPIO,
+       FLASH_DRIVER_DEFAULT
+};
+
+enum msm_flash_cfg_type_t {
+       CFG_FLASH_INIT,
+       CFG_FLASH_RELEASE,
+       CFG_FLASH_OFF,
+       CFG_FLASH_LOW,
+       CFG_FLASH_HIGH,
+};
+
+enum msm_sensor_output_format_t {
+       MSM_SENSOR_BAYER,
+       MSM_SENSOR_YCBCR,
+       MSM_SENSOR_META,
+};
+
+struct msm_sensor_power_setting {
+       enum msm_sensor_power_seq_type_t seq_type;
+       uint16_t seq_val;
+       long config_val;
+       uint16_t delay;
+       void *data[10];
+};
+
+struct msm_sensor_power_setting_array {
+       struct msm_sensor_power_setting  power_setting_a[MAX_POWER_CONFIG];
+       struct msm_sensor_power_setting *power_setting;
+       uint16_t size;
+       struct msm_sensor_power_setting  power_down_setting_a[MAX_POWER_CONFIG];
+       struct msm_sensor_power_setting *power_down_setting;
+       uint16_t size_down;
+};
+
+struct msm_sensor_init_params {
+       /* mask of modes supported: 2D, 3D */
+       int                 modes_supported;
+       /* sensor position: front, back */
+       enum camb_position_t position;
+       /* sensor mount angle */
+       uint32_t            sensor_mount_angle;
+};
+
+struct msm_sensor_id_info_t {
+       uint16_t sensor_id_reg_addr;
+       uint16_t sensor_id;
+};
+
+struct msm_camera_sensor_slave_info {
+       char sensor_name[32];
+       char eeprom_name[32];
+       char actuator_name[32];
+       char ois_name[32];
+       char flash_name[32];
+       enum msm_sensor_camera_id_t camera_id;
+       uint16_t slave_addr;
+       enum i2c_freq_mode_t i2c_freq_mode;
+       enum msm_camera_i2c_reg_addr_type addr_type;
+       struct msm_sensor_id_info_t sensor_id_info;
+       struct msm_sensor_power_setting_array power_setting_array;
+       uint8_t  is_init_params_valid;
+       struct msm_sensor_init_params sensor_init_params;
+       uint8_t is_flash_supported;
+       enum msm_sensor_output_format_t output_format;
+};
+
+struct msm_camera_i2c_reg_array {
+       uint16_t reg_addr;
+       uint16_t reg_data;
+       uint32_t delay;
+};
+
+struct msm_camera_i2c_reg_setting {
+       struct msm_camera_i2c_reg_array *reg_setting;
+       uint16_t size;
+       enum msm_camera_i2c_reg_addr_type addr_type;
+       enum msm_camera_i2c_data_type data_type;
+       uint16_t delay;
+       enum msm_camera_qup_i2c_write_batch_t qup_i2c_batch;
+};
+
+struct msm_camera_csid_vc_cfg {
+       uint8_t cid;
+       uint8_t dt;
+       uint8_t decode_format;
+};
+
+struct msm_camera_csid_lut_params {
+       uint8_t num_cid;
+       struct msm_camera_csid_vc_cfg vc_cfg_a[MAX_CID];
+       struct msm_camera_csid_vc_cfg *vc_cfg[MAX_CID];
+};
+
+struct msm_camera_csid_params {
+       uint8_t lane_cnt;
+       uint16_t lane_assign;
+       uint8_t phy_sel;
+       uint32_t csi_clk;
+       struct msm_camera_csid_lut_params lut_params;
+};
+
+struct msm_camera_csiphy_params {
+       uint8_t lane_cnt;
+       uint8_t settle_cnt;
+       uint16_t lane_mask;
+       uint8_t combo_mode;
+       uint8_t csid_core;
+       uint32_t csiphy_clk;
+};
+
+struct msm_camera_i2c_seq_reg_array {
+       uint16_t reg_addr;
+       uint8_t reg_data[I2C_SEQ_REG_DATA_MAX];
+       uint16_t reg_data_size;
+};
+
+struct msm_camera_i2c_seq_reg_setting {
+       struct msm_camera_i2c_seq_reg_array *reg_setting;
+       uint16_t size;
+       enum msm_camera_i2c_reg_addr_type addr_type;
+       uint16_t delay;
+};
+
+struct msm_actuator_reg_params_t {
+       enum msm_actuator_write_type reg_write_type;
+       uint32_t hw_mask;
+       uint16_t reg_addr;
+       uint16_t hw_shift;
+       uint16_t data_shift;
+};
+
+struct damping_params_t {
+       uint32_t damping_step;
+       uint32_t damping_delay;
+       uint32_t hw_params;
+};
+
+struct region_params_t {
+       /* [0] = ForwardDirection Macro boundary
+          [1] = ReverseDirection Inf boundary
+       */
+       uint16_t step_bound[2];
+       uint16_t code_per_step;
+       /* qvalue for converting float type numbers to integer format */
+       uint32_t qvalue;
+};
+
+struct reg_settings_t {
+       uint16_t reg_addr;
+       enum msm_actuator_addr_type addr_type;
+       uint16_t reg_data;
+       enum msm_actuator_data_type data_type;
+       enum msm_actuator_i2c_operation i2c_operation;
+       uint32_t delay;
+};
+
+struct msm_camera_i2c_reg_setting_array {
+       struct msm_camera_i2c_reg_array reg_setting_a[MAX_I2C_REG_SET];
+       uint16_t size;
+       enum msm_camera_i2c_reg_addr_type addr_type;
+       enum msm_camera_i2c_data_type data_type;
+       uint16_t delay;
+};
+#endif /* __LINUX_MSM_CAM_SENSOR_H */
diff --git a/drivers/media/platform/msm/cci/msm_cci.c b/drivers/media/platform/msm/cci/msm_cci.c
new file mode 100644 (file)
index 0000000..de3cfb8
--- /dev/null
@@ -0,0 +1,1636 @@
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
+#include "msm_cci.h"
+#include "msm_cam_cci_hwreg.h"
+
+#define V4L2_IDENT_CCI 50005
+#define CCI_I2C_QUEUE_0_SIZE 64
+#define CCI_I2C_QUEUE_1_SIZE 16
+#define CYCLES_PER_MICRO_SEC_DEFAULT 4915
+#define CCI_MAX_DELAY 1000000
+
+#define CCI_TIMEOUT msecs_to_jiffies(100)
+
+/* TODO move this somewhere else */
+#define MSM_CCI_DRV_NAME "msm_cci"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+
+/* Max bytes that can be read per CCI read transaction */
+#define CCI_READ_MAX 12
+#define CCI_I2C_READ_MAX_RETRIES 3
+#define CCI_I2C_MAX_READ 8192
+#define CCI_I2C_MAX_WRITE 8192
+
+static struct v4l2_subdev *g_cci_subdev;
+
+struct msm_video_device {
+       struct video_device *vdev;
+       atomic_t opened;
+};
+
+#define MSM_CONFIGURATION_NAME "msm_config"
+
+static int msm_probe(struct platform_device *pdev,
+                    struct v4l2_device *msm_v4l2_dev)
+{
+       struct msm_video_device *pvdev;
+       int rc = 0;
+
+       pvdev = kzalloc(sizeof(struct msm_video_device),
+               GFP_KERNEL);
+       if (WARN_ON(!pvdev)) {
+               rc = -ENOMEM;
+               goto pvdev_fail;
+       }
+
+       pvdev->vdev = video_device_alloc();
+       if (WARN_ON(!pvdev->vdev)) {
+               rc = -ENOMEM;
+               goto video_fail;
+       }
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device),
+               GFP_KERNEL);
+       if (!msm_v4l2_dev->mdev) {
+               rc = -ENOMEM;
+               goto mdev_fail;
+       }
+       strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME,
+                       sizeof(msm_v4l2_dev->mdev->model));
+       msm_v4l2_dev->mdev->dev = &(pdev->dev);
+
+       rc = media_device_register(msm_v4l2_dev->mdev);
+       if (WARN_ON(rc < 0))
+               goto media_fail;
+
+       if (WARN_ON((rc == media_entity_init(&pvdev->vdev->entity,
+                       0, NULL, 0)) < 0))
+               goto entity_fail;
+
+       pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+       pvdev->vdev->entity.group_id = 2;
+#endif
+
+//     msm_v4l2_dev->notify = msm_sd_notify;
+
+       pvdev->vdev->v4l2_dev = msm_v4l2_dev;
+
+       rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev);
+       if (WARN_ON(rc < 0))
+               goto register_fail;
+
+       goto probe_end;
+
+#if 0
+       strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name));
+       pvdev->vdev->release  = video_device_release;
+       pvdev->vdev->fops     = &msm_fops;
+       pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops;
+       pvdev->vdev->minor     = -1;
+       pvdev->vdev->vfl_type  = VFL_TYPE_GRABBER;
+       rc = video_register_device(pvdev->vdev,
+               VFL_TYPE_GRABBER, -1);
+       if (WARN_ON(rc < 0))
+               goto v4l2_fail;
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       /* FIXME: How to get rid of this messy? */
+       pvdev->vdev->entity.name = video_device_node_name(pvdev->vdev);
+#endif
+
+       atomic_set(&pvdev->opened, 0);
+       video_set_drvdata(pvdev->vdev, pvdev);
+
+       msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
+       if (WARN_ON(!msm_session_q))
+               goto v4l2_fail;
+
+       msm_init_queue(msm_session_q);
+       spin_lock_init(&msm_eventq_lock);
+       spin_lock_init(&msm_pid_lock);
+       INIT_LIST_HEAD(&ordered_sd_list);
+       goto probe_end;
+
+v4l2_fail:
+       v4l2_device_unregister(pvdev->vdev->v4l2_dev);
+#endif
+
+register_fail:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       media_entity_cleanup(&pvdev->vdev->entity);
+entity_fail:
+       media_device_unregister(msm_v4l2_dev->mdev);
+media_fail:
+       kzfree(msm_v4l2_dev->mdev);
+mdev_fail:
+#endif
+       video_device_release(pvdev->vdev);
+video_fail:
+       kzfree(pvdev);
+pvdev_fail:
+probe_end:
+       return rc;
+}
+
+static void msm_sd_unregister_subdev(struct video_device *vdev)
+{
+       struct v4l2_subdev *sd = video_get_drvdata(vdev);
+       sd->devnode = NULL;
+       kzfree(vdev);
+}
+
+static inline int __msm_sd_register_subdev(struct v4l2_subdev *sd,
+                                          struct v4l2_device *msm_v4l2_dev)
+{
+       int rc = 0;
+       struct video_device *vdev;
+
+       if (!msm_v4l2_dev || !sd || !sd->name[0])
+               return -EINVAL;
+
+       rc = v4l2_device_register_subdev(msm_v4l2_dev, sd);
+       if (rc < 0)
+               return rc;
+
+       /* Register a device node for every subdev marked with the
+        * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+        */
+       if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+               return rc;
+
+       vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+       if (!vdev) {
+               rc = -ENOMEM;
+               goto clean_up;
+       }
+
+       video_set_drvdata(vdev, sd);
+       strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+       vdev->v4l2_dev = msm_v4l2_dev;
+       vdev->fops = &v4l2_subdev_fops;
+       vdev->release = msm_sd_unregister_subdev;
+       rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+                 sd->owner);
+       if (rc < 0) {
+               kzfree(vdev);
+               goto clean_up;
+       }
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       sd->entity.info.dev.major = VIDEO_MAJOR;
+       sd->entity.info.dev.minor = vdev->minor;
+       sd->entity.name = video_device_node_name(vdev);
+#endif
+       sd->devnode = vdev;
+       return 0;
+
+clean_up:
+       if (sd->devnode)
+               video_unregister_device(sd->devnode);
+       return rc;
+}
+
+int msm_sd_register(struct msm_sd_subdev *msm_subdev,
+                   struct v4l2_device *msm_v4l2_dev)
+{
+       if (WARN_ON(!msm_subdev))
+               return -EINVAL;
+
+       if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
+               return -EIO;
+
+       return __msm_sd_register_subdev(&msm_subdev->sd, msm_v4l2_dev);
+}
+
+struct msm_cam_clk_info {
+       const char *clk_name;
+       long clk_rate;
+       uint32_t delay;
+};
+
+static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX];
+
+#define INIT_RATE -2
+
+static int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
+               struct clk **clk_ptr, int num_clk, int enable)
+{
+       int i;
+       int rc = 0;
+       long clk_rate;
+       if (enable) {
+               for (i = 0; i < num_clk; i++) {
+                       CDBG("%s enable %s\n", __func__, clk_info[i].clk_name);
+                       clk_ptr[i] = clk_get(dev, clk_info[i].clk_name);
+                       if (IS_ERR(clk_ptr[i])) {
+                               pr_err("%s get failed\n", clk_info[i].clk_name);
+                               rc = PTR_ERR(clk_ptr[i]);
+                               goto cam_clk_get_err;
+                       }
+                       if (clk_info[i].clk_rate > 0) {
+                               clk_rate = clk_round_rate(clk_ptr[i],
+                                       clk_info[i].clk_rate);
+                               if (clk_rate < 0) {
+                                       pr_err("%s round failed\n",
+                                                  clk_info[i].clk_name);
+                                       goto cam_clk_set_err;
+                               }
+                               rc = clk_set_rate(clk_ptr[i],
+                                       clk_rate);
+                               if (rc < 0) {
+                                       pr_err("%s set failed\n",
+                                               clk_info[i].clk_name);
+                                       goto cam_clk_set_err;
+                               }
+
+                       } else if (clk_info[i].clk_rate == INIT_RATE) {
+                               clk_rate = clk_get_rate(clk_ptr[i]);
+                               if (clk_rate == 0) {
+                                       clk_rate =
+                                                 clk_round_rate(clk_ptr[i], 0);
+                                       if (clk_rate < 0) {
+                                               pr_err("%s round rate failed\n",
+                                                         clk_info[i].clk_name);
+                                               goto cam_clk_set_err;
+                                       }
+                                       rc = clk_set_rate(clk_ptr[i],
+                                                               clk_rate);
+                                       if (rc < 0) {
+                                               pr_err("%s set rate failed\n",
+                                                         clk_info[i].clk_name);
+                                               goto cam_clk_set_err;
+                                       }
+                               }
+                       }
+                       rc = clk_prepare(clk_ptr[i]);
+                       if (rc < 0) {
+                               pr_err("%s prepare failed\n",
+                                          clk_info[i].clk_name);
+                               goto cam_clk_prepare_err;
+                       }
+
+                       rc = clk_enable(clk_ptr[i]);
+                       if (rc < 0) {
+                               pr_err("%s enable failed\n",
+                                          clk_info[i].clk_name);
+                               goto cam_clk_enable_err;
+                       }
+                       if (clk_info[i].delay > 20) {
+                               msleep(clk_info[i].delay);
+                       } else if (clk_info[i].delay) {
+                               usleep_range(clk_info[i].delay * 1000,
+                                       (clk_info[i].delay * 1000) + 1000);
+                       }
+               }
+       } else {
+               for (i = num_clk - 1; i >= 0; i--) {
+                       if (clk_ptr[i] != NULL) {
+                               CDBG("%s disable %s\n", __func__,
+                                       clk_info[i].clk_name);
+                               clk_disable(clk_ptr[i]);
+                               clk_unprepare(clk_ptr[i]);
+                               clk_put(clk_ptr[i]);
+                       }
+               }
+       }
+       return rc;
+
+
+cam_clk_enable_err:
+       clk_unprepare(clk_ptr[i]);
+cam_clk_prepare_err:
+cam_clk_set_err:
+       clk_put(clk_ptr[i]);
+cam_clk_get_err:
+       for (i--; i >= 0; i--) {
+               if (clk_ptr[i] != NULL) {
+                       clk_disable(clk_ptr[i]);
+                       clk_unprepare(clk_ptr[i]);
+                       clk_put(clk_ptr[i]);
+               }
+       }
+       return rc;
+}
+
+int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
+       int gpio_en)
+{
+       return 0;
+}
+
+static void msm_camera_io_w_mb(u32 data, void __iomem *addr)
+{
+       CDBG("%s: 0x%p %08x\n", __func__,  (addr), (data));
+       wmb();
+       writel_relaxed((data), (addr));
+       wmb();
+}
+
+static u32 msm_camera_io_r_mb(void __iomem *addr)
+{
+       uint32_t data;
+       rmb();
+       data = readl_relaxed(addr);
+       rmb();
+       CDBG("%s: 0x%p %08x\n", __func__,  (addr), (data));
+       return data;
+}
+
+static void msm_cci_set_clk_param(struct cci_device *cci_dev,
+       struct msm_camera_cci_ctrl *c_ctrl)
+{
+       struct msm_cci_clk_params_t *clk_params = NULL;
+       enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+       enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
+
+       if (cci_dev->master_clk_init[master])
+               return;
+       clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
+
+       if (MASTER_0 == master) {
+               msm_camera_io_w_mb(clk_params->hw_thigh << 16 |
+                       clk_params->hw_tlow,
+                       cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 |
+                       clk_params->hw_tsu_sta,
+                       cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 |
+                       clk_params->hw_thd_sta,
+                       cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_tbuf,
+                       cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 |
+                       clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
+                       cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR);
+       } else if (MASTER_1 == master) {
+               msm_camera_io_w_mb(clk_params->hw_thigh << 16 |
+                       clk_params->hw_tlow,
+                       cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_tsu_sto << 16 |
+                       clk_params->hw_tsu_sta,
+                       cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_thd_dat << 16 |
+                       clk_params->hw_thd_sta,
+                       cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_tbuf,
+                       cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR);
+               msm_camera_io_w_mb(clk_params->hw_scl_stretch_en << 8 |
+                       clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
+                       cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR);
+       }
+       cci_dev->master_clk_init[master] = 1;
+       return;
+}
+
+static void msm_cci_flush_queue(struct cci_device *cci_dev,
+       enum cci_i2c_master_t master)
+{
+       int32_t rc = 0;
+
+       msm_camera_io_w_mb(1 << master, cci_dev->base + CCI_HALT_REQ_ADDR);
+       rc = wait_for_completion_timeout(
+               &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
+       if (rc < 0) {
+               pr_err("%s:%d wait failed\n", __func__, __LINE__);
+       } else if (rc == 0) {
+               pr_err("%s:%d wait timeout\n", __func__, __LINE__);
+
+               /* Set reset pending flag to TRUE */
+               cci_dev->cci_master_info[master].reset_pending = TRUE;
+
+               /* Set proper mask to RESET CMD address based on MASTER */
+               if (master == MASTER_0)
+                       msm_camera_io_w_mb(CCI_M0_RESET_RMSK,
+                               cci_dev->base + CCI_RESET_CMD_ADDR);
+               else
+                       msm_camera_io_w_mb(CCI_M1_RESET_RMSK,
+                               cci_dev->base + CCI_RESET_CMD_ADDR);
+
+               /* wait for reset done irq */
+               rc = wait_for_completion_timeout(
+                       &cci_dev->cci_master_info[master].reset_complete,
+                       CCI_TIMEOUT);
+               if (rc <= 0)
+                       pr_err("%s:%d wait failed %d\n", __func__, __LINE__,
+                               rc);
+       }
+       return;
+}
+
+static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
+       uint32_t len,
+       enum cci_i2c_master_t master,
+       enum cci_i2c_queue_t queue)
+{
+       int32_t rc = 0;
+       uint32_t read_val = 0;
+       uint32_t reg_offset = master * 0x200 + queue * 0x100;
+       read_val = msm_camera_io_r_mb(cci_dev->base +
+               CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
+       CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n",
+               __func__, __LINE__, read_val, len,
+               cci_dev->cci_i2c_queue_info[master][queue].max_queue_size);
+       if ((read_val + len + 1) > cci_dev->
+               cci_i2c_queue_info[master][queue].max_queue_size) {
+               uint32_t reg_val = 0;
+               uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8);
+               CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__);
+               msm_camera_io_w_mb(report_val,
+                       cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+                       reg_offset);
+               read_val++;
+               CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n",
+                       __func__, __LINE__, read_val);
+               msm_camera_io_w_mb(read_val, cci_dev->base +
+                       CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
+               reg_val = 1 << ((master * 2) + queue);
+               CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
+               msm_camera_io_w_mb(reg_val, cci_dev->base +
+                       CCI_QUEUE_START_ADDR);
+               CDBG("%s line %d wait_for_completion_timeout\n",
+                       __func__, __LINE__);
+               rc = wait_for_completion_timeout(&cci_dev->
+                       cci_master_info[master].reset_complete, CCI_TIMEOUT);
+               if (rc <= 0) {
+                       pr_err("%s: wait_for_completion_timeout %d\n",
+                                __func__, __LINE__);
+                       if (rc == 0)
+                               rc = -ETIMEDOUT;
+                       msm_cci_flush_queue(cci_dev, master);
+                       return rc;
+               }
+               rc = cci_dev->cci_master_info[master].status;
+               if (rc < 0)
+                       pr_err("%s failed rc %d\n", __func__, rc);
+       }
+       return rc;
+}
+
+static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
+       struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue)
+{
+       uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
+       int32_t rc = 0;
+       uint32_t cmd = 0, delay = 0;
+       uint8_t data[11];
+       uint16_t reg_addr = 0;
+       struct msm_camera_i2c_reg_setting *i2c_msg =
+               &c_ctrl->cfg.cci_i2c_write_cfg;
+       uint16_t cmd_size = i2c_msg->size;
+       struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
+       enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+
+       if (i2c_cmd == NULL) {
+               pr_err("%s:%d Failed line\n", __func__,
+                       __LINE__);
+               return -EINVAL;
+       }
+
+       if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) {
+               pr_err("%s:%d Failed line\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       CDBG("%s addr type %d data type %d\n", __func__,
+               i2c_msg->addr_type, i2c_msg->data_type);
+
+       if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+               pr_err("%s failed line %d\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+       if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) {
+               pr_err("%s failed line %d\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+       /* assume total size within the max queue */
+       while (cmd_size) {
+               CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
+                       cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
+               delay = i2c_cmd->delay;
+               data[i++] = CCI_I2C_WRITE_CMD;
+               if (i2c_cmd->reg_addr)
+                       reg_addr = i2c_cmd->reg_addr;
+               /* either byte or word addr */
+               if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
+                       data[i++] = reg_addr;
+               else {
+                       data[i++] = (reg_addr & 0xFF00) >> 8;
+                       data[i++] = reg_addr & 0x00FF;
+               }
+               /* max of 10 data bytes */
+               do {
+                       if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+                               data[i++] = i2c_cmd->reg_data;
+                               reg_addr++;
+                       } else {
+                               if ((i + 1) <= 10) {
+                                       data[i++] = (i2c_cmd->reg_data &
+                                               0xFF00) >> 8; /* MSB */
+                                       data[i++] = i2c_cmd->reg_data &
+                                               0x00FF; /* LSB */
+                                       reg_addr += 2;
+                               } else
+                                       break;
+                       }
+                       i2c_cmd++;
+               } while (--cmd_size && !i2c_cmd->reg_addr && (i <= 10));
+               data[0] |= ((i-1) << 4);
+               len = ((i-1)/4) + 1;
+               rc = msm_cci_validate_queue(cci_dev, len, master, queue);
+               if (rc < 0) {
+                       pr_err("%s: failed %d", __func__, __LINE__);
+                       return rc;
+               }
+               for (h = 0, k = 0; h < len; h++) {
+                       cmd = 0;
+                       for (j = 0; (j < 4 && k < i); j++)
+                               cmd |= (data[k++] << (j * 8));
+                       CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
+                               __func__, cmd);
+                       msm_camera_io_w_mb(cmd, cci_dev->base +
+                               CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+                               master * 0x200 + queue * 0x100);
+               }
+               if ((delay > 0) && (delay < CCI_MAX_DELAY)) {
+                       cmd = (uint32_t)((delay * cci_dev->cycles_per_us) /
+                               0x100);
+                       cmd <<= 4;
+                       cmd |= CCI_I2C_WAIT_CMD;
+                       CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
+                               __func__, cmd);
+                       msm_camera_io_w_mb(cmd, cci_dev->base +
+                               CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+                               master * 0x200 + queue * 0x100);
+               }
+               i = 0;
+       }
+       return rc;
+}
+
+static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev,
+       uint32_t val,
+       enum cci_i2c_master_t master,
+       enum cci_i2c_queue_t queue)
+{
+       int32_t rc = 0;
+       uint32_t reg_offset = master * 0x200 + queue * 0x100;
+       CDBG("%s:%d called\n", __func__, __LINE__);
+       rc = msm_cci_validate_queue(cci_dev, 1, master, queue);
+       if (rc < 0) {
+               pr_err("%s: failed %d", __func__, __LINE__);
+               return rc;
+       }
+       CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x\n",
+               __func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+               reg_offset, val);
+       msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+               reg_offset);
+       return rc;
+}
+
+static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd,
+       struct msm_camera_cci_ctrl *c_ctrl)
+{
+       int32_t rc = 0;
+       uint32_t val = 0;
+       int32_t read_words = 0, exp_words = 0;
+       int32_t index = 0, first_byte = 0;
+       uint32_t i = 0;
+       enum cci_i2c_master_t master;
+       enum cci_i2c_queue_t queue = QUEUE_1;
+       struct cci_device *cci_dev = NULL;
+       struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL;
+       CDBG("%s line %d\n", __func__, __LINE__);
+       cci_dev = v4l2_get_subdevdata(sd);
+       master = c_ctrl->cci_info->cci_i2c_master;
+       read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
+       mutex_lock(&cci_dev->cci_master_info[master].mutex);
+
+       /*
+        * Call validate queue to make sure queue is empty before starting.
+        * If this call fails, don't proceed with i2c_read call. This is to
+        * avoid overflow / underflow of queue
+        */
+       rc = msm_cci_validate_queue(cci_dev,
+               cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1,
+               master, queue);
+       if (rc < 0) {
+               pr_err("%s:%d Initial validataion failed rc %d\n", __func__,
+                       __LINE__, rc);
+               goto ERROR;
+       }
+
+       if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+               pr_err("%s:%d More than max retries\n", __func__,
+                       __LINE__);
+               goto ERROR;
+       }
+
+       if (read_cfg->data == NULL) {
+               pr_err("%s:%d Data ptr is NULL\n", __func__,
+                       __LINE__);
+               goto ERROR;
+       }
+
+       CDBG("%s master %d, queue %d\n", __func__, master, queue);
+       CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+               c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+               c_ctrl->cci_info->id_map);
+       val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
+               c_ctrl->cci_info->retries << 16 |
+               c_ctrl->cci_info->id_map << 18;
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = CCI_I2C_LOCK_CMD;
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
+               val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
+                       ((read_cfg->addr & 0xFF) << 8);
+       if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR)
+               val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
+                       (((read_cfg->addr & 0xFF00) >> 8) << 8) |
+                       ((read_cfg->addr & 0xFF) << 16);
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4);
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = CCI_I2C_UNLOCK_CMD;
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR
+                       + master * 0x200 + queue * 0x100);
+       CDBG("%s cur word cnt 0x%x\n", __func__, val);
+       msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR
+                       + master * 0x200 + queue * 0x100);
+
+       val = 1 << ((master * 2) + queue);
+       msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR);
+       CDBG("%s:%d E wait_for_completion_timeout\n", __func__,
+               __LINE__);
+       rc = wait_for_completion_timeout(&cci_dev->
+               cci_master_info[master].reset_complete, CCI_TIMEOUT);
+       if (rc <= 0) {
+               pr_err("%s: wait_for_completion_timeout %d\n",
+                        __func__, __LINE__);
+               if (rc == 0)
+                       rc = -ETIMEDOUT;
+               msm_cci_flush_queue(cci_dev, master);
+               goto ERROR;
+       } else {
+               rc = 0;
+       }
+       CDBG("%s:%d E wait_for_completion_timeout\n", __func__,
+               __LINE__);
+
+       read_words = msm_camera_io_r_mb(cci_dev->base +
+               CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
+       exp_words = ((read_cfg->num_byte / 4) + 1);
+       if (read_words != exp_words) {
+               pr_err("%s:%d read_words = %d, exp words = %d\n", __func__,
+                       __LINE__, read_words, exp_words);
+               memset(read_cfg->data, 0, read_cfg->num_byte);
+               rc = -EINVAL;
+               goto ERROR;
+       }
+       index = 0;
+       CDBG("%s index %d num_type %d\n", __func__, index,
+               read_cfg->num_byte);
+       first_byte = 0;
+       do {
+               val = msm_camera_io_r_mb(cci_dev->base +
+                       CCI_I2C_M0_READ_DATA_ADDR + master * 0x100);
+               CDBG("%s read val 0x%x\n", __func__, val);
+               for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) {
+                       CDBG("%s i %d index %d\n", __func__, i, index);
+                       if (!first_byte) {
+                               CDBG("%s sid 0x%x\n", __func__, val & 0xFF);
+                               first_byte++;
+                       } else {
+                               read_cfg->data[index] =
+                                       (val  >> (i * 8)) & 0xFF;
+                               CDBG("%s data[%d] 0x%x\n", __func__, index,
+                                       read_cfg->data[index]);
+                               index++;
+                       }
+               }
+       } while (--read_words > 0);
+ERROR:
+       mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+       return rc;
+}
+
+static int32_t msm_cci_i2c_read_bytes(struct v4l2_subdev *sd,
+       struct msm_camera_cci_ctrl *c_ctrl)
+{
+       int32_t rc = 0;
+       struct cci_device *cci_dev = NULL;
+       enum cci_i2c_master_t master;
+       struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL;
+       uint16_t read_bytes = 0;
+
+       if (!sd || !c_ctrl) {
+               pr_err("%s:%d sd %p c_ctrl %p\n", __func__,
+                       __LINE__, sd, c_ctrl);
+               return -EINVAL;
+       }
+       if (!c_ctrl->cci_info) {
+               pr_err("%s:%d cci_info NULL\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+       cci_dev = v4l2_get_subdevdata(sd);
+       if (!cci_dev) {
+               pr_err("%s:%d cci_dev NULL\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX
+                       || c_ctrl->cci_info->cci_i2c_master < 0) {
+               pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       master = c_ctrl->cci_info->cci_i2c_master;
+       read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
+       if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) {
+               pr_err("%s:%d read num bytes 0\n", __func__, __LINE__);
+               rc = -EINVAL;
+               goto ERROR;
+       }
+
+       read_bytes = read_cfg->num_byte;
+       do {
+               if (read_bytes > CCI_READ_MAX)
+                       read_cfg->num_byte = CCI_READ_MAX;
+               else
+                       read_cfg->num_byte = read_bytes;
+               rc = msm_cci_i2c_read(sd, c_ctrl);
+               if (rc < 0) {
+                       pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+                       goto ERROR;
+               }
+               if (read_bytes > CCI_READ_MAX) {
+                       read_cfg->addr += CCI_READ_MAX;
+                       read_cfg->data += CCI_READ_MAX;
+                       read_bytes -= CCI_READ_MAX;
+               } else {
+                       read_bytes = 0;
+               }
+       } while (read_bytes);
+ERROR:
+       return rc;
+}
+
+static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd,
+       struct msm_camera_cci_ctrl *c_ctrl)
+{
+       int32_t rc = 0;
+       struct cci_device *cci_dev;
+       uint32_t val;
+       enum cci_i2c_master_t master;
+       enum cci_i2c_queue_t queue = QUEUE_0;
+       cci_dev = v4l2_get_subdevdata(sd);
+       if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX
+                       || c_ctrl->cci_info->cci_i2c_master < 0) {
+               pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+       master = c_ctrl->cci_info->cci_i2c_master;
+       CDBG("%s master %d, queue %d\n", __func__, master, queue);
+       CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+               c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+               c_ctrl->cci_info->id_map);
+       mutex_lock(&cci_dev->cci_master_info[master].mutex);
+
+       /*
+        * Call validate queue to make sure queue is empty before starting.
+        * If this call fails, don't proceed with i2c_write call. This is to
+        * avoid overflow / underflow of queue
+        */
+       rc = msm_cci_validate_queue(cci_dev,
+               cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1,
+               master, queue);
+       if (rc < 0) {
+               pr_err("%s:%d Initial validataion failed rc %d\n", __func__,
+                       __LINE__, rc);
+               goto ERROR;
+       }
+       if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+               pr_err("%s:%d More than max retries\n", __func__,
+                       __LINE__);
+               goto ERROR;
+       }
+
+       val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
+               c_ctrl->cci_info->retries << 16 |
+               c_ctrl->cci_info->id_map << 18;
+       CDBG("%s:%d CCI_I2C_SET_PARAM_CMD\n", __func__, __LINE__);
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = CCI_I2C_LOCK_CMD;
+       CDBG("%s:%d CCI_I2C_LOCK_CMD\n", __func__, __LINE__);
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       rc = msm_cci_data_queue(cci_dev, c_ctrl, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+       val = CCI_I2C_UNLOCK_CMD;
+       CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__);
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = CCI_I2C_REPORT_CMD | (1 << 8);
+       CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__);
+       rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
+       if (rc < 0) {
+               CDBG("%s failed line %d\n", __func__, __LINE__);
+               goto ERROR;
+       }
+
+       val = msm_camera_io_r_mb(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR
+                       + master * 0x200 + queue * 0x100);
+       CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val);
+       CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__);
+       msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR
+                       + master * 0x200 + queue * 0x100);
+
+       val = 1 << ((master * 2) + queue);
+       CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
+       msm_camera_io_w_mb(val, cci_dev->base + CCI_QUEUE_START_ADDR);
+
+       CDBG("%s:%d E wait_for_completion_timeout\n",
+               __func__, __LINE__);
+       rc = wait_for_completion_timeout(&cci_dev->
+               cci_master_info[master].reset_complete, CCI_TIMEOUT);
+       if (rc <= 0) {
+               pr_err("%s: wait_for_completion_timeout %d\n",
+                        __func__, __LINE__);
+               if (rc == 0)
+                       rc = -ETIMEDOUT;
+               msm_cci_flush_queue(cci_dev, master);
+               goto ERROR;
+       } else {
+               rc = cci_dev->cci_master_info[master].status;
+       }
+       CDBG("%s:%d X wait_for_completion_timeout\n", __func__,
+               __LINE__);
+
+ERROR:
+       mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+       return rc;
+}
+
+static int32_t msm_cci_init(struct v4l2_subdev *sd,
+       struct msm_camera_cci_ctrl *c_ctrl)
+{
+       uint8_t i = 0;
+       int32_t rc = 0;
+       struct cci_device *cci_dev;
+       enum cci_i2c_master_t master;
+
+       cci_dev = v4l2_get_subdevdata(sd);
+       if (!cci_dev || !c_ctrl) {
+               pr_err("%s:%d failed: invalid params %p %p\n", __func__,
+                       __LINE__, cci_dev, c_ctrl);
+               rc = -ENOMEM;
+               return rc;
+       }
+       if (cci_dev->ref_count++) {
+               CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+               master = c_ctrl->cci_info->cci_i2c_master;
+               CDBG("%s:%d master %d\n", __func__, __LINE__, master);
+               msm_cci_set_clk_param(cci_dev, c_ctrl);
+               if (master < MASTER_MAX && master >= 0) {
+                       mutex_lock(&cci_dev->cci_master_info[master].mutex);
+                       /* Set reset pending flag to TRUE */
+                       cci_dev->cci_master_info[master].reset_pending = TRUE;
+                       /* Set proper mask to RESET CMD address */
+                       if (master == MASTER_0)
+                               msm_camera_io_w_mb(CCI_M0_RESET_RMSK,
+                                       cci_dev->base + CCI_RESET_CMD_ADDR);
+                       else
+                               msm_camera_io_w_mb(CCI_M1_RESET_RMSK,
+                                       cci_dev->base + CCI_RESET_CMD_ADDR);
+                       /* wait for reset done irq */
+                       rc = wait_for_completion_timeout(
+                               &cci_dev->cci_master_info[master].
+                               reset_complete,
+                               CCI_TIMEOUT);
+                       if (rc <= 0)
+                               pr_err("%s:%d wait failed %d\n", __func__,
+                                       __LINE__, rc);
+                       mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+               }
+               return 0;
+       }
+       rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+               cci_dev->cci_gpio_tbl_size, 1);
+       if (rc < 0) {
+               CDBG("%s: request gpio failed\n", __func__);
+               goto request_gpio_failed;
+       }
+       cci_dev->reg_ptr = regulator_get(&(cci_dev->pdev->dev),
+                                        "qcom,gdscr-vdd");
+       if (IS_ERR_OR_NULL(cci_dev->reg_ptr)) {
+               pr_err(" %s: Failed in getting TOP gdscr regulator handle",
+                       __func__);
+       } else {
+               rc = regulator_enable(cci_dev->reg_ptr);
+               if (rc) {
+                       pr_err(" %s: regulator enable failed for TOP GDSCR\n",
+                               __func__);
+                       goto clk_enable_failed;
+               }
+       }
+       rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
+               cci_dev->cci_clk, cci_dev->num_clk, 1);
+       if (rc < 0) {
+               CDBG("%s: clk enable failed\n", __func__);
+               goto clk_enable_failed;
+       }
+       enable_irq(cci_dev->irq->start);
+       cci_dev->hw_version = msm_camera_io_r_mb(cci_dev->base +
+               CCI_HW_VERSION_ADDR);
+       pr_info("%s:%d: hw_version = 0x%x\n", __func__, __LINE__,
+               cci_dev->hw_version);
+       cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
+       msm_camera_io_w_mb(CCI_RESET_CMD_RMSK, cci_dev->base +
+                       CCI_RESET_CMD_ADDR);
+       msm_camera_io_w_mb(0x1, cci_dev->base + CCI_RESET_CMD_ADDR);
+       rc = wait_for_completion_timeout(
+               &cci_dev->cci_master_info[MASTER_0].reset_complete,
+               CCI_TIMEOUT);
+       if (rc <= 0) {
+               pr_err("%s: wait_for_completion_timeout %d\n",
+                        __func__, __LINE__);
+               if (rc == 0)
+                       rc = -ETIMEDOUT;
+               goto reset_complete_failed;
+       }
+       for (i = 0; i < MASTER_MAX; i++)
+               cci_dev->master_clk_init[i] = 0;
+       msm_cci_set_clk_param(cci_dev, c_ctrl);
+       msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK,
+               cci_dev->base + CCI_IRQ_MASK_0_ADDR);
+       msm_camera_io_w_mb(CCI_IRQ_MASK_0_RMSK,
+               cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
+       msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+       cci_dev->cci_state = CCI_STATE_ENABLED;
+
+       return 0;
+
+reset_complete_failed:
+       disable_irq(cci_dev->irq->start);
+       msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
+               cci_dev->cci_clk, cci_dev->num_clk, 0);
+clk_enable_failed:
+       msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+               cci_dev->cci_gpio_tbl_size, 0);
+
+       if (!IS_ERR_OR_NULL(cci_dev->reg_ptr)) {
+               regulator_disable(cci_dev->reg_ptr);
+               regulator_put(cci_dev->reg_ptr);
+               cci_dev->reg_ptr = NULL;
+       }
+request_gpio_failed:
+       cci_dev->ref_count--;
+       return rc;
+}
+
+static int32_t msm_cci_release(struct v4l2_subdev *sd)
+{
+       uint8_t i = 0;
+       struct cci_device *cci_dev;
+
+       cci_dev = v4l2_get_subdevdata(sd);
+       if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) {
+               pr_err("%s invalid ref count %d / cci state %d\n",
+                       __func__, cci_dev->ref_count, cci_dev->cci_state);
+               return -EINVAL;
+       }
+       if (--cci_dev->ref_count) {
+               CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count);
+               return 0;
+       }
+       disable_irq(cci_dev->irq->start);
+       msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
+               cci_dev->cci_clk, cci_dev->num_clk, 0);
+       if (!IS_ERR_OR_NULL(cci_dev->reg_ptr)) {
+               regulator_disable(cci_dev->reg_ptr);
+               regulator_put(cci_dev->reg_ptr);
+               cci_dev->reg_ptr = NULL;
+       }
+       msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+               cci_dev->cci_gpio_tbl_size, 0);
+       for (i = 0; i < MASTER_MAX; i++)
+               cci_dev->master_clk_init[i] = 0;
+       cci_dev->cci_state = CCI_STATE_DISABLED;
+
+       return 0;
+}
+
+static int32_t msm_cci_config(struct v4l2_subdev *sd,
+       struct msm_camera_cci_ctrl *cci_ctrl)
+{
+       int32_t rc = 0;
+       CDBG("%s line %d cmd %d\n", __func__, __LINE__,
+               cci_ctrl->cmd);
+       switch (cci_ctrl->cmd) {
+       case MSM_CCI_INIT:
+               rc = msm_cci_init(sd, cci_ctrl);
+               break;
+       case MSM_CCI_RELEASE:
+               rc = msm_cci_release(sd);
+               break;
+       case MSM_CCI_I2C_READ:
+               rc = msm_cci_i2c_read_bytes(sd, cci_ctrl);
+               break;
+       case MSM_CCI_I2C_WRITE:
+               rc = msm_cci_i2c_write(sd, cci_ctrl);
+               break;
+       case MSM_CCI_GPIO_WRITE:
+               break;
+       default:
+               rc = -ENOIOCTLCMD;
+       }
+       CDBG("%s line %d rc %d\n", __func__, __LINE__, rc);
+       cci_ctrl->status = rc;
+       return rc;
+}
+
+static irqreturn_t msm_cci_irq(int irq_num, void *data)
+{
+       uint32_t irq;
+       struct cci_device *cci_dev = data;
+       irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR);
+       msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
+       msm_camera_io_w_mb(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+       msm_camera_io_w_mb(0x0, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+       CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq);
+       if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) {
+               if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) {
+                       cci_dev->cci_master_info[MASTER_0].reset_pending =
+                               FALSE;
+                       complete(&cci_dev->cci_master_info[MASTER_0].
+                               reset_complete);
+               }
+               if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) {
+                       cci_dev->cci_master_info[MASTER_1].reset_pending =
+                               FALSE;
+                       complete(&cci_dev->cci_master_info[MASTER_1].
+                               reset_complete);
+               }
+       }
+       if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) ||
+               (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) ||
+               (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK)) {
+               cci_dev->cci_master_info[MASTER_0].status = 0;
+               complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
+       }
+       if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) ||
+               (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) ||
+               (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) {
+               cci_dev->cci_master_info[MASTER_1].status = 0;
+               complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
+       }
+       if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
+               cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
+               msm_camera_io_w_mb(CCI_M0_RESET_RMSK,
+                       cci_dev->base + CCI_RESET_CMD_ADDR);
+       }
+       if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) {
+               cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
+               msm_camera_io_w_mb(CCI_M1_RESET_RMSK,
+                       cci_dev->base + CCI_RESET_CMD_ADDR);
+       }
+       if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
+               pr_err("%s:%d MASTER_0 error 0x%x\n", __func__, __LINE__, irq);
+               cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
+               msm_camera_io_w_mb(CCI_M0_HALT_REQ_RMSK,
+                       cci_dev->base + CCI_HALT_REQ_ADDR);
+       }
+       if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
+               pr_err("%s:%d MASTER_1 error 0x%x\n", __func__, __LINE__, irq);
+               cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
+               msm_camera_io_w_mb(CCI_M1_HALT_REQ_RMSK,
+                       cci_dev->base + CCI_HALT_REQ_ADDR);
+       }
+       return IRQ_HANDLED;
+}
+
+static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status,
+       bool *handled)
+{
+       struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
+       irqreturn_t ret;
+       CDBG("%s line %d\n", __func__, __LINE__);
+       ret = msm_cci_irq(cci_dev->irq->start, cci_dev);
+       CDBG("%s: msm_cci_irq return %d\n", __func__, ret);
+       *handled = TRUE;
+       return 0;
+}
+
+static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd,
+       unsigned int cmd, void *arg)
+{
+       int32_t rc = 0;
+       CDBG("%s line %d\n", __func__, __LINE__);
+       switch (cmd) {
+       case VIDIOC_MSM_CCI_CFG:
+               rc = msm_cci_config(sd, arg);
+               break;
+/*     case MSM_SD_NOTIFY_FREEZE:
+               break;
+       case MSM_SD_SHUTDOWN: {
+               struct msm_camera_cci_ctrl ctrl_cmd;
+               ctrl_cmd.cmd = MSM_CCI_RELEASE;
+               rc = msm_cci_config(sd, &ctrl_cmd);
+               break;
+       }*/
+       default:
+               rc = -ENOIOCTLCMD;
+       }
+       CDBG("%s line %d rc %d\n", __func__, __LINE__, rc);
+       return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = {
+       .ioctl = &msm_cci_subdev_ioctl,
+       .interrupt_service_routine = msm_cci_irq_routine,
+};
+
+static const struct v4l2_subdev_ops msm_cci_subdev_ops = {
+       .core = &msm_cci_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_cci_internal_ops;
+
+static void msm_cci_init_cci_params(struct cci_device *new_cci_dev)
+{
+       uint8_t i = 0, j = 0;
+       for (i = 0; i < NUM_MASTERS; i++) {
+               new_cci_dev->cci_master_info[i].status = 0;
+               mutex_init(&new_cci_dev->cci_master_info[i].mutex);
+               init_completion(&new_cci_dev->
+                       cci_master_info[i].reset_complete);
+               for (j = 0; j < NUM_QUEUES; j++) {
+                       if (j == QUEUE_0)
+                               new_cci_dev->cci_i2c_queue_info[i][j].
+                                       max_queue_size = CCI_I2C_QUEUE_0_SIZE;
+                       else
+                               new_cci_dev->cci_i2c_queue_info[i][j].
+                                       max_queue_size = CCI_I2C_QUEUE_1_SIZE;
+                       }
+       }
+       return;
+}
+
+static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev)
+{
+       int32_t rc = 0, i = 0;
+       uint32_t *val_array = NULL;
+       uint8_t tbl_size = 0;
+       struct device_node *of_node = cci_dev->pdev->dev.of_node;
+       struct gpio *gpio_tbl = NULL;
+
+       cci_dev->cci_gpio_tbl_size = tbl_size = 0; //of_gpio_count(of_node);
+       CDBG("%s gpio count %d\n", __func__, tbl_size);
+       if (!tbl_size) {
+               pr_err("%s:%d gpio count 0\n", __func__, __LINE__);
+               return 0;
+       }
+
+       gpio_tbl = cci_dev->cci_gpio_tbl =
+               kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL);
+       if (!gpio_tbl) {
+               pr_err("%s failed %d\n", __func__, __LINE__);
+               return 0;
+       }
+
+       for (i = 0; i < tbl_size; i++) {
+               gpio_tbl[i].gpio = of_get_gpio(of_node, i);
+               CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i,
+                       gpio_tbl[i].gpio);
+       }
+
+       val_array = kzalloc(sizeof(uint32_t) * tbl_size, GFP_KERNEL);
+       if (!val_array) {
+               pr_err("%s failed %d\n", __func__, __LINE__);
+               rc = -ENOMEM;
+               goto ERROR1;
+       }
+
+       rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags",
+               val_array, tbl_size);
+       if (rc < 0) {
+               pr_err("%s failed %d\n", __func__, __LINE__);
+               goto ERROR2;
+       }
+       for (i = 0; i < tbl_size; i++) {
+               gpio_tbl[i].flags = val_array[i];
+               CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i,
+                       gpio_tbl[i].flags);
+       }
+
+       for (i = 0; i < tbl_size; i++) {
+               rc = of_property_read_string_index(of_node,
+                       "qcom,gpio-tbl-label", i, &gpio_tbl[i].label);
+               CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i,
+                       gpio_tbl[i].label);
+               if (rc < 0) {
+                       pr_err("%s failed %d\n", __func__, __LINE__);
+                       goto ERROR2;
+               }
+       }
+
+       kfree(val_array);
+       return rc;
+
+ERROR2:
+       kfree(val_array);
+ERROR1:
+       kfree(cci_dev->cci_gpio_tbl);
+       cci_dev->cci_gpio_tbl = NULL;
+       cci_dev->cci_gpio_tbl_size = 0;
+       return rc;
+}
+
+static void msm_cci_init_default_clk_params(struct cci_device *cci_dev,
+       uint8_t index)
+{
+       /* default clock params are for 100Khz */
+       cci_dev->cci_clk_params[index].hw_thigh = 78;
+       cci_dev->cci_clk_params[index].hw_tlow = 114;
+       cci_dev->cci_clk_params[index].hw_tsu_sto = 28;
+       cci_dev->cci_clk_params[index].hw_tsu_sta = 28;
+       cci_dev->cci_clk_params[index].hw_thd_dat = 10;
+       cci_dev->cci_clk_params[index].hw_thd_sta = 77;
+       cci_dev->cci_clk_params[index].hw_tbuf = 118;
+       cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0;
+       cci_dev->cci_clk_params[index].hw_trdhld = 6;
+       cci_dev->cci_clk_params[index].hw_tsp = 1;
+}
+
+static void msm_cci_init_clk_params(struct cci_device *cci_dev)
+{
+       int32_t rc = 0;
+       uint32_t val = 0;
+       uint8_t count = 0;
+       struct device_node *of_node = cci_dev->pdev->dev.of_node;
+       struct device_node *src_node = NULL;
+
+       for (count = 0; count < I2C_MAX_MODES; count++) {
+
+               if (I2C_STANDARD_MODE == count)
+                       src_node = of_find_node_by_name(of_node,
+                               "qcom,i2c_standard_mode");
+               else if (I2C_FAST_MODE == count)
+                       src_node = of_find_node_by_name(of_node,
+                               "qcom,i2c_fast_mode");
+               else
+                       src_node = of_find_node_by_name(of_node,
+                               "qcom,i2c_custom_mode");
+
+               rc = of_property_read_u32(src_node, "qcom,hw-thigh", &val);
+               CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc);
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_thigh = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-tlow",
+                               &val);
+                       CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_tlow = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-tsu-sto",
+                               &val);
+                       CDBG("%s qcom,hw-tsu-sto %d, rc %d\n",
+                               __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_tsu_sto = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-tsu-sta",
+                               &val);
+                       CDBG("%s qcom,hw-tsu-sta %d, rc %d\n",
+                               __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_tsu_sta = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-thd-dat",
+                               &val);
+                       CDBG("%s qcom,hw-thd-dat %d, rc %d\n",
+                               __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_thd_dat = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-thd-sta",
+                               &val);
+                       CDBG("%s qcom,hw-thd-sta %d, rc %d\n", __func__,
+                               val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_thd_sta = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-tbuf",
+                               &val);
+                       CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_tbuf = val;
+                       rc = of_property_read_u32(src_node,
+                               "qcom,hw-scl-stretch-en", &val);
+                       CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n",
+                               __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_scl_stretch_en = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-trdhld",
+                               &val);
+                       CDBG("%s qcom,hw-trdhld %d, rc %d\n",
+                               __func__, val, rc);
+               }
+               if (!rc) {
+                       cci_dev->cci_clk_params[count].hw_trdhld = val;
+                       rc = of_property_read_u32(src_node, "qcom,hw-tsp",
+                               &val);
+                       CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc);
+               }
+               if (!rc)
+                       cci_dev->cci_clk_params[count].hw_tsp = val;
+               else
+                       msm_cci_init_default_clk_params(cci_dev, count);
+               of_node_put(src_node);
+               src_node = NULL;
+       }
+       return;
+}
+
+struct v4l2_subdev *msm_cci_get_subdev(void)
+{
+       return g_cci_subdev;
+}
+
+static int msm_cci_get_clk_info(struct cci_device *cci_dev,
+       struct platform_device *pdev)
+{
+       uint32_t count;
+       int i, rc;
+       uint32_t rates[CCI_NUM_CLK_MAX];
+
+       struct device_node *of_node;
+       of_node = pdev->dev.of_node;
+
+       count = of_property_count_strings(of_node, "clock-names");
+       cci_dev->num_clk = count;
+
+       CDBG("%s: count = %d\n", __func__, count);
+       if (count == 0) {
+               pr_err("%s: no clocks found in device tree, count=%d",
+                       __func__, count);
+               return 0;
+       }
+
+       if (count > CCI_NUM_CLK_MAX) {
+               pr_err("%s: invalid count=%d, max is %d\n", __func__,
+                       count, CCI_NUM_CLK_MAX);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < count; i++) {
+               rc = of_property_read_string_index(of_node, "clock-names",
+                               i, &(cci_clk_info[i].clk_name));
+               CDBG("%s: clock-names[%d] = %s\n", __func__,
+                       i, cci_clk_info[i].clk_name);
+               if (rc < 0) {
+                       pr_err("%s:%d, failed\n", __func__, __LINE__);
+                       return rc;
+               }
+       }
+       rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
+               rates, count);
+       if (rc < 0) {
+               pr_err("%s:%d, failed", __func__, __LINE__);
+               return rc;
+       }
+       for (i = 0; i < count; i++) {
+               cci_clk_info[i].clk_rate = (rates[i] == 0) ?
+                       (long)-1 : rates[i];
+               CDBG("%s: clk_rate[%d] = %ld\n", __func__, i,
+                       cci_clk_info[i].clk_rate);
+       }
+       return 0;
+}
+
+static uint32_t msm_get_cycles_per_ms(void)
+{
+       int i = 0;
+       for (i = 0; i < CCI_NUM_CLK_MAX; i++) {
+               if (!strcmp(cci_clk_info[i].clk_name, "cci_src_clk")) {
+                       CDBG("%s:%d i %d cci_src_clk\n",
+                               __func__, __LINE__, i);
+                       return ((cci_clk_info[i].clk_rate/1000)*256)/1000;
+               }
+       }
+       pr_err("%s:%d, failed: Can use default: %d",
+               __func__, __LINE__, CYCLES_PER_MICRO_SEC_DEFAULT);
+       return CYCLES_PER_MICRO_SEC_DEFAULT;
+}
+
+static int msm_cci_probe(struct platform_device *pdev)
+{
+       struct cci_device *new_cci_dev;
+       int rc = 0;
+       CDBG("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id);
+       new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL);
+       if (!new_cci_dev) {
+               CDBG("%s: no enough memory\n", __func__);
+               return -ENOMEM;
+       }
+       v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops);
+       new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops;
+       snprintf(new_cci_dev->msm_sd.sd.name,
+                       ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci");
+       v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev);
+       platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd);
+       CDBG("%s sd %p\n", __func__, &new_cci_dev->msm_sd.sd);
+       if (pdev->dev.of_node)
+               of_property_read_u32((&pdev->dev)->of_node,
+                       "cell-index", &pdev->id);
+
+       new_cci_dev->reg_ptr = NULL;
+       rc = msm_cci_get_clk_info(new_cci_dev, pdev);
+       if (rc < 0) {
+               pr_err("%s: msm_cci_get_clk_info() failed", __func__);
+               return -EFAULT;
+       }
+
+       new_cci_dev->cycles_per_us = msm_get_cycles_per_ms();
+       new_cci_dev->ref_count = 0;
+       new_cci_dev->mem = platform_get_resource_byname(pdev,
+                                       IORESOURCE_MEM, "cci");
+       if (!new_cci_dev->mem) {
+               CDBG("%s: no mem resource?\n", __func__);
+               rc = -ENODEV;
+               goto cci_no_resource;
+       }
+       new_cci_dev->irq = platform_get_resource_byname(pdev,
+                                       IORESOURCE_IRQ, "cci");
+       CDBG("%s line %d cci irq start %d end %d\n", __func__,
+               __LINE__,
+               (int) new_cci_dev->irq->start,
+               (int) new_cci_dev->irq->end);
+       if (!new_cci_dev->irq) {
+               CDBG("%s: no irq resource?\n", __func__);
+               rc = -ENODEV;
+               goto cci_no_resource;
+       }
+       new_cci_dev->io = request_mem_region(new_cci_dev->mem->start,
+               resource_size(new_cci_dev->mem), pdev->name);
+       if (!new_cci_dev->io) {
+               CDBG("%s: no valid mem region\n", __func__);
+               rc = -EBUSY;
+               goto cci_no_resource;
+       }
+
+       new_cci_dev->base = ioremap(new_cci_dev->mem->start,
+               resource_size(new_cci_dev->mem));
+       if (!new_cci_dev->base) {
+               rc = -ENOMEM;
+               goto cci_release_mem;
+       }
+       rc = request_irq(new_cci_dev->irq->start, msm_cci_irq,
+               IRQF_TRIGGER_RISING, "cci", new_cci_dev);
+       if (rc < 0) {
+               CDBG("%s: irq request fail\n", __func__);
+               rc = -EBUSY;
+               goto cci_release_mem;
+       }
+       disable_irq(new_cci_dev->irq->start);
+//     new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
+       rc = msm_probe(pdev, &new_cci_dev->msm_v4l2_dev);
+       if (rc < 0) {
+               CDBG("%s: msm_probe fail\n", __func__);
+               goto cci_release_mem;
+       }
+       msm_sd_register(&new_cci_dev->msm_sd, &new_cci_dev->msm_v4l2_dev);
+       new_cci_dev->pdev = pdev;
+       msm_cci_init_cci_params(new_cci_dev);
+       msm_cci_init_clk_params(new_cci_dev);
+       msm_cci_init_gpio_params(new_cci_dev);
+       rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+       if (rc)
+               pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc);
+       new_cci_dev->cci_state = CCI_STATE_DISABLED;
+       g_cci_subdev = &new_cci_dev->msm_sd.sd;
+       CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd);
+       CDBG("%s line %d\n", __func__, __LINE__);
+       return 0;
+
+cci_release_mem:
+       release_mem_region(new_cci_dev->mem->start,
+               resource_size(new_cci_dev->mem));
+cci_no_resource:
+       kfree(new_cci_dev);
+       return 0;
+}
+
+static int msm_cci_exit(struct platform_device *pdev)
+{
+       struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
+       struct cci_device *cci_dev =
+               v4l2_get_subdevdata(subdev);
+       release_mem_region(cci_dev->mem->start, resource_size(cci_dev->mem));
+       kfree(cci_dev);
+       return 0;
+}
+
+static const struct of_device_id msm_cci_dt_match[] = {
+       {.compatible = "qcom,cci"},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, msm_cci_dt_match);
+
+static struct platform_driver cci_driver = {
+       .probe = msm_cci_probe,
+       .remove = msm_cci_exit,
+       .driver = {
+               .name = MSM_CCI_DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = msm_cci_dt_match,
+       },
+};
+
+static int __init msm_cci_init_module(void)
+{
+       return platform_driver_register(&cci_driver);
+}
+
+static void __exit msm_cci_exit_module(void)
+{
+       platform_driver_unregister(&cci_driver);
+}
+
+module_init(msm_cci_init_module);
+module_exit(msm_cci_exit_module);
+MODULE_DESCRIPTION("MSM CCI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/cci/msm_cci.h b/drivers/media/platform/msm/cci/msm_cci.h
new file mode 100644 (file)
index 0000000..7816911
--- /dev/null
@@ -0,0 +1,206 @@
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CCI_H
+#define MSM_CCI_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camsensor_sdk.h"
+
+#define NUM_MASTERS 2
+#define NUM_QUEUES 2
+
+#define TRUE  1
+#define FALSE 0
+
+#define CCI_PINCTRL_STATE_DEFAULT "cci_default"
+#define CCI_PINCTRL_STATE_SLEEP "cci_suspend"
+
+#define CCI_NUM_CLK_MAX        16
+
+enum cci_i2c_queue_t {
+       QUEUE_0,
+       QUEUE_1,
+};
+
+enum cci_i2c_master_t {
+       MASTER_0,
+       MASTER_1,
+       MASTER_MAX,
+};
+
+struct msm_camera_cci_client {
+       struct v4l2_subdev *cci_subdev;
+       uint32_t freq;
+       enum i2c_freq_mode_t i2c_freq_mode;
+       enum cci_i2c_master_t cci_i2c_master;
+       uint16_t sid;
+       uint16_t cid;
+       uint32_t timeout;
+       uint16_t retries;
+       uint16_t id_map;
+};
+
+enum msm_cci_cmd_type {
+       MSM_CCI_INIT,
+       MSM_CCI_RELEASE,
+       MSM_CCI_SET_SID,
+       MSM_CCI_SET_FREQ,
+       MSM_CCI_SET_SYNC_CID,
+       MSM_CCI_I2C_READ,
+       MSM_CCI_I2C_WRITE,
+       MSM_CCI_GPIO_WRITE,
+};
+
+struct msm_camera_cci_wait_sync_cfg {
+       uint16_t line;
+       uint16_t delay;
+};
+
+struct msm_camera_cci_gpio_cfg {
+       uint16_t gpio_queue;
+       uint16_t i2c_queue;
+};
+
+struct msm_camera_cci_i2c_read_cfg {
+       uint16_t addr;
+       enum msm_camera_i2c_reg_addr_type addr_type;
+       uint8_t *data;
+       uint16_t num_byte;
+};
+
+struct msm_camera_cci_i2c_queue_info {
+       uint32_t max_queue_size;
+       uint32_t report_id;
+       uint32_t irq_en;
+       uint32_t capture_rep_data;
+};
+
+struct msm_camera_cci_ctrl {
+       int32_t status;
+       struct msm_camera_cci_client *cci_info;
+       enum msm_cci_cmd_type cmd;
+       union {
+               struct msm_camera_i2c_reg_setting cci_i2c_write_cfg;
+               struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
+               struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
+               struct msm_camera_cci_gpio_cfg gpio_cfg;
+       } cfg;
+};
+
+struct msm_camera_cci_master_info {
+       uint32_t status;
+       uint8_t reset_pending;
+       struct mutex mutex;
+       struct completion reset_complete;
+};
+
+struct msm_cci_clk_params_t {
+       uint16_t hw_thigh;
+       uint16_t hw_tlow;
+       uint16_t hw_tsu_sto;
+       uint16_t hw_tsu_sta;
+       uint16_t hw_thd_dat;
+       uint16_t hw_thd_sta;
+       uint16_t hw_tbuf;
+       uint8_t hw_scl_stretch_en;
+       uint8_t hw_trdhld;
+       uint8_t hw_tsp;
+};
+
+enum msm_cci_state_t {
+       CCI_STATE_ENABLED,
+       CCI_STATE_DISABLED,
+};
+
+struct msm_sd_subdev {
+       struct v4l2_subdev sd;
+       int close_seq;
+       struct list_head list;
+};
+
+struct cci_device {
+       struct platform_device *pdev;
+       struct msm_sd_subdev msm_sd;
+       struct v4l2_subdev subdev;
+       struct resource *mem;
+       struct resource *irq;
+       struct resource *io;
+       void __iomem *base;
+
+       uint32_t hw_version;
+       uint8_t ref_count;
+       enum msm_cci_state_t cci_state;
+       uint32_t num_clk;
+
+       struct clk *cci_clk[CCI_NUM_CLK_MAX];
+       struct msm_camera_cci_i2c_queue_info
+               cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
+       struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS];
+       struct msm_cci_clk_params_t cci_clk_params[I2C_MAX_MODES];
+       struct gpio *cci_gpio_tbl;
+       uint8_t cci_gpio_tbl_size;
+       uint8_t master_clk_init[MASTER_MAX];
+       struct regulator *reg_ptr;
+       uint32_t cycles_per_us;
+       struct v4l2_device msm_v4l2_dev;
+};
+
+enum msm_cci_i2c_cmd_type {
+       CCI_I2C_SET_PARAM_CMD = 1,
+       CCI_I2C_WAIT_CMD,
+       CCI_I2C_WAIT_SYNC_CMD,
+       CCI_I2C_WAIT_GPIO_EVENT_CMD,
+       CCI_I2C_TRIG_I2C_EVENT_CMD,
+       CCI_I2C_LOCK_CMD,
+       CCI_I2C_UNLOCK_CMD,
+       CCI_I2C_REPORT_CMD,
+       CCI_I2C_WRITE_CMD,
+       CCI_I2C_READ_CMD,
+       CCI_I2C_WRITE_DISABLE_P_CMD,
+       CCI_I2C_READ_DISABLE_P_CMD,
+       CCI_I2C_WRITE_CMD2,
+       CCI_I2C_WRITE_CMD3,
+       CCI_I2C_REPEAT_CMD,
+       CCI_I2C_INVALID_CMD,
+};
+
+enum msm_cci_gpio_cmd_type {
+       CCI_GPIO_SET_PARAM_CMD = 1,
+       CCI_GPIO_WAIT_CMD,
+       CCI_GPIO_WAIT_SYNC_CMD,
+       CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD,
+       CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD,
+       CCI_GPIO_OUT_CMD,
+       CCI_GPIO_TRIG_EVENT_CMD,
+       CCI_GPIO_REPORT_CMD,
+       CCI_GPIO_REPEAT_CMD,
+       CCI_GPIO_CONTINUE_CMD,
+       CCI_GPIO_INVALID_CMD,
+};
+
+#ifdef CONFIG_MSM_CCI
+struct v4l2_subdev *msm_cci_get_subdev(void);
+#else
+static inline struct v4l2_subdev *msm_cci_get_subdev(void) {
+       return NULL;
+}
+#endif
+
+#define VIDIOC_MSM_CCI_CFG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *)
+
+#endif