/* Copyright (c) 2009, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include "vb6801.h" /*============================================================= SENSOR REGISTER DEFINES ==============================================================*/ enum { REG_HOLD = 0x0104, RELEASE_HOLD = 0x0000, HOLD = 0x0001, STANDBY_MODE = 0x0000, REG_COARSE_INTEGRATION_TIME = 0x0202, REG_ANALOGUE_GAIN_CODE_GLOBAL = 0x0204, REG_RAMP_SCALE = 0x3116, REG_POWER_MAN_ENABLE_3 = 0x3142, REG_POWER_MAN_ENABLE_4 = 0x3143, REG_POWER_MAN_ENABLE_5 = 0x3144, REG_CCP2_DATA_FORMAT = 0x0112, REG_PRE_PLL_CLK_DIV = 0x0304, REG_PLL_MULTIPLIER = 0x0306, REG_VT_SYS_CLK_DIV = 0x0302, REG_VT_PIX_CLK_DIV = 0x0300, REG_OP_SYS_CLK_DIV = 0x030A, REG_OP_PIX_CLK_DIV = 0x0308, REG_VT_LINE_LENGTH_PCK = 0x0342, REG_X_OUTPUT_SIZE = 0x034C, REG_Y_OUTPUT_SIZE = 0x034E, REG_X_ODD_INC = 0x0382, REG_Y_ODD_INC = 0x0386, REG_VT_FRAME_LENGTH_LINES = 0x0340, REG_ANALOG_TIMING_MODES_2 = 0x3113, REG_BRUCE_ENABLE = 0x37B0, REG_OP_CODER_SYNC_CLK_SETUP = 0x3400, REG_OP_CODER_ENABLE = 0x3401, REG_OP_CODER_SLOW_PAD_EN = 0x3402, REG_OP_CODER_AUTO_STARTUP = 0x3414, REG_SCYTHE_ENABLE = 0x3204, REG_SCYTHE_WEIGHT = 0x3206, REG_FRAME_COUNT = 0x0005, REG_MODE_SELECT = 0x0100, REG_CCP2_CHANNEL_IDENTIFIER = 0x0110, REG_CCP2_SIGNALLING_MODE = 0x0111, REG_BTL_LEVEL_SETUP = 0x311B, REG_OP_CODER_AUTOMATIC_MODE_ENABLE = 0x3403, REG_PLL_CTRL = 0x3801, REG_VCM_DAC_CODE = 0x3860, REG_VCM_DAC_STROBE = 0x3868, REG_VCM_DAC_ENABLE = 0x386C, REG_NVM_T1_ADDR_00 = 0x3600, REG_NVM_T1_ADDR_01 = 0x3601, REG_NVM_T1_ADDR_02 = 0x3602, REG_NVM_T1_ADDR_03 = 0x3603, REG_NVM_T1_ADDR_04 = 0x3604, REG_NVM_T1_ADDR_05 = 0x3605, REG_NVM_T1_ADDR_06 = 0x3606, REG_NVM_T1_ADDR_07 = 0x3607, REG_NVM_T1_ADDR_08 = 0x3608, REG_NVM_T1_ADDR_09 = 0x3609, REG_NVM_T1_ADDR_0A = 0x360A, REG_NVM_T1_ADDR_0B = 0x360B, REG_NVM_T1_ADDR_0C = 0x360C, REG_NVM_T1_ADDR_0D = 0x360D, REG_NVM_T1_ADDR_0E = 0x360E, REG_NVM_T1_ADDR_0F = 0x360F, REG_NVM_T1_ADDR_10 = 0x3610, REG_NVM_T1_ADDR_11 = 0x3611, REG_NVM_T1_ADDR_12 = 0x3612, REG_NVM_T1_ADDR_13 = 0x3613, REG_NVM_CTRL = 0x3680, REG_NVM_PDN = 0x3681, REG_NVM_PULSE_WIDTH = 0x368B, }; #define VB6801_LINES_PER_FRAME_PREVIEW 800 #define VB6801_LINES_PER_FRAME_SNAPSHOT 1600 #define VB6801_PIXELS_PER_LINE_PREVIEW 2500 #define VB6801_PIXELS_PER_LINE_SNAPSHOT 2500 /* AF constant */ #define VB6801_TOTAL_STEPS_NEAR_TO_FAR 25 #define VB6801_STEPS_NEAR_TO_CLOSEST_INF 25 /* for 30 fps preview */ #define VB6801_DEFAULT_CLOCK_RATE 12000000 enum vb6801_test_mode_t { TEST_OFF, TEST_1, TEST_2, TEST_3 }; enum vb6801_resolution_t { QTR_SIZE, FULL_SIZE, INVALID_SIZE }; enum vb6801_setting_t { RES_PREVIEW, RES_CAPTURE }; struct vb6801_work_t { struct work_struct work; }; struct sensor_dynamic_params_t { uint16_t preview_pixelsPerLine; uint16_t preview_linesPerFrame; uint16_t snapshot_pixelsPerLine; uint16_t snapshot_linesPerFrame; uint8_t snapshot_changed_fps; uint32_t pclk; }; struct vb6801_sensor_info { /* Sensor Configuration Input Parameters */ uint32_t ext_clk_freq_mhz; uint32_t target_frame_rate_fps; uint32_t target_vt_pix_clk_freq_mhz; uint32_t sub_sampling_factor; uint32_t analog_binning_allowed; uint32_t raw_mode; uint32_t capture_mode; /* Image Readout Registers */ uint32_t x_odd_inc; /* x pixel array addressing odd increment */ uint32_t y_odd_inc; /* y pixel array addressing odd increment */ uint32_t x_output_size; /* width of output image */ uint32_t y_output_size; /* height of output image */ /* Declare data format */ uint32_t ccp2_data_format; /* Clock Tree Registers */ uint32_t pre_pll_clk_div; uint32_t pll_multiplier; uint32_t vt_sys_clk_div; uint32_t vt_pix_clk_div; uint32_t op_sys_clk_div; uint32_t op_pix_clk_div; /* Video Timing Registers */ uint32_t vt_line_length_pck; uint32_t vt_frame_length_lines; /* Analogue Binning Registers */ uint8_t vtiming_major; uint8_t analog_timing_modes_4; /* Fine (pixel) Integration Time Registers */ uint32_t fine_integration_time; /* Coarse (lines) Integration Time Limit Registers */ uint32_t coarse_integration_time_max; /* Coarse (lines) Integration Timit Register (16-bit) */ uint32_t coarse_integration_time; /* Analogue Gain Code Global Registers */ uint32_t analogue_gain_code_global; /* Digital Gain Code Registers */ uint32_t digital_gain_code; /* Overall gain (analogue & digital) code * Note that this is not a real register but just * an abstraction for the combination of analogue * and digital gain */ uint32_t gain_code; /* FMT Test Information */ uint32_t pass_fail; uint32_t day; uint32_t month; uint32_t year; uint32_t tester; uint32_t part_number; /* Autofocus controls */ uint32_t vcm_dac_code; int vcm_max_dac_code_step; int vcm_proportional_factor; int vcm_dac_code_spacing_ms; /* VCM NVM Characterisation Information */ uint32_t vcm_dac_code_infinity_dn; uint32_t vcm_dac_code_macro_up; uint32_t vcm_dac_code_up_dn_delta; /* Internal Variables */ uint32_t min_vt_frame_length_lines; }; struct vb6801_work_t *vb6801_sensorw; struct i2c_client *vb6801_client; struct vb6801_ctrl_t { const struct msm_camera_sensor_info *sensordata; int sensormode; uint32_t factor_fps; /* init to 1 * 0x00000400 */ uint16_t curr_fps; uint16_t max_fps; int8_t pict_exp_update; int8_t reducel; uint16_t curr_lens_pos; uint16_t init_curr_lens_pos; enum vb6801_resolution_t prev_res; enum vb6801_resolution_t pict_res; enum vb6801_resolution_t curr_res; enum vb6801_test_mode_t set_test; struct vb6801_sensor_info s_info; struct sensor_dynamic_params_t s_dynamic_params; }; static struct vb6801_ctrl_t *vb6801_ctrl; static DECLARE_WAIT_QUEUE_HEAD(vb6801_wait_queue); DEFINE_MUTEX(vb6801_mut); static int vb6801_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, int length) { struct i2c_msg msgs[] = { { .addr = saddr, .flags = 0, .len = 2, .buf = rxdata, }, { .addr = saddr, .flags = I2C_M_RD, .len = 2, .buf = rxdata, }, }; if (i2c_transfer(vb6801_client->adapter, msgs, 2) < 0) { CDBG("vb6801_i2c_rxdata failed!\n"); return -EIO; } return 0; } static int32_t vb6801_i2c_read(unsigned short raddr, unsigned short *rdata, int rlen) { int32_t rc = 0; unsigned char buf[2]; if (!rdata) return -EIO; memset(buf, 0, sizeof(buf)); buf[0] = (raddr & 0xFF00) >> 8; buf[1] = (raddr & 0x00FF); rc = vb6801_i2c_rxdata(vb6801_client->addr, buf, rlen); if (rc < 0) { CDBG("vb6801_i2c_read 0x%x failed!\n", raddr); return rc; } *rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]); return rc; } static int32_t vb6801_i2c_read_table(struct vb6801_i2c_reg_conf_t *regs, int items) { int i; int32_t rc = -EFAULT; for (i = 0; i < items; i++) { unsigned short *buf = regs->dlen == D_LEN_BYTE ? (unsigned short *)®s->bdata : (unsigned short *)®s->wdata; rc = vb6801_i2c_read(regs->waddr, buf, regs->dlen + 1); if (rc < 0) { CDBG("vb6801_i2c_read_table Failed!!!\n"); break; } regs++; } return rc; } static int32_t vb6801_i2c_txdata(unsigned short saddr, unsigned char *txdata, int length) { struct i2c_msg msg[] = { { .addr = saddr, .flags = 0, .len = length, .buf = txdata, }, }; if (i2c_transfer(vb6801_client->adapter, msg, 1) < 0) { CDBG("vb6801_i2c_txdata faild 0x%x\n", vb6801_client->addr); return -EIO; } return 0; } static int32_t vb6801_i2c_write_b(unsigned short waddr, uint8_t bdata) { int32_t rc = -EFAULT; unsigned char buf[3]; memset(buf, 0, sizeof(buf)); buf[0] = (waddr & 0xFF00) >> 8; buf[1] = (waddr & 0x00FF); buf[2] = bdata; CDBG("i2c_write_b addr = %d, val = %d\n", waddr, bdata); rc = vb6801_i2c_txdata(vb6801_client->addr, buf, 3); if (rc < 0) { CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n", waddr, bdata); } return rc; } static int32_t vb6801_i2c_write_w(unsigned short waddr, unsigned short wdata) { int32_t rc = -EFAULT; unsigned char buf[4]; memset(buf, 0, sizeof(buf)); buf[0] = (waddr & 0xFF00) >> 8; buf[1] = (waddr & 0x00FF); buf[2] = (wdata & 0xFF00) >> 8; buf[3] = (wdata & 0x00FF); CDBG("i2c_write_w addr = %d, val = %d, buf[2] = 0x%x, buf[3] = 0x%x\n", waddr, wdata, buf[2], buf[3]); rc = vb6801_i2c_txdata(vb6801_client->addr, buf, 4); if (rc < 0) { CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", waddr, wdata); } return rc; } static int32_t vb6801_i2c_write_table(struct vb6801_i2c_reg_conf_t *regs, int items) { int i; int32_t rc = -EFAULT; for (i = 0; i < items; i++) { rc = ((regs->dlen == D_LEN_BYTE) ? vb6801_i2c_write_b(regs->waddr, regs->bdata) : vb6801_i2c_write_w(regs->waddr, regs->wdata)); if (rc < 0) { CDBG("vb6801_i2c_write_table Failed!!!\n"); break; } regs++; } return rc; } static int32_t vb6801_reset(const struct msm_camera_sensor_info *data) { int rc; rc = gpio_request(data->sensor_reset, "vb6801"); if (!rc) { CDBG("sensor_reset SUcceeded\n"); gpio_direction_output(data->sensor_reset, 0); mdelay(50); gpio_direction_output(data->sensor_reset, 1); mdelay(13); } else CDBG("sensor_reset FAiled\n"); return rc; } static int32_t vb6801_set_default_focus(void) { int32_t rc = 0; /* FIXME: Default focus not supported */ return rc; } static void vb6801_get_pict_fps(uint16_t fps, uint16_t *pfps) { /* input fps is preview fps in Q8 format */ uint32_t divider; /*Q10 */ uint32_t pclk_mult; /*Q10 */ uint32_t d1; uint32_t d2; d1 = (uint32_t)( (vb6801_ctrl->s_dynamic_params.preview_linesPerFrame * 0x00000400) / vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame); d2 = (uint32_t)( (vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine * 0x00000400) / vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine); divider = (uint32_t) (d1 * d2) / 0x00000400; pclk_mult = (48 * 0x400) / 60; /* Verify PCLK settings and frame sizes. */ *pfps = (uint16_t)((((fps * pclk_mult) / 0x00000400) * divider)/ 0x00000400); } static uint16_t vb6801_get_prev_lines_pf(void) { if (vb6801_ctrl->prev_res == QTR_SIZE) return vb6801_ctrl->s_dynamic_params.preview_linesPerFrame; else return vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame; } static uint16_t vb6801_get_prev_pixels_pl(void) { if (vb6801_ctrl->prev_res == QTR_SIZE) return vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine; else return vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine; } static uint16_t vb6801_get_pict_lines_pf(void) { return vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame; } static uint16_t vb6801_get_pict_pixels_pl(void) { return vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine; } static uint32_t vb6801_get_pict_max_exp_lc(void) { uint16_t snapshot_lines_per_frame; if (vb6801_ctrl->pict_res == QTR_SIZE) { snapshot_lines_per_frame = vb6801_ctrl->s_dynamic_params.preview_linesPerFrame - 3; } else { snapshot_lines_per_frame = vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame - 3; } return snapshot_lines_per_frame; } static int32_t vb6801_set_fps(struct fps_cfg *fps) { int32_t rc = 0; /* input is new fps in Q8 format */ switch (fps->fps_div) { case 7680: /* 30 * Q8 */ vb6801_ctrl->factor_fps = 1; break; case 3840: /* 15 * Q8 */ vb6801_ctrl->factor_fps = 2; break; case 2560: /* 10 * Q8 */ vb6801_ctrl->factor_fps = 3; break; case 1920: /* 7.5 * Q8 */ vb6801_ctrl->factor_fps = 4; break; default: rc = -ENODEV; break; } return rc; } static int32_t vb6801_write_exp_gain(uint16_t gain, uint32_t line) { int32_t rc = 0; uint16_t lpf; if (vb6801_ctrl->curr_res == SENSOR_FULL_SIZE) lpf = VB6801_LINES_PER_FRAME_SNAPSHOT; else lpf = VB6801_LINES_PER_FRAME_PREVIEW; /* hold */ rc = vb6801_i2c_write_w(REG_HOLD, HOLD); if (rc < 0) goto exp_gain_done; if ((vb6801_ctrl->curr_fps < vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps) && (!vb6801_ctrl->pict_exp_update)) { if (vb6801_ctrl->reducel) { rc = vb6801_i2c_write_w(REG_VT_FRAME_LENGTH_LINES, lpf * vb6801_ctrl->factor_fps); vb6801_ctrl->curr_fps = vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps; } else if (!vb6801_ctrl->reducel) { rc = vb6801_i2c_write_w(REG_COARSE_INTEGRATION_TIME, line * vb6801_ctrl->factor_fps); vb6801_ctrl->reducel = 1; } } else if ((vb6801_ctrl->curr_fps > vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps) && (!vb6801_ctrl->pict_exp_update)) { rc = vb6801_i2c_write_w(REG_VT_FRAME_LENGTH_LINES, lpf * vb6801_ctrl->factor_fps); vb6801_ctrl->curr_fps = vb6801_ctrl->max_fps / vb6801_ctrl->factor_fps; } else { /* analogue_gain_code_global */ rc = vb6801_i2c_write_w(REG_ANALOGUE_GAIN_CODE_GLOBAL, gain); if (rc < 0) goto exp_gain_done; /* coarse_integration_time */ rc = vb6801_i2c_write_w(REG_COARSE_INTEGRATION_TIME, line * vb6801_ctrl->factor_fps); if (rc < 0) goto exp_gain_done; vb6801_ctrl->pict_exp_update = 1; } rc = vb6801_i2c_write_w(REG_HOLD, RELEASE_HOLD); exp_gain_done: return rc; } static int32_t vb6801_set_pict_exp_gain(uint16_t gain, uint32_t line) { vb6801_ctrl->pict_exp_update = 1; return vb6801_write_exp_gain(gain, line); } static int32_t vb6801_power_down(void) { int32_t rc = 0; rc = vb6801_i2c_write_b(REG_NVM_PDN, 0); mdelay(5); return rc; } static int32_t vb6801_go_to_position(uint32_t target_vcm_dac_code, struct vb6801_sensor_info *ps) { /* Prior to running this function the following values must * be initialised in the sensor data structure, PS * ps->vcm_dac_code * ps->vcm_max_dac_code_step * ps->vcm_dac_code_spacing_ms */ int32_t rc = 0; ps->vcm_dac_code = target_vcm_dac_code; /* Restore Strobe to zero state */ rc = vb6801_i2c_write_b(REG_VCM_DAC_STROBE, 0x00); if (rc < 0) return rc; /* Write 9-bit VCM DAC Code */ rc = vb6801_i2c_write_w(REG_VCM_DAC_CODE, ps->vcm_dac_code); if (rc < 0) return rc; /* Generate a rising edge on the dac_strobe to latch * new DAC value */ rc = vb6801_i2c_write_w(REG_VCM_DAC_STROBE, 0x01); return rc; } static int32_t vb6801_move_focus(int direction, int32_t num_steps) { int16_t step_direction; int16_t actual_step; int16_t next_position; uint32_t step_size; int16_t small_move[4]; uint16_t i; int32_t rc = 0; step_size = (vb6801_ctrl->s_info.vcm_dac_code_macro_up - vb6801_ctrl->s_info.vcm_dac_code_infinity_dn) / VB6801_TOTAL_STEPS_NEAR_TO_FAR; if (num_steps > VB6801_TOTAL_STEPS_NEAR_TO_FAR) num_steps = VB6801_TOTAL_STEPS_NEAR_TO_FAR; else if (num_steps == 0) return -EINVAL; if (direction == MOVE_NEAR) step_direction = 4; else if (direction == MOVE_FAR) step_direction = -4; else return -EINVAL; /* need to decide about default position and power supplied * at start up and reset */ if (vb6801_ctrl->curr_lens_pos < vb6801_ctrl->init_curr_lens_pos) vb6801_ctrl->curr_lens_pos = vb6801_ctrl->init_curr_lens_pos; actual_step = (step_direction * num_steps); next_position = vb6801_ctrl->curr_lens_pos; for (i = 0; i < 4; i++) { if (actual_step >= 0) small_move[i] = (i + 1) * actual_step / 4 - i * actual_step / 4; if (actual_step < 0) small_move[i] = (i + 1) * actual_step / 4 - i * actual_step / 4; } if (next_position > 511) next_position = 511; else if (next_position < 0) next_position = 0; /* for damping */ for (i = 0; i < 4; i++) { next_position = (int16_t) (vb6801_ctrl->curr_lens_pos + small_move[i]); /* Writing the digital code for current to the actuator */ CDBG("next_position in damping mode = %d\n", next_position); rc = vb6801_go_to_position(next_position, &vb6801_ctrl->s_info); if (rc < 0) { CDBG("go_to_position Failed!!!\n"); return rc; } vb6801_ctrl->curr_lens_pos = next_position; if (i < 3) mdelay(5); } return rc; } static int vb6801_read_nvm_data(struct vb6801_sensor_info *ps) { /* +--------+------+------+----------------+---------------+ * | Index | NVM | NVM | Name | Description | * | | Addr | Byte | | | * +--------+------+------+----------------+---------------+ * | 0x3600 | 0 | 3 | nvm_t1_addr_00 | {PF[2:0]:Day[4:0]} | * | 0x3601 | 0 | 2 | nvm_t1_addr_01 | {Month[3:0]:Year[3:0]} | * | 0x3602 | 0 | 1 | nvm_t1_addr_02 | Tester[7:0] | * | 0x3603 | 0 | 0 | nvm_t1_addr_03 | Part[15:8] | * +--------+------+------+----------------+---------------+ * | 0x3604 | 1 | 3 | nvm_t1_addr_04 | Part[7:0] | * | 0x3605 | 1 | 2 | nvm_t1_addr_05 | StartWPM[7:0] | * | 0x3606 | 1 | 1 | nvm_t1_addr_06 | Infinity[7:0] | * | 0x3607 | 1 | 0 | nvm_t1_addr_07 | Macro[7:0] | * +--------+------+------+----------------+---------------+ * | 0x3608 | 2 | 3 | nvm_t1_addr_08 | Reserved | * | 0x3609 | 2 | 2 | nvm_t1_addr_09 | Reserved | * | 0x360A | 2 | 1 | nvm_t1_addr_0A | UpDown[7:0] | * | 0x360B | 2 | 0 | nvm_t1_addr_0B | Reserved | * +--------+------+------+----------------+---------------+ * | 0x360C | 3 | 3 | nvm_t1_addr_0C | Reserved | * | 0x360D | 3 | 2 | nvm_t1_addr_0D | Reserved | * | 0x360E | 3 | 1 | nvm_t1_addr_0E | Reserved | * | 0x360F | 3 | 0 | nvm_t1_addr_0F | Reserved | * +--------+------+------+----------------+---------------+ * | 0x3610 | 4 | 3 | nvm_t1_addr_10 | Reserved | * | 0x3611 | 4 | 2 | nvm_t1_addr_11 | Reserved | * | 0x3612 | 4 | 1 | nvm_t1_addr_12 | Reserved | * | 0x3613 | 4 | 0 | nvm_t1_addr_13 | Reserved | * +--------+------+------+----------------+---------------+*/ int32_t rc; struct vb6801_i2c_reg_conf_t rreg[] = { {REG_NVM_T1_ADDR_00, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_01, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_02, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_03, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_04, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_05, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_06, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_07, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_08, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_09, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_0A, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_0B, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_0C, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_0D, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_0E, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_0F, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_10, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_11, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_12, 0, 0, D_LEN_BYTE}, {REG_NVM_T1_ADDR_13, 0, 0, D_LEN_BYTE}, }; struct vb6801_i2c_reg_conf_t wreg[] = { /* Enable NVM for Direct Reading */ {REG_NVM_CTRL, 0, 2, D_LEN_BYTE}, /* Power up NVM */ {REG_NVM_PDN, 0, 1, D_LEN_BYTE}, }; rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg)); if (rc < 0) { CDBG("I2C Write Table FAILED!!!\n"); return rc; } /* NVM Read Pulse Width * ==================== * nvm_pulse_width_us = nvm_pulse_width_ext_clk / ext_clk_freq_mhz * Valid Range for Read Pulse Width = 400ns -> 3.0us * Min ext_clk_freq_mhz = 6MHz => 3.0 * 6 = 18 * Max ext_clk_freq_mhz = 27MHz => 0.4 * 27 = 10.8 * Choose 15 as a common value * - 15 / 6.0 = 2.5000us * - 15 / 12.0 = 1.2500us * - 15 / 27.0 = 0.5555us */ rc = vb6801_i2c_write_w(REG_NVM_PULSE_WIDTH, 15); if (rc < 0) { rc = -EBUSY; goto nv_shutdown; } rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg)); if (rc < 0) { CDBG("I2C Read Table FAILED!!!\n"); rc = -EBUSY; goto nv_shutdown; } /* Decode and Save FMT Info */ ps->pass_fail = (rreg[0].bdata & 0x00E0) >> 5; ps->day = (rreg[0].bdata & 0x001F); ps->month = (rreg[1].bdata & 0x00F0) >> 4; ps->year = (rreg[1].bdata & 0x000F) + 2000; ps->tester = rreg[2].bdata; ps->part_number = (rreg[3].bdata << 8) + rreg[4].bdata; /* Decode and Save VCM Dac Values in data structure */ ps->vcm_dac_code_infinity_dn = rreg[6].bdata; ps->vcm_dac_code_macro_up = rreg[7].bdata << 1; ps->vcm_dac_code_up_dn_delta = rreg[10].bdata; nv_shutdown: /* Power Down NVM to extend life time */ rc = vb6801_i2c_write_b(REG_NVM_PDN, 0); return rc; } static int vb6801_config_sensor(int32_t ext_clk_freq_mhz, int32_t target_frame_rate_fps, int32_t target_vt_pix_clk_freq_mhz, uint32_t sub_sampling_factor, uint32_t analog_binning_allowed, uint32_t raw_mode, int capture_mode, enum vb6801_resolution_t res) { uint32_t rc; /* ext_clk_freq_mhz = 6.0 -> 27.0 MHz * target_frame_rate_fps = 15 fps * target_vt_pix_clk_freq_mhz = 24.0 -> 64.0MHz * sub_sampling factor = 1, 2, 3, or 4 * raw_mode factor = 10 * * capture_mode, 0 = CCP1 * capture_mode, 1 = CCP2 * capture_mode, 2 = 10-bit parallel + hsync + vsync */ /* Declare data format */ uint32_t ccp2_data_format = 0x0A0A; /* Declare clock tree variables */ int32_t min_pll_ip_freq_mhz = 6; int32_t max_pll_op_freq_mhz = 640; uint32_t pre_pll_clk_div = 1; int32_t pll_ip_freq_mhz = 6; uint32_t pll_multiplier = 100; int32_t pll_op_freq_mhz = 600; uint32_t vt_sys_clk_div = 1; int32_t vt_sys_clk_freq_mhz = 600; uint32_t vt_pix_clk_div = 10; int32_t vt_pix_clk_freq_mhz = 60; uint32_t op_sys_clk_div = 1; int32_t op_sys_clk_freq_mhz = 60; uint32_t op_pix_clk_div = 10; int32_t op_pix_clk_freq_mhz = 60; /* Declare pixel array and frame timing variables */ uint32_t x_pixel_array = 2064; uint32_t y_pixel_array = 1544; uint32_t x_even_inc = 1; uint32_t x_odd_inc = 1; uint32_t y_even_inc = 1; uint32_t y_odd_inc = 1; uint32_t x_output_size = 2064; uint32_t y_output_size = 1544; uint32_t additional_rows = 2; uint32_t min_vt_frame_blanking_lines = 16; uint32_t vt_line_length_pck = 2500; uint32_t vt_line_length_us = 0; uint32_t min_vt_frame_length_lines = 1562; uint32_t vt_frame_length_lines = 1600; uint32_t target_vt_frame_length_ms; /* 200 * 0x0001000 / 3; */ uint32_t vt_frame_length_ms; /* 200 * 0x0001000 / 3; */ uint32_t frame_rate_fps = 15; /* Coarse intergration time */ uint32_t coarse_integration_time = 1597; uint32_t coarse_integration_time_max_margin = 3; uint16_t frame_count; int timeout; struct vb6801_sensor_info *pinfo = &vb6801_ctrl->s_info; struct vb6801_i2c_reg_conf_t rreg[] = { {REG_PRE_PLL_CLK_DIV, 0, 0, D_LEN_WORD}, {REG_PLL_MULTIPLIER, 0, 0, D_LEN_WORD}, {REG_VT_SYS_CLK_DIV, 0, 0, D_LEN_WORD}, {REG_VT_PIX_CLK_DIV, 0, 0, D_LEN_WORD}, {REG_OP_SYS_CLK_DIV, 0, 0, D_LEN_WORD}, {REG_OP_PIX_CLK_DIV, 0, 0, D_LEN_WORD}, {REG_FRAME_COUNT, 0, 0, D_LEN_BYTE}, }; struct vb6801_i2c_reg_conf_t wreg2[] = { {REG_POWER_MAN_ENABLE_3, 0, 95, D_LEN_BYTE}, {REG_POWER_MAN_ENABLE_4, 0, 142, D_LEN_BYTE}, {REG_POWER_MAN_ENABLE_5, 0, 7, D_LEN_BYTE}, }; /* VIDEO TIMING CALCULATIONS * ========================= */ /* Pixel Array Size */ x_pixel_array = 2064; y_pixel_array = 1544; /* set current resolution */ vb6801_ctrl->curr_res = res; /* Analogue binning setup */ if (pinfo->analog_binning_allowed > 0 && pinfo->sub_sampling_factor == 4) { pinfo->vtiming_major = 1; pinfo->analog_timing_modes_4 = 32; } else if (pinfo->analog_binning_allowed > 0 && pinfo->sub_sampling_factor == 2) { pinfo->vtiming_major = 1; pinfo->analog_timing_modes_4 = 0; } else { pinfo->vtiming_major = 0; pinfo->analog_timing_modes_4 = 0; } /* Sub-Sampling X & Y Odd Increments: valid values 1, 3, 5, 7 */ x_even_inc = 1; y_even_inc = 1; x_odd_inc = (sub_sampling_factor << 1) - x_even_inc; y_odd_inc = (sub_sampling_factor << 1) - y_even_inc; /* Output image size * Must always be a multiple of 2 - round down */ x_output_size = ((x_pixel_array / sub_sampling_factor) >> 1) << 1; y_output_size = ((y_pixel_array / sub_sampling_factor) >> 1) << 1; /* Output data format */ ccp2_data_format = (raw_mode << 8) + raw_mode; /* Pre PLL clock divider : valid values 1, 2 or 4 * The 1st step is to ensure that PLL input frequency is as close * as possible to the min allowed PLL input frequency. * This yields the smallest step size in the PLL output frequency. */ pre_pll_clk_div = ((int)(ext_clk_freq_mhz / min_pll_ip_freq_mhz) >> 1) << 1; if (pre_pll_clk_div < 2) pre_pll_clk_div = 1; pll_ip_freq_mhz = ext_clk_freq_mhz / pre_pll_clk_div; /* Video Timing System Clock divider: valid values 1, 2, 4 * Now need to work backwards through the clock tree to determine the * 1st pass estimates for vt_sys_clk_freq_mhz and then the PLL output * frequency.*/ vt_sys_clk_freq_mhz = vt_pix_clk_div * target_vt_pix_clk_freq_mhz; vt_sys_clk_div = max_pll_op_freq_mhz / vt_sys_clk_freq_mhz; if (vt_sys_clk_div < 2) vt_sys_clk_div = 1; /* PLL Mulitplier: min , max 106 */ pll_op_freq_mhz = vt_sys_clk_div * vt_sys_clk_freq_mhz; pll_multiplier = (pll_op_freq_mhz * 0x0001000) / pll_ip_freq_mhz; /* Calculate the acutal pll output frequency * - the pll_multiplier calculation introduces a quantisation error * due the integer nature of the pll multiplier */ pll_op_freq_mhz = (pll_ip_freq_mhz * pll_multiplier) / 0x0001000; /* Re-calculate video timing clock frequencies based * on actual PLL freq */ vt_sys_clk_freq_mhz = pll_op_freq_mhz / vt_sys_clk_div; vt_pix_clk_freq_mhz = ((vt_sys_clk_freq_mhz * 0x0001000) / vt_pix_clk_div)/0x0001000; /* Output System Clock Divider: valid value 1, 2, 4, 6, 8 * op_sys_clk_div = vt_sys_clk_div;*/ op_sys_clk_div = (vt_sys_clk_div * sub_sampling_factor); if (op_sys_clk_div < 2) op_sys_clk_div = 1; /* Calculate output timing clock frequencies */ op_sys_clk_freq_mhz = pll_op_freq_mhz / op_sys_clk_div; op_pix_clk_freq_mhz = (op_sys_clk_freq_mhz * 0x0001000) / (op_pix_clk_div * 0x0001000); /* Line length in pixels and us */ vt_line_length_pck = 2500; vt_line_length_us = vt_line_length_pck * 0x0001000 / vt_pix_clk_freq_mhz; /* Target vt_frame_length_ms */ target_vt_frame_length_ms = (1000 * 0x0001000 / target_frame_rate_fps); /* Frame length in lines */ min_vt_frame_length_lines = additional_rows + y_output_size + min_vt_frame_blanking_lines; vt_frame_length_lines = ((1000 * target_vt_frame_length_ms) / vt_line_length_us); if (vt_frame_length_lines <= min_vt_frame_length_lines) vt_frame_length_lines = min_vt_frame_length_lines; /* Calcuate the actual frame length in ms */ vt_frame_length_ms = (vt_frame_length_lines * vt_line_length_us / 1000); /* Frame Rate in fps */ frame_rate_fps = (1000 * 0x0001000 / vt_frame_length_ms); /* Set coarse integration to max */ coarse_integration_time = vt_frame_length_lines - coarse_integration_time_max_margin; CDBG("SENSOR VIDEO TIMING SUMMARY:\n"); CDBG(" ============================\n"); CDBG("ext_clk_freq_mhz = %d\n", ext_clk_freq_mhz); CDBG("pre_pll_clk_div = %d\n", pre_pll_clk_div); CDBG("pll_ip_freq_mhz = %d\n", pll_ip_freq_mhz); CDBG("pll_multiplier = %d\n", pll_multiplier); CDBG("pll_op_freq_mhz = %d\n", pll_op_freq_mhz); CDBG("vt_sys_clk_div = %d\n", vt_sys_clk_div); CDBG("vt_sys_clk_freq_mhz = %d\n", vt_sys_clk_freq_mhz); CDBG("vt_pix_clk_div = %d\n", vt_pix_clk_div); CDBG("vt_pix_clk_freq_mhz = %d\n", vt_pix_clk_freq_mhz); CDBG("op_sys_clk_div = %d\n", op_sys_clk_div); CDBG("op_sys_clk_freq_mhz = %d\n", op_sys_clk_freq_mhz); CDBG("op_pix_clk_div = %d\n", op_pix_clk_div); CDBG("op_pix_clk_freq_mhz = %d\n", op_pix_clk_freq_mhz); CDBG("vt_line_length_pck = %d\n", vt_line_length_pck); CDBG("vt_line_length_us = %d\n", vt_line_length_us/0x0001000); CDBG("vt_frame_length_lines = %d\n", vt_frame_length_lines); CDBG("vt_frame_length_ms = %d\n", vt_frame_length_ms/0x0001000); CDBG("frame_rate_fps = %d\n", frame_rate_fps); CDBG("ccp2_data_format = %d\n", ccp2_data_format); CDBG("x_output_size = %d\n", x_output_size); CDBG("y_output_size = %d\n", y_output_size); CDBG("x_odd_inc = %d\n", x_odd_inc); CDBG("y_odd_inc = %d\n", y_odd_inc); CDBG("(vt_frame_length_lines * frame_rate_factor ) = %d\n", (vt_frame_length_lines * vb6801_ctrl->factor_fps)); CDBG("coarse_integration_time = %d\n", coarse_integration_time); CDBG("pinfo->vcm_dac_code = %d\n", pinfo->vcm_dac_code); CDBG("capture_mode = %d\n", capture_mode); /* RE-CONFIGURE SENSOR WITH NEW TIMINGS * ==================================== * Enter Software Standby Mode */ rc = vb6801_i2c_write_b(REG_MODE_SELECT, 0); if (rc < 0) { CDBG("I2C vb6801_i2c_write_b FAILED!!!\n"); return rc; } /* Wait 100ms */ mdelay(100); if (capture_mode == 0) { rc = vb6801_i2c_write_b(REG_CCP2_CHANNEL_IDENTIFIER, 0); rc = vb6801_i2c_write_b(REG_CCP2_SIGNALLING_MODE, 0); } else if (capture_mode == 1) { rc = vb6801_i2c_write_b(REG_CCP2_CHANNEL_IDENTIFIER, 0); rc = vb6801_i2c_write_b(REG_CCP2_SIGNALLING_MODE, 1); } { struct vb6801_i2c_reg_conf_t wreg[] = { /* Re-configure Sensor */ {REG_CCP2_DATA_FORMAT, ccp2_data_format, 0, D_LEN_WORD}, {REG_ANALOGUE_GAIN_CODE_GLOBAL, 128, 0, D_LEN_WORD}, {REG_PRE_PLL_CLK_DIV, pre_pll_clk_div, 0, D_LEN_WORD}, {REG_VT_SYS_CLK_DIV, vt_sys_clk_div, 0, D_LEN_WORD}, {REG_VT_PIX_CLK_DIV, vt_pix_clk_div, 0, D_LEN_WORD}, {REG_OP_SYS_CLK_DIV, vt_sys_clk_div, 0, D_LEN_WORD}, {REG_OP_PIX_CLK_DIV, vt_pix_clk_div, 0, D_LEN_WORD}, {REG_VT_LINE_LENGTH_PCK, vt_line_length_pck, 0, D_LEN_WORD}, {REG_X_OUTPUT_SIZE, x_output_size, 0, D_LEN_WORD}, {REG_Y_OUTPUT_SIZE, y_output_size, 0, D_LEN_WORD}, {REG_X_ODD_INC, x_odd_inc, 0, D_LEN_WORD}, {REG_Y_ODD_INC, y_odd_inc, 0, D_LEN_WORD}, {REG_VT_FRAME_LENGTH_LINES, vt_frame_length_lines * vb6801_ctrl->factor_fps, 0, D_LEN_WORD}, {REG_COARSE_INTEGRATION_TIME, coarse_integration_time, 0, D_LEN_WORD}, /* Analogue Settings */ {REG_ANALOG_TIMING_MODES_2, 0, 132, D_LEN_BYTE}, {REG_RAMP_SCALE, 0, 5, D_LEN_BYTE}, {REG_BTL_LEVEL_SETUP, 0, 11, D_LEN_BYTE}, /* Enable Defect Correction */ {REG_SCYTHE_ENABLE, 0, 1, D_LEN_BYTE}, {REG_SCYTHE_WEIGHT, 0, 16, D_LEN_BYTE}, {REG_BRUCE_ENABLE, 0, 1, D_LEN_BYTE}, /* Auto Focus Configuration * Please note that the DAC Code is a written as a * 16-bit value 0 = infinity (no DAC current) */ {REG_VCM_DAC_CODE, pinfo->vcm_dac_code, 0, D_LEN_WORD}, {REG_VCM_DAC_STROBE, 0, 0, D_LEN_BYTE}, {REG_VCM_DAC_ENABLE, 0, 1, D_LEN_BYTE}, }; rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg)); if (rc < 0) { CDBG("I2C Write Table FAILED!!!\n"); return rc; } } /* Parallel Interface Configuration */ if (capture_mode >= 2) { struct vb6801_i2c_reg_conf_t wreg1[] = { {REG_OP_CODER_SYNC_CLK_SETUP, 0, 15, D_LEN_BYTE}, {REG_OP_CODER_ENABLE, 0, 3, D_LEN_BYTE}, {REG_OP_CODER_SLOW_PAD_EN, 0, 1, D_LEN_BYTE}, {REG_OP_CODER_AUTOMATIC_MODE_ENABLE, 0, 3, D_LEN_BYTE}, {REG_OP_CODER_AUTO_STARTUP, 0, 2, D_LEN_BYTE}, }; rc = vb6801_i2c_write_table(wreg1, ARRAY_SIZE(wreg1)); if (rc < 0) { CDBG("I2C Write Table FAILED!!!\n"); return rc; } } /* Enter Streaming Mode */ rc = vb6801_i2c_write_b(REG_MODE_SELECT, 1); if (rc < 0) { CDBG("I2C Write Table FAILED!!!\n"); return rc; } /* Wait until the sensor starts streaming * Poll until the reported frame_count value is != 0xFF */ frame_count = 0xFF; timeout = 2000; while (frame_count == 0xFF && timeout > 0) { rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); if (rc < 0) return rc; CDBG("REG_FRAME_COUNT = 0x%x\n", frame_count); timeout--; } /* Post Streaming Configuration */ rc = vb6801_i2c_write_table(wreg2, ARRAY_SIZE(wreg2)); if (rc < 0) { CDBG("I2C Write Table FAILED!!!\n"); return rc; } rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg)); if (rc < 0) { CDBG("I2C Read Table FAILED!!!\n"); return rc; } CDBG("REG_PRE_PLL_CLK_DIV = 0x%x\n", rreg[0].wdata); CDBG("REG_PLL_MULTIPLIER = 0x%x\n", rreg[1].wdata); CDBG("REG_VT_SYS_CLK_DIV = 0x%x\n", rreg[2].wdata); CDBG("REG_VT_PIX_CLK_DIV = 0x%x\n", rreg[3].wdata); CDBG("REG_OP_SYS_CLK_DIV = 0x%x\n", rreg[4].wdata); CDBG("REG_OP_PIX_CLK_DIV = 0x%x\n", rreg[5].wdata); CDBG("REG_FRAME_COUNT = 0x%x\n", rreg[6].bdata); mdelay(50); frame_count = 0; rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); CDBG("REG_FRAME_COUNT1 = 0x%x\n", frame_count); mdelay(150); frame_count = 0; rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); CDBG("REG_FRAME_COUNT2 = 0x%x\n", frame_count); mdelay(100); frame_count = 0; rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); CDBG("REG_FRAME_COUNT3 = 0x%x\n", frame_count); mdelay(250); frame_count = 0; rc = vb6801_i2c_read(REG_FRAME_COUNT, &frame_count, 1); CDBG("REG_FRAME_COUNT4 = 0x%x\n", frame_count); return rc; } static int vb6801_sensor_init_done(const struct msm_camera_sensor_info *data) { gpio_direction_output(data->sensor_reset, 0); gpio_free(data->sensor_reset); return 0; } static int vb6801_init_client(struct i2c_client *client) { /* Initialize the MSM_CAMI2C Chip */ init_waitqueue_head(&vb6801_wait_queue); return 0; } static int32_t vb6801_video_config(int mode, int res) { int32_t rc = 0; vb6801_ctrl->prev_res = res; vb6801_ctrl->curr_res = res; vb6801_ctrl->sensormode = mode; rc = vb6801_config_sensor(12, 30, 60, 2, 1, 10, 2, RES_PREVIEW); if (rc < 0) return rc; rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, &vb6801_ctrl->s_dynamic_params. preview_pixelsPerLine, 2); if (rc < 0) return rc; rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, &vb6801_ctrl->s_dynamic_params. preview_linesPerFrame, 2); return rc; } static int32_t vb6801_snapshot_config(int mode, int res) { int32_t rc = 0; vb6801_ctrl->curr_res = vb6801_ctrl->pict_res; vb6801_ctrl->sensormode = mode; rc = vb6801_config_sensor(12, 12, 48, 1, 1, 10, 2, RES_CAPTURE); if (rc < 0) return rc; rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, &vb6801_ctrl->s_dynamic_params. snapshot_pixelsPerLine, 2); if (rc < 0) return rc; rc = vb6801_i2c_read(REG_VT_LINE_LENGTH_PCK, &vb6801_ctrl->s_dynamic_params. snapshot_linesPerFrame, 2); return rc; } static int32_t vb6801_set_sensor_mode(int mode, int res) { int32_t rc = 0; switch (mode) { case SENSOR_PREVIEW_MODE: rc = vb6801_video_config(mode, res); break; case SENSOR_SNAPSHOT_MODE: case SENSOR_RAW_SNAPSHOT_MODE: rc = vb6801_snapshot_config(mode, res); break; default: rc = -EINVAL; break; } return rc; } int vb6801_sensor_config(void __user *argp) { struct sensor_cfg_data cdata; long rc = 0; if (copy_from_user(&cdata, (void *)argp, sizeof(struct sensor_cfg_data))) return -EFAULT; mutex_lock(&vb6801_mut); CDBG("vb6801_sensor_config, cfgtype = %d\n", cdata.cfgtype); switch (cdata.cfgtype) { case CFG_GET_PICT_FPS: vb6801_get_pict_fps(cdata.cfg.gfps.prevfps, &(cdata.cfg.gfps.pictfps)); if (copy_to_user((void *)argp, &cdata, sizeof(struct sensor_cfg_data))) rc = -EFAULT; break; case CFG_GET_PREV_L_PF: cdata.cfg.prevl_pf = vb6801_get_prev_lines_pf(); if (copy_to_user((void *)argp, &cdata, sizeof(struct sensor_cfg_data))) rc = -EFAULT; break; case CFG_GET_PREV_P_PL: cdata.cfg.prevp_pl = vb6801_get_prev_pixels_pl(); if (copy_to_user((void *)argp, &cdata, sizeof(struct sensor_cfg_data))) rc = -EFAULT; break; case CFG_GET_PICT_L_PF: cdata.cfg.pictl_pf = vb6801_get_pict_lines_pf(); if (copy_to_user((void *)argp, &cdata, sizeof(struct sensor_cfg_data))) rc = -EFAULT; break; case CFG_GET_PICT_P_PL: cdata.cfg.pictp_pl = vb6801_get_pict_pixels_pl(); if (copy_to_user((void *)argp, &cdata, sizeof(struct sensor_cfg_data))) rc = -EFAULT; break; case CFG_GET_PICT_MAX_EXP_LC: cdata.cfg.pict_max_exp_lc = vb6801_get_pict_max_exp_lc(); if (copy_to_user((void *)argp, &cdata, sizeof(struct sensor_cfg_data))) rc = -EFAULT; break; case CFG_SET_FPS: case CFG_SET_PICT_FPS: rc = vb6801_set_fps(&(cdata.cfg.fps)); break; case CFG_SET_EXP_GAIN: rc = vb6801_write_exp_gain(cdata.cfg.exp_gain.gain, cdata.cfg.exp_gain.line); break; case CFG_SET_PICT_EXP_GAIN: rc = vb6801_set_pict_exp_gain(cdata.cfg.exp_gain.gain, cdata.cfg.exp_gain.line); break; case CFG_SET_MODE: rc = vb6801_set_sensor_mode(cdata.mode, cdata.rs); break; case CFG_PWR_DOWN: rc = vb6801_power_down(); break; case CFG_MOVE_FOCUS: rc = vb6801_move_focus(cdata.cfg.focus.dir, cdata.cfg.focus.steps); break; case CFG_SET_DEFAULT_FOCUS: rc = vb6801_set_default_focus(); break; default: rc = -EFAULT; break; } mutex_unlock(&vb6801_mut); return rc; } static int vb6801_sensor_release(void) { int rc = -EBADF; mutex_lock(&vb6801_mut); vb6801_power_down(); vb6801_sensor_init_done(vb6801_ctrl->sensordata); kfree(vb6801_ctrl); mutex_unlock(&vb6801_mut); return rc; } static int vb6801_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { rc = -ENOTSUPP; goto probe_failure; } vb6801_sensorw = kzalloc(sizeof(struct vb6801_work_t), GFP_KERNEL); if (!vb6801_sensorw) { rc = -ENOMEM; goto probe_failure; } i2c_set_clientdata(client, vb6801_sensorw); vb6801_init_client(client); vb6801_client = client; vb6801_client->addr = vb6801_client->addr >> 1; return 0; probe_failure: if (vb6801_sensorw != NULL) { kfree(vb6801_sensorw); vb6801_sensorw = NULL; } return rc; } static int __exit vb6801_i2c_remove(struct i2c_client *client) { struct vb6801_work_t *sensorw = i2c_get_clientdata(client); free_irq(client->irq, sensorw); vb6801_client = NULL; kfree(sensorw); return 0; } static const struct i2c_device_id vb6801_i2c_id[] = { {"vb6801", 0}, {} }; static struct i2c_driver vb6801_i2c_driver = { .id_table = vb6801_i2c_id, .probe = vb6801_i2c_probe, .remove = __exit_p(vb6801_i2c_remove), .driver = { .name = "vb6801", }, }; static int vb6801_probe_init_sensor(const struct msm_camera_sensor_info *data) { int rc; struct vb6801_i2c_reg_conf_t rreg[] = { {0x0000, 0, 0, D_LEN_BYTE}, {0x0001, 0, 0, D_LEN_BYTE}, }; rc = vb6801_reset(data); if (rc < 0) goto init_probe_done; mdelay(20); rc = vb6801_i2c_read_table(rreg, ARRAY_SIZE(rreg)); if (rc < 0) { CDBG("I2C Read Table FAILED!!!\n"); goto init_probe_fail; } /* 4. Compare sensor ID to VB6801 ID: */ if (rreg[0].bdata != 0x03 || rreg[1].bdata != 0x53) { CDBG("vb6801_sensor_init: sensor ID don't match!\n"); goto init_probe_fail; } goto init_probe_done; init_probe_fail: vb6801_sensor_init_done(data); init_probe_done: return rc; } int vb6801_sensor_open_init(const struct msm_camera_sensor_info *data) { int32_t rc; struct vb6801_i2c_reg_conf_t wreg[] = { {REG_MODE_SELECT, 0, STANDBY_MODE, D_LEN_BYTE}, {0x0113, 0, 0x0A, D_LEN_BYTE}, }; vb6801_ctrl = kzalloc(sizeof(struct vb6801_ctrl_t), GFP_KERNEL); if (!vb6801_ctrl) { rc = -ENOMEM; goto open_init_fail1; } vb6801_ctrl->factor_fps = 1 /** 0x00000400*/ ; vb6801_ctrl->curr_fps = 7680; /* 30 * Q8 */ ; vb6801_ctrl->max_fps = 7680; /* 30 * Q8 */ ; vb6801_ctrl->pict_exp_update = 0; /* 30 * Q8 */ ; vb6801_ctrl->reducel = 0; /* 30 * Q8 */ ; vb6801_ctrl->set_test = TEST_OFF; vb6801_ctrl->prev_res = QTR_SIZE; vb6801_ctrl->pict_res = FULL_SIZE; vb6801_ctrl->s_dynamic_params.preview_linesPerFrame = VB6801_LINES_PER_FRAME_PREVIEW; vb6801_ctrl->s_dynamic_params.preview_pixelsPerLine = VB6801_PIXELS_PER_LINE_PREVIEW; vb6801_ctrl->s_dynamic_params.snapshot_linesPerFrame = VB6801_LINES_PER_FRAME_SNAPSHOT; vb6801_ctrl->s_dynamic_params.snapshot_pixelsPerLine = VB6801_PIXELS_PER_LINE_SNAPSHOT; if (data) vb6801_ctrl->sensordata = data; /* enable mclk first */ msm_camio_clk_rate_set(VB6801_DEFAULT_CLOCK_RATE); mdelay(20); rc = vb6801_reset(data); if (rc < 0) goto open_init_fail1; rc = vb6801_i2c_write_table(wreg, ARRAY_SIZE(wreg)); if (rc < 0) { CDBG("I2C Write Table FAILED!!!\n"); goto open_init_fail2; } rc = vb6801_read_nvm_data(&vb6801_ctrl->s_info); if (rc < 0) { CDBG("vb6801_read_nvm_data FAILED!!!\n"); goto open_init_fail2; } mdelay(66); rc = vb6801_config_sensor(12, 30, 60, 2, 1, 10, 2, RES_PREVIEW); if (rc < 0) goto open_init_fail2; goto open_init_done; open_init_fail2: vb6801_sensor_init_done(data); open_init_fail1: kfree(vb6801_ctrl); open_init_done: return rc; } static int vb6801_sensor_probe(const struct msm_camera_sensor_info *info, struct msm_sensor_ctrl *s) { int rc = i2c_add_driver(&vb6801_i2c_driver); if (rc < 0 || vb6801_client == NULL) { rc = -ENOTSUPP; goto probe_done; } /* enable mclk first */ msm_camio_clk_rate_set(VB6801_DEFAULT_CLOCK_RATE); mdelay(20); rc = vb6801_probe_init_sensor(info); if (rc < 0) goto probe_done; s->s_init = vb6801_sensor_open_init; s->s_release = vb6801_sensor_release; s->s_config = vb6801_sensor_config; s->s_mount_angle = 0; vb6801_sensor_init_done(info); probe_done: return rc; } static int __vb6801_probe(struct platform_device *pdev) { return msm_camera_drv_start(pdev, vb6801_sensor_probe); } static struct platform_driver msm_camera_driver = { .probe = __vb6801_probe, .driver = { .name = "msm_camera_vb6801", .owner = THIS_MODULE, }, }; static int __init vb6801_init(void) { return platform_driver_register(&msm_camera_driver); } module_init(vb6801_init); void vb6801_exit(void) { i2c_del_driver(&vb6801_i2c_driver); }