diff options
Diffstat (limited to 'drivers/media/sprd_sensor')
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, ®u_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, ®_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(®, (struct sensor_reg_bits_tag *) arg, sizeof(struct sensor_reg_bits_tag)); + + if (0 == ret) { + ret = _Sensor_K_ReadReg(p_file, ®); + if(SENSOR_K_FAIL != ret){ + ret = copy_to_user((struct sensor_reg_bits_tag *)arg, ®, 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(®, (struct sensor_reg_bits_tag *) arg, sizeof(struct sensor_reg_bits_tag)); + + if (0 == ret) { + ret = _Sensor_K_WriteReg(p_file, ®); + } + + } + 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(®Tab, (struct sensor_reg_tab_tag *) arg, sizeof(struct sensor_reg_tab_tag)); + if (0 == ret) + ret = _sensor_k_wr_regtab(p_file, ®Tab); + } + 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, ¶->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(¶->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(¶->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(¶->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(¶->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_ |
