summaryrefslogtreecommitdiff
path: root/drivers/media/sprd_sensor
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/sprd_sensor')
-rw-r--r--drivers/media/sprd_sensor/Makefile14
-rw-r--r--drivers/media/sprd_sensor/compat_sensor_drv_k.c213
-rw-r--r--drivers/media/sprd_sensor/compat_sensor_drv_k.h25
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_access.c26
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_access.h17
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_api.c730
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_api.h79
-rwxr-xr-xdrivers/media/sprd_sensor/csi2/csi_api_null.c130
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_driver.c502
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_driver.h136
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_log.c177
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_log.h78
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_system.c84
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_system.h28
-rw-r--r--drivers/media/sprd_sensor/csi2/csi_types.h15
-rw-r--r--drivers/media/sprd_sensor/csi2/usc28c_init.c281
-rw-r--r--drivers/media/sprd_sensor/otp/Makefile6
-rw-r--r--drivers/media/sprd_sensor/otp/sensor_otp.c23
-rw-r--r--drivers/media/sprd_sensor/otp/sensor_otp.h18
-rw-r--r--drivers/media/sprd_sensor/otp/sensor_otp_coreprime3g_ve.c268
-rwxr-xr-xdrivers/media/sprd_sensor/power/Makefile22
-rw-r--r--drivers/media/sprd_sensor/power/sensor_power.c40
-rw-r--r--drivers/media/sprd_sensor/power/sensor_power.h21
-rwxr-xr-xdrivers/media/sprd_sensor/power/sensor_power_coreprime3g_ve.c159
-rw-r--r--drivers/media/sprd_sensor/power/sensor_power_coreprimelite.c160
-rw-r--r--drivers/media/sprd_sensor/power/sensor_power_grandprime3g_ve.c247
-rwxr-xr-xdrivers/media/sprd_sensor/power/sensor_power_grandprime_dtv.c247
-rw-r--r--drivers/media/sprd_sensor/power/sensor_power_sharkl_t8.c247
-rw-r--r--drivers/media/sprd_sensor/power/sensor_power_sharkls_z3lte.c160
-rwxr-xr-xdrivers/media/sprd_sensor/power/sensor_power_tshark2tabe.c143
-rwxr-xr-xdrivers/media/sprd_sensor/sensor_drv_k.c2005
-rw-r--r--drivers/media/sprd_sensor/sensor_drv_sprd.h93
32 files changed, 6394 insertions, 0 deletions
diff --git a/drivers/media/sprd_sensor/Makefile b/drivers/media/sprd_sensor/Makefile
new file mode 100644
index 00000000..99fff856
--- /dev/null
+++ b/drivers/media/sprd_sensor/Makefile
@@ -0,0 +1,14 @@
+include drivers/media/sprd_dcam/common/Makefile.inc
+
+common-file := csi2/csi_access.o csi2/csi_driver.o csi2/csi_log.o csi2/csi_system.o
+
+sprd_sensor-objs := csi2/csi_api.o
+
+ifeq ($(CONFIG_64BIT),y)
+sprd_sensor-objs += compat_sensor_drv_k.o $(common-file)
+endif
+
+sprd_sensor-objs += sensor_drv_k.o $(common-file)
+obj-y += sprd_sensor.o
+obj-y += power/ otp/
+
diff --git a/drivers/media/sprd_sensor/compat_sensor_drv_k.c b/drivers/media/sprd_sensor/compat_sensor_drv_k.c
new file mode 100644
index 00000000..f17613d4
--- /dev/null
+++ b/drivers/media/sprd_sensor/compat_sensor_drv_k.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/compat.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <video/sensor_drv_k.h>
+#include "compat_sensor_drv_k.h"
+
+//#define DEBUG_COMPAT_SENSOR_DRV
+#ifdef DEBUG_COMPAT_SENSOR_DRV
+#define COMPAT_SENSOR_PRINT printk
+#else
+#define COMPAT_SENSOR_PRINT(...)
+#endif
+
+struct compat_sensor_reg_tab_tag {
+ compat_caddr_t sensor_reg_tab_ptr;
+ uint32_t reg_count;
+ uint32_t reg_bits;
+ uint32_t burst_mode;
+};
+
+struct compat_sensor_i2c_tag {
+ compat_caddr_t i2c_data;
+ uint16_t i2c_count;
+ uint16_t slave_addr;
+};
+
+struct compat_sensor_otp_data_info_tag {
+ uint32_t size;
+ compat_caddr_t data_ptr;
+};
+
+struct compat_sensor_otp_param_tag {
+ uint32_t start_addr;
+ uint32_t len;
+ compat_caddr_t buff;
+ struct compat_sensor_otp_data_info_tag golden;
+ struct compat_sensor_otp_data_info_tag awb;
+ struct compat_sensor_otp_data_info_tag lsc;
+ uint32_t type;
+};
+
+#define COMPAT_SENSOR_IO_I2C_WRITE_REGS _IOW(SENSOR_IOC_MAGIC, 14, struct compat_sensor_reg_tab_tag)
+#define COMPAT_SENSOR_IO_I2C_WRITE_EXT _IOW(SENSOR_IOC_MAGIC, 17, struct compat_sensor_i2c_tag)
+#define COMPAT_SENSOR_IO_I2C_READ_EXT _IOWR(SENSOR_IOC_MAGIC, 20, struct compat_sensor_i2c_tag)
+#define COMPAT_SENSOR_IO_READ_OTPDATA _IOWR(SENSOR_IOC_MAGIC, 254,struct compat_sensor_otp_param_tag)
+
+static long compat_get_sensor_reg_tab_tag(
+ struct compat_sensor_reg_tab_tag __user *data32,
+ struct sensor_reg_tab_tag __user *data)
+{
+ compat_caddr_t c;
+ uint32_t i;
+ int err;
+
+ err = get_user(c, &data32->sensor_reg_tab_ptr);
+ err |= put_user(c, &data->sensor_reg_tab_ptr);
+ err |= get_user(i, &data32->reg_count);
+ err |= put_user(i, &data->reg_count);
+ err |= get_user(i, &data32->reg_bits);
+ err |= put_user(i, &data->reg_bits);
+ err |= get_user(i, &data32->burst_mode);
+ err |= put_user(i, &data->burst_mode);
+
+ COMPAT_SENSOR_PRINT("sensor_reg_tab_ptr: %p reg_count: %d reg_bits: %d burst_mode: %d\n",
+ data->sensor_reg_tab_ptr, data->reg_count, data->reg_bits, data->burst_mode);
+ return err;
+}
+
+
+static long compat_get_sensor_i2c_tag(
+ struct compat_sensor_i2c_tag __user *data32,
+ struct sensor_i2c_tag __user *data)
+{
+ compat_caddr_t c;
+ uint16_t i;
+ int err;
+
+ err = get_user(c, &data32->i2c_data);
+ err |= put_user(c, &data->i2c_data);
+ err |= get_user(i, &data32->i2c_count);
+ err |= put_user(i, &data->i2c_count);
+ err |= get_user(i, &data32->slave_addr);
+ err |= put_user(i, &data->slave_addr);
+
+ COMPAT_SENSOR_PRINT("i2c_data: %p i2c_count: %d slave_addr: %d\n",
+ data->i2c_data, data->i2c_count, data->slave_addr);
+ return err;
+}
+
+static long compat_get_otp_param_tag(
+ struct compat_sensor_otp_param_tag __user *data32,
+ struct _sensor_otp_param_tag __user *data)
+{
+ compat_caddr_t c;
+ uint32_t i;
+ int err;
+
+ err = get_user(i, &data32->start_addr);
+ err |= put_user(i, &data->start_addr);
+ err |= get_user(i, &data32->len);
+ err |= put_user(i, &data->len);
+ err |= get_user(c, &data32->buff);
+ err |= put_user(c, &data->buff);
+
+ err |= get_user(c, &data32->awb.data_ptr);
+ err |= put_user(c, &data->awb.data_ptr);
+ err |= get_user(i, &data32->awb.size);
+ err |= put_user(i, &data->awb.size);
+
+ err |= get_user(c, &data32->lsc.data_ptr);
+ err |= put_user(c, &data->lsc.data_ptr);
+ err |= get_user(i, &data32->lsc.size);
+ err |= put_user(i, &data->lsc.size);
+ return err;
+}
+
+long compat_sensor_k_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int compatible_arg = 1;
+ long err = 0;
+
+ if (!filp->f_op || !filp->f_op->unlocked_ioctl)
+ return -ENOTTY;
+
+ switch (cmd) {
+ case COMPAT_SENSOR_IO_I2C_WRITE_REGS:
+ {
+ struct compat_sensor_reg_tab_tag __user *data32;
+ struct sensor_reg_tab_tag __user *data;
+
+ data32 = compat_ptr(arg);
+ data = compat_alloc_user_space(sizeof(*data));
+ if (NULL == data)
+ return -EFAULT;
+
+ err = compat_get_sensor_reg_tab_tag(data32, data);
+ if (err)
+ return err;
+ return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_I2C_WRITE_REGS,
+ (unsigned long)data);
+ }
+
+ case COMPAT_SENSOR_IO_I2C_WRITE_EXT:
+ {
+ struct compat_sensor_i2c_tag __user *data32;
+ struct sensor_i2c_tag __user *data;
+
+ data32 = compat_ptr(arg);
+ data = compat_alloc_user_space(sizeof(*data));
+ if (NULL == data)
+ return -EFAULT;
+
+ err = compat_get_sensor_i2c_tag(data32, data);
+ if (err)
+ return err;
+ return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_I2C_WRITE_EXT,
+ (unsigned long)data);
+ }
+
+ case COMPAT_SENSOR_IO_I2C_READ_EXT:
+ {
+ struct compat_sensor_i2c_tag __user *data32;
+ struct sensor_i2c_tag __user *data;
+
+ data32 = compat_ptr(arg);
+ data = compat_alloc_user_space(sizeof(*data));
+ if (NULL == data)
+ return -EFAULT;
+
+ err = compat_get_sensor_i2c_tag(data32, data);
+ if (err)
+ return err;
+ return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_I2C_READ_EXT,
+ (unsigned long)data);
+ }
+
+ case COMPAT_SENSOR_IO_READ_OTPDATA:
+ {
+ struct compat_sensor_otp_param_tag __user *data32;
+ SENSOR_OTP_PARAM_T __user *data;
+
+ printk("SENSOR: ioctl COMPAT_SENSOR_IO_READ_OTPDATA \n");
+ data32 = compat_ptr(arg);
+ data = compat_alloc_user_space(sizeof(*data));
+ if (NULL == data)
+ return -EFAULT;
+
+ err = compat_get_otp_param_tag(data32, data);
+ if (err)
+ return err;
+ return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_READ_OTPDATA,
+ (unsigned long)data);
+ }
+ break;
+
+ default:
+ return filp->f_op->unlocked_ioctl(filp, cmd,
+ (unsigned long)compat_ptr(arg));
+ }
+}
diff --git a/drivers/media/sprd_sensor/compat_sensor_drv_k.h b/drivers/media/sprd_sensor/compat_sensor_drv_k.h
new file mode 100644
index 00000000..9cededeb
--- /dev/null
+++ b/drivers/media/sprd_sensor/compat_sensor_drv_k.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 _COMPAT_IMG_SCALE_H_
+#define _COMPAT_IMG_SCALE_H_
+
+#if IS_ENABLED(CONFIG_COMPAT)
+
+long compat_sensor_k_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+
+#else
+
+#define compat_sensor_k_ioctl NULL
+
+#endif /* CONFIG_COMPAT */
+#endif
diff --git a/drivers/media/sprd_sensor/csi2/csi_access.c b/drivers/media/sprd_sensor/csi2/csi_access.c
new file mode 100644
index 00000000..9a37476f
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_access.c
@@ -0,0 +1,26 @@
+/*
+ * access.c
+ *
+ * Created on: Jun 25, 2010
+ * Author: klabadi & dlopo
+ */
+#include "csi_types.h"
+#include "csi_access.h"
+#include "csi_log.h"
+
+static u32 * access_base_addr = 0;
+int access_init(u32 * base_addr)
+{
+ access_base_addr = base_addr;
+ return 0;
+}
+
+u32 access_read(u16 addr)
+{
+ return access_base_addr[addr];
+}
+
+void access_write(u32 data, u16 addr)
+{
+ access_base_addr[addr] = data;
+} \ No newline at end of file
diff --git a/drivers/media/sprd_sensor/csi2/csi_access.h b/drivers/media/sprd_sensor/csi2/csi_access.h
new file mode 100644
index 00000000..6c9e8ee9
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_access.h
@@ -0,0 +1,17 @@
+/*
+ * access.h
+ *
+ * Created on: Jun 25, 2010
+ * Author: klabadi & dlopo
+ */
+
+#ifndef ACCESS_H_
+#define ACCESS_H_
+
+#include <linux/types.h>
+int access_init(u32 * base_addr);
+u32 access_read(u16 addr);
+
+void access_write(u32 data, u16 addr);
+
+#endif /* ACCESS_H_ */ \ No newline at end of file
diff --git a/drivers/media/sprd_sensor/csi2/csi_api.c b/drivers/media/sprd_sensor/csi2/csi_api.c
new file mode 100644
index 00000000..12af2bf6
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_api.c
@@ -0,0 +1,730 @@
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <soc/sprd/sci_glb_regs.h>
+
+#ifndef CONFIG_64BIT
+#include <mach/irqs.h>
+#include <soc/sprd/globalregs.h>
+#include <soc/sprd/hardware.h>
+#else
+#include <soc/sprd/irqs.h>
+#endif
+#include "parse_hwinfo.h"
+#include <soc/sprd/sci.h>
+
+#include "csi_api.h"
+#include "csi_log.h"
+
+#define CSI2_EB (SPRD_MMAHB_BASE)
+#define CSI2_EB_BIT (1 << 4)
+#define CSI2_RST (SPRD_MMAHB_BASE + 0x4)
+#define CSI2_RST_BIT (1 << 5)
+
+#if defined(CONFIG_SC_FPGA) && defined(CONFIG_MACH_SP7720EA)
+extern void usc28c_csi_init(void);
+#endif
+void csi_api_event1_handler(int irq, void *handle);
+void csi_api_event2_handler(int irq, void *handle);
+
+
+static void csi_phy_power_down(u32 phy_id, u32 is_eb)
+{
+#if IS_ENABLED(VERSION3T) || IS_ENABLED(VERSION3D)
+ /*bit0: phya ; bit1: phyb*/
+ if (is_eb) {
+ if (0x03 == (phy_id & 0x03)) {
+ sci_glb_set(REG_AON_APB_PWR_CTRL, (BIT_CSI0_PHY_PD | BIT_CSI1_PHY_PD));
+ } else {
+ if (0x01 == (phy_id & 0x01)) {
+ sci_glb_set(REG_AON_APB_PWR_CTRL, BIT_CSI0_PHY_PD);
+ }
+
+ if (0x02 == (phy_id & 0x02)) {
+ sci_glb_set(REG_AON_APB_PWR_CTRL, BIT_CSI1_PHY_PD);
+ }
+ }
+ } else {
+ if (0x03 == (phy_id & 0x03)) {
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, (BIT_CSI0_PHY_PD | BIT_CSI1_PHY_PD));
+ } else {
+ if (0x01 == (phy_id & 0x01)) {
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, BIT_CSI0_PHY_PD);
+ }
+
+ if (0x02 == (phy_id & 0x02)) {
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, BIT_CSI1_PHY_PD);
+ }
+ }
+ }
+#elif IS_ENABLED(VERSION3L)
+ /*bit0: phya ; bit1: phyb*/
+ if (is_eb) {
+ if (0x03 == (phy_id & 0x03)) {
+ printk("csi phy erro: scx35l does not support the combination of phya & phyb\n");
+ } else {
+ if (0x01 == (phy_id & 0x01)) {
+ sci_glb_set(REG_AON_APB_PWR_CTRL, (3 << 12));
+ }
+
+ if (0x02 == (phy_id & 0x02)) {
+ sci_glb_set(REG_AON_APB_PWR_CTRL, (3 << 10));
+ }
+ }
+ } else {
+ if (0x03 == (phy_id & 0x03)) {
+ printk("csi phy erro: scx35l does not support the combination of phya & phyb\n");
+ } else {
+ if (0x01 == (phy_id & 0x01)) {
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, (1 << 13));
+ udelay(500);
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, (1 << 12));
+ }
+
+ if (0x02 == (phy_id & 0x02)) {
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, (1 << 11));
+ udelay(500);
+ sci_glb_clr(REG_AON_APB_PWR_CTRL, (1 << 10));
+ }
+ }
+ }
+#endif
+}
+
+static void csi_enable(void)
+{
+ sci_glb_set(CSI2_EB, CSI2_EB_BIT);
+ sci_glb_set(CSI2_RST, CSI2_RST_BIT);
+ udelay(1);
+ sci_glb_clr(CSI2_RST, CSI2_RST_BIT);
+}
+
+int csi_api_malloc(void **handle)
+{
+ int ret = 0;
+ struct csi_context *csi_handle = NULL;
+ csi_handle = (struct csi_context *)vzalloc(sizeof(struct csi_context));
+ if (NULL == handle) {
+ printk("vzalloc fail,no mem");
+ return -1;
+ }
+ csi_handle->g_csi2_irq = 0x12000034;
+ spin_lock_init(&csi_handle->csi2_lock);
+ *handle = csi_handle;
+
+ return ret;
+}
+
+void csi_api_free(void *handle)
+{
+ if (handle != NULL) {
+ vfree(handle);
+ handle = NULL;
+ }
+}
+
+u8 csi_api_init(u32 bps_per_lane, u32 phy_id)
+{
+ csi_error_t e = SUCCESS;
+ u64 base_address = CSI2_BASE;
+
+#if defined(CONFIG_SC_FPGA) && defined(CONFIG_MACH_SP7720EA)
+ usc28c_csi_init();
+#endif
+
+ do {
+ csi_phy_power_down(phy_id, 0);
+ csi_enable();
+ e = csi_init(base_address);
+ if(e != SUCCESS) {
+ LOG_ERROR("Unable to initialise driver");
+ break;
+ }
+ dphy_init(bps_per_lane, phy_id);
+ }while(0);
+
+ return e;
+}
+
+u8 csi_api_start(void *handle)
+{
+ csi_error_t e = SUCCESS;
+ int ret = 0;
+ struct csi_context *csi_handle = handle;
+
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+ do {
+ /* set only one lane (lane 0) as active (ON) */
+ e = csi_set_on_lanes(1);
+ if(e != SUCCESS) {
+ LOG_ERROR("Unable to set lanes");
+ csi_close();
+ break;
+ }
+ LOG_DEBUG("Lane set OK");
+ e = csi_shut_down_phy(0);
+ if(e != SUCCESS) {
+ LOG_ERROR("Unable to bring up PHY");
+ csi_close();
+ break;
+ }
+ LOG_DEBUG("PHY power up OK");
+
+ e = csi_reset_phy();
+ if(e != SUCCESS) {
+ LOG_ERROR("Unable to reset PHY");
+ csi_close();
+ break;
+ }
+ LOG_DEBUG("PHY reset OK");
+
+ e = csi_reset_controller();
+ if(e != SUCCESS) {
+ LOG_ERROR("Unable to reset controller");
+ csi_close();
+ break;
+ }
+ /* MASK all interrupts */
+ csi_event_disable(0xffffffff, 1);
+ csi_event_disable(0xffffffff, 2);
+ ret = request_irq(IRQ_CSI_INT0,
+ (irq_handler_t)csi_api_event1_handler,
+ IRQF_SHARED,
+ "CSI2_0",
+ (void *)csi_handle);
+ if (ret) {
+ e = ERR_UNDEFINED;
+ break;
+ }
+
+ ret = request_irq(IRQ_CSI_INT1,
+ (irq_handler_t)csi_api_event2_handler,
+ IRQF_SHARED,
+ "CSI2_1",
+ (void *)csi_handle);
+ if (ret) {
+ e = ERR_UNDEFINED;
+ break;
+ }
+
+ } while(0);
+
+ return e;
+}
+
+u8 csi_api_close(void *handle, u32 phy_id)
+{
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+ LOG_DEBUG("exit");
+ csi_api_unregister_all_events(handle);
+ csi_shut_down_phy(1);
+ free_irq(IRQ_CSI_INT0, &csi_handle->g_csi2_irq);
+ free_irq(IRQ_CSI_INT1, &csi_handle->g_csi2_irq);
+ csi_close();
+ csi_phy_power_down(phy_id, 1);
+
+ return SUCCESS;
+}
+
+u8 csi_api_set_on_lanes(u8 no_of_lanes)
+{
+ return csi_set_on_lanes(no_of_lanes);
+}
+
+u8 csi_api_get_on_lanes()
+{
+ return csi_get_on_lanes();
+}
+
+csi_lane_state_t csi_api_get_clk_state()
+{
+ return csi_clk_state();
+}
+
+csi_lane_state_t csi_api_get_lane_state(u8 lane)
+{
+ return csi_lane_module_state(lane);
+}
+
+static u32 csi_api_event_map(u8 event, u8 vc_lane)
+{
+ switch((csi_event_t)(event)) {
+ case ERR_PHY_TX_START:
+ return (0x1 << (event + vc_lane));
+ case ERR_FRAME_BOUNDARY_MATCH:
+ return (0x1 << (event + vc_lane));
+ case ERR_FRAME_SEQUENCE:
+ return (0x1 << (event + vc_lane));
+ case ERR_CRC_DURING_FRAME:
+ return (0x1 << (event + vc_lane));
+ case ERR_LINE_CRC:
+ return (0x1 << (24 + vc_lane));
+ case ERR_DOUBLE_ECC:
+ return (0x1 << 28);
+ case ERR_PHY_ESCAPE_ENTRY:
+ return (0x1 << (0 + vc_lane));
+ case ERR_ECC_SINGLE:
+ return (0x1 << (8 + vc_lane));
+ case ERR_UNSUPPORTED_DATA_TYPE:
+ return (0x1 << (12 + vc_lane));
+ case MAX_EVENT:
+ break;
+ default:
+ break;
+ }
+ switch((csi_line_event_t)(event)) {
+ case ERR_LINE_BOUNDARY_MATCH:
+ return (0x1 << (16 + (vc_lane % 4)));
+ case ERR_LINE_SEQUENCE:
+ return (0x1 << (20 + (vc_lane % 4)));
+ default:
+ break;
+ }
+ /* writing the following value affects nothing */
+ return 0x80000000;
+}
+
+u8 csi_api_register_event(void *handle, csi_event_t event, u8 vc_lane, handler_t handler)
+{
+ /* the VC_LANE value is the lane number ONLY in PHY ERRORS
+ * e rest are all virtual channels number except for
+ * double ECC, where VC is unknown
+ */
+ u8 e = SUCCESS;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+ /* the maximum */
+ if (vc_lane < 4) {
+ switch(event) {
+ case ERR_PHY_TX_START:
+ LOG_WARNING("the lane value depends on the synthesis defines");
+ LOG_WARNING("make sure this value does not exceed these defines");
+ case ERR_FRAME_BOUNDARY_MATCH:
+ case ERR_FRAME_SEQUENCE:
+ case ERR_CRC_DURING_FRAME:
+ case ERR_LINE_CRC:
+ case ERR_DOUBLE_ECC:
+ e = csi_event_enable(csi_api_event_map(event, vc_lane), 1);
+ break;
+
+ case ERR_PHY_ESCAPE_ENTRY:
+ LOG_WARNING("the lane value depends on the synthesis defines");
+ LOG_WARNING("make sure this value does not exceed these defines");
+ case ERR_ECC_SINGLE:
+ case ERR_UNSUPPORTED_DATA_TYPE:
+ e = csi_event_enable(csi_api_event_map(event, vc_lane), 2);
+ break;
+
+ default:
+ e = ERROR_EVENT_TYPE_INVALID;
+ break;
+ }
+ } else {
+ e = ERROR_VC_LANE_OUT_OF_BOUND;
+ }
+ if (e == SUCCESS) {
+ csi_handle->csi_api_event_registry[event + vc_lane] = handler;
+ }
+
+ return e;
+}
+
+u8 csi_api_unregister_event(void *handle, csi_event_t event, u8 vc_lane)
+{
+ csi_error_t e = SUCCESS;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+ /* the maximum */
+ if (vc_lane < 4) {
+ switch(event) {
+ case ERR_PHY_TX_START:
+ LOG_WARNING("the lane value depends on the synthesis defines");
+ LOG_WARNING("make sure this value does not exceed these defines");
+ case ERR_FRAME_BOUNDARY_MATCH:
+ case ERR_FRAME_SEQUENCE:
+ case ERR_CRC_DURING_FRAME:
+ case ERR_LINE_CRC:
+ case ERR_DOUBLE_ECC:
+ e = csi_event_disable(csi_api_event_map(event, vc_lane), 1);
+ break;
+
+ case ERR_PHY_ESCAPE_ENTRY:
+ LOG_WARNING("the lane value depends on the synthesis defines");
+ LOG_WARNING("make sure this value does not exceed these defines");
+ case ERR_ECC_SINGLE:
+ case ERR_UNSUPPORTED_DATA_TYPE:
+ e = csi_event_disable(csi_api_event_map(event, vc_lane), 2);
+ break;
+
+ default:
+ e = ERROR_EVENT_TYPE_INVALID;
+ break;
+
+ }
+ } else {
+ e = ERROR_VC_LANE_OUT_OF_BOUND;
+ }
+ if (e == SUCCESS) {
+ csi_handle->csi_api_event_registry[event + vc_lane] = NULL;
+ }
+
+ return e;
+}
+
+u8 csi_api_register_line_event(void *handle, u8 vc, csi_data_type_t data_type, csi_line_event_t line_event, handler_t handler)
+{
+ u8 id = 0;
+ int counter = 0;
+ int first_slot = -1;
+ int already_registered = 0;
+ u8 e = SUCCESS;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+
+ if ((data_type < NULL_PACKET)
+ || ((data_type > EMBEDDED_8BIT_NON_IMAGE_DATA) && (data_type < YUV420_8BIT))
+ || ((data_type > RGB888) && (data_type < RAW6))
+ || ((data_type > RAW14) && (data_type < USER_DEFINED_8BIT_DATA_TYPE_1 ))
+ || (data_type > USER_DEFINED_8BIT_DATA_TYPE_8)) {
+ /* wrong data type - not long packet */
+ return ERROR_DATA_TYPE_INVALID;
+ }
+ /* the maximum */
+ if (vc > 3) {
+ return ERROR_VC_LANE_OUT_OF_BOUND;
+ }
+ id = (u8)((vc << 6)) | (u8)(data_type);
+
+ for (counter = 0; counter < 8; counter++) {
+ if (csi_get_registered_line_event(counter) == 0) {
+ /* first empty slot to register event */
+ first_slot = counter;
+ break;
+ }
+ if (id == csi_get_registered_line_event(counter)) {
+ LOG_WARNING("already registered line/datatype");
+ already_registered = 1;
+ first_slot = counter; /* no need to register it again */
+ /* but NOT that there are no slots!*/
+ break;
+ }
+ }
+ /* if not all slots are taken */
+ if (first_slot != -1) {
+ /* un-mask (whether registered or not) */
+ e = csi_event_enable(csi_api_event_map(line_event, first_slot), (first_slot / 4 == 1)? 2: 1);
+ if (e == SUCCESS) {
+ /* if not already registered */
+ if (already_registered != 1) {
+ e = csi_register_line_event(vc, data_type, first_slot);
+ if (csi_handle->csi_api_event_registry[line_event + first_slot] != NULL) {
+ LOG_WARNING("already registered event and callback (overwriting!)");
+ }
+ }
+ /* register callback */
+ csi_handle->csi_api_event_registry[line_event + first_slot] = handler;
+ }
+ } else {
+ LOG_WARNING("all slots are taken");
+ e = ERROR_SLOTS_FULL;
+ }
+
+ return e;
+}
+
+u8 csi_api_unregister_line_event(void *handle, u8 vc, csi_data_type_t data_type, csi_line_event_t line_event)
+{
+ u8 id = 0;
+ int counter = 0;
+ int replace_slot = -1;
+ int last_slot = -1;
+ u8 vc_new = 0;
+ csi_data_type_t dt_new;
+ csi_line_event_t other_line_event;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+
+ if ((data_type < NULL_PACKET)
+ || ((data_type > EMBEDDED_8BIT_NON_IMAGE_DATA) && (data_type < YUV420_8BIT))
+ || ((data_type > RGB888) && (data_type < RAW6))
+ || ((data_type > RAW14) && (data_type < USER_DEFINED_8BIT_DATA_TYPE_1 ))
+ || (data_type > USER_DEFINED_8BIT_DATA_TYPE_8)) {
+ /* wrong data type - not long packet */
+ return ERROR_DATA_TYPE_INVALID;
+ }
+ /* the maximum */
+ if (vc > 3) {
+ return ERROR_VC_LANE_OUT_OF_BOUND;
+ }
+ if (line_event == ERR_LINE_BOUNDARY_MATCH) {
+ other_line_event = ERR_LINE_SEQUENCE;
+ } else if (line_event == ERR_LINE_SEQUENCE) {
+ other_line_event = ERR_LINE_BOUNDARY_MATCH;
+ } else {
+ return ERROR_DATA_TYPE_INVALID;
+ }
+ id = (vc << 6) | data_type;
+ for (counter = 0; counter < 8; counter++) {
+ if (id == csi_get_registered_line_event(counter)) {
+ replace_slot = counter;
+ }
+ if (csi_get_registered_line_event(counter) == 0) {
+ last_slot = counter - 1;
+ break;
+ }
+ }
+ if (replace_slot == -1) {
+ return ERROR_NOT_REGISTERED;
+ }
+ if (last_slot == -1) {
+ last_slot = 7; /* the very last entry */
+ }
+ vc_new = csi_get_registered_line_event(last_slot) >> 6;
+ dt_new = (csi_get_registered_line_event(last_slot) << 2) >> 2;
+
+ if ((csi_handle->csi_api_event_registry[other_line_event + replace_slot] == NULL) && (last_slot != replace_slot)) {
+ /* swap IDI with last registered if its NOT the last entry*/
+ /* copy the last to (over) the one to be deleted*/
+ csi_register_line_event(vc_new, dt_new, replace_slot);
+ /* now that last registered is copied to a new location, unregister old location */
+ csi_event_disable(csi_api_event_map(line_event, last_slot), (last_slot / 4 == 1)? 2: 1);
+ /* swap event registry */
+ csi_handle->csi_api_event_registry[line_event + replace_slot] = csi_handle->csi_api_event_registry[line_event + last_slot];
+ /* mask last slot */
+ if (csi_handle->csi_api_event_registry[other_line_event + last_slot] != NULL) {
+ /* swap event registry - the other possible line event of the last slot */
+ csi_handle->csi_api_event_registry[other_line_event + replace_slot] = csi_handle->csi_api_event_registry[other_line_event + last_slot];
+ /* mask last slot, other line event!*/
+ csi_event_disable(csi_api_event_map(other_line_event, last_slot), (last_slot / 4 == 1)? 2: 1);
+ /* un mask other line event */
+ csi_event_enable(csi_api_event_map(other_line_event, replace_slot), (replace_slot / 4 == 1)? 2: 1);
+ }
+ csi_unregister_line_event(last_slot);
+ } else {
+ /* remove from event registry */
+ csi_handle->csi_api_event_registry[line_event + replace_slot] = NULL;
+ /* mask */
+ csi_event_disable(csi_api_event_map(line_event, replace_slot), (replace_slot / 4 == 1)? 2: 1);
+
+ if ((csi_handle->csi_api_event_registry[other_line_event + replace_slot] == NULL) && (last_slot == replace_slot)) { /* if it is last entry */
+ csi_unregister_line_event(last_slot);
+ }
+ }
+
+ return SUCCESS;
+}
+
+void csi_api_event1_handler(int irq, void *handle)
+{
+ u32 source = 0;
+ unsigned long flag;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return;
+ }
+
+ source = csi_event_get_source(1);
+ spin_lock_irqsave(&csi_handle->csi2_lock,flag);
+ if (NULL != csi_handle->isr_cb) {
+ (*csi_handle->isr_cb)(1, source, csi_handle->u_data);
+ }
+ spin_unlock_irqrestore(&csi_handle->csi2_lock, flag);
+
+ return;
+#if 0
+ if (source > 0) { /* map to enumerator csi_event_t or csi_line_event_t */
+ if ((source & (0xf << 0)) > 0) {
+ tmp = ERR_PHY_TX_START + ((source & 0xf) >> 1);
+ }
+ if ((source & (0xf << 4)) > 0) {
+ tmp = ERR_FRAME_BOUNDARY_MATCH + ((source & 0xf0) >> 5);
+ }
+ if ((source & (0xf << 8)) > 0) {
+ tmp = ERR_FRAME_SEQUENCE + ((source & (0xf << 8)) >> 9);
+ }
+ if ((source & (0xf << 12)) > 0) {
+ tmp = ERR_CRC_DURING_FRAME + ((source & (0xf << 12)) >> 13);
+ }
+ if ((source & (0xf << 16)) > 0) {
+ tmp = ERR_LINE_BOUNDARY_MATCH + ((source & (0xf << 16)) >> 17);
+ }
+ if ((source & (0xf << 20)) > 0) {
+ tmp = ERR_LINE_SEQUENCE + ((source & (0xf << 20)) >> 21);
+ }
+ if ((source & (0xf << 24)) > 0) {
+ tmp = ERR_LINE_CRC + ((source & (0xf << 24)) >> 25);
+ }
+ if ((source & (0xf << 28)) > 0) {
+ tmp = ERR_DOUBLE_ECC;
+ }
+ /* call callback if valid */
+ if (tmp != 0x80000000) {
+ if (csi_api_event_registry[tmp] != NULL) {
+ csi_api_event_registry[tmp](param);
+ }
+ }
+ }
+#endif
+}
+
+void csi_api_event2_handler(int irq, void *handle)
+{
+ u32 source = 0;
+ unsigned long flag;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ;
+ }
+
+ source = csi_event_get_source(2);
+ spin_lock_irqsave(&csi_handle->csi2_lock, flag);
+ if (csi_handle->isr_cb) {
+ (*csi_handle->isr_cb)(2, source, csi_handle->u_data);
+ }
+ spin_unlock_irqrestore(&csi_handle->csi2_lock, flag);
+
+ return;
+
+#if 0
+ source = csi_event_get_source(2);
+
+ if (source > 0) {
+ /* map to enumerator csi_event_t or csi_line_event_t */
+ if ((source & (0xf << 0)) > 0) {
+ tmp = ERR_PHY_ESCAPE_ENTRY + ((source & 0xf) >> 1);
+ }
+
+ if ((source & (0xf << 4)) > 0) {
+ ; /* error discarded */
+ }
+
+ if ((source & (0xf << 8)) > 0) {
+ tmp = ERR_ECC_SINGLE + ((source & (0xf << 8)) >> 9);
+ }
+ if ((source & (0xf << 12)) > 0) {
+ tmp = ERR_UNSUPPORTED_DATA_TYPE + ((source & (0xf << 12)) >> 13);
+ }
+ if ((source & (0xf << 16)) > 0) {
+ tmp = ERR_LINE_BOUNDARY_MATCH + 4 + ((source & (0xf << 16)) >> 17);
+ /* 4 added because its in ERR2. ERR1 already has 4 */
+ }
+ if ((source & (0xf << 20)) > 0) {
+ tmp = ERR_LINE_SEQUENCE + 4 + ((source & (0xf << 20)) >> 21);
+ }
+ /* call callback if valid */
+ if (tmp != 0x80000000) {
+ if (csi_api_event_registry[tmp] != NULL) {
+ csi_api_event_registry[tmp](param);
+ }
+ }
+ }
+#endif
+}
+
+u8 csi_api_unregister_all_events(void *handle)
+{
+ u8 e = SUCCESS;
+ u8 counter = 0;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return -1;
+ }
+
+ e = csi_event_disable(0xffffffff, 1);
+ e = csi_event_disable(0xffffffff, 2);
+ if (e == SUCCESS) {
+ for (counter = 0; counter < 8; counter++) {
+ e = csi_unregister_line_event(counter);
+ }
+ for (counter = (u8)(ERR_PHY_TX_START); counter < (u8)(MAX_EVENT); counter++) {
+ csi_handle->csi_api_event_registry[counter] = NULL;
+ }
+ }
+
+ return e;
+}
+
+u8 csi_api_shut_down_phy(u8 shutdown)
+{
+ return csi_shut_down_phy(shutdown);
+}
+
+u8 csi_api_reset_phy()
+{
+ return csi_reset_phy();
+}
+
+u8 csi_api_reset_controller()
+{
+ return csi_reset_controller();
+}
+
+u8 csi_api_core_write(csi_registers_t address, u32 data)
+{
+ return csi_core_write(address, data);
+}
+
+u32 csi_api_core_read(csi_registers_t address)
+{
+ return csi_core_read(address);
+}
+
+int csi_reg_isr(void *handle, csi2_isr_func user_func, void* user_data)
+{
+ unsigned long flag;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+
+ spin_lock_irqsave(&csi_handle->csi2_lock, flag);
+ csi_handle->isr_cb = user_func;
+ csi_handle->u_data = user_data;
+ spin_unlock_irqrestore(&csi_handle->csi2_lock, flag);
+
+ return 0;
+}
+
+int csi_read_registers(u32* reg_buf, u32 *buf_len)
+{
+ u32 *reg_addr = (u32*)CSI2_BASE;
+
+ if (NULL == reg_buf || NULL == buf_len || 0 != (*buf_len % 4)) {
+ return -1;
+ }
+
+ while (buf_len != 0 && reg_addr < (u64)(CSI2_BASE + SPRD_CSI2_REG_SIZE)) {
+ *reg_buf++ = *(volatile u32*)reg_addr++;
+ *buf_len -= 4;
+ }
+
+ *buf_len = SPRD_CSI2_REG_SIZE;
+
+ return 0;
+}
diff --git a/drivers/media/sprd_sensor/csi2/csi_api.h b/drivers/media/sprd_sensor/csi2/csi_api.h
new file mode 100644
index 00000000..b49bee7a
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_api.h
@@ -0,0 +1,79 @@
+/*
+ * csi_driver
+ * 12/05/2010
+ * Synopsys Inc. PT02
+ */
+
+#ifndef CSI_API_H_
+#define CSI_API_H_
+
+#include "csi_types.h"
+#include "csi_driver.h"
+#include <linux/spinlock.h>
+
+#define SPRD_CSI2_REG_SIZE 0x40
+
+typedef int (*csi2_isr_func)(u32 err_id, u32 err_status, void* u_data);
+
+/* enumerators index the handler array rather than masks */
+typedef enum
+{
+ ERR_PHY_TX_START = 0,
+ ERR_FRAME_BOUNDARY_MATCH = 4,
+ ERR_FRAME_SEQUENCE = 8,
+ ERR_CRC_DURING_FRAME = 12,
+ ERR_LINE_CRC = 16,
+ ERR_DOUBLE_ECC = 20,
+ ERR_PHY_ESCAPE_ENTRY = 21,
+ ERR_ECC_SINGLE = 25,
+ ERR_UNSUPPORTED_DATA_TYPE = 29,
+ MAX_EVENT = 49
+} csi_event_t;
+typedef enum
+{
+ ERR_LINE_BOUNDARY_MATCH = 33,
+ ERR_LINE_SEQUENCE = 41
+} csi_line_event_t;
+typedef enum
+{
+ ERROR_VC_LANE_OUT_OF_BOUND = 0xCA,
+ ERROR_EVENT_TYPE_INVALID = 0xC9,
+ ERROR_DATA_TYPE_INVALID = 0xC8,
+ ERROR_SLOTS_FULL = 0xC7,
+ ERROR_ALREADY_REGISTERED = 0xC6,
+ ERROR_NOT_REGISTERED = 0xC5
+} csi_api_error_t;
+
+struct csi_context {
+ u32 g_csi2_irq;
+ csi2_isr_func isr_cb;
+ void *u_data;
+ spinlock_t csi2_lock;
+ handler_t csi_api_event_registry[MAX_EVENT];
+};
+
+int csi_api_malloc(void **handle);
+void csi_api_free(void *handle);
+u8 csi_api_init(u32 bps_per_lane, u32 phy_id);
+u8 csi_api_start(void *handle);
+//u8 csi_api_start(u32 base_address);
+u8 csi_api_close(void *handle, u32 phy_id);
+u8 csi_api_set_on_lanes(u8 no_of_lanes);
+u8 csi_api_get_on_lanes(void);
+csi_lane_state_t csi_api_get_clk_state(void);
+csi_lane_state_t csi_api_get_lane_state(u8 lane);
+u8 csi_api_register_line_event(void *handle, u8 vc, csi_data_type_t data_type, csi_line_event_t line_event, handler_t handler);
+u8 csi_api_unregister_line_event(void *handle, u8 vc, csi_data_type_t data_type, csi_line_event_t line_event);
+u8 csi_api_register_event(void *handle, csi_event_t event, u8 vc_lane, handler_t handler);
+u8 csi_api_unregister_event(void *handle, csi_event_t event, u8 vc_lane);
+u8 csi_api_unregister_all_events(void *handle);
+u8 csi_api_shut_down_phy(u8 shutdown);
+u8 csi_api_reset_phy(void);
+u8 csi_api_reset_controller(void);
+u8 csi_api_core_write(csi_registers_t address, u32 data);
+u32 csi_api_core_read(csi_registers_t address);
+int csi_reg_isr(void *handle, csi2_isr_func user_func, void* user_data);
+int csi_read_registers(uint32_t* reg_buf, uint32_t *buf_len);
+
+#endif /* CSI_API_H_ */
+
diff --git a/drivers/media/sprd_sensor/csi2/csi_api_null.c b/drivers/media/sprd_sensor/csi2/csi_api_null.c
new file mode 100755
index 00000000..56b7556f
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_api_null.c
@@ -0,0 +1,130 @@
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+
+#include "csi_api.h"
+#include "csi_log.h"
+
+void csi_api_event1_handler(int irq, void *handle);
+void csi_api_event2_handler(int irq, void *handle);
+int csi_api_malloc(void **handle)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+
+void csi_api_free(void *handle)
+{
+}
+u8 csi_api_init(u32 bps_per_lane, u32 phy_id)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_start(void *handle)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_close(void *handle, u32 phy_id)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_set_on_lanes(u8 no_of_lanes)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+
+u8 csi_api_get_on_lanes()
+{
+ return ERR_NOT_COMPATIBLE;
+}
+csi_lane_state_t csi_api_get_clk_state()
+{
+ return ERR_NOT_COMPATIBLE;
+}
+csi_lane_state_t csi_api_get_lane_state(u8 lane)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_register_event(void *handle, csi_event_t event, u8 vc_lane, handler_t handler)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_unregister_event(void *handle, csi_event_t event, u8 vc_lane)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_register_line_event(void *handle, u8 vc, csi_data_type_t data_type, csi_line_event_t line_event, handler_t handler)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_unregister_line_event(void *handle, u8 vc, csi_data_type_t data_type, csi_line_event_t line_event)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+void csi_api_event1_handler(int irq, void *handle)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+void csi_api_event2_handler(int irq, void *handle)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_unregister_all_events(void *handle)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_shut_down_phy(u8 shutdown)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_reset_phy()
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_reset_controller()
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u8 csi_api_core_write(csi_registers_t address, u32 data)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+u32 csi_api_core_read(csi_registers_t address)
+{
+ return ERR_NOT_COMPATIBLE;
+}
+
+int csi_reg_isr(void *handle, csi2_isr_func user_func, void* user_data)
+{
+ unsigned long flag;
+ struct csi_context *csi_handle = handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return ERR_UNDEFINED;
+ }
+
+ spin_lock_irqsave(&csi_handle->csi2_lock, flag);
+ csi_handle->isr_cb = user_func;
+ csi_handle->u_data = user_data;
+ spin_unlock_irqrestore(&csi_handle->csi2_lock, flag);
+ return 0;
+}
+
+int csi_read_registers(u32* reg_buf, u32 *buf_len)
+{
+ u32 *reg_addr = (u32*)CSI2_BASE;
+
+ if (NULL == reg_buf || NULL == buf_len || 0 != (*buf_len % 4)) {
+ return -1;
+ }
+
+ while (buf_len != 0 && (u32)reg_addr < (CSI2_BASE + SPRD_CSI2_REG_SIZE)) {
+ *reg_buf++ = *(volatile u32*)reg_addr++;
+ *buf_len -= 4;
+ }
+
+ *buf_len = SPRD_CSI2_REG_SIZE;
+ return 0;
+}
diff --git a/drivers/media/sprd_sensor/csi2/csi_driver.c b/drivers/media/sprd_sensor/csi2/csi_driver.c
new file mode 100644
index 00000000..dc4c922c
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_driver.c
@@ -0,0 +1,502 @@
+#include <linux/delay.h>
+#include "csi_driver.h"
+#include "csi_access.h"
+#include "csi_log.h"
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#else
+#include "parse_hwinfo.h"
+#endif
+#include <soc/sprd/sci.h>
+
+
+static int csi_core_initialized = 0;
+
+static const struct csi_pclk_cfg csi_pclk_setting[CSI_PCLK_CFG_COUNTER] = {
+ {80, 90, 0x00, 4},
+ {90, 100, 0x10, 4},
+ {100, 110, 0x20, 4},
+ {110, 130, 0x01, 6},
+ {130, 140, 0x11, 6},
+ {140, 150, 0x21, 6},
+ {150, 170, 0x02, 9},
+ {170, 180, 0x12, 9},
+ {180, 200, 0x22, 9},
+ {200, 220, 0x03, 10},
+ {220, 240, 0x13, 10},
+ {240, 250, 0x23, 10},
+ {250, 270, 0x04, 13},
+ {270, 300, 0x14, 13},
+ {300, 330, 0x05, 17},
+ {330, 360, 0x15, 17},
+ {360, 400, 0x25, 17},
+#ifdef IS_ENABLED(VERSION3T) || IS_ENABLED(VERSION3D)
+ {400, 450, 0x06, 25},
+ {450, 500, 0x16, 26},
+#elif IS_ENABLED(VERSION3L)
+ {400, 450, 0x06, 23},
+ {450, 500, 0x16, 23},
+#endif
+ {500, 550, 0x07, 28},
+ {550, 600, 0x17, 28},
+ {600, 650, 0x08, 33},
+ {650, 700, 0x18, 33},
+ {700, 750, 0x09, 38},
+ {750, 800, 0x19, 38},
+ {800, 850, 0x29, 38},
+ {850, 900, 0x39, 38},
+ {900, 950, 0x0A, 52},
+ {950, 1000, 0x1A, 52}
+};
+
+#if IS_ENABLED(VERSION3T)
+static void dpy_ab_clr(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x1F);
+}
+
+static void dpy_a_enable(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x07);
+ sci_glb_set(SPRD_MMAHB_BASE + 0x000C, 0x0C);
+}
+
+static void dpy_b_enable(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x07);
+ sci_glb_set(SPRD_MMAHB_BASE + 0x000C, 0x0F);
+}
+
+static void dpy_c_enable(void)
+{
+
+}
+
+static void dpy_ab_sync(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x07);
+}
+#elif IS_ENABLED(VERSION3D)
+static void dpy_ab_clr(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x3F);
+}
+
+static void dpy_a_enable(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x07);
+ sci_glb_set(SPRD_MMAHB_BASE + 0x000C, 0x0C);
+}
+
+static void dpy_b_enable(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x07);
+ sci_glb_set(SPRD_MMAHB_BASE + 0x000C, 0x0F);
+}
+
+static void dpy_c_enable(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x3F);
+ sci_glb_set(SPRD_MMAHB_BASE + 0x000C, 0x2C);
+}
+
+static void dpy_ab_sync(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x07);
+}
+#else IS_ENABLED(VERSION3L)
+static void dpy_ab_clr(void)
+{
+}
+static void dpy_a_enable(void)
+{
+ sci_glb_clr(SPRD_MMAHB_BASE + 0x000C, 0x01);
+}
+static void dpy_b_enable(void)
+{
+ sci_glb_set(SPRD_MMAHB_BASE + 0x000C, 0x01);
+}
+
+static void dpy_c_enable(void)
+{
+}
+
+static void dpy_ab_sync(void)
+{
+}
+#endif
+
+static void dphy_write(u8 test_code, u8 test_data, u8* test_out)
+{
+ u32 temp = 0xffffff00;
+
+ csi_core_write_part(PHY_TST_CRTL1, 0, PHY_TESTEN, 1); //phy_testen = 0
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0,1, PHY_TESTCLK, 1); //phy_testclk = 1
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL1, test_code, PHY_TESTDIN, PHY_TESTDIN_W); //phy_testdin
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL1, 1, PHY_TESTEN, 1);//phy_testen = 1
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0, 0, PHY_TESTCLK, 1);//phy_testclk = 0
+ udelay(1);
+ temp = csi_core_read_part(PHY_TST_CRTL1, PHY_TESTDOUT,PHY_TESTDOUT_W);
+ *test_out = (u8)temp;
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL1, 0, PHY_TESTEN, 1); //phy_testen = 0
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL1, test_data, PHY_TESTDIN, PHY_TESTDIN_W);//phy_testdin
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0,1, PHY_TESTCLK, 1);//phy_testclk = 1
+ udelay(1);
+}
+
+static void dphy_cfg_start(void)
+{
+ csi_core_write_part(PHY_TST_CRTL1, 0, PHY_TESTEN, 1); //phy_testen = 0
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0,1, PHY_TESTCLK, 1); //phy_testclk = 1
+ udelay(1);
+}
+
+static void dphy_cfg_done(void)
+{
+ csi_core_write_part(PHY_TST_CRTL1, 0, PHY_TESTEN, 1); //phy_testen = 0
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0,1, PHY_TESTCLK, 1); //phy_testclk = 1
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL1, 0, PHY_TESTDIN, PHY_TESTDIN_W);//phy_testdin
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL1, 1, PHY_TESTEN, 1);//phy_testen = 1
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0, 0, PHY_TESTCLK, 1);//phy_testclk = 0
+ udelay(1);
+}
+
+static void csi_get_pclk_cfg(u32 bps_per_lane, struct csi_pclk_cfg *csi_pclk_cfg_ptr)
+{
+ u32 i = 0;
+ int rtn = -1;
+
+ for (i =0 ; i < CSI_PCLK_CFG_COUNTER; i++) {
+ if ( bps_per_lane >= csi_pclk_setting[i].pclk_start && bps_per_lane < csi_pclk_setting[i].pclk_end) {
+ csi_pclk_cfg_ptr->hsfreqrange = csi_pclk_setting[i].hsfreqrange;
+ csi_pclk_cfg_ptr->hsrxthssettle = csi_pclk_setting[i].hsrxthssettle;
+ rtn = 0;
+ break;
+ }
+ }
+
+ if (rtn) {
+ csi_pclk_cfg_ptr->hsfreqrange = csi_pclk_setting[CSI_PCLK_CFG_COUNTER -2].hsfreqrange;
+ csi_pclk_cfg_ptr->hsrxthssettle = csi_pclk_setting[CSI_PCLK_CFG_COUNTER -2].hsrxthssettle;
+ }
+}
+
+static void dphy_init_common(u32 bps_per_lane, u32 phy_id, u32 rx_mode)
+{
+ u8 temp = 0;
+ struct csi_pclk_cfg csi_pclk_cfg_val = {0, 0, 0, 0};
+
+ csi_core_write_part(PHY_SHUTDOWNZ, 0, 0, 1);
+ csi_core_write_part(DPHY_RSTZ, 0, 0, 1);
+ csi_core_write_part(PHY_TST_CRTL0, 1, PHY_TESTCLR, 1);
+ udelay(1);
+ csi_core_write_part(PHY_TST_CRTL0, 0, PHY_TESTCLR, 1);
+ udelay(1);
+ dphy_cfg_start();
+
+#if defined(CONFIG_MACH_SP7720EA)
+#if defined(CONFIG_SC_FPGA)
+ sci_glb_write(SPRD_GPIO_BASE + 0x0008, 0xd, -1UL);
+ dphy_write(0x30, 0xc0, &temp);
+#endif
+ dphy_write(0x37, 0x03, &temp);
+ //LOG_DEBUG2 ("%04x default reg value: %04x\r\n", 0x37, temp);
+ dphy_write(0x47, 0x03, &temp);
+ //LOG_DEBUG2 ("%04x default reg value: %04x\r\n", 0x47, temp);
+ dphy_write(0x57, 0x03, &temp);
+ //LOG_DEBUG2 ("%04x default reg value: %04x\r\n", 0x57, temp);
+ dphy_write(0x67, 0x03, &temp);
+ dphy_write(0x77, 0x03, &temp);
+#else
+ csi_get_pclk_cfg(bps_per_lane, &csi_pclk_cfg_val);
+
+#if IS_ENABLED(VERSION3L) || IS_ENABLED(VERSION3T) || IS_ENABLED(VERSION3D)
+ if (0x03 == phy_id) {
+ if (0x00 == rx_mode) {
+ dphy_write(0x34, 0x14, &temp);
+ } else {
+ dphy_write(0x34, 0xA0, &temp);
+ }
+ } else {
+ dphy_write(0x34, 0x14, &temp);
+ }
+#else
+ dphy_write(0x34, 0x14, &temp);
+#endif
+
+ dphy_write(0x44, (((csi_pclk_cfg_val.hsfreqrange & 0x3F) << 1) & 0x7E), &temp);
+ dphy_write(0x75, (0x80 | (csi_pclk_cfg_val.hsrxthssettle & 0x7F)), &temp);
+ dphy_write(0x54, 0x14, &temp);
+ dphy_write(0x64, 0x14, &temp);
+ dphy_write(0x74, 0x14, &temp);
+#endif
+ dphy_cfg_done();
+}
+
+void dphy_init(u32 bps_per_lane, u32 phy_id)
+{
+#if IS_ENABLED(VERSION3L) || IS_ENABLED(VERSION3T) || IS_ENABLED(VERSION3D)
+ dpy_ab_clr();
+
+ if (phy_id & 0x01) {
+ dpy_a_enable();
+ dphy_init_common(bps_per_lane, phy_id, 0);
+ }
+
+ if (phy_id & 0x02) {
+ dpy_b_enable();
+ dphy_init_common(bps_per_lane, phy_id, 1);
+ }
+
+ if (0x03 == (phy_id & 0x03)) {
+ dpy_ab_sync();
+ }
+
+ if (phy_id & 0x04) {
+ dpy_c_enable();
+ dphy_init_common(bps_per_lane, phy_id, 0);
+ }
+
+#else
+ dphy_init_common(bps_per_lane, phy_id, 0);
+#endif
+}
+
+u8 csi_init(u64 base_address)
+{
+ csi_error_t e = SUCCESS;
+ do {
+ if (csi_core_initialized == 0) {
+ access_init((u32*)base_address);
+ if (csi_core_read(VERSION) == (u32)(CURRENT_VERSION)) {
+ csi_core_initialized = 1;
+ break;
+ } else {
+ LOG_ERROR("Driver not compatible with core");
+ e = ERR_NOT_COMPATIBLE;
+ break;
+ }
+ } else {
+ LOG_ERROR("driver already initialised");
+ e = ERR_ALREADY_INIT;
+ break;
+ }
+ } while(0);
+
+ return e;
+}
+
+u8 csi_close()
+{
+ csi_shut_down_phy(1);
+ csi_reset_controller();
+ csi_core_initialized = 0;
+ return SUCCESS;
+}
+
+u8 csi_get_on_lanes()
+{
+ return (csi_core_read_part(N_LANES, 0, 2) + 1);
+}
+
+u8 csi_set_on_lanes(u8 lanes)
+{
+ return csi_core_write_part(N_LANES, (lanes - 1), 0, 2);
+}
+
+u8 csi_shut_down_phy(u8 shutdown)
+{
+ LOG_DEBUG2("shutdown", shutdown);
+ /* active low - bit 0 */
+ return csi_core_write_part(PHY_SHUTDOWNZ, shutdown? 0: 1, 0, 1);
+}
+
+u8 csi_reset_phy()
+{
+ /* active low - bit 0 */
+ int retVal = 0xffff;
+ retVal = csi_core_write_part(DPHY_RSTZ, 0, 0, 1);
+ switch (retVal) {
+ case SUCCESS:
+ return csi_core_write_part(DPHY_RSTZ, 1, 0, 1);
+ break;
+ case ERR_NOT_INIT:
+ LOG_ERROR("Driver not initialized");
+ return retVal;
+ break;
+ default:
+ LOG_ERROR("Undefined error");
+ return ERR_UNDEFINED;
+ break;
+ }
+}
+
+u8 csi_reset_controller()
+{
+ /* active low - bit 0 */
+ int retVal = 0xffff;
+ retVal = csi_core_write_part(CSI2_RESETN, 0, 0, 1);
+ switch (retVal) {
+ case SUCCESS:
+ return csi_core_write_part(CSI2_RESETN, 1, 0, 1);
+ break;
+ case ERR_NOT_INIT:
+ LOG_ERROR("Driver not initialized");
+ return retVal;
+ break;
+ default:
+ LOG_ERROR("Undefined error");
+ return ERR_UNDEFINED;
+ break;
+ }
+}
+
+csi_lane_state_t csi_lane_module_state(u8 lane)
+{
+ if (lane < csi_core_read_part(N_LANES, 0, 2) + 1) {
+ if (csi_core_read_part(PHY_STATE, lane, 1)) {
+ return CSI_LANE_ULTRA_LOW_POWER;
+ }
+ else if (csi_core_read_part(PHY_STATE, (lane + 4), 1)) {
+ return CSI_LANE_STOP;
+ }
+ return CSI_LANE_ON;
+ } else {
+ LOG_WARNING("Lane switched off");
+ return CSI_LANE_OFF;
+ }
+}
+
+csi_lane_state_t csi_clk_state()
+{
+ if (!csi_core_read_part(PHY_STATE, 9, 1)) {
+ return CSI_LANE_ULTRA_LOW_POWER;
+ } else if (csi_core_read_part(PHY_STATE, 10, 1)) {
+ return CSI_LANE_STOP;
+ } else if (csi_core_read_part(PHY_STATE, 8, 1)) {
+ return CSI_LANE_HIGH_SPEED;
+ }
+
+ return CSI_LANE_ON;
+}
+
+u8 csi_payload_bypass(u8 on)
+{
+ return csi_core_write_part(PHY_STATE, on? 1: 0, 11, 1);
+}
+
+u8 csi_register_line_event(u8 virtual_channel_no, csi_data_type_t data_type, u8 offset)
+{
+ u8 id = 0;
+ csi_registers_t reg_offset = 0;
+ LOG_TRACE();
+ if ((virtual_channel_no > 4) || (offset > 8)) {
+ return ERR_OUT_OF_BOUND;
+ }
+ id = (virtual_channel_no << 6) | data_type;
+
+ reg_offset = ((offset / 4) == 1) ? DATA_IDS_2: DATA_IDS_1;
+
+ return csi_core_write_part(reg_offset, id, (offset * 8), 8);
+}
+u8 csi_unregister_line_event(u8 offset)
+{
+ csi_registers_t reg_offset = 0;
+ LOG_TRACE();
+ if (offset > 8) {
+ return ERR_OUT_OF_BOUND;
+ }
+ reg_offset = ((offset / 4) == 1) ? DATA_IDS_2: DATA_IDS_1;
+ return csi_core_write_part(reg_offset, 0x00, (offset * 8), 8);
+}
+
+u8 csi_get_registered_line_event(u8 offset)
+{
+ csi_registers_t reg_offset = 0;
+ LOG_TRACE();
+ if (offset > 8) {
+ return ERR_OUT_OF_BOUND;
+ }
+ reg_offset = ((offset / 4) == 1) ? DATA_IDS_2: DATA_IDS_1;
+ return (u8)csi_core_read_part(reg_offset, (offset * 8), 8);
+}
+
+u8 csi_event_disable(u32 mask, u8 err_reg_no)
+{
+ switch (err_reg_no) {
+ case 1:
+ return csi_core_write(MASK1, mask | csi_core_read(MASK1));
+ case 2:
+ return csi_core_write(MASK2, mask | csi_core_read(MASK2));
+ default:
+ return ERR_OUT_OF_BOUND;
+ }
+}
+
+u8 csi_event_enable(u32 mask, u8 err_reg_no)
+{
+ switch (err_reg_no) {
+ case 1:
+ return csi_core_write(MASK1, (~mask) & csi_core_read(MASK1));
+ case 2:
+ return csi_core_write(MASK2, (~mask) & csi_core_read(MASK2));
+ default:
+ return ERR_OUT_OF_BOUND;
+ }
+}
+u32 csi_event_get_source(u8 err_reg_no)
+{
+ switch (err_reg_no) {
+ case 1:
+ return csi_core_read(ERR1);
+ case 2:
+ return csi_core_read(ERR2);
+ default:
+ return ERR_OUT_OF_BOUND;
+ }
+}
+
+/* register methods */
+u32 csi_core_read(csi_registers_t address)
+{
+ return access_read(address>>2);
+}
+
+u8 csi_core_write(csi_registers_t address, u32 data)
+{
+ if (csi_core_initialized == 0) {
+ LOG_ERROR("driver not initialised");
+ return ERR_NOT_INIT;
+ }
+ LOG_DEBUG3("write", data, address>>2);
+ access_write(data, address>>2);
+
+ return SUCCESS;
+}
+
+u8 csi_core_write_part(csi_registers_t address, u32 data, u8 shift, u8 width)
+{
+ u32 mask = (1 << width) - 1;
+ u32 temp = csi_core_read(address);
+ temp &= ~(mask << shift);
+ temp |= (data & mask) << shift;
+ return csi_core_write(address, temp);
+}
+
+u32 csi_core_read_part(csi_registers_t address, u8 shift, u8 width)
+{
+ return (csi_core_read(address) >> shift) & ((1 << width) - 1);
+}
+
diff --git a/drivers/media/sprd_sensor/csi2/csi_driver.h b/drivers/media/sprd_sensor/csi2/csi_driver.h
new file mode 100644
index 00000000..dbe2648a
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_driver.h
@@ -0,0 +1,136 @@
+/*
+ * csi_driver
+ * 12/05/2010
+ * Synopsys Inc. PT02
+ */
+
+#ifndef CSI_DRIVER_H_
+#define CSI_DRIVER_H_
+
+#include "csi_types.h"
+
+//#define CURRENT_VERSION 0x3130302A
+#ifdef __SIMULATOR__
+#define CURRENT_VERSION 0
+#else // __SIMULATOR__
+
+#define CURRENT_VERSION 0x3130332A
+
+#endif // __SIMULATOR__
+
+#define PHY_TESTCLR 0
+#define PHY_TESTCLK 1
+#define PHY_TESTDIN 0
+#define PHY_TESTDOUT 8
+#define PHY_TESTEN 16
+
+#define PHY_TESTDIN_W 8
+#define PHY_TESTDOUT_W 8
+
+#define CSI_PCLK_CFG_COUNTER 29
+
+typedef enum
+{
+ VERSION = 0x00,
+ N_LANES = 0x04,
+ PHY_SHUTDOWNZ = 0x08,
+ DPHY_RSTZ = 0x0C,
+ CSI2_RESETN = 0x10,
+ PHY_STATE = 0x14,
+ DATA_IDS_1 = 0x18,
+ DATA_IDS_2 = 0x1C,
+ ERR1 = 0x20,
+ ERR2 = 0x24,
+ MASK1 = 0x28,
+ MASK2 = 0x2C,
+ PHY_TST_CRTL0 = 0x30,
+ PHY_TST_CRTL1 = 0x34
+} csi_registers_t;
+
+typedef enum
+{
+ CSI_LANE_OFF = 0,
+ CSI_LANE_ON,
+ CSI_LANE_ULTRA_LOW_POWER,
+ CSI_LANE_STOP,
+ CSI_LANE_HIGH_SPEED
+} csi_lane_state_t;
+
+typedef enum
+{
+ ERR_NOT_INIT = 0xFE,
+ ERR_ALREADY_INIT = 0xFD,
+ ERR_NOT_COMPATIBLE = 0xFC,
+ ERR_UNDEFINED = 0xFB,
+ ERR_OUT_OF_BOUND = 0xFA,
+ SUCCESS = 0
+} csi_error_t;
+
+typedef enum
+{
+ NULL_PACKET = 0x10,
+ BLANKING_DATA = 0x11,
+ EMBEDDED_8BIT_NON_IMAGE_DATA = 0x12,
+ YUV420_8BIT = 0x18,
+ YUV420_10BIT = 0x19,
+ LEGACY_YUV420_8BIT = 0x1A,
+ YUV420_8BIT_CHROMA_SHIFTED = 0x1C,
+ YUV420_10BIT_CHROMA_SHIFTED = 0x1D,
+ YUV422_8BIT = 0x1E,
+ YUV422_10BIT = 0x1F,
+ RGB444 = 0x20,
+ RGB555 = 0x21,
+ RGB565 = 0x22,
+ RGB666 = 0x23,
+ RGB888 = 0x24,
+ RAW6 = 0x28,
+ RAW7 = 0x29,
+ RAW8 = 0x2A,
+ RAW10 = 0x2B,
+ RAW12 = 0x2C,
+ RAW14 = 0x2D,
+ USER_DEFINED_8BIT_DATA_TYPE_1 = 0x30,
+ USER_DEFINED_8BIT_DATA_TYPE_2 = 0x31,
+ USER_DEFINED_8BIT_DATA_TYPE_3 = 0x32,
+ USER_DEFINED_8BIT_DATA_TYPE_4 = 0x33,
+ USER_DEFINED_8BIT_DATA_TYPE_5 = 0x34,
+ USER_DEFINED_8BIT_DATA_TYPE_6 = 0x35,
+ USER_DEFINED_8BIT_DATA_TYPE_7 = 0x36,
+ USER_DEFINED_8BIT_DATA_TYPE_8 = 0x37
+} csi_data_type_t;
+
+struct csi_pclk_cfg {
+ u32 pclk_start;
+ u32 pclk_end;
+ u8 hsfreqrange;
+ u8 hsrxthssettle;
+};
+
+void dphy_init(u32 bps_per_lane, u32 phy_id);
+u8 csi_init(u64 base_address);
+u8 csi_close(void);
+u8 csi_get_on_lanes(void);
+u8 csi_set_on_lanes(u8 lanes);
+u8 csi_shut_down_phy(u8 shutdown);
+u8 csi_reset_phy(void);
+u8 csi_reset_controller(void);
+csi_lane_state_t csi_lane_module_state(u8 lane);
+csi_lane_state_t csi_clk_state(void);
+u8 csi_payload_bypass(u8 on);
+u8 csi_register_line_event(u8 virtual_channel_no, csi_data_type_t data_type, u8 offset);
+u8 csi_unregister_line_event(u8 offset);
+u8 csi_get_registered_line_event(u8 offset);
+u8 csi_event_disable(u32 mask, u8 err_reg_no);
+u8 csi_event_enable(u32 mask, u8 err_reg_no);
+u32 csi_event_get_source(u8 err_reg_no);
+
+/******************************************************************************
+ * register access methods
+******************************************************************************/
+u32 csi_core_read(csi_registers_t address);
+u8 csi_core_write(csi_registers_t address, u32 data);
+u8 csi_core_write_part(csi_registers_t address, u32 data, u8 shift, u8 width);
+u32 csi_core_read_part(csi_registers_t address, u8 shift, u8 width);
+
+#endif /* CSI_DRIVER_H_ */
+
diff --git a/drivers/media/sprd_sensor/csi2/csi_log.c b/drivers/media/sprd_sensor/csi2/csi_log.c
new file mode 100644
index 00000000..38dd0589
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_log.c
@@ -0,0 +1,177 @@
+/*
+ * log.c
+ *
+ * Created on: Jun 25, 2010
+ * Author: klabadi & dlopo
+ */
+#include <linux/kernel.h>
+#include "csi_log.h"
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+static log_verbose_t log_verbose = VERBOSE_NOTICE;
+static log_numeric_t log_numeric = NUMERIC_HEX;
+static unsigned log_verbose_write = 0;
+
+void log_set_verbose(log_verbose_t verbose)
+{
+ log_verbose = verbose;
+}
+
+void log_set_numeric(log_numeric_t numeric)
+{
+ log_numeric = numeric;
+}
+
+void log_set_verbose_write(unsigned state)
+{
+ log_verbose_write = state;
+}
+
+void log_print_write(unsigned a, unsigned b)
+{
+ if (log_verbose_write == 1)
+ {
+ if (log_numeric == NUMERIC_DEC)
+ {
+ printk("%d, %d\n", a, b);
+ }
+ else
+ {
+ printk("0x%x, 0x%x\n", a, b);
+ }
+ }
+}
+
+void log_print0(log_verbose_t verbose, const char* function_name)
+{
+ if (verbose == VERBOSE_ERROR)
+ {
+ printk("ERROR: ");
+ }
+ if (verbose == VERBOSE_WARN)
+ {
+ printk("WARNING: ");
+ }
+ if (verbose <= log_verbose)
+ {
+ printk("%s\n", function_name);
+ }
+}
+
+void log_print1(log_verbose_t verbose, const char* function_name, const char* a)
+{
+ if (verbose == VERBOSE_ERROR)
+ {
+ printk("ERROR: ");
+ }
+ if (verbose == VERBOSE_WARN)
+ {
+ printk("WARNING: ");
+ }
+ if (verbose <= log_verbose)
+ {
+ printk("%s: %s\n", function_name, a);
+ }
+}
+
+void log_print2(log_verbose_t verbose, const char* function_name, const char* a,
+ unsigned b)
+{
+ if (verbose == VERBOSE_ERROR)
+ {
+ printk("ERROR: ");
+ }
+ if (verbose == VERBOSE_WARN)
+ {
+ printk("WARNING: ");
+ }
+ if (verbose <= log_verbose)
+ {
+ if (log_numeric == NUMERIC_DEC)
+ {
+ printk("%s: %s, %d\n", function_name, a, b);
+ }
+ else
+ {
+ printk("%s: %s, 0x%x\n", function_name, a, b);
+ }
+ }
+}
+
+void log_print3(log_verbose_t verbose, const char* function_name, const char* a,
+ unsigned b, unsigned c)
+{
+ if (verbose == VERBOSE_ERROR)
+ {
+ printk("ERROR: ");
+ }
+ if (verbose == VERBOSE_WARN)
+ {
+ printk("WARNING: ");
+ }
+ if (verbose <= log_verbose)
+ {
+ if (log_numeric == NUMERIC_DEC)
+ {
+ printk("%s: %s, %d, %d\n", function_name, a, b, c);
+ }
+ else
+ {
+ printk("%s: %s, 0x%x, 0x%x\n", function_name, a, b, c);
+ }
+ }
+}
+
+void log_print_int(log_verbose_t verbose, const char* a, unsigned b)
+{
+ if (verbose <= log_verbose)
+ {
+ if (log_numeric == NUMERIC_DEC)
+ {
+ printk("%s: %d\n", a, b);
+ }
+ else
+ {
+ printk("%s: 0x%x\n", a, b);
+ }
+ }
+}
+
+void log_print_int2(log_verbose_t verbose, const char* a, unsigned b,
+ unsigned c)
+{
+ if (verbose <= log_verbose)
+ {
+ if (log_numeric == NUMERIC_DEC)
+ {
+ printk("%s: %d, %d\n", a, b, c);
+ }
+ else
+ {
+ printk("%s: 0x%x, 0x%x\n", a, b, c);
+ }
+ }
+}
+
+void log_print_int3(log_verbose_t verbose, const char* a, unsigned b,
+ unsigned c, unsigned d)
+{
+ if (verbose <= log_verbose)
+ {
+ if (log_numeric == NUMERIC_DEC)
+ {
+ printk("%s: %d, %d, %d\n", a, b, c, d);
+ }
+ else
+ {
+ printk("%s: 0x%x, 0x%x, 0x%x\n", a, b, c, d);
+ }
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/drivers/media/sprd_sensor/csi2/csi_log.h b/drivers/media/sprd_sensor/csi2/csi_log.h
new file mode 100644
index 00000000..ff7c073a
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_log.h
@@ -0,0 +1,78 @@
+/*
+ * log.h
+ *
+ * Created on: Jun 25, 2010
+ * Author: klabadi & dlopo
+ */
+
+#ifndef LOG_H_
+#define LOG_H_
+
+#define __FUNCTION__ (__func__)
+
+typedef enum
+{
+ VERBOSE_ERROR = 0,
+ VERBOSE_WARN,
+ VERBOSE_NOTICE,
+ VERBOSE_DEBUG,
+ VERBOSE_TRACE
+} log_verbose_t;
+
+typedef enum
+{
+ NUMERIC_DEC = 0, NUMERIC_HEX
+} log_numeric_t;
+
+void log_set_verbose(log_verbose_t verbose);
+void log_set_numeric(log_numeric_t numeric);
+void log_set_verbose_write(unsigned state);
+
+void log_print_write(unsigned a, unsigned b);
+
+void log_print0(log_verbose_t verbose, const char* function_name);
+
+void log_print1(log_verbose_t verbose, const char* function_name, const char* a);
+
+void log_print2(log_verbose_t verbose, const char* function_name, const char* a,
+ unsigned b);
+
+void log_print3(log_verbose_t verbose, const char* function_name, const char* a,
+ unsigned b, unsigned c);
+
+void log_print_int(log_verbose_t verbose, const char* a, unsigned b);
+
+void log_print_int2(log_verbose_t verbose, const char* a, unsigned b,
+ unsigned c);
+
+void log_print_int3(log_verbose_t verbose, const char* a, unsigned b,
+ unsigned c, unsigned d);
+
+#define LOG_ASSERT(x, a) while (!(x)) { LOG_ERROR(a); exit(-1); }
+#define LOG_EXIT(a) do { LOG_ERROR(a); exit(-1); } while (0)
+#define LOG_WRITE(a, b) log_print_write((a), (b))
+
+#define LOG_ERROR(a) log_print1(VERBOSE_ERROR, __FUNCTION__, (a))
+#define LOG_ERROR2(a, b) log_print2(VERBOSE_ERROR, __FUNCTION__, (a), (b))
+#define LOG_ERROR3(a, b, c) log_print3(VERBOSE_ERROR, __FUNCTION__, (a), (b), (c))
+#define LOG_WARNING(a) log_print1(VERBOSE_WARN, __FUNCTION__, (a))
+#define LOG_WARNING2(a, b) log_print2(VERBOSE_WARN, __FUNCTION__, (a), (b))
+#define LOG_WARNING3(a, b, c) log_print3(VERBOSE_WARN, __FUNCTION__, (a), (b), (c))
+#define LOG_NOTICE(a) log_print1(VERBOSE_NOTICE, __FUNCTION__, (a))
+#define LOG_NOTICE2(a, b) log_print2(VERBOSE_NOTICE, __FUNCTION__, (a), (b))
+#define LOG_NOTICE3(a, b, c) log_print3(VERBOSE_NOTICE, __FUNCTION__, (a), (b), (c))
+#define LOG_DEBUG(a) log_print1(VERBOSE_DEBUG, __FUNCTION__, (a))
+#define LOG_DEBUG2(a, b) log_print2(VERBOSE_DEBUG, __FUNCTION__, (a), (b))
+#define LOG_DEBUG3(a, b, c) log_print3(VERBOSE_DEBUG, __FUNCTION__, (a), (b), (c))
+#define LOG_TRACE() log_print0(VERBOSE_TRACE, __FUNCTION__)
+#define LOG_TRACE1(a) log_print_int(VERBOSE_TRACE, __FUNCTION__, (a))
+#define LOG_TRACE2(a, b) log_print_int2(VERBOSE_TRACE, __FUNCTION__, (a), (b))
+#define LOG_TRACE3(a, b, c) log_print3(VERBOSE_TRACE, __FUNCTION__, (a), (b), (c))
+
+#define LOG_MENU(a) log_print0(VERBOSE_NOTICE, (a))
+#define LOG_MENUSTR(a, b) log_print1(VERBOSE_NOTICE, (a), (b))
+#define LOG_MENUINT(a, b) log_print_int(VERBOSE_NOTICE, (a),(b))
+#define LOG_MENUINT2(a, b, c) log_print_int2(VERBOSE_NOTICE, (a),(b), (c))
+#define LOG_MENUINT3(a, b, c, d) log_print_int3(VERBOSE_NOTICE, (a),(b), (c), (d))
+
+#endif /* LOG_H_ */
diff --git a/drivers/media/sprd_sensor/csi2/csi_system.c b/drivers/media/sprd_sensor/csi2/csi_system.c
new file mode 100644
index 00000000..408983e7
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_system.c
@@ -0,0 +1,84 @@
+/*
+ * system.c
+ *
+ * Created on: Jun 25, 2010
+ * Author: klabadi & dlopo
+ *
+ *
+ * @note: this file should be re-written to match the environment the
+ * API is running on
+ */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "csi_system.h"
+#include "csi_log.h"
+
+void system_sleep_ms(unsigned ms)
+{
+
+}
+
+int system_thread_create(void* handle, thread_t p_func, void* param)
+{
+ return 0;
+}
+int system_thread_destruct(void* handle)
+{
+ return 0;
+}
+
+int system_start(thread_t thread)
+{
+ return 1;
+}
+
+static unsigned system_interrupt_map(interrupt_id_t id)
+{
+ return ~0;
+}
+
+int system_interrupt_disable(interrupt_id_t id)
+{
+ if (system_interrupt_map(id) != (unsigned) (~0))
+ {
+ return 0;
+ }
+ LOG_ERROR("Interrupt not mapped");
+ return 0;
+}
+
+int system_interrupt_enable(interrupt_id_t id)
+{
+ if (system_interrupt_map(id) != (unsigned) (~0))
+ {
+ return 0;
+ }
+ LOG_ERROR("Interrupt not mapped");
+ return 0;
+}
+
+int system_interrupt_acknowledge(interrupt_id_t id)
+{
+ if (system_interrupt_map(id) != (unsigned) (~0))
+ {
+ return 0;
+ }
+ LOG_ERROR("Interrupt not mapped");
+ return 0;
+}
+int system_interrupt_handler_register(interrupt_id_t id, handler_t handler,
+ void * param)
+{
+ return 0;
+}
+
+int system_interrupt_handler_unregister(interrupt_id_t id)
+{
+ return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/drivers/media/sprd_sensor/csi2/csi_system.h b/drivers/media/sprd_sensor/csi2/csi_system.h
new file mode 100644
index 00000000..21f19886
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_system.h
@@ -0,0 +1,28 @@
+/*
+ * system.h
+ *
+ * Created on: Jun 25, 2010
+ * Author: klabadi & dlopo
+ */
+
+#ifndef SYSTEM_H_
+#define SYSTEM_H_
+
+#include "csi_types.h"
+
+typedef enum
+{
+ CSI_INT_ERR1 = 1, CSI_INT_ERR2
+} interrupt_id_t;
+void system_sleep_ms(unsigned ms);
+int system_thread_create(void* handle, thread_t p_func, void* param);
+int system_thread_destruct(void* handle);
+int system_start(thread_t thread);
+int system_interrupt_disable(interrupt_id_t id);
+int system_interrupt_enable(interrupt_id_t id);
+int system_interrupt_acknowledge(interrupt_id_t id);
+int system_interrupt_handler_register(interrupt_id_t id, handler_t handler, void * param);
+int system_interrupt_handler_unregister(interrupt_id_t id);
+
+
+#endif /* SYSTEM_H_ */ \ No newline at end of file
diff --git a/drivers/media/sprd_sensor/csi2/csi_types.h b/drivers/media/sprd_sensor/csi2/csi_types.h
new file mode 100644
index 00000000..d7c9031d
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/csi_types.h
@@ -0,0 +1,15 @@
+/*
+ * types.h
+ *
+ * Created on: Aug 25, 2010
+ * Author: klabadi & dlopo
+ */
+
+#ifndef TYPES_H_
+#define TYPES_H_
+#include <linux/types.h>
+
+typedef void (*handler_t)(void *);
+typedef void* (*thread_t)(void *);
+
+#endif /* TYPES_H_ */ \ No newline at end of file
diff --git a/drivers/media/sprd_sensor/csi2/usc28c_init.c b/drivers/media/sprd_sensor/csi2/usc28c_init.c
new file mode 100644
index 00000000..c0e2071a
--- /dev/null
+++ b/drivers/media/sprd_sensor/csi2/usc28c_init.c
@@ -0,0 +1,281 @@
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#else
+#include "parse_hwinfo.h"
+#endif
+
+#define CTL_BASE_ENABLE_USC28C_CSI 0x403f0008
+
+#define pr_info printk
+
+#define ARM_GPIO_BASE_CNT (192)
+
+#define SPI_USC28C_SCK_GPIO_PIN (200)
+#define SPI_USC28C_SEN_GPIO_PIN (201)
+#define SPI_USC28C_DAT_GPIO_PIN (202)
+
+#define SPI_USC28C_SCK_GPIO_MASK (1<<(SPI_USC28C_SCK_GPIO_PIN-ARM_GPIO_BASE_CNT))
+#define SPI_USC28C_SEN_GPIO_MASK (1<<(SPI_USC28C_SEN_GPIO_PIN-ARM_GPIO_BASE_CNT))
+#define SPI_USC28C_DAT_GPIO_MASK (1<<(SPI_USC28C_DAT_GPIO_PIN-ARM_GPIO_BASE_CNT))
+#define SPI_CLK_DELAY 0
+#define SPI_READ_REG 0x3F
+
+#define GPIO_CHIP_USC28C_OFFSET (SPRD_GPIO_BASE + 0x600)
+
+#if 0
+struct gpio_ctrl_reg {
+ volatile u32 data; /* bits data */
+ volatile u32 msk; /* bits data mask */
+ volatile u32 dir; /* bits data direction */
+ volatile u32 is; /* bits interrupt sense */
+ volatile u32 ibe; /* bits both edges interrupt */
+ volatile u32 iev; /* bits interrupt event */
+ volatile u32 ie; /* bits interrupt enable */
+ volatile u32 ris; /* bits raw interrupt status */
+ volatile u32 mis; /* bits masked interrupt status */
+ volatile u32 inen; /* input enable */
+};
+#endif
+
+static void gpio_set_dir(u8 port, u8 dir)
+{
+#if 0
+ volatile struct gpio_ctrl_reg *reg;
+
+ reg = (volatile struct gpio_ctrl_reg *)(GPIO_CHIP_USC28C_OFFSET);
+ if (dir) {
+ reg->dir |= 1 << ((u32) (port - ARM_GPIO_BASE_CNT)); // OUTPUT MODE.
+ } else {
+ reg->dir &= ~((u32)(1 << ((u32) (port - ARM_GPIO_BASE_CNT)))); // INPUT MODE.
+ }
+ reg->msk |= (1 << (u32)(port - ARM_GPIO_BASE_CNT)); // OUTPUT MODE.
+#else
+ u32 value;
+
+ if (dir) {
+ value = 1 << ((u32) (port - ARM_GPIO_BASE_CNT));
+ value |= __raw_readl(GPIO_CHIP_USC28C_OFFSET + 0x08);
+ } else {
+ value = ~((u32)(1 << ((u32) (port - ARM_GPIO_BASE_CNT))));
+ value &= __raw_readl(GPIO_CHIP_USC28C_OFFSET + 0x08);
+ }
+ __raw_writel(value, GPIO_CHIP_USC28C_OFFSET + 0x08);
+
+ value = (1 << (u32)(port - ARM_GPIO_BASE_CNT));
+ value |= __raw_readl(GPIO_CHIP_USC28C_OFFSET + 0x04);
+ __raw_writel(value, GPIO_CHIP_USC28C_OFFSET + 0x04);
+#endif
+}
+
+static void gpio_out(u8 port, u8 data)
+{
+#if 0
+ volatile struct gpio_ctrl_reg *reg;
+
+ reg = (volatile struct gpio_ctrl_reg *)(GPIO_CHIP_USC28C_OFFSET);
+ if (data) {
+ reg->data |= (1 << (u32)(port - ARM_GPIO_BASE_CNT)); // set 1.
+ } else {
+ reg->data &= ~(1 << (u32)(port - ARM_GPIO_BASE_CNT)); // set 0.
+ }
+#else
+ u32 value;
+
+ if (data) {
+ value = (1 << (u32)(port - ARM_GPIO_BASE_CNT));
+ value |= __raw_readl(GPIO_CHIP_USC28C_OFFSET);
+ } else {
+ value = ~(1 << (u32)(port - ARM_GPIO_BASE_CNT));
+ value &= __raw_readl(GPIO_CHIP_USC28C_OFFSET);
+ }
+ __raw_writel(value, GPIO_CHIP_USC28C_OFFSET);
+#endif
+}
+
+static void gpio_out_combo(u32 sclk, u32 sen, u32 dat)
+{
+#if 0
+ volatile struct gpio_ctrl_reg *reg;
+ u32 read_dat;
+ u32 reg_set = 0;
+
+ reg = (volatile struct gpio_ctrl_reg *)(GPIO_CHIP_USC28C_OFFSET);
+
+ if (sclk) {
+ reg_set |= SPI_USC28C_SCK_GPIO_MASK;
+ }
+ if (sen) {
+ reg_set |= SPI_USC28C_SEN_GPIO_MASK;
+ }
+ if (dat) {
+ reg_set |= SPI_USC28C_DAT_GPIO_MASK;
+ }
+ read_dat = reg->data;
+ read_dat &= ~(SPI_USC28C_SCK_GPIO_MASK | SPI_USC28C_SEN_GPIO_MASK
+ | SPI_USC28C_DAT_GPIO_MASK);
+ read_dat |= reg_set;
+ reg->data = read_dat;
+#else
+ u32 value;
+ u32 reg_set = 0;
+
+ if (sclk) {
+ reg_set |= SPI_USC28C_SCK_GPIO_MASK;
+ }
+ if (sen) {
+ reg_set |= SPI_USC28C_SEN_GPIO_MASK;
+ }
+ if (dat) {
+ reg_set |= SPI_USC28C_DAT_GPIO_MASK;
+ }
+
+ value = __raw_readl(GPIO_CHIP_USC28C_OFFSET);
+ value &= ~(SPI_USC28C_SCK_GPIO_MASK | SPI_USC28C_SEN_GPIO_MASK
+ | SPI_USC28C_DAT_GPIO_MASK);
+ value |= reg_set;
+ __raw_writel(value, GPIO_CHIP_USC28C_OFFSET);
+#endif
+}
+
+static u8 gpio_in(u8 port)
+{
+#if 0
+ volatile struct gpio_ctrl_reg *reg;
+ u32 data;
+
+ reg = (volatile struct gpio_ctrl_reg *)(GPIO_CHIP_USC28C_OFFSET);
+
+ data = reg->data;
+ if (data & (1 << (port - ARM_GPIO_BASE_CNT))) {
+ return 1;
+ }
+ return 0;
+#else
+ u32 value;
+
+ value = __raw_readl(GPIO_CHIP_USC28C_OFFSET);
+ if (value & (1 << (port - ARM_GPIO_BASE_CNT))) {
+ return 1;
+ }
+ return 0;
+#endif
+}
+
+static void __usc28c_spi_init(void)
+{
+ gpio_set_dir(SPI_USC28C_SCK_GPIO_PIN, 1);
+ gpio_set_dir(SPI_USC28C_SEN_GPIO_PIN, 1);
+ gpio_set_dir(SPI_USC28C_DAT_GPIO_PIN, 1);
+
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 0);
+ gpio_out(SPI_USC28C_SEN_GPIO_PIN, 1);
+ gpio_out(SPI_USC28C_DAT_GPIO_PIN, 0);
+}
+
+static void __spi_reg_w(u16 reg, u16 val)
+{
+ s8 i;
+ u8 temp = 0;
+
+ gpio_set_dir(SPI_USC28C_SCK_GPIO_PIN, 1);
+ gpio_set_dir(SPI_USC28C_SEN_GPIO_PIN, 1);
+ gpio_set_dir(SPI_USC28C_DAT_GPIO_PIN, 1);
+
+ gpio_out_combo(0, 1, 0);
+ udelay(SPI_CLK_DELAY);
+ if (val & (1 << 15)) {
+ gpio_out_combo(0, 0, 1);
+ } else {
+ gpio_out_combo(0, 0, 0);
+ }
+ udelay(SPI_CLK_DELAY);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 1);
+ udelay(SPI_CLK_DELAY);
+
+ for (i = 14; i >= 0; i--) {
+ gpio_out_combo(0, 0, val & (1 << i));
+ udelay(SPI_CLK_DELAY);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 1);
+ udelay(SPI_CLK_DELAY);
+ }
+
+ for (i = 1; i >= 0; i--) {
+ gpio_out_combo(0, 0, temp & (1 << i));
+ udelay(SPI_CLK_DELAY);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 1);
+ udelay(SPI_CLK_DELAY);
+ }
+
+ for (i = 15; i >= 0; i--) {
+ gpio_out_combo(0, 0, reg & (1 << i));
+ udelay(SPI_CLK_DELAY);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 1);
+ udelay(SPI_CLK_DELAY);
+ }
+ udelay(SPI_CLK_DELAY);
+ gpio_out_combo(0, 1, 1);
+}
+
+static u16 __spi_reg_r(u16 reg)
+{
+ s8 i;
+ u16 recv = 0;
+
+ __spi_reg_w(SPI_READ_REG, reg);
+ gpio_set_dir(SPI_USC28C_DAT_GPIO_PIN, 0);
+
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 1);
+ udelay(SPI_CLK_DELAY);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 0);
+
+ for (i = 15; i >= 0; i--) {
+ udelay(SPI_CLK_DELAY);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 1);
+ recv <<= 1;
+ udelay(SPI_CLK_DELAY);
+ recv |= gpio_in(SPI_USC28C_DAT_GPIO_PIN);
+ gpio_out(SPI_USC28C_SCK_GPIO_PIN, 0);
+ }
+
+ return recv;
+}
+
+void usc28c_csi_init(void)
+{
+ static u32 initialized = 0;
+ u32 base_addr;
+
+ if (initialized) {
+ /* already initialized */
+ return;
+ }
+
+ base_addr = ioremap(CTL_BASE_ENABLE_USC28C_CSI, 0x10);
+ pr_info("%s: usc28c base addr: 0x%x\n", __func__, base_addr);
+ __raw_writel(0x1000, base_addr);
+
+ __usc28c_spi_init();
+
+ /* reg 0x00:
+ bit0: DSI power switch (normal function set 1)
+ bit1: CSI power switch for V1 (normal function set 1)
+ bit2: CSI power switch for V2 (normal function set 1)
+ bit3: CSI select signal (0 for V1, 1 for V2)
+
+ reg 0x10:
+ 0x02 for DSI mode, 0x03 for CSI mode
+ */
+ __spi_reg_w(0x00, 0x0f);
+ __spi_reg_w(0x10, 0x03);
+ pr_info("%s: chip usc28c csi mode is chosen\n", __func__);
+
+ pr_info("Reg0x%04x, value: 0x%04x and Reg0x%04x, value: 0x%04x\n",
+ 0x0, __spi_reg_r(0x0), 0x10, __spi_reg_r(0x10));
+
+ initialized = 1;
+}
+
diff --git a/drivers/media/sprd_sensor/otp/Makefile b/drivers/media/sprd_sensor/otp/Makefile
new file mode 100644
index 00000000..17f91f11
--- /dev/null
+++ b/drivers/media/sprd_sensor/otp/Makefile
@@ -0,0 +1,6 @@
+
+ifeq ($(CONFIG_MACH_GRANDPRIME3G_VE),y)
+obj-y += sensor_otp_coreprime3g_ve.o
+else
+obj-y += sensor_otp.o
+endif
diff --git a/drivers/media/sprd_sensor/otp/sensor_otp.c b/drivers/media/sprd_sensor/otp/sensor_otp.c
new file mode 100644
index 00000000..53075776
--- /dev/null
+++ b/drivers/media/sprd_sensor/otp/sensor_otp.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <video/sensor_drv_k.h>
+
+int sensor_reloadinfo_thread(void *data)
+{
+ int ret = 0;
+ return ret;
+}
diff --git a/drivers/media/sprd_sensor/otp/sensor_otp.h b/drivers/media/sprd_sensor/otp/sensor_otp.h
new file mode 100644
index 00000000..ae8ca508
--- /dev/null
+++ b/drivers/media/sprd_sensor/otp/sensor_otp.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 _SENSOR_OTP_H_
+#define _SENSOR_OTP_H_
+
+int sensor_reloadinfo_thread(void *data);
+#endif
diff --git a/drivers/media/sprd_sensor/otp/sensor_otp_coreprime3g_ve.c b/drivers/media/sprd_sensor/otp/sensor_otp_coreprime3g_ve.c
new file mode 100644
index 00000000..927ffbd5
--- /dev/null
+++ b/drivers/media/sprd_sensor/otp/sensor_otp_coreprime3g_ve.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/fs.h>
+
+#include <video/sensor_drv_k.h>
+#include <linux/vmalloc.h>
+#include <linux/sprd_mm.h>
+
+#include "sensor_otp.h"
+
+
+#define DW9807_EEPROM_SLAVE_ADDR (0xB0 >> 1)
+
+#define SENSOR_SUCCESS 0
+#define cmr_bzero(b, len) memset((b), '\0', (len))
+#define cmr_copy(b, a, len) memcpy((b), (a), (len))
+
+
+enum sensor_cmd {
+ SENSOR_ACCESS_VAL,
+};
+
+typedef enum {
+ SENSOR_VAL_TYPE_READ_OTP,
+} SENSOR_IOCTL_VAL_TYPE;
+
+
+typedef struct _sensor_val_tag {
+ uint8_t type;
+ void *pval;
+} SENSOR_VAL_T, *SENSOR_VAL_T_PTR;
+
+struct isp_data_t {
+ uint32_t size;
+ void *data_ptr;
+};
+
+
+ //static struct task_struct * otp_task = NULL;
+static struct file *pfile = NULL;
+static struct file *pdebugfile = NULL;
+
+static int z_ioctl (struct file *f, unsigned int cmd, unsigned long arg)
+{
+ if (f->f_op->compat_ioctl)
+ return f->f_op->compat_ioctl (f, cmd, arg);
+ else if (f->f_op->unlocked_ioctl)
+ return f->f_op->unlocked_ioctl (f, cmd, arg);
+}
+
+static void Sensor_PowerOn (uint32_t power_on)
+{
+ struct sensor_power_info_tag power_cfg;
+ uint32_t mclk = 24;
+
+ memset (&power_cfg, 0, sizeof (struct sensor_power_info_tag));
+ power_cfg.op_sensor_id = 0;
+ if (power_on) {
+ power_cfg.is_on = 1;
+ } else {
+ power_cfg.is_on = 0;
+ }
+ z_ioctl (pfile, SENSOR_IO_POWER_CFG, &power_cfg);
+
+ if (power_on) {
+ z_ioctl (pfile, SENSOR_IO_SET_MCLK, &mclk);
+ }
+}
+
+static int Sensor_WriteI2C (uint16_t slave_addr, uint8_t * cmd, uint16_t cmd_length)
+{
+ struct sensor_i2c_tag i2c_tab;
+ int ret = SENSOR_SUCCESS;
+
+ i2c_tab.slave_addr = slave_addr;
+ i2c_tab.i2c_data = cmd;
+ i2c_tab.i2c_count = cmd_length;
+
+ MM_TRACE ("Sensor_ReadI2C, slave_addr=0x%x, ptr=0x%p, count=%d\n",
+ i2c_tab.slave_addr, i2c_tab.i2c_data, i2c_tab.i2c_count);
+
+ ret = z_ioctl (pfile, SENSOR_IO_I2C_WRITE_EXT, &i2c_tab);
+
+ return ret;
+}
+
+static int Sensor_ReadI2C (uint16_t slave_addr, uint8_t * cmd, uint16_t cmd_length)
+{
+ struct sensor_i2c_tag i2c_tab;
+ int ret = SENSOR_SUCCESS;
+
+ i2c_tab.slave_addr = slave_addr;
+ i2c_tab.i2c_data = cmd;
+ i2c_tab.i2c_count = cmd_length;
+
+// MM_TRACE("Sensor_ReadI2C, slave_addr=0x%x, ptr=0x%p, count=%d\n",
+// i2c_tab.slave_addr, i2c_tab.i2c_data, i2c_tab.i2c_count);
+
+ ret = z_ioctl (pfile, SENSOR_IO_I2C_READ_EXT, &i2c_tab);
+
+ return ret;
+}
+
+static uint32_t _read_otp (void *sensor_handle, int sensor_id, int cmd, long arg)
+{
+ uint32_t rtn = SENSOR_SUCCESS;
+ SENSOR_OTP_PARAM_T *param_ptr = (SENSOR_OTP_PARAM_T *) (((SENSOR_VAL_T *) arg)->pval);
+ uint32_t start_addr = 0;
+ uint32_t len = 0;
+ uint8_t *buff = NULL;
+ uint8_t cmd_val[3] = { 0x00 };
+ uint16_t cmd_len;
+ uint32_t i;
+
+ if (NULL == param_ptr) {
+ return -1;
+ }
+
+ MM_TRACE ("SENSOR_s5k4h5yc: _s5k4h5yc_read_otp E\n");
+
+ cmd_len = 2;
+ cmd_val[0] = 0x00;
+ cmd_val[1] = 0x00;
+ rtn = Sensor_WriteI2C (DW9807_EEPROM_SLAVE_ADDR, (uint8_t *) & cmd_val[0], cmd_len);
+ udelay (1000); //usleep(1000);
+
+ MM_TRACE ("write i2c rtn %d type %d\n", rtn, param_ptr->type);
+
+ buff = param_ptr->buff;
+ if (SENSOR_OTP_PARAM_NORMAL == param_ptr->type) {
+ start_addr = param_ptr->start_addr;
+ len = 8192;
+ } else if (SENSOR_OTP_PARAM_CHECKSUM == param_ptr->type) {
+ start_addr = 0xFC;
+ len = 4;
+ } else if (SENSOR_OTP_PARAM_READBYTE == param_ptr->type) {
+ start_addr = param_ptr->start_addr;
+ len = param_ptr->len;
+ }
+
+ // EEPROM READ
+ for (i = 0; i < len; i++) {
+ cmd_val[0] = ((start_addr + i) >> 8) & 0xff;
+ cmd_val[1] = (start_addr + i) & 0xff;
+ rtn = Sensor_ReadI2C (DW9807_EEPROM_SLAVE_ADDR, (uint8_t *) & cmd_val[0], cmd_len);
+ if (SENSOR_SUCCESS == rtn) {
+ buff[i] = (cmd_val[0]) & 0xff;
+ }
+ //MM_TRACE("rtn %d value %d addr 0x%x\ns", rtn, buff[i], start_addr + i);
+ }
+ param_ptr->len = len;
+
+ MM_TRACE ("SENSOR_s5k4h5yc: _s5k4h5yc_read_otp X\n");
+
+ return rtn;
+
+}
+
+int sensor_reloadinfo_thread (void *data)
+{
+ int32_t rtn = 0;
+ int ret = 0;
+ SENSOR_OTP_PARAM_T *param_ptr = (SENSOR_OTP_PARAM_T *) data;
+
+ uint32_t clock = 400000;
+
+ loff_t otp_start_addr = 0;
+ uint32_t otp_data_len = 0;
+ SENSOR_VAL_T val;
+ struct isp_data_t checksum_otp;
+ struct isp_data_t sensor_otp;
+ uint32_t is_need_checksum = 0;
+
+ MM_TRACE ("sensor_reloadinfo_thread start\n");
+ msleep (2500);
+
+ cmr_bzero (&checksum_otp, sizeof (checksum_otp));
+ cmr_bzero (&sensor_otp, sizeof (sensor_otp));
+ cmr_bzero (param_ptr, sizeof (SENSOR_OTP_PARAM_T));
+
+ pfile = filp_open ("/dev/sprd_sensor", O_RDWR, 0);
+ if (IS_ERR (pfile)) {
+ MM_TRACE ("open /dev/sprd_sensor failed\n");
+ return -1;
+ }
+ Sensor_PowerOn (1);
+
+ ret = z_ioctl (pfile, SENSOR_IO_SET_I2CCLOCK, &clock);
+
+ //checksum
+ checksum_otp.size = 4;
+ checksum_otp.data_ptr = vmalloc (checksum_otp.size);
+ if (NULL == checksum_otp.data_ptr) {
+ MM_TRACE ("malloc checksum_otp buffer failed\n");
+ goto EXIT;
+ }
+
+ cmr_bzero (param_ptr, sizeof (SENSOR_OTP_PARAM_T));
+ param_ptr->start_addr = 0;
+ param_ptr->len = checksum_otp.size;
+ param_ptr->buff = checksum_otp.data_ptr;
+ param_ptr->type = SENSOR_OTP_PARAM_CHECKSUM;
+ val.type = SENSOR_VAL_TYPE_READ_OTP;
+ val.pval = param_ptr;
+ ret = _read_otp (NULL, 0, SENSOR_ACCESS_VAL, (long) &val);
+ if (ret || 0 == param_ptr->len) {
+ MM_TRACE ("read otp data checksum failed\n");
+ goto EXIT;
+ }
+
+ /*read lsc, awb from real otp */
+ //camera_calibrationconfigure_load(&otp_start_addr, &otp_data_len);
+ otp_data_len = 8192;
+ sensor_otp.data_ptr = vmalloc (otp_data_len);
+ if (NULL == sensor_otp.data_ptr) {
+ MM_TRACE ("malloc random lsc file failed\n");
+ goto EXIT;
+ }
+
+ cmr_bzero (param_ptr, sizeof (SENSOR_OTP_PARAM_T));
+ param_ptr->start_addr = 0;
+ param_ptr->len = 0;
+ param_ptr->buff = sensor_otp.data_ptr;
+ param_ptr->type = SENSOR_OTP_PARAM_NORMAL;
+ val.type = SENSOR_VAL_TYPE_READ_OTP;
+ val.pval = param_ptr;
+ ret = _read_otp (NULL, 0, SENSOR_ACCESS_VAL, (long) &val);
+ if (ret || 0 == param_ptr->len) {
+ MM_TRACE ("read otp data failed\n");
+ goto EXIT;
+ }
+ param_ptr->golden.size = checksum_otp.size;
+ param_ptr->golden.data_ptr = checksum_otp.data_ptr;
+#if 0
+ pdebugfile = filp_open ("/data/otp.bin", O_CREAT|O_RDWR, 0);
+ if (IS_ERR (pdebugfile)) {
+ MM_TRACE ("open /data/otp.bin failed\n");
+ return -1;
+ }
+ vfs_write(pdebugfile, param_ptr->buff,otp_data_len, &otp_start_addr);
+ filp_close(pdebugfile, NULL);
+#endif
+
+EXIT:
+ filp_close (pfile, NULL);
+ Sensor_PowerOn (0);
+ MM_TRACE ("sensor_reloadinfo_thread end\n");
+ return rtn;
+}
diff --git a/drivers/media/sprd_sensor/power/Makefile b/drivers/media/sprd_sensor/power/Makefile
new file mode 100755
index 00000000..cba96600
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/Makefile
@@ -0,0 +1,22 @@
+
+ifeq ($(CONFIG_MACH_COREPRIMELITE),y)
+obj-y += sensor_power_coreprimelite.o
+else ifeq ($(CONFIG_MACH_TSHARK2TABE),y)
+obj-y += sensor_power_tshark2tabe.o
+else ifeq ($(CONFIG_MACH_GRANDPRIME3G_VE),y)
+obj-y += sensor_power_grandprime3g_ve.o
+else ifeq ($(CONFIG_MACH_SS_SHARKLT8),y)
+obj-y += sensor_power_sharkl_t8.o
+else ifeq ($(CONFIG_MACH_SS_SHARKLT8LIGHTSLEEP),y)
+obj-y += sensor_power_sharkl_t8.o
+else ifeq ($(CONFIG_MACH_GRANDPRIME_DTV),y)
+obj-y += sensor_power_grandprime_dtv.o
+else ifeq ($(CONFIG_MACH_COREPRIME3G_VE),y)
+obj-y += sensor_power_coreprime3g_ve.o
+else ifeq ($(CONFIG_MACH_SHARKLS_Z3LTE),y)
+obj-y += sensor_power_sharkls_z3lte.o
+else ifeq ($(CONFIG_MACH_TIZENZ3_3G),y)
+obj-y += sensor_power_sharkls_z3lte.o
+else
+obj-y += sensor_power.o
+endif
diff --git a/drivers/media/sprd_sensor/power/sensor_power.c b/drivers/media/sprd_sensor/power/sensor_power.c
new file mode 100644
index 00000000..85957fe9
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+//#include <mach/hardware.h>
+//#include <mach/board.h>
+#include <video/sensor_drv_k.h>
+#include "../sensor_drv_sprd.h"
+
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+ (void)sensor_id;(void)dev0;(void)dev1;(void)dev2;
+
+ return ret;
+}
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+ (void)sensor_id;(void)dev0;(void)dev1;(void)dev2;
+
+
+ return ret;
+}
diff --git a/drivers/media/sprd_sensor/power/sensor_power.h b/drivers/media/sprd_sensor/power/sensor_power.h
new file mode 100644
index 00000000..f7769dfd
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 _SENSOR_POWER_H_
+#define _SENSOR_POWER_H_
+
+#include <linux/types.h>
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2);
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2);
+#endif
diff --git a/drivers/media/sprd_sensor/power/sensor_power_coreprime3g_ve.c b/drivers/media/sprd_sensor/power/sensor_power_coreprime3g_ve.c
new file mode 100755
index 00000000..d0be249d
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_coreprime3g_ve.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include "../sensor_drv_sprd.h"
+
+static int sensor_s5k4ecgx_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ /*set default status for main and sub sensor*/
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor(sensor hi255);
+ sensor_k_set_pd_level(fd_handle,0);//power down valid for hi255
+ sensor_k_set_rst_level(fd_handle,0);//reset valid for hi255
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ sensor_k_set_pd_level(fd_handle,0);//power down valid for hi544
+ sensor_k_set_rst_level(fd_handle,0);//reset valid for hi544
+ mdelay(1);
+
+ /*power on sequence*/
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);//AF monitor
+ mdelay(1);//delay
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);//IO vdd
+ udelay(500);//delay >2ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);//anolog vdd
+ udelay(1000);//delay > 0us
+ sensor_k_set_mclk(fd_handle,24);
+ udelay(500);//delay > 0us
+ sensor_k_set_voltage_dvdd(fd_handle,SENSOR_VDD_1200MV);//core vdd
+ udelay(1000);//delay >= 10us
+ sensor_k_set_pd_level(fd_handle,1);//power down
+ udelay(30);//delay >= 15us
+ sensor_k_set_rst_level(fd_handle,1);//reset
+ udelay(100);//delay > 60us
+ printk("sensor_s5k4ecgx_poweron OK \n");
+ return ret;
+}
+
+static int sensor_s5k4ecgx_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle,0);//reset valid for hi544
+ udelay(100);//delay >50us
+ sensor_k_set_mclk(fd_handle,0);// disable mclk
+ udelay(100);//delay >= 0us
+ sensor_k_set_pd_level(fd_handle,0);//power down valid for hi544
+ udelay(100);//delay < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle,SENSOR_VDD_CLOSED);
+ udelay(10);//delay < 10ms
+ sensor_k_set_voltage_avdd(fd_handle,SENSOR_VDD_CLOSED);//close anolog vdd
+ mdelay(5);//delay >= 0us
+ sensor_k_set_voltage_dvdd(fd_handle,SENSOR_VDD_CLOSED);//close core vdd
+ mdelay(1);//delay
+ sensor_k_set_voltage_cammot(fd_handle,SENSOR_VDD_CLOSED);//AF monitor
+ udelay(10);//delay
+
+ printk("sensor_s5k4ecgx_poweroff OK \n");
+ return ret;
+
+}
+
+
+static int sensor_hi255_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ sensor_k_set_pd_level(fd_handle,0);//power down valid for hi544
+ sensor_k_set_rst_level(fd_handle,0);//reset valid for hi544
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor(sensor hi255);
+ sensor_k_set_pd_level(fd_handle,0);//power down valid for hi255
+ sensor_k_set_rst_level(fd_handle,0);//reset valid for hi255
+ udelay(1);
+ sensor_k_set_voltage_iovdd(fd_handle,SENSOR_VDD_1800MV);//IO vdd
+ udelay(10);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle,SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);
+ sensor_k_set_voltage_dvdd(fd_handle,SENSOR_VDD_1200MV);//core vdd
+ mdelay(2);
+ sensor_k_set_voltage_dvdd(fd_handle,SENSOR_VDD_CLOSED);//close core vdd
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_pd_level(fd_handle,1);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_mclk(fd_handle,24);
+ mdelay(31);//delay 30ms >= 30ms
+ sensor_k_set_rst_level(fd_handle,1);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ printk("hi255_poweron OK \n");
+
+ return ret;
+}
+
+static int sensor_hi255_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor(sensor hi255);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle,0);//reset valid for hi255
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_mclk(fd_handle,0);// disable mclk
+ udelay(1);//delay 1us > 0ns
+ sensor_k_set_pd_level(fd_handle,0);//power down valid for hi255
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle,SENSOR_VDD_CLOSED);
+ //mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle,SENSOR_VDD_CLOSED);
+ udelay(1);
+ printk("hi255_poweroff OK \n");
+
+ return ret;
+}
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_s5k4ecgx_poweron(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweron(fd_handle, dev0, dev1, dev2);
+ }
+ return ret;
+}
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_s5k4ecgx_poweroff(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweroff(fd_handle, dev0, dev1, dev2);
+ }
+
+ return ret;
+}
diff --git a/drivers/media/sprd_sensor/power/sensor_power_coreprimelite.c b/drivers/media/sprd_sensor/power/sensor_power_coreprimelite.c
new file mode 100644
index 00000000..e7d2010c
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_coreprimelite.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <video/sensor_drv_k.h>
+#include "../sensor_drv_sprd.h"
+
+static int sensor_s5k4ecgx_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ /*set default status for main and sub sensor*/
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor(sensor hi255);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi255
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi255
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi544
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi544
+ mdelay(1);
+
+ /*power on sequence*/
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);//AF monitor
+ mdelay(1);//delay
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);//IO vdd
+ udelay(500);//delay >2ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);//anolog vdd
+ udelay(1000);//delay > 0us
+ sensor_k_set_mclk(fd_handle, 24);
+ udelay(500);//delay > 0us
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);//core vdd
+ udelay(1000);//delay >= 10us
+ sensor_k_set_pd_level(fd_handle, 1);//power down
+ udelay(30);//delay >= 15us
+ sensor_k_set_rst_level(fd_handle, 1);//reset
+ udelay(100);//delay > 60us
+ printk("sensor_s5k4ecgx_poweron OK \n");
+ return ret;
+}
+
+static int sensor_s5k4ecgx_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi544
+ udelay(100);//delay >50us
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+ udelay(100);//delay >= 0us
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi544
+ udelay(100);//delay < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ udelay(10);//delay < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);//close anolog vdd
+ mdelay(5);//delay >= 0us
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);//close core vdd
+ mdelay(1);//delay
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_CLOSED);//AF monitor
+ udelay(10);//delay
+
+ printk("sensor_s5k4ecgx_poweroff OK \n");
+ return ret;
+
+}
+
+static int sensor_hi255_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi544
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi544
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor(sensor hi255);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi255
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi255
+ udelay(1);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);//IO vdd
+ udelay(10);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);//core vdd
+ mdelay(2);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);//close core vdd
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_pd_level(fd_handle, 1);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(31);//delay 30ms >= 30ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ printk("hi255_poweron OK \n");
+
+ return ret;
+}
+
+static int sensor_hi255_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor(sensor hi255);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi255
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+ udelay(1);//delay 1us > 0ns
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi255
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+ //mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ udelay(1);
+ printk("hi255_poweroff OK \n");
+
+ return ret;
+}
+
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_s5k4ecgx_poweron(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweron(fd_handle, dev0, dev1, dev2);
+ }
+ return ret;
+}
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_s5k4ecgx_poweroff(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweroff(fd_handle, dev0, dev1, dev2);
+ }
+
+ return ret;
+}
diff --git a/drivers/media/sprd_sensor/power/sensor_power_grandprime3g_ve.c b/drivers/media/sprd_sensor/power/sensor_power_grandprime3g_ve.c
new file mode 100644
index 00000000..fe5c25db
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_grandprime3g_ve.c
@@ -0,0 +1,247 @@
+/*
+
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+
+ *
+
+ * This software is licensed under the terms of the GNU General Public
+
+ * License version 2, as published by the Free Software Foundation, and
+
+ * may be copied, distributed, and modified under those terms.
+
+ *
+
+ * 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/module.h>
+
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+
+#include <linux/bitops.h>
+
+#include <linux/delay.h>
+
+#include <linux/kernel.h>
+
+#include <soc/sprd/hardware.h>
+
+#include <soc/sprd/board.h>
+
+#include "../sensor_drv_sprd.h"
+
+
+
+static int sensor_s5k4h5yc_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ udelay(100);
+
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);
+ udelay(10);
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(750);
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(2);//delay 6ms < 10ms
+ //sensor_k_set_pd_level(fd_handle, 1);
+// mdelay(30);//delay 30ms >= 30ms
+ printk("s5k4h5yc_poweron OK \n");
+ return ret;
+}
+
+
+
+static int sensor_s5k4h5yc_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_CLOSED);
+
+ udelay(10);
+
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ mdelay(6);//delay 6ms < 10ms
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ mdelay(2);//delay 2us > 16MCLK = 16/24 us
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(2);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(2);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(6);//delay 6ms < 10ms
+
+ printk("s5k4h5yc_poweroff OK \n");
+return ret;
+
+}
+
+
+
+static int sensor_s5k5e3yx_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select sub sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+
+ udelay(50);
+
+ sensor_k_set_rst_level(fd_handle, 1);
+
+ udelay(250);
+
+ sensor_k_set_mclk(fd_handle, 24);
+
+ udelay(200);//delay 6ms < 10ms
+
+ printk("s5k5e3yx poweron OK \n");
+
+ return ret;
+
+}
+
+
+
+static int sensor_s5k5e3yx_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+
+ udelay(100);//delay 2us > 16MCLK = 16/24 us
+
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ printk("s5k5e3yx poweroff OK \n");
+ return ret;
+
+}
+
+
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ if (SENSOR_DEV_0 == sensor_id) {
+
+ ret = sensor_s5k4h5yc_poweron(fd_handle, dev0, dev1, dev2);
+
+ } else if (SENSOR_DEV_1 == sensor_id) {
+
+ ret = sensor_s5k5e3yx_poweron(fd_handle, dev0, dev1, dev2);
+
+ }
+
+ return ret;
+
+}
+
+
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ if (SENSOR_DEV_0 == sensor_id) {
+
+ ret = sensor_s5k4h5yc_poweroff(fd_handle, dev0, dev1, dev2);
+
+ } else if (SENSOR_DEV_1 == sensor_id) {
+
+ ret = sensor_s5k5e3yx_poweroff(fd_handle, dev0, dev1, dev2);
+
+ }
+
+
+
+ return ret;
+
+}
+
diff --git a/drivers/media/sprd_sensor/power/sensor_power_grandprime_dtv.c b/drivers/media/sprd_sensor/power/sensor_power_grandprime_dtv.c
new file mode 100755
index 00000000..fe5c25db
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_grandprime_dtv.c
@@ -0,0 +1,247 @@
+/*
+
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+
+ *
+
+ * This software is licensed under the terms of the GNU General Public
+
+ * License version 2, as published by the Free Software Foundation, and
+
+ * may be copied, distributed, and modified under those terms.
+
+ *
+
+ * 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/module.h>
+
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+
+#include <linux/bitops.h>
+
+#include <linux/delay.h>
+
+#include <linux/kernel.h>
+
+#include <soc/sprd/hardware.h>
+
+#include <soc/sprd/board.h>
+
+#include "../sensor_drv_sprd.h"
+
+
+
+static int sensor_s5k4h5yc_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ udelay(100);
+
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);
+ udelay(10);
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(750);
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(2);//delay 6ms < 10ms
+ //sensor_k_set_pd_level(fd_handle, 1);
+// mdelay(30);//delay 30ms >= 30ms
+ printk("s5k4h5yc_poweron OK \n");
+ return ret;
+}
+
+
+
+static int sensor_s5k4h5yc_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_CLOSED);
+
+ udelay(10);
+
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ mdelay(6);//delay 6ms < 10ms
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ mdelay(2);//delay 2us > 16MCLK = 16/24 us
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(2);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(2);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(6);//delay 6ms < 10ms
+
+ printk("s5k4h5yc_poweroff OK \n");
+return ret;
+
+}
+
+
+
+static int sensor_s5k5e3yx_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select sub sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+
+ udelay(50);
+
+ sensor_k_set_rst_level(fd_handle, 1);
+
+ udelay(250);
+
+ sensor_k_set_mclk(fd_handle, 24);
+
+ udelay(200);//delay 6ms < 10ms
+
+ printk("s5k5e3yx poweron OK \n");
+
+ return ret;
+
+}
+
+
+
+static int sensor_s5k5e3yx_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+
+ udelay(100);//delay 2us > 16MCLK = 16/24 us
+
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ printk("s5k5e3yx poweroff OK \n");
+ return ret;
+
+}
+
+
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ if (SENSOR_DEV_0 == sensor_id) {
+
+ ret = sensor_s5k4h5yc_poweron(fd_handle, dev0, dev1, dev2);
+
+ } else if (SENSOR_DEV_1 == sensor_id) {
+
+ ret = sensor_s5k5e3yx_poweron(fd_handle, dev0, dev1, dev2);
+
+ }
+
+ return ret;
+
+}
+
+
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ if (SENSOR_DEV_0 == sensor_id) {
+
+ ret = sensor_s5k4h5yc_poweroff(fd_handle, dev0, dev1, dev2);
+
+ } else if (SENSOR_DEV_1 == sensor_id) {
+
+ ret = sensor_s5k5e3yx_poweroff(fd_handle, dev0, dev1, dev2);
+
+ }
+
+
+
+ return ret;
+
+}
+
diff --git a/drivers/media/sprd_sensor/power/sensor_power_sharkl_t8.c b/drivers/media/sprd_sensor/power/sensor_power_sharkl_t8.c
new file mode 100644
index 00000000..ad9736e8
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_sharkl_t8.c
@@ -0,0 +1,247 @@
+/*
+
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+
+ *
+
+ * This software is licensed under the terms of the GNU General Public
+
+ * License version 2, as published by the Free Software Foundation, and
+
+ * may be copied, distributed, and modified under those terms.
+
+ *
+
+ * 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/module.h>
+
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+
+#include <linux/bitops.h>
+
+#include <linux/delay.h>
+
+#include <linux/kernel.h>
+
+#include <soc/sprd/hardware.h>
+
+#include <soc/sprd/board.h>
+
+#include "../sensor_drv_sprd.h"
+
+
+
+static int sensor_s5k4h5yc_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ udelay(100);
+
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);
+ udelay(10);
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(750);
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(2);//delay 6ms < 10ms
+ //sensor_k_set_pd_level(fd_handle, 1);
+// mdelay(30);//delay 30ms >= 30ms
+ printk("s5k4h5yc_poweron OK \n");
+ return ret;
+}
+
+
+
+static int sensor_s5k4h5yc_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_CLOSED);
+
+ udelay(10);
+
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ mdelay(6);//delay 6ms < 10ms
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ mdelay(2);//delay 2us > 16MCLK = 16/24 us
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(2);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(2);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ mdelay(6);//delay 6ms < 10ms
+
+ printk("s5k4h5yc_poweroff OK \n");
+return ret;
+
+}
+
+
+
+static int sensor_s5k5e3yx_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select sub sensor
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+
+ udelay(50);
+
+ sensor_k_set_rst_level(fd_handle, 1);
+
+ udelay(250);
+
+ sensor_k_set_mclk(fd_handle, 24);
+
+ udelay(200);//delay 6ms < 10ms
+
+ printk("s5k5e3yx poweron OK \n");
+
+ return ret;
+
+}
+
+
+
+static int sensor_s5k5e3yx_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+
+ udelay(100);//delay 2us > 16MCLK = 16/24 us
+
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+
+ //sensor_k_set_pd_level(fd_handle, 0);//power down
+
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ printk("s5k5e3yx poweroff OK \n");
+ return ret;
+
+}
+
+
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ if (SENSOR_DEV_0 == sensor_id) {
+
+ //ret = sensor_s5k4h5yc_poweron(fd_handle, dev0, dev1, dev2);
+
+ } else if (SENSOR_DEV_1 == sensor_id) {
+
+ ret = sensor_s5k5e3yx_poweron(fd_handle, dev0, dev1, dev2);
+
+ }
+
+ return ret;
+
+}
+
+
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+
+{
+
+ int ret = 0;
+
+
+
+ if (SENSOR_DEV_0 == sensor_id) {
+
+ //ret = sensor_s5k4h5yc_poweroff(fd_handle, dev0, dev1, dev2);
+
+ } else if (SENSOR_DEV_1 == sensor_id) {
+
+ ret = sensor_s5k5e3yx_poweroff(fd_handle, dev0, dev1, dev2);
+
+ }
+
+
+
+ return ret;
+
+}
+
diff --git a/drivers/media/sprd_sensor/power/sensor_power_sharkls_z3lte.c b/drivers/media/sprd_sensor/power/sensor_power_sharkls_z3lte.c
new file mode 100644
index 00000000..e7d2010c
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_sharkls_z3lte.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <video/sensor_drv_k.h>
+#include "../sensor_drv_sprd.h"
+
+static int sensor_s5k4ecgx_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ /*set default status for main and sub sensor*/
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor(sensor hi255);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi255
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi255
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi544
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi544
+ mdelay(1);
+
+ /*power on sequence*/
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);//AF monitor
+ mdelay(1);//delay
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);//IO vdd
+ udelay(500);//delay >2ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);//anolog vdd
+ udelay(1000);//delay > 0us
+ sensor_k_set_mclk(fd_handle, 24);
+ udelay(500);//delay > 0us
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);//core vdd
+ udelay(1000);//delay >= 10us
+ sensor_k_set_pd_level(fd_handle, 1);//power down
+ udelay(30);//delay >= 15us
+ sensor_k_set_rst_level(fd_handle, 1);//reset
+ udelay(100);//delay > 60us
+ printk("sensor_s5k4ecgx_poweron OK \n");
+ return ret;
+}
+
+static int sensor_s5k4ecgx_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi544
+ udelay(100);//delay >50us
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+ udelay(100);//delay >= 0us
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi544
+ udelay(100);//delay < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ udelay(10);//delay < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);//close anolog vdd
+ mdelay(5);//delay >= 0us
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);//close core vdd
+ mdelay(1);//delay
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_CLOSED);//AF monitor
+ udelay(10);//delay
+
+ printk("sensor_s5k4ecgx_poweroff OK \n");
+ return ret;
+
+}
+
+static int sensor_hi255_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor(sensor hi544);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi544
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi544
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor(sensor hi255);
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi255
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi255
+ udelay(1);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);//IO vdd
+ udelay(10);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ udelay(10);
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_1200MV);//core vdd
+ mdelay(2);
+ sensor_k_set_voltage_dvdd(fd_handle, SENSOR_VDD_CLOSED);//close core vdd
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_pd_level(fd_handle, 1);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(31);//delay 30ms >= 30ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ printk("hi255_poweron OK \n");
+
+ return ret;
+}
+
+static int sensor_hi255_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor(sensor hi255);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle, 0);//reset valid for hi255
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+ udelay(1);//delay 1us > 0ns
+ sensor_k_set_pd_level(fd_handle, 0);//power down valid for hi255
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+ //mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ udelay(1);
+ printk("hi255_poweroff OK \n");
+
+ return ret;
+}
+
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_s5k4ecgx_poweron(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweron(fd_handle, dev0, dev1, dev2);
+ }
+ return ret;
+}
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_s5k4ecgx_poweroff(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweroff(fd_handle, dev0, dev1, dev2);
+ }
+
+ return ret;
+}
diff --git a/drivers/media/sprd_sensor/power/sensor_power_tshark2tabe.c b/drivers/media/sprd_sensor/power/sensor_power_tshark2tabe.c
new file mode 100755
index 00000000..4cfa6f18
--- /dev/null
+++ b/drivers/media/sprd_sensor/power/sensor_power_tshark2tabe.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include "../sensor_drv_sprd.h"
+
+static int sensor_hi544_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select sub sensor
+ sensor_k_set_pd_level(fd_handle, 0);//power down
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+ sensor_k_set_pd_level(fd_handle, 0);//power down
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+ udelay(10);
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_2800MV);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+ udelay(10);
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_pd_level(fd_handle, 1);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(30);//delay 30ms >= 30ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ printk("hi544_poweron OK \n");
+
+ return ret;
+}
+
+static int sensor_hi544_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select main sensor
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+ mdelay(10);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+ udelay(1);//delay 1us > 0ns
+ sensor_k_set_pd_level(fd_handle, 0);//power down
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ udelay(1);
+ sensor_k_set_voltage_cammot(fd_handle, SENSOR_VDD_CLOSED);
+ printk("hi544_poweroff OK \n");
+
+ return ret;
+}
+
+
+static int sensor_hi255_poweron(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_0);//select sub sensor
+ sensor_k_set_pd_level(fd_handle, 0);//power down
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+ sensor_k_set_pd_level(fd_handle, 0);//power down
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+ udelay(1);
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_1800MV);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_2800MV);
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_pd_level(fd_handle, 1);
+ mdelay(2);//delay 2ms > 1ms
+ sensor_k_set_mclk(fd_handle, 24);
+ mdelay(30);//delay 30ms >= 30ms
+ sensor_k_set_rst_level(fd_handle, 1);
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ printk("hi255_poweron OK \n");
+
+ return ret;
+}
+
+static int sensor_hi255_poweroff(uint32_t *fd_handle, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ sensor_k_sensor_sel(fd_handle, SENSOR_DEV_1);//select main sensor
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_rst_level(fd_handle, 0);//reset
+ udelay(2);//delay 2us > 16MCLK = 16/24 us
+ sensor_k_set_mclk(fd_handle, 0);// disable mclk
+ udelay(1);//delay 1us > 0ns
+ sensor_k_set_pd_level(fd_handle, 0);//power down
+ mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_avdd(fd_handle, SENSOR_VDD_CLOSED);
+ //mdelay(6);//delay 6ms < 10ms
+ sensor_k_set_voltage_iovdd(fd_handle, SENSOR_VDD_CLOSED);
+ udelay(1);
+ printk("hi255_poweroff OK \n");
+
+ return ret;
+}
+
+int sensor_power_on(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_hi544_poweron(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweron(fd_handle, dev0, dev1, dev2);
+ }
+ return ret;
+}
+
+int sensor_power_off(uint32_t *fd_handle, uint32_t sensor_id, struct sensor_power *dev0, struct sensor_power *dev1, struct sensor_power *dev2)
+{
+ int ret = 0;
+
+ if (SENSOR_DEV_0 == sensor_id) {
+ ret = sensor_hi544_poweroff(fd_handle, dev0, dev1, dev2);
+ } else if (SENSOR_DEV_1 == sensor_id) {
+ ret = sensor_hi255_poweroff(fd_handle, dev0, dev1, dev2);
+ }
+
+ return ret;
+}
diff --git a/drivers/media/sprd_sensor/sensor_drv_k.c b/drivers/media/sprd_sensor/sensor_drv_k.c
new file mode 100755
index 00000000..d0122dfb
--- /dev/null
+++ b/drivers/media/sprd_sensor/sensor_drv_k.c
@@ -0,0 +1,2005 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <asm/io.h>
+#include <linux/file.h>
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/wakelock.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
+#include <linux/kthread.h>
+
+#ifndef CONFIG_64BIT
+#include <soc/sprd/dma.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <soc/sprd/regulator.h>
+#include <soc/sprd/arch_misc.h>
+#include <soc/sprd/adi.h>
+
+#endif
+#include <soc/sprd/i2c-sprd.h>
+
+#include <video/sensor_drv_k.h>
+#include "sensor_drv_sprd.h"
+#include "compat_sensor_drv_k.h"
+#include "csi2/csi_api.h"
+#include "parse_hwinfo.h"
+#ifdef CONFIG_SC_FPGA
+#include "dcam_reg.h"
+#endif
+#include "power/sensor_power.h"
+#include "otp/sensor_otp.h"
+
+#define SENSOR_CLK "clk_sensor"
+#define SENSOR_DEVICE_NAME "sprd_sensor"
+
+#define DEBUG_SENSOR_DRV
+#ifdef DEBUG_SENSOR_DRV
+#define SENSOR_PRINT pr_debug
+#else
+#define SENSOR_PRINT(...)
+#endif
+#define SENSOR_PRINT_ERR printk
+#define SENSOR_PRINT_HIGH printk
+
+#define SENSOR_K_SUCCESS 0
+#define SENSOR_K_FAIL (-1)
+#define SENSOR_K_FALSE 0
+#define SENSOR_K_TRUE 1
+
+#ifndef CONFIG_SC_FPGA
+#define LOCAL static
+#else
+#define LOCAL
+#endif
+
+#define PNULL ((void *)0)
+
+#define NUMBER_MAX 0x7FFFFFF
+
+#define SENSOR_MINOR MISC_DYNAMIC_MINOR
+#define SLEEP_MS(ms) msleep(ms)
+
+#define SENSOR_I2C_ID 0
+#define SENSOR_I2C_OP_TRY_NUM 3
+#define SENSOR_CMD_BITS_8 1
+#define SENSOR_CMD_BITS_16 2
+#define SENSOR_I2C_VAL_8BIT 0x00
+#define SENSOR_I2C_VAL_16BIT 0x01
+#define SENSOR_I2C_REG_8BIT (0x00 << 1)
+#define SENSOR_I2C_REG_16BIT (0x01 << 1)
+#define SENSOR_I2C_CUSTOM (0x01 << 2)
+#define SENSOR_LOW_EIGHT_BIT 0xff
+
+#define SENSOR_WRITE_DELAY 0xffff
+#define DEBUG_STR "Error L %d, %s \n"
+#define DEBUG_ARGS __LINE__,__FUNCTION__
+#define SENSOR_MCLK_SRC_NUM 4
+#define SENSOR_MCLK_DIV_MAX 4
+#define SENSOR_ABS(a) ((a) > 0 ? (a) : -(a))
+#define SENSOR_LOWEST_ADDR 0x800
+#define SENSOR_ADDR_INVALID(addr) ((unsigned long)(addr) < SENSOR_LOWEST_ADDR)
+
+#define SENSOR_CHECK_ZERO(a) \
+ do { \
+ if (SENSOR_ADDR_INVALID(a)) { \
+ printk("SENSOR, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -EFAULT; \
+ } \
+ } while(0)
+
+#define SENSOR_CHECK_ZERO_VOID(a) \
+ do { \
+ if (SENSOR_ADDR_INVALID(a)) { \
+ printk("SENSOR, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return; \
+ } \
+ } while(0)
+
+struct sensor_mclk_tag {
+ uint32_t clock;
+ char *src_name;
+};
+
+struct sensor_mem_tag {
+ void *buf_ptr;
+ size_t size;
+};
+
+struct sensor_module_tag {
+ struct mutex sync_lock;
+ atomic_t users;
+ struct i2c_client *cur_i2c_client;
+ struct i2c_client *vcm_i2c_client;
+ uint32_t vcm_gpio_i2c_flag;
+};
+
+struct sensor_module_tab_tag {
+ atomic_t total_users;
+ uint32_t padding;
+ struct mutex sensor_id_lock;
+ struct device_node *of_node;
+ struct clk *sensor_mm_in_clk;
+ struct wake_lock wakelock;
+ struct sensor_module_tag sensor_dev_tab[SENSOR_DEV_MAX];
+ SENSOR_OTP_PARAM_T otp_param[SENSOR_DEV_MAX];
+};
+
+struct sensor_gpio_tag {
+ int pwn;
+ int reset;
+};
+
+struct sensor_file_tag {
+ struct sensor_module_tab_tag *module_data;
+ uint32_t sensor_id;
+ uint32_t sensor_mclk;
+ uint32_t iopower_on_count;
+ uint32_t avddpower_on_count;
+ uint32_t dvddpower_on_count;
+ uint32_t motpower_on_count;
+ uint32_t mipi_on;
+ uint32_t padding;
+ uint32_t phy_id;
+ uint32_t if_type;
+ struct sensor_gpio_tag gpio_tab;
+ struct clk *ccir_clk;
+ struct clk *ccir_enable_clk;
+ struct clk *mipi_clk;
+ struct regulator *camvio_regulator;
+ struct regulator *camavdd_regulator;
+ struct regulator *camdvdd_regulator;
+ struct regulator *cammot_regulator;
+ struct sensor_mem_tag sensor_mem;
+ void *csi_handle;
+};
+
+LOCAL const struct sensor_mclk_tag c_sensor_mclk_tab[SENSOR_MCLK_SRC_NUM] = {
+ {96, "clk_96m"},
+ {77, "clk_76m8"},
+ {48, "clk_48m"},
+ {26, "ext_26m"}
+};
+
+LOCAL struct sensor_name socname = {-1,-1};
+
+LOCAL void* _sensor_k_malloc(struct sensor_file_tag *fd_handle, size_t size)
+{
+ if (SENSOR_ADDR_INVALID(fd_handle)) {
+ printk("SENSOR, zero pointer \n");
+ printk(DEBUG_STR, DEBUG_ARGS);
+ return PNULL;
+ }
+
+ if(PNULL == fd_handle->sensor_mem.buf_ptr) {
+ fd_handle->sensor_mem.buf_ptr = vzalloc(size);
+ if(PNULL != fd_handle->sensor_mem.buf_ptr) {
+ fd_handle->sensor_mem.size = size;
+ }
+
+ } else if (size > fd_handle->sensor_mem.size) {
+ //realloc memory
+ vfree(fd_handle->sensor_mem.buf_ptr);
+ fd_handle->sensor_mem.buf_ptr = PNULL;
+ fd_handle->sensor_mem.size = 0;
+ fd_handle->sensor_mem.buf_ptr = vzalloc(size);
+ if (PNULL != fd_handle->sensor_mem.buf_ptr) {
+ fd_handle->sensor_mem.size = size;
+ }
+ }
+
+ return fd_handle->sensor_mem.buf_ptr;
+}
+
+LOCAL void _sensor_k_free(struct sensor_file_tag *fd_handle, void *p)
+{
+ /* memory will not be free */
+ return;
+}
+
+#if 0
+LOCAL struct platform_device* _sensor_k_get_platform_device(void)
+{
+ struct device *dev;
+
+ dev = bus_find_device_by_name(&platform_bus_type, NULL, SENSOR_DEVICE_NAME);
+ if (!dev) {
+ printk("%s error: find device\n", __func__);
+ return NULL;
+ }
+
+ return to_platform_device(dev);
+}
+#endif
+
+int sensor_k_set_pd_level(uint32_t *fd_handle, uint8_t power_level)
+{
+ struct sensor_module_tab_tag *p_mod;
+ struct sensor_file_tag *fd = (struct sensor_file_tag *)fd_handle;
+
+ SENSOR_CHECK_ZERO(fd);
+ p_mod = fd->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+#ifndef CONFIG_SC_FPGA_PIN
+ get_gpio_id(p_mod->of_node, &fd->gpio_tab.pwn, &fd->gpio_tab.reset, fd->sensor_id);
+ SENSOR_PRINT_HIGH("SENSOR: pwn %d \n", fd->gpio_tab.pwn);
+ if (0 == power_level) {
+ gpio_direction_output(fd->gpio_tab.pwn, 0);
+ } else {
+ gpio_direction_output(fd->gpio_tab.pwn, 1);
+ }
+#else
+ SENSOR_PRINT_HIGH("CAP_SENSOR_CTRL 0x%lx\n", CAP_SENSOR_CTRL);
+ if (0 == power_level) {
+ REG_MWR(CAP_SENSOR_CTRL,0x0f,0);
+ } else {
+ REG_MWR(CAP_SENSOR_CTRL,0x0f,0x0f);
+ }
+ SENSOR_PRINT_HIGH("CAP_SENSOR_CTRL val=0x%x\n", REG_RD(CAP_SENSOR_CTRL));
+#endif
+
+ return SENSOR_K_SUCCESS;
+}
+
+LOCAL void _sensor_regulator_disable(struct sensor_file_tag *fd_handle, uint32_t *power_on_count, struct regulator * ptr_cam_regulator)
+{
+ SENSOR_CHECK_ZERO_VOID(fd_handle);
+
+ while (*power_on_count > 0) {
+ regulator_disable(ptr_cam_regulator);
+ (*power_on_count)--;
+ }
+ SENSOR_PRINT("sensor pwr off done: cnt=0x%x, io=%x, av=%x, dv=%x, mo=%x \n", *power_on_count,
+ fd_handle->iopower_on_count,
+ fd_handle->avddpower_on_count,
+ fd_handle->dvddpower_on_count,
+ fd_handle->motpower_on_count);
+
+}
+
+LOCAL int _sensor_regulator_enable(struct sensor_file_tag *fd_handle, uint32_t *power_on_count, struct regulator * ptr_cam_regulator)
+{
+ int err;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ err = regulator_enable(ptr_cam_regulator);
+ (*power_on_count)++;
+
+ SENSOR_PRINT("sensor pwr on done: cnt=0x%x, io=%x, av=%x, dv=%x, mo=%x \n", *power_on_count,
+ fd_handle->iopower_on_count,
+ fd_handle->avddpower_on_count,
+ fd_handle->dvddpower_on_count,
+ fd_handle->motpower_on_count);
+
+ return err;
+}
+
+LOCAL int _sensor_k_get_voltage_value(uint32_t *val)
+{
+ uint32_t volt_value = 0;
+
+ SENSOR_CHECK_ZERO(val);
+
+ switch (*val) {
+ case SENSOR_VDD_3800MV:
+ volt_value = SENSOER_VDD_3800MV;
+ break;
+ case SENSOR_VDD_3300MV:
+ volt_value = SENSOER_VDD_3300MV;
+ break;
+ case SENSOR_VDD_3000MV:
+ volt_value = SENSOER_VDD_3000MV;
+ break;
+ case SENSOR_VDD_2800MV:
+ volt_value = SENSOER_VDD_2800MV;
+ break;
+ case SENSOR_VDD_2500MV:
+ volt_value = SENSOER_VDD_2500MV;
+ break;
+ case SENSOR_VDD_1800MV:
+ volt_value = SENSOER_VDD_1800MV;
+ break;
+ case SENSOR_VDD_1500MV:
+ volt_value = SENSOER_VDD_1500MV;
+ break;
+ case SENSOR_VDD_1300MV:
+ volt_value = SENSOER_VDD_1300MV;
+ break;
+ case SENSOR_VDD_1200MV:
+ volt_value = SENSOER_VDD_1200MV;
+ break;
+ case SENSOR_VDD_CLOSED:
+ case SENSOR_VDD_UNUSED:
+ default:
+ volt_value = 0;
+ break;
+ }
+
+ *val = volt_value;
+
+ SENSOR_PRINT("sensor get voltage val: %d \n", *val);
+
+ return SENSOR_K_SUCCESS;
+}
+
+LOCAL int _sensor_k_set_voltage(struct sensor_file_tag *fd_handle, uint32_t val, uint32_t type)
+{
+#ifdef CONFIG_SC_FPGA_LDO
+ return 0;
+#else
+ int ret = SENSOR_K_SUCCESS;
+ uint32_t volt_value = 0;
+ uint32_t *poweron_count = NULL;
+ char *regu_name;
+ struct sensor_module_tab_tag *p_mod;
+ struct regulator **p_regulator = NULL;
+
+ SENSOR_CHECK_ZERO(fd_handle);
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ SENSOR_PRINT("sensor set voltage val: %d \n", val);
+
+ get_regulator_name(p_mod->of_node, &type, fd_handle->sensor_id, &regu_name);
+
+ switch (type) {
+ case REGU_CAMAVDD:
+ p_regulator = &fd_handle->camavdd_regulator;
+ poweron_count = &fd_handle->avddpower_on_count;
+ break;
+
+ case REGU_CAMDVDD:
+ p_regulator = &fd_handle->camdvdd_regulator;
+ poweron_count = &fd_handle->dvddpower_on_count;
+ break;
+
+ case REGU_CAMIOVDD:
+ p_regulator = &fd_handle->camvio_regulator;
+ poweron_count = &fd_handle->iopower_on_count;
+ break;
+
+ case REGU_CAMMOT:
+ p_regulator = &fd_handle->cammot_regulator;
+ poweron_count = &fd_handle->motpower_on_count;
+ break;
+
+ default:
+ SENSOR_PRINT_ERR("error type = %d\n",type);
+ break;
+ }
+
+ if ((NULL == poweron_count) || (NULL == p_regulator)) {
+ SENSOR_PRINT_ERR("error param");
+ return SENSOR_K_FAIL;
+ }
+
+ if (NULL == *p_regulator) {
+ *p_regulator = regulator_get(NULL, regu_name);
+ if (IS_ERR(*p_regulator)) {
+ SENSOR_PRINT_ERR("SENSOR:get regu.fail %s %d\n", regu_name, type);
+ return SENSOR_K_FAIL;
+ }
+ }
+ volt_value = val;
+ _sensor_k_get_voltage_value(&volt_value);
+
+ if (0 != volt_value) {
+ ret = regulator_set_voltage(*p_regulator, volt_value, volt_value);
+ }
+ if (ret) {
+ SENSOR_PRINT_ERR("SENSOR:set vol err %d %s %d!.\n", ret, regu_name, type);
+ return SENSOR_K_FAIL;
+ }
+
+ if (0 != volt_value) {
+ ret = _sensor_regulator_enable(fd_handle, poweron_count, *p_regulator);
+ if (ret) {
+ regulator_put(*p_regulator);
+ *p_regulator = NULL;
+ SENSOR_PRINT_ERR("SENSOR:can't en %d %s %d!.\n", ret, regu_name, type);
+ return SENSOR_K_FAIL;
+ }
+ } else {
+ _sensor_regulator_disable(fd_handle, poweron_count, *p_regulator);
+ regulator_put(*p_regulator);
+ *p_regulator = NULL;
+ SENSOR_PRINT("SENSOR:dis regu.\n");
+ }
+
+ SENSOR_PRINT_HIGH("SENSOR:set vol %d %s %d!.\n", volt_value, regu_name, type);
+
+ return ret;
+#endif
+}
+
+int sensor_k_set_voltage_cammot(uint32_t *fd_handle, uint32_t cammot_val)
+{
+ return _sensor_k_set_voltage((struct sensor_file_tag *)fd_handle, cammot_val, REGU_CAMMOT);
+}
+
+int sensor_k_set_voltage_avdd(uint32_t *fd_handle, uint32_t avdd_val)
+{
+ return _sensor_k_set_voltage((struct sensor_file_tag *)fd_handle, avdd_val, REGU_CAMAVDD);
+}
+
+int sensor_k_set_voltage_dvdd(uint32_t *fd_handle, uint32_t dvdd_val)
+{
+#ifdef CONFIG_SC_FPGA_LDO
+ return 0;
+#else
+ int gpio_id = 0;
+ struct sensor_module_tab_tag *p_mod;
+ struct sensor_file_tag *fd = (struct sensor_file_tag *)fd_handle;
+
+ SENSOR_CHECK_ZERO(fd);
+ p_mod = fd->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ get_gpio_id_ex(p_mod->of_node, GPIO_CAMDVDD, &gpio_id, fd->sensor_id);
+ if (SENSOR_DEV_0 == fd->sensor_id && 0 != gpio_id) {
+ SENSOR_PRINT_HIGH("sensor set DVDD gpio %d\n", gpio_id);
+ if (SENSOR_VDD_CLOSED == dvdd_val) {
+ gpio_direction_output(gpio_id, 1);
+ gpio_set_value(gpio_id, 0);
+ } else {
+ gpio_direction_output(gpio_id, 1);
+ gpio_set_value(gpio_id, 1);
+ }
+ return SENSOR_K_SUCCESS;
+ }
+
+ if (SENSOR_DEV_1 == fd->sensor_id && 0 != gpio_id) {
+ SENSOR_PRINT_HIGH("sensor set DVDD gpio %d\n", gpio_id);
+ if (SENSOR_VDD_CLOSED == dvdd_val) {
+ gpio_direction_output(gpio_id, 1);
+ gpio_set_value(gpio_id, 0);
+ } else {
+ gpio_direction_output(gpio_id, 1);
+ gpio_set_value(gpio_id, 1);
+ }
+ return SENSOR_K_SUCCESS;
+ }
+
+ return _sensor_k_set_voltage((struct sensor_file_tag *)fd_handle, dvdd_val, REGU_CAMDVDD);
+#endif
+}
+
+int sensor_k_set_voltage_iovdd(uint32_t *fd_handle, uint32_t iodd_val)
+{
+ return _sensor_k_set_voltage((struct sensor_file_tag *)fd_handle, iodd_val, REGU_CAMIOVDD);
+}
+
+LOCAL int _select_sensor_mclk(struct sensor_file_tag *fd_handle, uint8_t clk_set, char **clk_src_name,
+ uint8_t * clk_div)
+{
+ uint8_t i = 0;
+ uint8_t j = 0;
+ uint8_t mark_src = 0;
+ uint8_t mark_div = 0;
+ uint8_t mark_src_tmp = 0;
+ int clk_tmp = NUMBER_MAX;
+ int src_delta = NUMBER_MAX;
+ int src_delta_min = NUMBER_MAX;
+ int div_delta_min = NUMBER_MAX;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ SENSOR_PRINT("SENSOR sel mclk %d.\n", clk_set);
+ if (clk_set > 96 || !clk_src_name || !clk_div) {
+ return SENSOR_K_FAIL;
+ }
+ for (i = 0; i < SENSOR_MCLK_DIV_MAX; i++) {
+ clk_tmp = (int)(clk_set * (i + 1));
+ src_delta_min = NUMBER_MAX;
+ for (j = 0; j < SENSOR_MCLK_SRC_NUM; j++) {
+ src_delta = c_sensor_mclk_tab[j].clock - clk_tmp;
+ src_delta = SENSOR_ABS(src_delta);
+ if (src_delta < src_delta_min) {
+ src_delta_min = src_delta;
+ mark_src_tmp = j;
+ }
+ }
+ if (src_delta_min < div_delta_min) {
+ div_delta_min = src_delta_min;
+ mark_src = mark_src_tmp;
+ mark_div = i;
+ }
+ }
+ SENSOR_PRINT("src %d, div=%d .\n", mark_src,
+ mark_div);
+
+ *clk_src_name = c_sensor_mclk_tab[mark_src].src_name;
+ *clk_div = mark_div + 1;
+
+ return SENSOR_K_SUCCESS;
+}
+
+int32_t _sensor_k_mipi_clk_en(struct sensor_file_tag *fd_handle, struct device_node *dn)
+{
+#ifdef CONFIG_SC_FPGA_CLK
+ return 0;
+#else
+ int ret = 0;
+
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ if (NULL == fd_handle->mipi_clk) {
+ fd_handle->mipi_clk = parse_clk(dn,"clk_dcam_mipi");
+ }
+
+ if (IS_ERR(fd_handle->mipi_clk)) {
+ printk("SENSOR: get dcam mipi clk error \n");
+ return -1;
+ } else {
+ ret = clk_enable(fd_handle->mipi_clk);
+ if (ret) {
+ printk("SENSOR: enable dcam mipi clk error %d \n", ret);
+ return -1;
+ }
+ }
+
+ return ret;
+#endif
+}
+
+int32_t _sensor_k_mipi_clk_dis(struct sensor_file_tag *fd_handle)
+{
+#ifdef CONFIG_SC_FPGA_CLK
+ return 0;
+#else
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ if (fd_handle->mipi_clk) {
+ clk_disable(fd_handle->mipi_clk);
+ clk_put(fd_handle->mipi_clk);
+ fd_handle->mipi_clk = NULL;
+ }
+ return 0;
+#endif
+}
+
+LOCAL int _sensor_k_set_mclk(struct sensor_file_tag *fd_handle, struct device_node *dn, uint32_t mclk)
+{
+#ifdef CONFIG_SC_FPGA_CLK
+ return 0;
+#else
+ struct clk *clk_parent = NULL;
+ int ret;
+ char *clk_src_name = NULL;
+ uint8_t clk_div;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ SENSOR_PRINT_HIGH("SENSOR: set mclk org = %d, clk = %d\n",
+ fd_handle->sensor_mclk, mclk);
+
+ if ((0 != mclk) && (fd_handle->sensor_mclk != mclk)) {
+ if (fd_handle->ccir_clk) {
+ clk_disable(fd_handle->ccir_clk);
+ SENSOR_PRINT("###sensor ccir clk off ok.\n");
+ } else {
+ fd_handle->ccir_clk = parse_clk(dn, SENSOR_CLK);
+ if (IS_ERR(fd_handle->ccir_clk)) {
+ SENSOR_PRINT_ERR("###: Failed: Can't get clock [ccir_mclk]!\n");
+ SENSOR_PRINT_ERR("###: s_sensor_clk = %p.\n",fd_handle->ccir_clk);
+ } else {
+ SENSOR_PRINT("###sensor ccir clk get ok.\n");
+ }
+ }
+ if (mclk > SENSOR_MAX_MCLK) {
+ mclk = SENSOR_MAX_MCLK;
+ }
+ if (SENSOR_K_SUCCESS != _select_sensor_mclk(fd_handle, (uint8_t) mclk, &clk_src_name, &clk_div)) {
+ SENSOR_PRINT_ERR("SENSOR:Sensor_SetMCLK select clock source fail.\n");
+ return -EINVAL;
+ }
+ SENSOR_PRINT("clk_src_name=%s, clk_div=%d \n", clk_src_name, clk_div);
+
+ clk_parent = clk_get(NULL, clk_src_name);
+ if (!clk_parent) {
+ SENSOR_PRINT_ERR("###:clock: failed to get clock [%s] by clk_get()!\n", clk_src_name);
+ return -EINVAL;
+ }
+ SENSOR_PRINT("clk_get clk_src_name=%s done\n", clk_src_name);
+
+ ret = clk_set_parent(fd_handle->ccir_clk, clk_parent);
+ if (ret) {
+ SENSOR_PRINT_ERR("###:clock: clk_set_parent() failed!parent \n");
+ return -EINVAL;
+ }
+ SENSOR_PRINT("clk_set_parent s_ccir_clk=%s done\n", (char *)(fd_handle->ccir_clk));
+
+ ret = clk_set_rate(fd_handle->ccir_clk, (mclk * SENOR_CLK_M_VALUE));
+ if (ret) {
+ SENSOR_PRINT_ERR("###:clock: clk_set_rate failed!\n");
+ return -EINVAL;
+ }
+ SENSOR_PRINT("clk_set_rate s_ccir_clk=%s done\n", (char *)(fd_handle->ccir_clk));
+
+ ret = clk_enable(fd_handle->ccir_clk);
+ if (ret) {
+ SENSOR_PRINT_ERR("###:clock: clk_enable() failed!\n");
+ } else {
+ SENSOR_PRINT("######ccir enable clk ok\n");
+ }
+
+ if (NULL == fd_handle->ccir_enable_clk) {
+ fd_handle->ccir_enable_clk = parse_clk(dn,"clk_ccir");
+ if (IS_ERR(fd_handle->ccir_enable_clk)) {
+ SENSOR_PRINT_ERR("###: Failed: Can't get clock [clk_ccir]!\n");
+ SENSOR_PRINT_ERR("###: ccir_enable_clk = %p.\n", fd_handle->ccir_enable_clk);
+ return -EINVAL;
+ } else {
+ SENSOR_PRINT("###sensor ccir_enable_clk clk_get ok.\n");
+ }
+ ret = clk_enable(fd_handle->ccir_enable_clk);
+ if (ret) {
+ SENSOR_PRINT_ERR("###:clock: clk_enable() failed!\n");
+ } else {
+ SENSOR_PRINT("###ccir enable clk ok\n");
+ }
+ }
+
+ fd_handle->sensor_mclk = mclk;
+ SENSOR_PRINT("SENSOR: set mclk %d Hz.\n",
+ fd_handle->sensor_mclk);
+ } else if (0 == mclk) {
+ if (fd_handle->ccir_clk) {
+ clk_disable(fd_handle->ccir_clk);
+ SENSOR_PRINT("###sensor clk disable ok.\n");
+ clk_put(fd_handle->ccir_clk);
+ SENSOR_PRINT("###sensor clk put ok.\n");
+ fd_handle->ccir_clk = NULL;
+ }
+
+ if (fd_handle->ccir_enable_clk) {
+ clk_disable(fd_handle->ccir_enable_clk);
+ SENSOR_PRINT("###sensor clk disable ok.\n");
+ clk_put(fd_handle->ccir_enable_clk);
+ SENSOR_PRINT("###sensor clk put ok.\n");
+ fd_handle->ccir_enable_clk = NULL;
+ }
+ fd_handle->sensor_mclk = 0;
+ SENSOR_PRINT("SENSOR: Disable MCLK !!!");
+ } else {
+ SENSOR_PRINT("SENSOR: Do nothing !! ");
+ }
+ SENSOR_PRINT_HIGH("SENSOR: set mclk X\n");
+ return 0;
+#endif
+}
+
+int sensor_k_set_mclk(uint32_t *fd_handle, uint32_t mclk)
+{
+ struct sensor_module_tab_tag *p_mod;
+ struct sensor_file_tag *fd = (struct sensor_file_tag *)fd_handle;
+
+ SENSOR_CHECK_ZERO(fd);
+ p_mod = fd->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ return _sensor_k_set_mclk(fd, p_mod->of_node, mclk);
+}
+
+LOCAL int _sensor_k_reset(struct sensor_file_tag *fd_handle, uint32_t level, uint32_t width)
+{
+#ifndef CONFIG_SC_FPGA_PIN
+ struct sensor_module_tab_tag *p_mod;
+
+ SENSOR_CHECK_ZERO(fd_handle);
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ get_gpio_id(p_mod->of_node, &fd_handle->gpio_tab.pwn, &fd_handle->gpio_tab.reset, fd_handle->sensor_id);
+ SENSOR_PRINT_HIGH("SENSOR: reset val %d id %d reset %d\n",level, fd_handle->sensor_id, fd_handle->gpio_tab.reset);
+
+ gpio_direction_output(fd_handle->gpio_tab.reset, level);
+ gpio_set_value(fd_handle->gpio_tab.reset, level);
+ SLEEP_MS(width);
+ gpio_set_value(fd_handle->gpio_tab.reset, !level);
+#else
+ SENSOR_PRINT_HIGH("CAP_SENSOR_CTRL 0x%lx\n", CAP_SENSOR_CTRL);
+
+ REG_MWR(CAP_SENSOR_CTRL,0xf0,level!=0?0xf0:0);
+ SLEEP_MS(width);
+ REG_MWR(CAP_SENSOR_CTRL,0xf0,level!=0?0:0xf0);
+ mdelay(1);
+#endif
+
+ return SENSOR_K_SUCCESS;
+}
+
+int sensor_k_sensor_sel(uint32_t *fd_handle, uint32_t sensor_id)
+{
+ struct sensor_file_tag *fd = (struct sensor_file_tag *)fd_handle;
+ SENSOR_CHECK_ZERO(fd);
+ fd->sensor_id = sensor_id;
+
+ return SENSOR_K_SUCCESS;
+}
+
+int sensor_k_sensor_desel(struct sensor_file_tag *fd_handle, uint32_t sensor_id)
+{
+ SENSOR_CHECK_ZERO(fd_handle);
+ //fd_handle->sensor_id = SENSOR_ID_MAX;
+
+ SENSOR_PRINT_HIGH("sensor desel %d OK.\n", sensor_id);
+
+ return SENSOR_K_SUCCESS;
+}
+
+int sensor_k_set_rst_level(uint32_t *fd_handle, uint32_t plus_level)
+{
+ struct sensor_module_tab_tag *p_mod;
+ struct sensor_file_tag *fd = (struct sensor_file_tag *)fd_handle;
+
+ SENSOR_CHECK_ZERO(fd);
+ p_mod = fd->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ get_gpio_id(p_mod->of_node, &fd->gpio_tab.pwn, &fd->gpio_tab.reset, fd->sensor_id);
+ SENSOR_PRINT("SENSOR: set rst lvl: lvl %d, rst pin %d \n", plus_level, fd->gpio_tab.reset);
+
+#ifndef CONFIG_SC_FPGA_PIN
+ gpio_direction_output(fd->gpio_tab.reset, plus_level);
+ gpio_set_value(fd->gpio_tab.reset, plus_level);
+#else
+ SENSOR_PRINT_HIGH("CAP_SENSOR_CTRL 0x%lx\n", CAP_SENSOR_CTRL);
+ REG_MWR(CAP_SENSOR_CTRL,0xf0,plus_level!=0?0xf0:0x0);
+ SENSOR_PRINT_HIGH("CAP_SENSOR_CTRL val=0x%x\n", REG_RD(CAP_SENSOR_CTRL));
+#endif
+ return SENSOR_K_SUCCESS;
+}
+
+LOCAL int _Sensor_K_ReadReg(struct sensor_file_tag *fd_handle, struct sensor_reg_bits_tag *pReg)
+{
+ uint8_t cmd[2] = { 0 };
+ uint16_t w_cmd_num = 0;
+ uint16_t r_cmd_num = 0;
+ uint8_t buf_r[2] = { 0 };
+ int32_t ret = SENSOR_K_SUCCESS;
+ struct i2c_msg msg_r[2];
+ uint16_t reg_addr;
+ int i;
+ struct sensor_module_tab_tag *p_mod;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ reg_addr = pReg->reg_addr;
+
+ if (SENSOR_I2C_REG_16BIT ==(pReg->reg_bits & SENSOR_I2C_REG_16BIT)) {
+ cmd[w_cmd_num++] = (uint8_t) ((reg_addr >> 8) & SENSOR_LOW_EIGHT_BIT);
+ cmd[w_cmd_num++] = (uint8_t) (reg_addr & SENSOR_LOW_EIGHT_BIT);
+ } else {
+ cmd[w_cmd_num++] = (uint8_t) reg_addr;
+ }
+
+ if (SENSOR_I2C_VAL_16BIT == (pReg->reg_bits & SENSOR_I2C_VAL_16BIT)) {
+ r_cmd_num = SENSOR_CMD_BITS_16;
+ } else {
+ r_cmd_num = SENSOR_CMD_BITS_8;
+ }
+
+ for (i = 0; i < SENSOR_I2C_OP_TRY_NUM; i++) {
+ msg_r[0].addr = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->addr;
+ msg_r[0].flags = 0;
+ msg_r[0].buf = cmd;
+ msg_r[0].len = w_cmd_num;
+ msg_r[1].addr = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->addr;
+ msg_r[1].flags = I2C_M_RD;
+ msg_r[1].buf = buf_r;
+ msg_r[1].len = r_cmd_num;
+ ret = i2c_transfer(p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->adapter, msg_r, 2);
+ if (ret != 2) {
+ SENSOR_PRINT_ERR("SENSOR:read reg fail, ret %d, addr 0x%x, reg_addr 0x%x \n",
+ ret, p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->addr,reg_addr);
+ SLEEP_MS(1);
+ ret = SENSOR_K_FAIL;
+ } else {
+ pReg->reg_value = (r_cmd_num == 1) ? (uint16_t) buf_r[0] : (uint16_t) ((buf_r[0] << 8) + buf_r[1]);
+ ret = SENSOR_K_SUCCESS;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+LOCAL int _Sensor_K_WriteReg(struct sensor_file_tag *fd_handle, struct sensor_reg_bits_tag *pReg)
+{
+ uint8_t cmd[4] = { 0 };
+ uint32_t index = 0;
+ uint32_t cmd_num = 0;
+ struct i2c_msg msg_w;
+ int32_t ret = SENSOR_K_SUCCESS;
+ uint16_t subaddr;
+ uint16_t data;
+ int i;
+ struct sensor_module_tab_tag *p_mod;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ subaddr = pReg->reg_addr;
+ data = pReg->reg_value;
+
+ if (SENSOR_I2C_REG_16BIT ==(pReg->reg_bits & SENSOR_I2C_REG_16BIT)) {
+ cmd[cmd_num++] = (uint8_t) ((subaddr >> 8) & SENSOR_LOW_EIGHT_BIT);
+ index++;
+ cmd[cmd_num++] = (uint8_t) (subaddr & SENSOR_LOW_EIGHT_BIT);
+ index++;
+ } else {
+ cmd[cmd_num++] = (uint8_t) subaddr;
+ index++;
+ }
+
+ if (SENSOR_I2C_VAL_16BIT == (pReg->reg_bits & SENSOR_I2C_VAL_16BIT)) {
+ cmd[cmd_num++] = (uint8_t) ((data >> 8) & SENSOR_LOW_EIGHT_BIT);
+ index++;
+ cmd[cmd_num++] = (uint8_t) (data & SENSOR_LOW_EIGHT_BIT);
+ index++;
+ } else {
+ cmd[cmd_num++] = (uint8_t) data;
+ index++;
+ }
+
+ if (SENSOR_WRITE_DELAY != subaddr) {
+ for (i = 0; i < SENSOR_I2C_OP_TRY_NUM; i++) {
+ msg_w.addr = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = cmd;
+ msg_w.len = index;
+ ret = i2c_transfer(p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ SENSOR_PRINT_ERR("_Sensor_K_WriteReg failed:i2cAddr=%x, addr=%x, value=%x, bit=%d \n",
+ p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->addr, pReg->reg_addr, pReg->reg_value, pReg->reg_bits);
+ ret = SENSOR_K_FAIL;
+ continue;
+ } else {
+ ret = SENSOR_K_SUCCESS;
+ break;
+ }
+ }
+ } else {
+ SLEEP_MS(data);
+ }
+
+ return ret;
+}
+
+LOCAL int _sensor_k_get_flash_level(struct sensor_file_tag *fd_handle, struct sensor_flash_level *level)
+{
+ level->low_light = SPRD_FLASH_LOW_CUR;
+ level->high_light = SPRD_FLASH_HIGH_CUR;
+
+ SENSOR_PRINT("Sensor get flash lvl: low %d, high %d \n", level->low_light, level->high_light);
+
+ return SENSOR_K_SUCCESS;
+}
+
+int _sensor_burst_write_init(struct sensor_file_tag *fd_handle, struct sensor_reg_tag *p_reg_table, uint32_t init_table_size);
+
+LOCAL int _sensor_k_wr_regtab(struct sensor_file_tag *fd_handle, struct sensor_reg_tab_tag *pRegTab)
+{
+ char *pBuff = PNULL;
+ uint32_t cnt = pRegTab->reg_count;
+ int ret = SENSOR_K_SUCCESS;
+ uint32_t size;
+ struct sensor_reg_tag *sensor_reg_ptr;
+ struct sensor_reg_bits_tag reg_bit;
+ uint32_t i;
+ int rettmp;
+ struct timeval time1, time2;
+
+ do_gettimeofday(&time1);
+
+ size = cnt*sizeof(struct sensor_reg_tag);
+ pBuff = _sensor_k_malloc(fd_handle, size);
+ if (PNULL == pBuff) {
+ ret = SENSOR_K_FAIL;
+ SENSOR_PRINT_ERR("sensor W RegTab err:alloc fail, cnt %d, size %d\n", cnt, size);
+ goto _Sensor_K_WriteRegTab_return;
+ } else {
+ SENSOR_PRINT("sensor W RegTab: alloc success, cnt %d, size %d \n",cnt, size);
+ }
+
+ if (copy_from_user(pBuff, pRegTab->sensor_reg_tab_ptr, size)) {
+ ret = SENSOR_K_FAIL;
+ SENSOR_PRINT_ERR("sensor w err:copy user fail, size %d \n", size);
+ goto _Sensor_K_WriteRegTab_return;
+ }
+
+ sensor_reg_ptr = (struct sensor_reg_tag *)pBuff;
+
+ if (0 == pRegTab->burst_mode) {
+ for (i=0; i<cnt; i++) {
+ reg_bit.reg_addr = sensor_reg_ptr[i].reg_addr;
+ reg_bit.reg_value = sensor_reg_ptr[i].reg_value;
+ reg_bit.reg_bits = pRegTab->reg_bits;
+
+ rettmp = _Sensor_K_WriteReg(fd_handle, &reg_bit);
+ if(SENSOR_K_FAIL == rettmp)
+ ret = SENSOR_K_FAIL;
+ }
+ } else if (SENSOR_I2C_BUST_NB == pRegTab->burst_mode) {
+ printk("CAM %s, Line %d, burst_mode=%d, cnt=%d, start \n", __FUNCTION__, __LINE__, pRegTab->burst_mode, cnt);
+ ret = _sensor_burst_write_init(fd_handle, sensor_reg_ptr, pRegTab->reg_count);
+ printk("CAM %s, Line %d, burst_mode=%d, cnt=%d end\n", __FUNCTION__, __LINE__, pRegTab->burst_mode, cnt);
+ }
+
+
+_Sensor_K_WriteRegTab_return:
+ if (PNULL != pBuff)
+ _sensor_k_free(fd_handle, pBuff);
+
+ do_gettimeofday(&time2);
+ SENSOR_PRINT("sensor w RegTab: done, ret %d, cnt %d, time %d us \n", ret, cnt,
+ (uint32_t)((time2.tv_sec - time1.tv_sec)*1000000+(time2.tv_usec - time1.tv_usec)));
+ return ret;
+}
+
+LOCAL int _sensor_k_set_i2c_clk(struct sensor_file_tag *fd_handle, uint32_t clock)
+{
+ struct sensor_module_tab_tag *p_mod;
+ struct i2c_client *i2c_client;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ if (NULL != p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client) {
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client;
+ sprd_i2c_ctl_chg_clk(i2c_client->adapter->nr, clock);
+ SENSOR_PRINT("sensor set i2c id %d clk %d \n", i2c_client->adapter->nr, clock);
+ }
+ if (NULL != p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_i2c_client
+ && 0 == p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_gpio_i2c_flag) {
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_i2c_client;
+ sprd_i2c_ctl_chg_clk(i2c_client->adapter->nr, clock);
+ SENSOR_PRINT("sensor set i2c id %d clk %d \n", i2c_client->adapter->nr, clock);
+ }
+ SENSOR_PRINT("sensor set i2c clk %d \n", clock);
+
+ return SENSOR_K_SUCCESS;
+}
+
+LOCAL int _sensor_k_wr_i2c(struct sensor_file_tag *fd_handle, struct sensor_i2c_tag *pI2cTab)
+{
+ char *pBuff = PNULL;
+ struct i2c_msg msg_w;
+ uint32_t cnt = pI2cTab->i2c_count;
+ int ret = SENSOR_K_FAIL;
+ struct sensor_module_tab_tag *p_mod;
+ struct i2c_client *i2c_client;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ pBuff = _sensor_k_malloc(fd_handle, cnt);
+ if (PNULL == pBuff) {
+ SENSOR_PRINT_ERR("sensor W I2C ERR: alloc fail, size %d\n", cnt);
+ goto sensor_k_writei2c_return;
+ } else {
+ SENSOR_PRINT("sensor W I2C: alloc success, size %d\n", cnt);
+ }
+
+ if (copy_from_user(pBuff, pI2cTab->i2c_data, cnt)) {
+ SENSOR_PRINT_ERR("sensor W I2C ERR: copy user fail, size %d \n", cnt);
+ goto sensor_k_writei2c_return;
+ }
+
+ msg_w.addr = pI2cTab->slave_addr;
+ msg_w.flags = 0;
+ msg_w.buf = pBuff;
+ msg_w.len = cnt;
+#if 1
+ if (NULL == p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_i2c_client) {
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client;
+ } else {
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_i2c_client;
+ }
+#else
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client;
+#endif
+ ret = i2c_transfer(i2c_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ SENSOR_PRINT_ERR("SENSOR: w reg fail, ret: %d, addr: 0x%x\n",
+ ret, msg_w.addr);
+ } else {
+ ret = SENSOR_K_SUCCESS;
+ }
+
+sensor_k_writei2c_return:
+ if(PNULL != pBuff)
+ _sensor_k_free(fd_handle, pBuff);
+
+ SENSOR_PRINT("sensor w done, ret %d \n", ret);
+ return ret;
+}
+
+LOCAL int _sensor_k_rd_i2c(struct sensor_file_tag *fd_handle, struct sensor_i2c_tag *pI2cTab)
+{
+ struct i2c_msg msg_r[2];
+ int i;
+ char *pBuff = PNULL;
+ uint32_t cnt = pI2cTab->i2c_count;
+ int ret = SENSOR_K_FAIL;
+ uint16_t read_num = cnt;
+ struct sensor_module_tab_tag *p_mod;
+ struct i2c_client *i2c_client;
+ SENSOR_CHECK_ZERO(fd_handle);
+
+ p_mod = fd_handle->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ /*alloc buffer */
+ pBuff = _sensor_k_malloc(fd_handle, cnt);
+ if (PNULL == pBuff) {
+ ret = SENSOR_K_FAIL;
+ SENSOR_PRINT_ERR("sensor rd I2C ERR: alloc fail, size %d\n", cnt);
+ goto sensor_k_readi2c_return;
+ } else {
+ SENSOR_PRINT("sensor rd I2C: alloc success, size %d\n", cnt);
+ }
+
+ if (copy_from_user(pBuff, pI2cTab->i2c_data, cnt)) {
+ ret = SENSOR_K_FAIL;
+ SENSOR_PRINT_ERR("sensor W I2C ERR: copy user fail, size %d \n", cnt);
+ goto sensor_k_readi2c_return;
+ }
+
+
+ for (i = 0; i < SENSOR_I2C_OP_TRY_NUM; i++) {
+ msg_r[0].addr = pI2cTab->slave_addr;
+ msg_r[0].flags = 0;
+ msg_r[0].buf = pBuff;
+ msg_r[0].len = cnt;
+ msg_r[1].addr = pI2cTab->slave_addr;
+ msg_r[1].flags = I2C_M_RD;
+ msg_r[1].buf = pBuff;
+ msg_r[1].len = read_num;
+#if 1
+ if (NULL == p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_i2c_client) {
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client;
+ } else {
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].vcm_i2c_client;
+ }
+#else
+ i2c_client = p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client;
+#endif
+ ret = i2c_transfer(i2c_client->adapter, msg_r, 2);
+ if (ret != 2) {
+ SENSOR_PRINT_ERR("SENSOR:read reg fail, ret %d, addr 0x%x \n",
+ ret, p_mod->sensor_dev_tab[fd_handle->sensor_id].cur_i2c_client->addr);
+ SLEEP_MS(20);
+ ret = SENSOR_K_FAIL;
+ } else {
+ ret = SENSOR_K_SUCCESS;
+ if (copy_to_user(pI2cTab->i2c_data, pBuff, read_num)) {
+ ret = SENSOR_K_FAIL;
+ SENSOR_PRINT_ERR("sensor W I2C ERR: copy user fail, size %d \n", cnt);
+ goto sensor_k_readi2c_return;
+ }
+ break;
+ }
+ }
+
+sensor_k_readi2c_return:
+ if(PNULL != pBuff)
+ _sensor_k_free(fd_handle, pBuff);
+
+ SENSOR_PRINT("_Sensor_K_ReadI2C, ret %d \n", ret);
+ return ret;
+}
+
+LOCAL int _sensor_csi2_error(uint32_t err_id, uint32_t err_status, void* u_data)
+{
+ int ret = 0;
+
+ printk("V4L2: csi2_error, %d 0x%x \n", err_id, err_status);
+
+ return ret;
+
+}
+
+int sensor_k_open(struct inode *node, struct file *file)
+{
+ int ret = 0;
+ struct sensor_file_tag *p_file;
+ struct sensor_module_tab_tag *p_mod = NULL;// platform_get_drvdata(_sensor_k_get_platform_device());
+ struct miscdevice *md = (struct miscdevice *)file->private_data ;
+
+ if (!md) {
+ ret = -EFAULT;
+ printk("rot_k_open fail miscdevice NULL \n");
+ return -1;
+ }
+ p_mod = (struct sensor_module_tab_tag*)md->this_device->platform_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ p_file = (struct sensor_file_tag *)vzalloc(sizeof(struct sensor_file_tag));
+ SENSOR_CHECK_ZERO(p_file);
+ file->private_data = p_file;
+ p_file->module_data = p_mod;
+ ret = csi_api_malloc(&p_file->csi_handle);
+ if (ret) {
+ vfree(p_file);
+ p_file = NULL;
+ return -1;
+ }
+
+ if (atomic_inc_return(&p_mod->total_users) == 1) {
+ struct device_node *dn = p_mod->of_node;
+ ret = clk_mm_i_eb(dn,1);
+ wake_lock(&p_mod->wakelock);
+ }
+ printk("sensor open %d\n", ret);
+ return ret;
+}
+
+int _sensor_k_close_mipi(struct file *file)
+{
+ int ret = 0;
+ struct sensor_file_tag *p_file = file->private_data;
+ struct csi_context *handle = NULL;
+ SENSOR_CHECK_ZERO(p_file);
+ handle = p_file->csi_handle;
+ if (NULL == handle) {
+ printk("handle null\n");
+ return -1;
+ }
+ if (INTERFACE_MIPI == p_file->if_type) {
+ if (1 == p_file->mipi_on) {
+ csi_api_close(handle, p_file->phy_id);
+ _sensor_k_mipi_clk_dis(p_file);
+ p_file->mipi_on = 0;
+ printk("MIPI off \n");
+ } else {
+ printk("MIPI already off \n");
+ }
+
+ }
+ return ret;
+}
+
+int sensor_k_release(struct inode *node, struct file *file)
+{
+ int ret = 0;
+ struct sensor_file_tag *p_file = file->private_data;
+ struct sensor_module_tab_tag *p_mod;
+
+ SENSOR_CHECK_ZERO(p_file);
+ p_mod = p_file->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ printk("sensor: release \n");
+ if (atomic_dec_return(&p_mod->total_users) == 0) {
+ struct device_node *dn = p_mod->of_node;
+ sensor_k_set_voltage_cammot((uint32_t *)p_file, SENSOR_VDD_CLOSED);
+ sensor_k_set_voltage_avdd((uint32_t *)p_file, SENSOR_VDD_CLOSED);
+ sensor_k_set_voltage_dvdd((uint32_t *)p_file, SENSOR_VDD_CLOSED);
+ sensor_k_set_voltage_iovdd((uint32_t *)p_file, SENSOR_VDD_CLOSED);
+ _sensor_k_set_mclk(p_file, dn, 0);
+ _sensor_k_close_mipi(file);
+ ret = clk_mm_i_eb(dn,0);
+
+ wake_unlock(&p_mod->wakelock);
+ }
+ if (SENSOR_ADDR_INVALID(p_file)) {
+ printk("SENSOR: Invalid addr, %p", p_mod);
+ } else {
+ csi_api_free(p_file->csi_handle);
+ vfree(p_file);
+ p_file = NULL;
+ file->private_data = NULL;
+ }
+ printk("sensor: release %d \n", ret);
+ return ret;
+}
+
+LOCAL ssize_t sensor_k_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos)
+{
+ return 0;
+}
+
+LOCAL ssize_t sensor_k_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos)
+{
+ char buf[64];
+ char *pBuff = PNULL;
+ struct i2c_msg msg_w;
+ int ret = SENSOR_K_FAIL;
+ int need_alloc = 1;
+ struct i2c_client *i2c_client = PNULL;
+ struct sensor_file_tag *p_file = filp->private_data;
+ struct sensor_module_tab_tag *p_mod;
+ SENSOR_CHECK_ZERO(p_file);
+
+ p_mod = p_file->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ i2c_client = p_mod->sensor_dev_tab[p_file->sensor_id].cur_i2c_client;
+
+ SENSOR_PRINT("sensor w cnt %ld, buf %ld\n", cnt, sizeof(buf));
+
+ if (cnt < sizeof(buf)) {
+ pBuff = buf;
+ need_alloc = 0;
+ } else {
+ pBuff = _sensor_k_malloc(p_file, cnt);
+ if (PNULL == pBuff) {
+ SENSOR_PRINT_ERR("sensor w ERR: alloc fail, size %ld \n", cnt);
+ goto sensor_k_write_return;
+ } else {
+ SENSOR_PRINT("sensor w: alloc success, size %ld \n", cnt);
+ }
+ }
+
+ if (copy_from_user(pBuff, ubuf, cnt)) {
+ SENSOR_PRINT_ERR("sensor w ERR: copy user fail, size %ld\n", cnt);
+ goto sensor_k_write_return;
+ }
+ printk("sensor clnt addr 0x%x.\n", i2c_client->addr);
+ msg_w.addr = i2c_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = pBuff;
+ msg_w.len = cnt;
+
+ ret = i2c_transfer(i2c_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ SENSOR_PRINT_ERR("SENSOR: w reg fail, ret %d, w addr: 0x%x,\n",
+ ret, i2c_client->addr);
+ } else {
+ ret = SENSOR_K_SUCCESS;
+ }
+
+sensor_k_write_return:
+ if ((PNULL != pBuff) && need_alloc)
+ _sensor_k_free(p_file, pBuff);
+
+ SENSOR_PRINT("sensor w done, ret %d \n", ret);
+ return ret;
+}
+
+int _sensor_burst_write_init(struct sensor_file_tag *fd_handle, struct sensor_reg_tag *p_reg_table, uint32_t init_table_size)
+{
+ uint32_t rtn = 0;
+ int ret = 0;
+ uint32_t i = 0;
+ uint32_t written_num = 0;
+ uint16_t wr_reg = 0;
+ uint16_t wr_val = 0;
+ uint32_t wr_num_once = 0;
+ uint8_t *p_reg_val_tmp = 0;
+ struct i2c_msg msg_w;
+ struct i2c_client *i2c_client = PNULL;
+ struct sensor_file_tag *p_file = fd_handle;
+ struct sensor_module_tab_tag *p_mod;
+ SENSOR_CHECK_ZERO(p_file);
+
+ p_mod = p_file->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ i2c_client = p_mod->sensor_dev_tab[p_file->sensor_id].cur_i2c_client;
+
+ printk("SENSOR: burst w Init\n");
+ if (0 == i2c_client) {
+ SENSOR_PRINT_ERR("SENSOR: burst w Init err, i2c_clnt NULL!.\n");
+ return -1;
+ }
+ p_reg_val_tmp = (uint8_t*)_sensor_k_malloc(fd_handle, init_table_size*sizeof(uint16_t) + 16);
+
+ if(PNULL == p_reg_val_tmp){
+ SENSOR_PRINT_ERR("_sensor_burst_write_init ERROR: alloc is fail, size = %ld \n", init_table_size*sizeof(uint16_t) + 16);
+ return -1;
+ }
+ else{
+ SENSOR_PRINT_HIGH("_sensor_burst_write_init: alloc success, size = %ld \n", init_table_size*sizeof(uint16_t) + 16);
+ }
+
+
+ while (written_num < init_table_size) {
+ wr_num_once = 2;
+
+ wr_reg = p_reg_table[written_num].reg_addr;
+ wr_val = p_reg_table[written_num].reg_value;
+ if (SENSOR_WRITE_DELAY == wr_reg) {
+ if (wr_val >= 10) {
+ msleep(wr_val);
+ } else {
+ mdelay(wr_val);
+ }
+ } else {
+ p_reg_val_tmp[0] = (uint8_t)(wr_reg);
+ p_reg_val_tmp[1] = (uint8_t)(wr_val);
+
+ if ((0x0e == wr_reg) && (0x01 == wr_val)) {
+ for (i = written_num + 1; i < init_table_size; i++) {
+ if ((0x0e == wr_reg) && (0x00 == wr_val)) {
+ break;
+ } else {
+ wr_val = p_reg_table[i].reg_value;
+ p_reg_val_tmp[wr_num_once+1] = (uint8_t)(wr_val);
+ wr_num_once ++;
+ }
+ }
+ }
+ msg_w.addr = i2c_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = p_reg_val_tmp;
+ msg_w.len = (uint32_t)(wr_num_once);
+ ret = i2c_transfer(i2c_client->adapter, &msg_w, 1);
+ if (ret!=1) {
+ SENSOR_PRINT("SENSOR: s err, val {0x%x 0x%x} {0x%x 0x%x} {0x%x 0x%x} {0x%x 0x%x} {0x%x 0x%x} {0x%x 0x%x}.\n",
+ p_reg_val_tmp[0],p_reg_val_tmp[1],p_reg_val_tmp[2],p_reg_val_tmp[3],
+ p_reg_val_tmp[4],p_reg_val_tmp[5],p_reg_val_tmp[6],p_reg_val_tmp[7],
+ p_reg_val_tmp[8],p_reg_val_tmp[9],p_reg_val_tmp[10],p_reg_val_tmp[11]);
+ SENSOR_PRINT("SENSOR: i2c w once err\n");
+ rtn = 1;
+ break;
+ }
+ }
+ written_num += wr_num_once - 1;
+ }
+ SENSOR_PRINT("SENSOR: burst w Init OK\n");
+ _sensor_k_free(fd_handle, p_reg_val_tmp);
+ return rtn;
+}
+
+LOCAL long sensor_k_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+ struct sensor_module_tab_tag *p_mod;
+ struct sensor_file_tag *p_file = file->private_data;
+
+ SENSOR_CHECK_ZERO(p_file);
+ p_mod = p_file->module_data;
+ SENSOR_CHECK_ZERO(p_mod);
+
+ SENSOR_PRINT("SENSOR: ioctl cmd %d id %d \n", cmd, p_file->sensor_id);
+
+ if (SENSOR_IO_SET_ID == cmd)
+ {
+ mutex_lock(&p_mod->sensor_id_lock);
+ ret = copy_from_user(&p_file->sensor_id, (uint32_t *) arg, sizeof(uint32_t));
+ mutex_unlock(&p_mod->sensor_id_lock);
+ }
+
+ mutex_lock(&p_mod->sensor_dev_tab[p_file->sensor_id].sync_lock);
+ switch (cmd) {
+ case SENSOR_IO_PD:
+ {
+ uint8_t power_level;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_PD \n");
+ ret = copy_from_user(&power_level, (uint8_t *) arg, sizeof(uint8_t));
+
+ if (0 == ret)
+ ret = sensor_k_set_pd_level((uint32_t *)p_file, power_level);
+ }
+ break;
+
+ case SENSOR_IO_SET_CAMMOT:
+ {
+ uint32_t vdd_val;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_CAMMOT \n");
+ ret = copy_from_user(&vdd_val, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_set_voltage_cammot((uint32_t *)p_file, vdd_val);
+ }
+ break;
+
+ case SENSOR_IO_SET_AVDD:
+ {
+ uint32_t vdd_val;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_AVDD \n");
+ ret = copy_from_user(&vdd_val, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_set_voltage_avdd((uint32_t *)p_file, vdd_val);
+ }
+ break;
+
+ case SENSOR_IO_SET_DVDD:
+ {
+ uint32_t vdd_val;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_DVDD \n");
+ ret = copy_from_user(&vdd_val, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_set_voltage_dvdd((uint32_t *)p_file, vdd_val);
+ }
+ break;
+
+ case SENSOR_IO_SET_IOVDD:
+ {
+ uint32_t vdd_val;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_IOVDD \n");
+ ret = copy_from_user(&vdd_val, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_set_voltage_iovdd((uint32_t *)p_file, vdd_val);
+ }
+ break;
+
+ case SENSOR_IO_SET_MCLK:
+ {
+ uint32_t mclk;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_MCLK \n");
+ ret = copy_from_user(&mclk, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = _sensor_k_set_mclk(p_file, p_mod->of_node, mclk);
+ }
+ break;
+
+ case SENSOR_IO_RST:
+ {
+ uint32_t rst_val[2];
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_RST \n");
+ ret = copy_from_user(rst_val, (uint32_t *) arg, 2*sizeof(uint32_t));
+ if (0 == ret)
+ ret = _sensor_k_reset(p_file, rst_val[0], rst_val[1]);
+ }
+ break;
+
+ case SENSOR_IO_I2C_INIT:
+ {
+ uint32_t sensor_id;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_INIT \n");
+ ret = copy_from_user(&sensor_id, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_sensor_sel((uint32_t *)p_file, sensor_id);
+ }
+ break;
+
+ case SENSOR_IO_I2C_DEINIT:
+ {
+ uint32_t sensor_id;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_DEINIT \n");
+ ret = copy_from_user(&sensor_id, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_sensor_desel(p_file, sensor_id);
+ }
+ break;
+
+ case SENSOR_IO_SET_ID:
+ {
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_ID \n");
+ ret = copy_from_user(&p_file->sensor_id, (uint32_t *) arg, sizeof(uint32_t));
+ get_gpio_id(p_mod->of_node, &p_file->gpio_tab.pwn, &p_file->gpio_tab.reset, p_file->sensor_id);
+ }
+ break;
+
+ case SENSOR_IO_RST_LEVEL:
+ {
+ uint32_t level;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_RST_LEVEL \n");
+ ret = copy_from_user(&level, (uint32_t *) arg, sizeof(uint32_t));
+ if (0 == ret)
+ ret = sensor_k_set_rst_level((uint32_t *)p_file, level);
+ }
+ break;
+
+ case SENSOR_IO_I2C_ADDR:
+ {
+ uint16_t i2c_addr;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_ADDR \n");
+ ret = copy_from_user(&i2c_addr, (uint16_t *) arg, sizeof(uint16_t));
+ if (0 == ret) {
+ p_mod->sensor_dev_tab[p_file->sensor_id].cur_i2c_client->addr = (p_mod->sensor_dev_tab[p_file->sensor_id].cur_i2c_client->addr & (~0xFF)) |i2c_addr;
+ printk("SENSOR_IO_I2C_ADDR: addr = %x, %x \n", i2c_addr, p_mod->sensor_dev_tab[p_file->sensor_id].cur_i2c_client->addr);
+ }
+ }
+ break;
+
+ case SENSOR_IO_I2C_READ:
+ {
+ struct sensor_reg_bits_tag reg;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_READ \n");
+ ret = copy_from_user(&reg, (struct sensor_reg_bits_tag *) arg, sizeof(struct sensor_reg_bits_tag));
+
+ if (0 == ret) {
+ ret = _Sensor_K_ReadReg(p_file, &reg);
+ if(SENSOR_K_FAIL != ret){
+ ret = copy_to_user((struct sensor_reg_bits_tag *)arg, &reg, sizeof(struct sensor_reg_bits_tag));
+ }
+ }
+ }
+ break;
+
+ case SENSOR_IO_I2C_WRITE:
+ {
+ struct sensor_reg_bits_tag reg;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_WRITE \n");
+ ret = copy_from_user(&reg, (struct sensor_reg_bits_tag *) arg, sizeof(struct sensor_reg_bits_tag));
+
+ if (0 == ret) {
+ ret = _Sensor_K_WriteReg(p_file, &reg);
+ }
+
+ }
+ break;
+
+ case SENSOR_IO_I2C_WRITE_REGS:
+ {
+ struct sensor_reg_tab_tag regTab;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_WRITE_REGS \n");
+ ret = copy_from_user(&regTab, (struct sensor_reg_tab_tag *) arg, sizeof(struct sensor_reg_tab_tag));
+ if (0 == ret)
+ ret = _sensor_k_wr_regtab(p_file, &regTab);
+ }
+ break;
+
+ case SENSOR_IO_SET_I2CCLOCK:
+ {
+ uint32_t clock;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_SET_I2CCLOCK \n");
+ ret = copy_from_user(&clock, (uint32_t *) arg, sizeof(uint32_t));
+ if(0 == ret){
+ _sensor_k_set_i2c_clk(p_file, clock);
+ }
+ }
+ break;
+
+ case SENSOR_IO_I2C_WRITE_EXT:
+ {
+ struct sensor_i2c_tag i2cTab;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_WRITE_EXT \n");
+ ret = copy_from_user(&i2cTab, (struct sensor_i2c_tag*)arg, sizeof(struct sensor_i2c_tag));
+ if (0 == ret)
+ ret = _sensor_k_wr_i2c(p_file, &i2cTab);
+ }
+ break;
+
+ case SENSOR_IO_I2C_READ_EXT:
+ {
+ struct sensor_i2c_tag i2cTab;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_I2C_READ_EXT \n");
+ ret = copy_from_user(&i2cTab, (struct sensor_i2c_tag*) arg, sizeof(struct sensor_i2c_tag));
+ if (0 == ret)
+ ret = _sensor_k_rd_i2c(p_file, &i2cTab);
+ }
+ break;
+
+ case SENSOR_IO_GET_FLASH_LEVEL:
+ {
+ struct sensor_flash_level flash_level;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_GET_FLASH_LEVEL \n");
+ ret = copy_from_user(&flash_level, (struct sensor_flash_level *) arg, sizeof(struct sensor_flash_level));
+ if (0 == ret) {
+ ret = _sensor_k_get_flash_level(p_file, &flash_level);
+ if(SENSOR_K_FAIL != ret){
+ ret = copy_to_user((struct sensor_flash_level *)arg, &flash_level, sizeof(struct sensor_flash_level));
+ }
+ }
+ }
+ break;
+ case SENSOR_IO_GET_SOCID:
+ {
+ //struct sensor_socid_tag Id ;
+ uint32_t id;
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_GET_SOCID \n");
+ //Id.d_die=sci_get_chip_id();
+ //Id.a_die=sci_get_ana_chip_id()|sci_get_ana_chip_ver();
+ gpio_direction_input(238);
+ id = gpio_get_value(238);
+ //SENSOR_PRINT("cpu id 0x%x,0x%x \n", Id.d_die,Id.a_die);
+ ret = copy_to_user((uint32_t *)arg, &id, sizeof(uint32_t));
+ }
+ break;
+ case SENSOR_IO_SET_SOCNAME:
+ {
+ ret = copy_from_user(&socname,(struct sensor_name *)arg,sizeof(struct sensor_name));
+ }
+ break;
+ case SENSOR_IO_IF_CFG:
+ {
+ struct sensor_if_cfg_tag if_cfg;
+ struct csi_context *csi_handle;
+ csi_handle = p_file->csi_handle;
+ if (NULL == csi_handle) {
+ printk("handle null\n");
+ return -1;
+ }
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_IF_CFG \n");
+ ret = copy_from_user((void*)&if_cfg, (struct sensor_if_cfg_tag *)arg, sizeof(struct sensor_if_cfg_tag));
+ if (0 == ret) {
+ if (INTERFACE_OPEN == if_cfg.is_open) {
+ if (INTERFACE_MIPI == if_cfg.if_type) {
+ if (0 == p_file->mipi_on) {
+ _sensor_k_mipi_clk_en(p_file, p_mod->of_node);
+ udelay(1);
+ ret = csi_api_init(if_cfg.bps_per_lane, if_cfg.phy_id);
+ SENSOR_PRINT("csi_api_init: %d \n", ret);
+ ret = csi_api_start(csi_handle);
+ SENSOR_PRINT("csi_api_start: %d \n", ret);
+ ret = csi_reg_isr(csi_handle, _sensor_csi2_error, (void*)p_file);
+ SENSOR_PRINT("csi_reg_isr: %d \n", ret);
+ ret = csi_set_on_lanes(if_cfg.lane_num);
+ SENSOR_PRINT("csi_set_on_lanes: %d \n", ret);
+ p_file->mipi_on = 1;
+ p_file->phy_id = if_cfg.phy_id;
+ p_file->if_type = INTERFACE_MIPI;
+ printk("MIPI on, lane %d, bps_per_lane %d, wait 10us \n", if_cfg.lane_num, if_cfg.bps_per_lane);
+ } else {
+ printk("MIPI already on \n");
+ }
+ }
+ } else {
+ if (INTERFACE_MIPI == if_cfg.if_type) {
+ if (1 == p_file->mipi_on) {
+ csi_api_close(csi_handle, if_cfg.phy_id);
+ _sensor_k_mipi_clk_dis(p_file);
+ p_file->mipi_on = 0;
+ printk("MIPI off \n");
+ } else {
+ printk("MIPI already off \n");
+ }
+
+ }
+
+ }
+ }
+ }
+ break;
+
+ case SENSOR_IO_POWER_CFG:
+ {
+ struct sensor_power_info_tag pwr_cfg;
+
+ SENSOR_PRINT("SENSOR: ioctl SENSOR_IO_POWER_CFG \n");
+ ret = copy_from_user(&pwr_cfg, (struct sensor_power_info_tag*) arg, sizeof(struct sensor_power_info_tag));
+ if (0 == ret) {
+ if (pwr_cfg.is_on) {
+ ret = sensor_power_on((uint32_t *)p_file, pwr_cfg.op_sensor_id, &pwr_cfg.dev0, &pwr_cfg.dev1, &pwr_cfg.dev2);
+ } else {
+ ret = sensor_power_off((uint32_t *)p_file, pwr_cfg.op_sensor_id, &pwr_cfg.dev0, &pwr_cfg.dev1, &pwr_cfg.dev2);
+ }
+ }
+ }
+ break;
+
+ case SENSOR_IO_READ_OTPDATA:
+ {
+ SENSOR_OTP_PARAM_T *para = (SENSOR_OTP_PARAM_T *)arg;
+ uint32_t type;
+ copy_from_user(&type, &para->type, sizeof(uint32_t));
+ printk("SENSOR: ioctl SENSOR_IO_READ_OTPDATA %p type %d\n", arg, para->type);
+
+ if(type == SENSOR_OTP_PARAM_CHECKSUM) {
+ SENSOR_OTP_DATA_INFO_T *chksum = &p_mod->otp_param[p_file->sensor_id].golden;
+ if(chksum->data_ptr && chksum->size > 0) {
+ copy_to_user(para->buff, chksum->data_ptr, chksum->size);
+ copy_to_user(&para->len, &chksum->size, sizeof(uint32_t));
+ }
+ } else if(type == SENSOR_OTP_PARAM_NORMAL) {
+
+ SENSOR_OTP_DATA_INFO_T *awb = &p_mod->otp_param[p_file->sensor_id].awb;
+ SENSOR_OTP_DATA_INFO_T *lsc = &p_mod->otp_param[p_file->sensor_id].lsc;
+
+ if(p_mod->otp_param[p_file->sensor_id].buff && p_mod->otp_param[p_file->sensor_id].len > 0) {
+ copy_to_user(para->buff, p_mod->otp_param[p_file->sensor_id].buff,
+ p_mod->otp_param[p_file->sensor_id].len);
+ copy_to_user(&para->len, &p_mod->otp_param[p_file->sensor_id].len,
+ sizeof(uint32_t));
+ }
+ if(awb->data_ptr && awb->size > 0) {
+ copy_to_user(para->awb.data_ptr, awb->data_ptr, awb->size);
+ copy_to_user(&para->awb.size, &awb->size, sizeof(uint32_t));
+ }
+ if(lsc->data_ptr && lsc->size > 0) {
+ copy_to_user(para->lsc.data_ptr, lsc->data_ptr, lsc->size);
+ copy_to_user(&para->lsc.size, &lsc->size, sizeof(uint32_t));
+ }
+ } else {
+ printk("SENSOR: ioctl SENSOR_IO_READ_OTPDATA mismatch type \n");
+ }
+ }
+ break;
+
+ default:
+ SENSOR_PRINT("sensor_k_ioctl: inv cmd %x \n", cmd);
+ break;
+ }
+
+ mutex_unlock(&p_mod->sensor_dev_tab[p_file->sensor_id].sync_lock);
+ return (long)ret;
+}
+
+LOCAL struct file_operations sensor_fops = {
+ .owner = THIS_MODULE,
+ .open = sensor_k_open,
+ .read = sensor_k_read,
+ .write = sensor_k_write,
+ .unlocked_ioctl = sensor_k_ioctl,
+ .compat_ioctl = compat_sensor_k_ioctl,
+ .release = sensor_k_release,
+};
+
+LOCAL struct miscdevice sensor_dev = {
+ .minor = SENSOR_MINOR,
+ .name = SENSOR_DEVICE_NAME,
+ .fops = &sensor_fops,
+};
+
+LOCAL int sensor_k_register_subdevs(struct platform_device *pdev)
+{
+ struct device_node *adapter, *child;
+ struct sensor_module_tab_tag *p_mod = platform_get_drvdata(pdev);
+
+ SENSOR_CHECK_ZERO(p_mod);
+
+ printk("sensor register sub device E\n");
+ for_each_compatible_node(adapter, NULL, "sprd,i2c") {
+ if (!of_find_device_by_node(adapter)) {
+ of_node_put(adapter);
+ printk("sensor find device fail\n");
+ //return -EPROBE_DEFER;
+ return 0;
+ }
+
+ for_each_available_child_of_node(adapter, child) {
+ struct i2c_client *client;
+
+ client = of_find_i2c_device_by_node(child);
+ if (!client) {
+ printk("sensor find i2c device fail\n");
+ goto e_retry;
+ }
+ if (0 == strcmp(client->name, SENSOR_DEV0_I2C_NAME)) {
+ printk("sensor dev0 i2c device 0x%x %s\n", client->addr, client->name);
+ p_mod->sensor_dev_tab[0].cur_i2c_client = client;
+ }
+ if (0 == strcmp(client->name, SENSOR_DEV1_I2C_NAME)) {
+ printk("sensor dev1 i2c device 0x%x %s\n", client->addr, client->name);
+ p_mod->sensor_dev_tab[1].cur_i2c_client = client;
+ }
+ if (0 == strcmp(client->name, SENSOR_DEV2_I2C_NAME)) {
+ printk("sensor dev2 i2c device 0x%x %s\n", client->addr, client->name);
+ p_mod->sensor_dev_tab[2].cur_i2c_client = client;
+ }
+ if (0 == strcmp(client->name, SENSOR_VCM0_I2C_NAME)) {
+ printk("sensor vcm0 i2c device 0x%x %s\n", client->addr, client->name);
+ p_mod->sensor_dev_tab[0].vcm_i2c_client = client;
+ p_mod->sensor_dev_tab[0].vcm_gpio_i2c_flag = 0;
+ }
+ }
+ }
+
+ for_each_compatible_node(adapter, NULL, "i2c-gpio") {
+ if (!of_find_device_by_node(adapter)) {
+ of_node_put(adapter);
+ printk("sensor find device fail\n");
+ return -EPROBE_DEFER;
+ }
+
+ for_each_available_child_of_node(adapter, child) {
+ struct i2c_client *client;
+
+ client = of_find_i2c_device_by_node(child);
+ if (!client) {
+ printk("sensor find vcm %s i2c device fail\n",child->name);
+ } else {
+ if (0 == strcmp(client->name, SENSOR_VCM0_I2C_NAME)) {
+ printk("sensor vcm i2c device 0x%x %s\n", client->addr, client->name);
+ p_mod->sensor_dev_tab[0].vcm_i2c_client = client;
+ p_mod->sensor_dev_tab[0].vcm_gpio_i2c_flag = 1;
+ }
+ }
+ }
+ }
+
+
+ printk("sensor register sub device success\n");
+ return 0;
+
+e_retry:
+ of_node_put(child);
+ return -EPROBE_DEFER;
+}
+
+static ssize_t sensor_name_show(struct device *dev,struct device_attribute *attr, char *buf){
+ return sprintf(buf,"%d,%d\n",socname.back_name,socname.front_name);
+}
+
+static DEVICE_ATTR(sensor_name, S_IRUGO, sensor_name_show, NULL);
+
+int sensor_k_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ uint32_t tmp = 0;
+ int i;
+ struct sensor_module_tab_tag *p_mod;
+#ifndef CONFIG_SC_FPGA_PIN
+ struct sensor_gpio_tag gpio_tab;
+#endif
+ int gpio_id = 0;
+
+ printk(KERN_ALERT "sensor probe called\n");
+ device_create_file(&pdev->dev, &dev_attr_sensor_name);
+ p_mod = (struct sensor_module_tab_tag *)vzalloc(sizeof(struct sensor_module_tab_tag));
+ SENSOR_CHECK_ZERO(p_mod);
+
+ for (i = 0; i < SENSOR_DEV_MAX; i++) {
+ mutex_init(&p_mod->sensor_dev_tab[i].sync_lock);
+ atomic_set(&p_mod->sensor_dev_tab[i].users, 0);
+ }
+ mutex_init(&p_mod->sensor_id_lock);
+ wake_lock_init(&p_mod->wakelock, WAKE_LOCK_SUSPEND,
+ "pm_message_wakelock_sensor_k");
+ platform_set_drvdata(pdev, p_mod);
+ atomic_set(&p_mod->total_users, 0);
+
+ ret = misc_register(&sensor_dev);
+ if (ret) {
+ printk(KERN_ERR "can't reg miscdev on minor=%d (%d)\n",
+ SENSOR_MINOR, ret);
+ goto misc_register_error;
+ }
+
+ p_mod->of_node = pdev->dev.of_node;
+ parse_baseaddress(pdev->dev.of_node);
+ sensor_dev.this_device->platform_data = (void*)p_mod;
+
+#ifndef CONFIG_SC_FPGA_PIN
+ for (i = 0; i < SENSOR_DEV_MAX; i++) {
+ get_gpio_id(p_mod->of_node, &gpio_tab.pwn, &gpio_tab.reset, i);
+ ret = gpio_request(gpio_tab.pwn, NULL);
+ if (ret) {
+ tmp = 1;
+ printk("sensor: gpio already request pwn %d %d.\n", gpio_tab.pwn, i);
+ }
+ ret = gpio_request(gpio_tab.reset, NULL);
+ if (ret) {
+ tmp = 1;
+ printk("sensor: gpio already request reset %d %d.\n", gpio_tab.reset, i);
+ }
+ }
+
+ get_gpio_id_ex(p_mod->of_node, GPIO_CAMDVDD, &gpio_id, 0);
+ ret = gpio_request(gpio_id, NULL);
+ if (ret) {
+ tmp = 1;
+ printk("sensor: gpio already request GPIO_CAMDVDD %d.\n", gpio_id);
+ }
+#endif
+
+ ret = sensor_k_register_subdevs(pdev);
+ if (ret) {
+ printk(KERN_ERR "can't reg sub dev=%d (%d)\n",
+ SENSOR_MINOR, ret);
+ goto misc_register_error;
+ }
+ kthread_run(sensor_reloadinfo_thread, p_mod->otp_param, "otpreload");
+ goto exit;
+
+misc_register_error:
+ misc_deregister(&sensor_dev);
+
+ if (SENSOR_ADDR_INVALID(p_mod)) {
+ printk("SENSOR: Invalid addr, %p", p_mod);
+ } else {
+ vfree(p_mod);
+ p_mod = NULL;
+ platform_set_drvdata(pdev, NULL);
+ }
+exit:
+ if (ret) {
+ printk(KERN_ERR "sensor prb fail req gpio %d err %d\n",
+ tmp, ret);
+ } else {
+ printk(KERN_ALERT " sensor prb Success\n");
+ }
+ return ret;
+}
+
+LOCAL int sensor_k_remove(struct platform_device *dev)
+{
+ struct sensor_module_tab_tag *p_mod = platform_get_drvdata(dev);
+#ifndef CONFIG_SC_FPGA_PIN
+ struct sensor_gpio_tag gpio_tab;
+ int i;
+#endif
+ int gpio_id = 0;
+
+ SENSOR_CHECK_ZERO(p_mod);
+
+ printk(KERN_INFO "sensor remove called !\n");
+
+#ifndef CONFIG_SC_FPGA_PIN
+ for (i = 0; i < SENSOR_DEV_MAX; i++) {
+ get_gpio_id(p_mod->of_node, &gpio_tab.pwn, &gpio_tab.reset, i);
+ gpio_free(gpio_tab.pwn);
+ gpio_free(gpio_tab.reset);
+ }
+
+ get_gpio_id_ex(p_mod->of_node, GPIO_CAMDVDD, &gpio_id, 0);
+ gpio_free(gpio_id);
+#endif
+
+ misc_deregister(&sensor_dev);
+ wake_lock_destroy(&p_mod->wakelock);
+
+ if (SENSOR_ADDR_INVALID(p_mod)) {
+ printk("SENSOR: Invalid addr, %p", p_mod);
+ } else {
+ vfree(p_mod);
+ p_mod = NULL;
+ platform_set_drvdata(dev, NULL);
+ }
+ printk(KERN_INFO "sensor remove Success !\n");
+ return 0;
+}
+
+LOCAL const struct of_device_id of_match_table_sensor[] = {
+ { .compatible = "sprd,sprd_sensor", },
+ { },
+};
+
+static struct platform_driver sensor_dev_driver = {
+ .probe = sensor_k_probe,
+ .remove =sensor_k_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = SENSOR_DEVICE_NAME,
+ .of_match_table = of_match_ptr(of_match_table_sensor),
+ },
+};
+
+int __init sensor_k_init(void)
+{
+ printk(KERN_INFO "sensor_k_init called !\n");
+
+ if (platform_driver_register(&sensor_dev_driver) != 0) {
+ printk("platform device register Failed \n");
+ return SENSOR_K_FAIL;
+ }
+ return 0;
+}
+
+void sensor_k_exit(void)
+{
+ printk(KERN_INFO "sensor_k_exit called !\n");
+ platform_driver_unregister(&sensor_dev_driver);
+}
+
+module_init(sensor_k_init);
+module_exit(sensor_k_exit);
+
+MODULE_DESCRIPTION("Sensor Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/sprd_sensor/sensor_drv_sprd.h b/drivers/media/sprd_sensor/sensor_drv_sprd.h
new file mode 100644
index 00000000..bd7d3915
--- /dev/null
+++ b/drivers/media/sprd_sensor/sensor_drv_sprd.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 _SENSOR_DRV_SPRD_H_
+#define _SENSOR_DRV_SPRD_H_
+
+#define SENSOER_VDD_1200MV 1200000
+#define SENSOER_VDD_1300MV 1300000
+#define SENSOER_VDD_1500MV 1500000
+#define SENSOER_VDD_1800MV 1800000
+#define SENSOER_VDD_2500MV 2500000
+#define SENSOER_VDD_2800MV 2800000
+#define SENSOER_VDD_3000MV 3000000
+#define SENSOER_VDD_3300MV 3300000
+#define SENSOER_VDD_3800MV 3800000
+
+typedef enum {
+ SENSOR_VDD_3800MV = 0,
+ SENSOR_VDD_3300MV,
+ SENSOR_VDD_3000MV,
+ SENSOR_VDD_2800MV,
+ SENSOR_VDD_2500MV,
+ SENSOR_VDD_1800MV,
+ SENSOR_VDD_1500MV,
+ SENSOR_VDD_1300MV,
+ SENSOR_VDD_1200MV,
+ SENSOR_VDD_CLOSED,
+ SENSOR_VDD_UNUSED
+} SENSOR_VDD_VAL_E;
+
+enum sensor_id_e {
+ SENSOR_DEV_0 = 0,
+ SENSOR_DEV_1,
+ SENSOR_DEV_2,
+ SENSOR_DEV_MAX
+};
+
+#define SENSOR_DEV0_I2C_NAME "sensor_main"
+#define SENSOR_DEV1_I2C_NAME "sensor_sub"
+#define SENSOR_DEV2_I2C_NAME "sensor_i2c_dev2"
+#define SENSOR_VCM0_I2C_NAME "sensor_i2c_vcm0"
+
+
+#define SENSOR_DEV0_I2C_ADDR 0x30
+#define SENSOR_DEV1_I2C_ADDR 0x21
+#define SENSOR_DEV2_I2C_ADDR 0x30
+
+#define SENSOR_I2C_BUST_NB 7
+
+
+#define SENSOR_MAX_MCLK 96 /*MHz*/
+#define SENOR_CLK_M_VALUE 1000000
+
+#define GLOBAL_BASE SPRD_GREG_BASE /*0xE0002E00UL <--> 0x8b000000 */
+#define ARM_GLOBAL_REG_GEN0 (GLOBAL_BASE + 0x008UL)
+#define ARM_GLOBAL_REG_GEN3 (GLOBAL_BASE + 0x01CUL)
+#define ARM_GLOBAL_PLL_SCR (GLOBAL_BASE + 0x070UL)
+#define GR_CLK_GEN5 (GLOBAL_BASE + 0x07CUL)
+
+#define AHB_BASE SPRD_AHB_BASE /*0xE000A000 <--> 0x20900000UL */
+#define AHB_GLOBAL_REG_CTL0 (AHB_BASE + 0x200UL)
+#define AHB_GLOBAL_REG_SOFTRST (AHB_BASE + 0x210UL)
+
+#define PIN_CTL_BASE SPRD_CPC_BASE /*0xE002F000<-->0x8C000000UL */
+#define PIN_CTL_CCIRPD1 PIN_CTL_BASE + 0x344UL
+#define PIN_CTL_CCIRPD0 PIN_CTL_BASE + 0x348UL
+
+#define MISC_BASE SPRD_MISC_BASE /*0xE0033000<-->0x82000000 */
+
+#define ANA_REG_BASE MISC_BASE + 0x480
+#define ANA_LDO_PD_CTL ANA_REG_BASE + 0x10
+#define ANA_LDO_VCTL2 ANA_REG_BASE + 0x1C
+
+
+int sensor_k_set_pd_level(uint32_t *fd_handle, uint8_t power_level);
+int sensor_k_set_rst_level(uint32_t *fd_handle, uint32_t plus_level);
+int sensor_k_set_voltage_cammot(uint32_t *fd_handle, uint32_t cammot_val);
+int sensor_k_set_voltage_avdd(uint32_t *fd_handle, uint32_t avdd_val);
+int sensor_k_set_voltage_dvdd(uint32_t *fd_handle, uint32_t dvdd_val);
+int sensor_k_set_voltage_iovdd(uint32_t *fd_handle, uint32_t iodd_val);
+int sensor_k_set_mclk(uint32_t *fd_handle, uint32_t mclk);
+int sensor_k_sensor_sel(uint32_t *fd_handle, uint32_t sensor_id);
+
+#endif //_SENSOR_DRV_K_H_