3105 lines
81 KiB
C

/*
* Copyright (C) 2008-2009 QUALCOMM Incorporated.
*/
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <media/msm_camera.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/camera.h>
#include <linux/clk.h>
#include <linux/wakelock.h>
static uint16_t g_usModuleVersion; /*0: rev.4, 1: rev.5 */
/* prepare for modify PCLK*/
#define REG_PLL_MULTIPLIER_LSB_VALUE 0x90
/* 0xA0 for PCLK=80MHz */
/* 0x90 for PCLK=72MHz */
/* prepare for modify initial gain*/
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE 0x80
#define S5K3E2FX_REG_MODEL_ID 0x0000
#define S5K3E2FX_MODEL_ID 0x3E2F
#define S5K3E2FX_REG_MODULE_VER 0x0002
#define S5K3E2FX_DEF_MCLK 24000000
#define S5K3E2FX_QTR_SIZE_WIDTH 1296
#define S5K3E2FX_QTR_SIZE_HEIGHT 972
#define S5K3E2FX_FULL_SIZE_WIDTH 2608
#define S5K3E2FX_FULL_SIZE_HEIGHT 1960
/* AEC_FLASHING */
#define REG_GROUPED_PARAMETER_HOLD 0x0104
#define GROUPED_PARAMETER_HOLD 0x01
#define GROUPED_PARAMETER_UPDATE 0x00
/* Greenish in low light */
#define REG_MASK_CORRUPTED_FRAMES 0x0105
#define MASK 0x01
#define NO_MASK 0x00
/* PLL Registers */
#define REG_PRE_PLL_CLK_DIV 0x0305
#define REG_PLL_MULTIPLIER_MSB 0x0306
#define REG_PLL_MULTIPLIER_LSB 0x0307
#define REG_VT_PIX_CLK_DIV 0x0301
#define REG_VT_SYS_CLK_DIV 0x0303
#define REG_OP_PIX_CLK_DIV 0x0309
#define REG_OP_SYS_CLK_DIV 0x030B
/* Data Format Registers */
#define REG_CCP_DATA_FORMAT_MSB 0x0112
#define REG_CCP_DATA_FORMAT_LSB 0x0113
/* Output Size */
#define REG_X_OUTPUT_SIZE_MSB 0x034C
#define REG_X_OUTPUT_SIZE_LSB 0x034D
#define REG_Y_OUTPUT_SIZE_MSB 0x034E
#define REG_Y_OUTPUT_SIZE_LSB 0x034F
/* Binning */
#define REG_X_EVEN_INC 0x0381
#define REG_X_ODD_INC 0x0383
#define REG_Y_EVEN_INC 0x0385
#define REG_Y_ODD_INC 0x0387
/*Reserved register */
#define REG_BINNING_ENABLE 0x3014
/* Frame Fotmat */
#define REG_FRAME_LENGTH_LINES_MSB 0x0340
#define REG_FRAME_LENGTH_LINES_LSB 0x0341
#define REG_LINE_LENGTH_PCK_MSB 0x0342
#define REG_LINE_LENGTH_PCK_LSB 0x0343
/* MSR setting */
/* Reserved registers */
#define REG_SHADE_CLK_ENABLE 0x30AC
#define REG_SEL_CCP 0x30C4
#define REG_VPIX 0x3024
#define REG_CLAMP_ON 0x3015
#define REG_OFFSET 0x307E
/* CDS timing settings */
/* Reserved registers */
#define REG_LD_START 0x3000
#define REG_LD_END 0x3001
#define REG_SL_START 0x3002
#define REG_SL_END 0x3003
#define REG_RX_START 0x3004
#define REG_S1_START 0x3005
#define REG_S1_END 0x3006
#define REG_S1S_START 0x3007
#define REG_S1S_END 0x3008
#define REG_S3_START 0x3009
#define REG_S3_END 0x300A
#define REG_CMP_EN_START 0x300B
#define REG_CLP_SL_START 0x300C
#define REG_CLP_SL_END 0x300D
#define REG_OFF_START 0x300E
#define REG_RMP_EN_START 0x300F
#define REG_TX_START 0x3010
#define REG_TX_END 0x3011
#define REG_STX_WIDTH 0x3012
#define REG_TYPE1_AF_ENABLE 0x3130
#define DRIVER_ENABLED 0x0001
#define AUTO_START_ENABLED 0x0010
#define REG_NEW_POSITION 0x3131
#define REG_3152_RESERVED 0x3152
#define REG_315A_RESERVED 0x315A
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205
#define REG_FINE_INTEGRATION_TIME 0x0200
#define REG_COARSE_INTEGRATION_TIME 0x0202
#define REG_COARSE_INTEGRATION_TIME_LSB 0x0203
/* Mode select register */
#define S5K3E2FX_REG_MODE_SELECT 0x0100
#define S5K3E2FX_MODE_SELECT_STREAM 0x01 /* start streaming */
#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00 /* software standby */
#define S5K3E2FX_REG_SOFTWARE_RESET 0x0103
#define S5K3E2FX_SOFTWARE_RESET 0x01
#define REG_TEST_PATTERN_MODE 0x0601
/* Samsung other MSR setting*/
#define REG_301D_RESERVED 0x301D
#define REG_3028_RESERVED 0x3028
#define REG_3070_RESERVED 0x3070
#define REG_3072_RESERVED 0x3072
#define REG_301B_RESERVED 0x301B
#define REG_30BD_RESERVED 0x30BD
#define REG_30C2_RESERVED 0x30C2
#define REG_3151_RESERVED 0x3151
#define REG_3029_RESERVED 0x3029
#define REG_30BF_RESERVED 0x30BF
#define REG_3022_RESERVED 0x3022
#define REG_3019_RESERVED 0x3019
#define REG_3150_RESERVED 0x3150
#define REG_3157_RESERVED 0x3157
#define REG_3159_RESERVED 0x3159
/* LC Preview/Snapshot difference register */
#define REG_SH4CH_BLK_WIDTH_R 0x309E
#define REG_SH4CH_BLK_HEIGHT_R 0x309F
#define REG_SH4CH_STEP_X_R_MSB 0x30A0
#define REG_SH4CH_STEP_X_R_LSB 0x30A1
#define REG_SH4CH_STEP_Y_R_MSB 0x30A2
#define REG_SH4CH_STEP_Y_R_LSB 0x30A3
#define REG_SH4CH_START_BLK_CNT_X_R 0x30A4
#define REG_SH4CH_START_BLK_INT_X_R 0x30A5
#define REG_SH4CH_START_FRAC_X_R_MSB 0x30A6
#define REG_SH4CH_START_FRAC_X_R_LSB 0x30A7
#define REG_SH4CH_START_BLK_CNT_Y_R 0x30A8
#define REG_SH4CH_START_BLK_INT_Y_R 0x30A9
#define REG_SH4CH_START_FRAC_Y_R_MSB 0x30AA
#define REG_SH4CH_START_FRAC_Y_R_LSB 0x30AB
#define REG_X_ADDR_START_MSB 0x0344
#define REG_X_ADDR_START_LSB 0x0345
#define REG_Y_ADDR_START_MSB 0x0346
#define REG_Y_ADDR_START_LSB 0x0347
#define REG_X_ADDR_END_MSB 0x0348
#define REG_X_ADDR_END_LSB 0x0349
#define REG_Y_ADDR_END_MSB 0x034A
#define REG_Y_ADDR_END_LSB 0x034B
#define NUM_INIT_REG 94
#define NUM_LC_REG 434
struct s5k3e2fx_i2c_reg_conf {
unsigned short waddr;
unsigned char bdata;
};
/* Separate the EVT4/EVT5 sensor init and LC setting start */
struct s5k3e2fx_i2c_reg_conf Init_setting[2][NUM_INIT_REG] = {
/*EVT4 */
{
{REG_PRE_PLL_CLK_DIV, 0x06}, /* PLL setting */
{REG_PLL_MULTIPLIER_MSB, 0x00},
{REG_PLL_MULTIPLIER_LSB, REG_PLL_MULTIPLIER_LSB_VALUE},
{REG_VT_PIX_CLK_DIV, 0x08},
{REG_VT_SYS_CLK_DIV, 0x01},
{REG_OP_PIX_CLK_DIV, 0x08},
{REG_OP_SYS_CLK_DIV, 0x01},
/* Data Format */
{REG_CCP_DATA_FORMAT_MSB, 0x0a},
{REG_CCP_DATA_FORMAT_LSB, 0x0a},
/* Preview Output Size */
{REG_X_OUTPUT_SIZE_MSB, 0x05},
{REG_X_OUTPUT_SIZE_LSB, 0x10},
{REG_Y_OUTPUT_SIZE_MSB, 0x03},
{REG_Y_OUTPUT_SIZE_LSB, 0xcc},
{REG_X_ADDR_START_MSB, 0x00},
{REG_X_ADDR_START_LSB, 0x08},
{REG_Y_ADDR_START_MSB, 0x00},
{REG_Y_ADDR_START_LSB, 0x08},
{REG_X_ADDR_END_MSB, 0x0a},
{REG_X_ADDR_END_LSB, 0x27},
{REG_Y_ADDR_END_MSB, 0x07},
{REG_Y_ADDR_END_LSB, 0x9f},
/* Frame format */
{REG_FRAME_LENGTH_LINES_MSB, 0x03},
{REG_FRAME_LENGTH_LINES_LSB, 0xe2},
{REG_LINE_LENGTH_PCK_MSB, 0x0a},
{REG_LINE_LENGTH_PCK_LSB, 0xac},
/* Preview Binning */
{REG_X_EVEN_INC, 0x01},
{REG_X_ODD_INC, 0x01},
{REG_Y_EVEN_INC, 0x01},
{REG_Y_ODD_INC, 0x03},
{REG_BINNING_ENABLE, 0x06},
/* Samsung MSR Setting */
{REG_SEL_CCP, 0x01},
{REG_LD_START, 0x03},
/* Add EVT5 sensor Samsung MSR setting, Start */
{REG_LD_END, 0x94},
{REG_SL_START, 0x02},
{REG_SL_END, 0x95},
{REG_RX_START, 0x0f},
{REG_S1_START, 0x05},
{REG_S1_END, 0x3c},
{REG_S1S_START, 0x8c},
{REG_S1S_END, 0x93},
{REG_S3_START, 0x05},
{REG_S3_END, 0x3a},
{REG_CMP_EN_START, 0x10},
{REG_CLP_SL_START, 0x02},
{REG_CLP_SL_END, 0x3e},
{REG_OFF_START, 0x02},
{REG_RMP_EN_START, 0x0e},
{REG_TX_START, 0x46},
{REG_TX_END, 0x64},
{REG_STX_WIDTH, 0x1e},
{REG_CLAMP_ON, 0x00},
{REG_301D_RESERVED, 0x3f},
{REG_VPIX, 0x04},
{REG_3028_RESERVED, 0x40},
{REG_3070_RESERVED, 0xdf},
{REG_3072_RESERVED, 0x20},
{REG_301B_RESERVED, 0x73},
{REG_OFFSET, 0x02},
{REG_30BD_RESERVED, 0x06},
{REG_30C2_RESERVED, 0x0b},
{REG_SHADE_CLK_ENABLE, 0x81},
{REG_3151_RESERVED, 0xe6},
{REG_3029_RESERVED, 0x02},
{REG_30BF_RESERVED, 0x00},
{REG_3022_RESERVED, 0x87},
{REG_3019_RESERVED, 0x60},
{REG_3019_RESERVED, 0x60},
{REG_3019_RESERVED, 0x60},
{REG_3019_RESERVED, 0x60},
{REG_3019_RESERVED, 0x60},
{REG_3019_RESERVED, 0x60},
{REG_3152_RESERVED, 0x08},
{REG_3150_RESERVED, 0x50}, /* from 0x40 to 0x50 for PCLK=80MHz */
/* Inverse PCLK = 0x50 */
{REG_3157_RESERVED, 0x04}, /* from 0x00 to 0x04 for PCLK=80MHz */
/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
{REG_3159_RESERVED, 0x0f}, /* from 0x00 to 0x0f for PCLK=80MHz */
/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
* 11:8mA
*/
{REG_315A_RESERVED, 0xf0}, /* from 0x10 to 0xf0 for PCLK=80MHz */
/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA
* 10:6mA, 11:8mA
*/
/* AEC Setting */
{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, 0x00},
{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE},
{REG_FINE_INTEGRATION_TIME, 0x02},
{REG_COARSE_INTEGRATION_TIME, 0x03},
/* Preview LC config Setting */
{REG_SH4CH_BLK_WIDTH_R, 0x52},
{REG_SH4CH_BLK_HEIGHT_R, 0x3e},
{REG_SH4CH_STEP_X_R_MSB, 0x03},
{REG_SH4CH_STEP_X_R_LSB, 0x1f},
{REG_SH4CH_STEP_Y_R_MSB, 0x04},
{REG_SH4CH_STEP_Y_R_LSB, 0x21},
{REG_SH4CH_START_BLK_CNT_X_R, 0x04},
{REG_SH4CH_START_BLK_INT_X_R, 0x00},
{REG_SH4CH_START_FRAC_X_R_MSB, 0x0c},
{REG_SH4CH_START_FRAC_X_R_LSB, 0x7c},
{REG_SH4CH_START_BLK_CNT_Y_R, 0x04},
{REG_SH4CH_START_BLK_INT_Y_R, 0x00},
{REG_SH4CH_START_FRAC_Y_R_MSB, 0x10},
{REG_SH4CH_START_FRAC_Y_R_LSB, 0x84},
},
/* EVT5 */
{
{REG_PRE_PLL_CLK_DIV, 0x06}, /* PLL setting */
{REG_PLL_MULTIPLIER_MSB, 0x00},
{REG_PLL_MULTIPLIER_LSB, REG_PLL_MULTIPLIER_LSB_VALUE},
{REG_VT_PIX_CLK_DIV, 0x08},
{REG_VT_SYS_CLK_DIV, 0x01},
{REG_OP_PIX_CLK_DIV, 0x08},
{REG_OP_SYS_CLK_DIV, 0x01},
/* Data Format */
{REG_CCP_DATA_FORMAT_MSB, 0x0a},
{REG_CCP_DATA_FORMAT_LSB, 0x0a},
/* Preview Output Size */
{REG_X_OUTPUT_SIZE_MSB, 0x05},
{REG_X_OUTPUT_SIZE_LSB, 0x10},
{REG_Y_OUTPUT_SIZE_MSB, 0x03},
{REG_Y_OUTPUT_SIZE_LSB, 0xcc},
{REG_X_ADDR_START_MSB, 0x00},
{REG_X_ADDR_START_LSB, 0x08},
{REG_Y_ADDR_START_MSB, 0x00},
{REG_Y_ADDR_START_LSB, 0x08},
{REG_X_ADDR_END_MSB, 0x0a},
{REG_X_ADDR_END_LSB, 0x27},
{REG_Y_ADDR_END_MSB, 0x07},
{REG_Y_ADDR_END_LSB, 0x9f},
/* Frame format */
{REG_FRAME_LENGTH_LINES_MSB, 0x03},
{REG_FRAME_LENGTH_LINES_LSB, 0xe2},
{REG_LINE_LENGTH_PCK_MSB, 0x0a},
{REG_LINE_LENGTH_PCK_LSB, 0xac},
/* Preview Binning */
{REG_X_EVEN_INC, 0x01},
{REG_X_ODD_INC, 0x01},
{REG_Y_EVEN_INC, 0x01},
{REG_Y_ODD_INC, 0x03},
{REG_BINNING_ENABLE, 0x06},
/* Samsung MSR Setting */
{REG_SEL_CCP, 0x01},
{REG_LD_START, 0x03},
/* EVT5 sensor Samsung MSR setting */
{REG_LD_END, 0x99},
{REG_SL_START, 0x02},
{REG_SL_END, 0x9A},
{REG_RX_START, 0x0f},
{REG_S1_START, 0x05},
{REG_S1_END, 0x3c},
{REG_S1S_START, 0x8c},
{REG_S1S_END, 0x26},
{REG_S3_START, 0x05},
{REG_S3_END, 0x3a},
{REG_CMP_EN_START, 0x10},
{REG_CLP_SL_START, 0x02},
{REG_CLP_SL_END, 0x3e},
{REG_OFF_START, 0x02},
{REG_RMP_EN_START, 0x0e},
{REG_TX_START, 0x46},
{REG_TX_END, 0x64},
{REG_STX_WIDTH, 0x1e},
{REG_CLAMP_ON, 0x00},
{REG_301D_RESERVED, 0x3f},
{REG_VPIX, 0x04},
{REG_3028_RESERVED, 0x40},
{REG_3070_RESERVED, 0xdf},
{REG_3072_RESERVED, 0x20},
{REG_301B_RESERVED, 0x73},
{REG_OFFSET, 0x02},
{REG_30BD_RESERVED, 0x06},
{REG_30C2_RESERVED, 0x0b},
{REG_SHADE_CLK_ENABLE, 0x81},
{REG_3151_RESERVED, 0xe6},
{REG_3029_RESERVED, 0x02},
{REG_30BF_RESERVED, 0x00},
{REG_3022_RESERVED, 0x87},
{REG_3019_RESERVED, 0x60},
{0x3060, 0x03},
{0x3061, 0x6C},
{0x3062, 0x00},
{0x3063, 0xD6},
{0x3023, 0x0C},
{REG_3152_RESERVED, 0x08},
{REG_3150_RESERVED, 0x50}, /* from 0x40 to 0x50 for PCLK=80MHz */
/* Inverse PCLK = 0x50 */
{REG_3157_RESERVED, 0x04}, /* from 0x00 to 0x04 for PCLK=80MHz */
/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
{REG_3159_RESERVED, 0x0f}, /* from 0x00 to 0x0f for PCLK=80MHz */
/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
* 11:8mA
*/
{REG_315A_RESERVED, 0xf0}, /* from 0x10 to 0xf0 for PCLK=80MHz */
/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA,
* 10:6mA, 11:8mA
*/
/* AEC Setting */
{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, 0x00},
{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE},
{REG_FINE_INTEGRATION_TIME, 0x02},
{REG_COARSE_INTEGRATION_TIME, 0x03},
/* Preview LC config Setting */
{REG_SH4CH_BLK_WIDTH_R, 0x52},
{REG_SH4CH_BLK_HEIGHT_R, 0x3e},
{REG_SH4CH_STEP_X_R_MSB, 0x03},
{REG_SH4CH_STEP_X_R_LSB, 0x1f},
{REG_SH4CH_STEP_Y_R_MSB, 0x04},
{REG_SH4CH_STEP_Y_R_LSB, 0x21},
{REG_SH4CH_START_BLK_CNT_X_R, 0x04},
{REG_SH4CH_START_BLK_INT_X_R, 0x00},
{REG_SH4CH_START_FRAC_X_R_MSB, 0x0c},
{REG_SH4CH_START_FRAC_X_R_LSB, 0x7c},
{REG_SH4CH_START_BLK_CNT_Y_R, 0x04},
{REG_SH4CH_START_BLK_INT_Y_R, 0x00},
{REG_SH4CH_START_FRAC_Y_R_MSB, 0x10},
{REG_SH4CH_START_FRAC_Y_R_LSB, 0x84},
}
};
struct s5k3e2fx_i2c_reg_conf lc_setting[2][NUM_LC_REG] = {
/*EVT4 */
{
/*EVT4 */ /* 100108 Modify LC setting DNP light source t75-r73*/
{0x3200, 0x00},
{0x3201, 0x99},
{0x3202, 0xc1},
{0x3203, 0x0f},
{0x3204, 0xd0},
{0x3205, 0x1b},
{0x3206, 0x00},
{0x3207, 0x24},
{0x3208, 0x8d},
{0x3209, 0x0f},
{0x320a, 0xee},
{0x320b, 0x0f},
{0x320c, 0x00},
{0x320d, 0x04},
{0x320e, 0x5c},
{0x320f, 0x00},
{0x3210, 0x07},
{0x3211, 0x68},
{0x3212, 0x0f},
{0x3213, 0xc2},
{0x3214, 0x82},
{0x3215, 0x00},
{0x3216, 0x29},
{0x3217, 0x3e},
{0x3218, 0x0f},
{0x3219, 0xd3},
{0x321a, 0x63},
{0x321b, 0x00},
{0x321c, 0x22},
{0x321d, 0x6c},
{0x321e, 0x0f},
{0x321f, 0xf8},
{0x3220, 0xce},
{0x3221, 0x0f},
{0x3222, 0xed},
{0x3223, 0x30},
{0x3224, 0x00},
{0x3225, 0x37},
{0x3226, 0x87},
{0x3227, 0x0f},
{0x3228, 0xc2},
{0x3229, 0x87},
{0x322a, 0x00},
{0x322b, 0x2a},
{0x322c, 0xc6},
{0x322d, 0x0f},
{0x322e, 0xf3},
{0x322f, 0xd9},
{0x3230, 0x0f},
{0x3231, 0xea},
{0x3232, 0x1a},
{0x3233, 0x00},
{0x3234, 0x2d},
{0x3235, 0x9f},
{0x3236, 0x0f},
{0x3237, 0xde},
{0x3238, 0x7d},
{0x3239, 0x00},
{0x323a, 0x37},
{0x323b, 0x1e},
{0x323c, 0x0f},
{0x323d, 0xed},
{0x323e, 0x9c},
{0x323f, 0x0f},
{0x3240, 0xf6},
{0x3241, 0xfd},
{0x3242, 0x00},
{0x3243, 0x15},
{0x3244, 0xeb},
{0x3245, 0x0f},
{0x3246, 0xd3},
{0x3247, 0xca},
{0x3248, 0x00},
{0x3249, 0x08},
{0x324a, 0xe6},
{0x324b, 0x0f},
{0x324c, 0xf4},
{0x324d, 0x7a},
{0x324e, 0x0f},
{0x324f, 0xed},
{0x3250, 0x1e},
{0x3251, 0x00},
{0x3252, 0x0d},
{0x3253, 0x46},
{0x3254, 0x00},
{0x3255, 0x0c},
{0x3256, 0x3e},
{0x3257, 0x00},
{0x3258, 0x09},
{0x3259, 0xcf},
{0x325a, 0x00},
{0x325b, 0x09},
{0x325c, 0xb5},
{0x325d, 0x0f},
{0x325e, 0xec},
{0x325f, 0x47},
{0x3260, 0x00},
{0x3261, 0x1d},
{0x3262, 0xd8},
{0x3263, 0x0f},
{0x3264, 0xf7},
{0x3265, 0x11},
{0x3266, 0x0f},
{0x3267, 0xea},
{0x3268, 0x3d},
{0x3269, 0x00},
{0x326a, 0x09},
{0x326b, 0xcc},
{0x326c, 0x00},
{0x326d, 0x9b},
{0x326e, 0x73},
{0x326f, 0x0f},
{0x3270, 0xd4},
{0x3271, 0x9e},
{0x3272, 0x00},
{0x3273, 0x1a},
{0x3274, 0x87},
{0x3275, 0x0f},
{0x3276, 0xfd},
{0x3277, 0xeb},
{0x3278, 0x0f},
{0x3279, 0xf5},
{0x327a, 0xb4},
{0x327b, 0x00},
{0x327c, 0x0d},
{0x327d, 0x8c},
{0x327e, 0x0f},
{0x327f, 0xc9},
{0x3280, 0x4d},
{0x3281, 0x00},
{0x3282, 0x1d},
{0x3283, 0x2d},
{0x3284, 0x0f},
{0x3285, 0xea},
{0x3286, 0x5b},
{0x3287, 0x00},
{0x3288, 0x04},
{0x3289, 0x76},
{0x328a, 0x00},
{0x328b, 0x10},
{0x328c, 0x2d},
{0x328d, 0x0f},
{0x328e, 0xe6},
{0x328f, 0xde},
{0x3290, 0x00},
{0x3291, 0x26},
{0x3292, 0x85},
{0x3293, 0x0f},
{0x3294, 0xcf},
{0x3295, 0x12},
{0x3296, 0x00},
{0x3297, 0x14},
{0x3298, 0x0f},
{0x3299, 0x00},
{0x329a, 0x0b},
{0x329b, 0x36},
{0x329c, 0x0f},
{0x329d, 0xe4},
{0x329e, 0xa4},
{0x329f, 0x00},
{0x32a0, 0x21},
{0x32a1, 0x1f},
{0x32a2, 0x0f},
{0x32a3, 0xf3},
{0x32a4, 0x99},
{0x32a5, 0x00},
{0x32a6, 0x30},
{0x32a7, 0x8f},
{0x32a8, 0x0f},
{0x32a9, 0xf9},
{0x32aa, 0x35},
{0x32ab, 0x0f},
{0x32ac, 0xee},
{0x32ad, 0x6e},
{0x32ae, 0x00},
{0x32af, 0x09},
{0x32b0, 0x19},
{0x32b1, 0x0f},
{0x32b2, 0xf0},
{0x32b3, 0x57},
{0x32b4, 0x00},
{0x32b5, 0x01},
{0x32b6, 0xcc},
{0x32b7, 0x0f},
{0x32b8, 0xf1},
{0x32b9, 0x0b},
{0x32ba, 0x0f},
{0x32bb, 0xee},
{0x32bc, 0x99},
{0x32bd, 0x00},
{0x32be, 0x11},
{0x32bf, 0x3d},
{0x32c0, 0x00},
{0x32c1, 0x10},
{0x32c2, 0x64},
{0x32c3, 0x0f},
{0x32c4, 0xf6},
{0x32c5, 0xab},
{0x32c6, 0x00},
{0x32c7, 0x03},
{0x32c8, 0x19},
{0x32c9, 0x0f},
{0x32ca, 0xf3},
{0x32cb, 0xc9},
{0x32cc, 0x00},
{0x32cd, 0x17},
{0x32ce, 0xb3},
{0x32cf, 0x0f},
{0x32d0, 0xf2},
{0x32d1, 0x3d},
{0x32d2, 0x0f},
{0x32d3, 0xf4},
{0x32d4, 0x7e},
{0x32d5, 0x00},
{0x32d6, 0x09},
{0x32d7, 0x46},
{0x32d8, 0x00},
{0x32d9, 0x7c},
{0x32da, 0x79},
{0x32db, 0x0f},
{0x32dc, 0xde},
{0x32dd, 0x19},
{0x32de, 0x00},
{0x32df, 0x19},
{0x32e0, 0xe8},
{0x32e1, 0x0f},
{0x32e2, 0xf3},
{0x32e3, 0x41},
{0x32e4, 0x00},
{0x32e5, 0x03},
{0x32e6, 0x4c},
{0x32e7, 0x00},
{0x32e8, 0x05},
{0x32e9, 0x73},
{0x32ea, 0x0f},
{0x32eb, 0xd6},
{0x32ec, 0xa5},
{0x32ed, 0x00},
{0x32ee, 0x1f},
{0x32ef, 0x81},
{0x32f0, 0x0f},
{0x32f1, 0xdc},
{0x32f2, 0xe6},
{0x32f3, 0x00},
{0x32f4, 0x18},
{0x32f5, 0x65},
{0x32f6, 0x00},
{0x32f7, 0x00},
{0x32f8, 0x11},
{0x32f9, 0x0f},
{0x32fa, 0xed},
{0x32fb, 0x65},
{0x32fc, 0x00},
{0x32fd, 0x23},
{0x32fe, 0x12},
{0x32ff, 0x0f},
{0x3300, 0xcf},
{0x3301, 0x28},
{0x3302, 0x00},
{0x3303, 0x2b},
{0x3304, 0xda},
{0x3305, 0x0f},
{0x3306, 0xef},
{0x3307, 0xae},
{0x3308, 0x0f},
{0x3309, 0xeb},
{0x330a, 0x13},
{0x330b, 0x00},
{0x330c, 0x27},
{0x330d, 0xb8},
{0x330e, 0x0f},
{0x330f, 0xec},
{0x3310, 0x69},
{0x3311, 0x00},
{0x3312, 0x2f},
{0x3313, 0x5f},
{0x3314, 0x0f},
{0x3315, 0xdf},
{0x3316, 0x4f},
{0x3317, 0x00},
{0x3318, 0x05},
{0x3319, 0x70},
{0x331a, 0x00},
{0x331b, 0x0f},
{0x331c, 0xd2},
{0x331d, 0x0f},
{0x331e, 0xe1},
{0x331f, 0xd8},
{0x3320, 0x00},
{0x3321, 0x09},
{0x3322, 0xcf},
{0x3323, 0x0f},
{0x3324, 0xf2},
{0x3325, 0x6e},
{0x3326, 0x0f},
{0x3327, 0xf6},
{0x3328, 0xb4},
{0x3329, 0x00},
{0x332a, 0x0d},
{0x332b, 0x87},
{0x332c, 0x00},
{0x332d, 0x08},
{0x332e, 0x1e},
{0x332f, 0x0f},
{0x3330, 0xfa},
{0x3331, 0x6e},
{0x3332, 0x0f},
{0x3333, 0xff},
{0x3334, 0xaa},
{0x3335, 0x0f},
{0x3336, 0xf2},
{0x3337, 0xc0},
{0x3338, 0x00},
{0x3339, 0x1d},
{0x333a, 0x18},
{0x333b, 0x0f},
{0x333c, 0xef},
{0x333d, 0xed},
{0x333e, 0x0f},
{0x333f, 0xec},
{0x3340, 0xf6},
{0x3341, 0x00},
{0x3342, 0x16},
{0x3343, 0x8e},
{0x3344, 0x00},
{0x3345, 0x9c},
{0x3346, 0x52},
{0x3347, 0x0f},
{0x3348, 0xcf},
{0x3349, 0xb9},
{0x334a, 0x00},
{0x334b, 0x29},
{0x334c, 0xe9},
{0x334d, 0x0f},
{0x334e, 0xe2},
{0x334f, 0x83},
{0x3350, 0x00},
{0x3351, 0x11},
{0x3352, 0xcc},
{0x3353, 0x0f},
{0x3354, 0xff},
{0x3355, 0xf4},
{0x3356, 0x0f},
{0x3357, 0xc1},
{0x3358, 0xa4},
{0x3359, 0x00},
{0x335a, 0x2f},
{0x335b, 0xce},
{0x335c, 0x0f},
{0x335d, 0xc5},
{0x335e, 0xbb},
{0x335f, 0x00},
{0x3360, 0x35},
{0x3361, 0x2a},
{0x3362, 0x0f},
{0x3363, 0xe6},
{0x3364, 0x2a},
{0x3365, 0x0f},
{0x3366, 0xf7},
{0x3367, 0x44},
{0x3368, 0x00},
{0x3369, 0x31},
{0x336a, 0xfe},
{0x336b, 0x0f},
{0x336c, 0xb6},
{0x336d, 0x84},
{0x336e, 0x00},
{0x336f, 0x3c},
{0x3370, 0x71},
{0x3371, 0x0f},
{0x3372, 0xe5},
{0x3373, 0xfe},
{0x3374, 0x0f},
{0x3375, 0xf2},
{0x3376, 0x87},
{0x3377, 0x00},
{0x3378, 0x29},
{0x3379, 0x2b},
{0x337a, 0x0f},
{0x337b, 0xe5},
{0x337c, 0x3f},
{0x337d, 0x00},
{0x337e, 0x45},
{0x337f, 0xc6},
{0x3380, 0x0f},
{0x3381, 0xdf},
{0x3382, 0xe6},
{0x3383, 0x0f},
{0x3384, 0xfb},
{0x3385, 0x0f},
{0x3386, 0x00},
{0x3387, 0x0f},
{0x3388, 0xf4},
{0x3389, 0x0f},
{0x338a, 0xdf},
{0x338b, 0x72},
{0x338c, 0x00},
{0x338d, 0x0e},
{0x338e, 0xaf},
{0x338f, 0x0f},
{0x3390, 0xed},
{0x3391, 0x7a},
{0x3392, 0x0f},
{0x3393, 0xe5},
{0x3394, 0xab},
{0x3395, 0x00},
{0x3396, 0x18},
{0x3397, 0x43},
{0x3398, 0x00},
{0x3399, 0x1b},
{0x339a, 0x41},
{0x339b, 0x0f},
{0x339c, 0xea},
{0x339d, 0x84},
{0x339e, 0x0f},
{0x339f, 0xfd},
{0x33a0, 0xdb},
{0x33a1, 0x0f},
{0x33a2, 0xe9},
{0x33a3, 0xbd},
{0x33a4, 0x00},
{0x33a5, 0x30},
{0x33a6, 0x77},
{0x33a7, 0x0f},
{0x33a8, 0xe9},
{0x33a9, 0x93},
{0x33aa, 0x0f},
{0x33ab, 0xd7},
{0x33ac, 0xde},
{0x33ad, 0x00},
{0x33ae, 0x2a},
{0x33af, 0x14},
{0x309D, 0x62},
{0x309d, 0x22},
/* LC setting End */
},
/*EVT5 */
{
/* LC setting Start */
{0x3200, 0x00}, /* 100108 Modify LC setting DNP light source t75-r73*/
{0x3201, 0x99},
{0x3202, 0xc1},
{0x3203, 0x0f},
{0x3204, 0xd0},
{0x3205, 0x1b},
{0x3206, 0x00},
{0x3207, 0x24},
{0x3208, 0x8d},
{0x3209, 0x0f},
{0x320a, 0xee},
{0x320b, 0x0f},
{0x320c, 0x00},
{0x320d, 0x04},
{0x320e, 0x5c},
{0x320f, 0x00},
{0x3210, 0x07},
{0x3211, 0x68},
{0x3212, 0x0f},
{0x3213, 0xc2},
{0x3214, 0x82},
{0x3215, 0x00},
{0x3216, 0x29},
{0x3217, 0x3e},
{0x3218, 0x0f},
{0x3219, 0xd3},
{0x321a, 0x63},
{0x321b, 0x00},
{0x321c, 0x22},
{0x321d, 0x6c},
{0x321e, 0x0f},
{0x321f, 0xf8},
{0x3220, 0xce},
{0x3221, 0x0f},
{0x3222, 0xed},
{0x3223, 0x30},
{0x3224, 0x00},
{0x3225, 0x37},
{0x3226, 0x87},
{0x3227, 0x0f},
{0x3228, 0xc2},
{0x3229, 0x87},
{0x322a, 0x00},
{0x322b, 0x2a},
{0x322c, 0xc6},
{0x322d, 0x0f},
{0x322e, 0xf3},
{0x322f, 0xd9},
{0x3230, 0x0f},
{0x3231, 0xea},
{0x3232, 0x1a},
{0x3233, 0x00},
{0x3234, 0x2d},
{0x3235, 0x9f},
{0x3236, 0x0f},
{0x3237, 0xde},
{0x3238, 0x7d},
{0x3239, 0x00},
{0x323a, 0x37},
{0x323b, 0x1e},
{0x323c, 0x0f},
{0x323d, 0xed},
{0x323e, 0x9c},
{0x323f, 0x0f},
{0x3240, 0xf6},
{0x3241, 0xfd},
{0x3242, 0x00},
{0x3243, 0x15},
{0x3244, 0xeb},
{0x3245, 0x0f},
{0x3246, 0xd3},
{0x3247, 0xca},
{0x3248, 0x00},
{0x3249, 0x08},
{0x324a, 0xe6},
{0x324b, 0x0f},
{0x324c, 0xf4},
{0x324d, 0x7a},
{0x324e, 0x0f},
{0x324f, 0xed},
{0x3250, 0x1e},
{0x3251, 0x00},
{0x3252, 0x0d},
{0x3253, 0x46},
{0x3254, 0x00},
{0x3255, 0x0c},
{0x3256, 0x3e},
{0x3257, 0x00},
{0x3258, 0x09},
{0x3259, 0xcf},
{0x325a, 0x00},
{0x325b, 0x09},
{0x325c, 0xb5},
{0x325d, 0x0f},
{0x325e, 0xec},
{0x325f, 0x47},
{0x3260, 0x00},
{0x3261, 0x1d},
{0x3262, 0xd8},
{0x3263, 0x0f},
{0x3264, 0xf7},
{0x3265, 0x11},
{0x3266, 0x0f},
{0x3267, 0xea},
{0x3268, 0x3d},
{0x3269, 0x00},
{0x326a, 0x09},
{0x326b, 0xcc},
{0x326c, 0x00},
{0x326d, 0x99},
{0x326e, 0x45},
{0x326f, 0x0f},
{0x3270, 0xd3},
{0x3271, 0x80},
{0x3272, 0x00},
{0x3273, 0x20},
{0x3274, 0xf7},
{0x3275, 0x0f},
{0x3276, 0xef},
{0x3277, 0x0d},
{0x3278, 0x00},
{0x3279, 0x09},
{0x327a, 0x3c},
{0x327b, 0x00},
{0x327c, 0x01},
{0x327d, 0x16},
{0x327e, 0x0f},
{0x327f, 0xc9},
{0x3280, 0x36},
{0x3281, 0x00},
{0x3282, 0x21},
{0x3283, 0xff},
{0x3284, 0x0f},
{0x3285, 0xdc},
{0x3286, 0xc2},
{0x3287, 0x00},
{0x3288, 0x1e},
{0x3289, 0xc0},
{0x328a, 0x0f},
{0x328b, 0xf0},
{0x328c, 0xa7},
{0x328d, 0x0f},
{0x328e, 0xf9},
{0x328f, 0x2a},
{0x3290, 0x00},
{0x3291, 0x29},
{0x3292, 0x5c},
{0x3293, 0x0f},
{0x3294, 0xc9},
{0x3295, 0x2a},
{0x3296, 0x00},
{0x3297, 0x1f},
{0x3298, 0x5c},
{0x3299, 0x0f},
{0x329a, 0xfa},
{0x329b, 0x0c},
{0x329c, 0x0f},
{0x329d, 0xf3},
{0x329e, 0x94},
{0x329f, 0x00},
{0x32a0, 0x1c},
{0x32a1, 0xce},
{0x32a2, 0x0f},
{0x32a3, 0xed},
{0x32a4, 0xb7},
{0x32a5, 0x00},
{0x32a6, 0x34},
{0x32a7, 0x51},
{0x32a8, 0x0f},
{0x32a9, 0xfa},
{0x32aa, 0x7d},
{0x32ab, 0x0f},
{0x32ac, 0xe6},
{0x32ad, 0xbf},
{0x32ae, 0x00},
{0x32af, 0x18},
{0x32b0, 0xc6},
{0x32b1, 0x0f},
{0x32b2, 0xe0},
{0x32b3, 0x72},
{0x32b4, 0x00},
{0x32b5, 0x08},
{0x32b6, 0x23},
{0x32b7, 0x0f},
{0x32b8, 0xf1},
{0x32b9, 0x54},
{0x32ba, 0x0f},
{0x32bb, 0xe1},
{0x32bc, 0x84},
{0x32bd, 0x00},
{0x32be, 0x26},
{0x32bf, 0xb1},
{0x32c0, 0x0f},
{0x32c1, 0xfa},
{0x32c2, 0xc2},
{0x32c3, 0x00},
{0x32c4, 0x05},
{0x32c5, 0x3d},
{0x32c6, 0x0f},
{0x32c7, 0xff},
{0x32c8, 0xaf},
{0x32c9, 0x0f},
{0x32ca, 0xf1},
{0x32cb, 0xe5},
{0x32cc, 0x00},
{0x32cd, 0x21},
{0x32ce, 0xdd},
{0x32cf, 0x0f},
{0x32d0, 0xe8},
{0x32d1, 0x6a},
{0x32d2, 0x0f},
{0x32d3, 0xf4},
{0x32d4, 0xfb},
{0x32d5, 0x00},
{0x32d6, 0x0c},
{0x32d7, 0x89},
{0x32d8, 0x00},
{0x32d9, 0x7c},
{0x32da, 0x79},
{0x32db, 0x0f},
{0x32dc, 0xde},
{0x32dd, 0x19},
{0x32de, 0x00},
{0x32df, 0x19},
{0x32e0, 0xe8},
{0x32e1, 0x0f},
{0x32e2, 0xf3},
{0x32e3, 0x41},
{0x32e4, 0x00},
{0x32e5, 0x03},
{0x32e6, 0x4c},
{0x32e7, 0x00},
{0x32e8, 0x05},
{0x32e9, 0x73},
{0x32ea, 0x0f},
{0x32eb, 0xd6},
{0x32ec, 0xa5},
{0x32ed, 0x00},
{0x32ee, 0x1f},
{0x32ef, 0x81},
{0x32f0, 0x0f},
{0x32f1, 0xdc},
{0x32f2, 0xe6},
{0x32f3, 0x00},
{0x32f4, 0x18},
{0x32f5, 0x65},
{0x32f6, 0x00},
{0x32f7, 0x00},
{0x32f8, 0x11},
{0x32f9, 0x0f},
{0x32fa, 0xed},
{0x32fb, 0x65},
{0x32fc, 0x00},
{0x32fd, 0x23},
{0x32fe, 0x12},
{0x32ff, 0x0f},
{0x3300, 0xcf},
{0x3301, 0x28},
{0x3302, 0x00},
{0x3303, 0x2b},
{0x3304, 0xda},
{0x3305, 0x0f},
{0x3306, 0xef},
{0x3307, 0xae},
{0x3308, 0x0f},
{0x3309, 0xeb},
{0x330a, 0x13},
{0x330b, 0x00},
{0x330c, 0x27},
{0x330d, 0xb8},
{0x330e, 0x0f},
{0x330f, 0xec},
{0x3310, 0x69},
{0x3311, 0x00},
{0x3312, 0x2f},
{0x3313, 0x5f},
{0x3314, 0x0f},
{0x3315, 0xdf},
{0x3316, 0x4f},
{0x3317, 0x00},
{0x3318, 0x05},
{0x3319, 0x70},
{0x331a, 0x00},
{0x331b, 0x0f},
{0x331c, 0xd2},
{0x331d, 0x0f},
{0x331e, 0xe1},
{0x331f, 0xd8},
{0x3320, 0x00},
{0x3321, 0x09},
{0x3322, 0xcf},
{0x3323, 0x0f},
{0x3324, 0xf2},
{0x3325, 0x6e},
{0x3326, 0x0f},
{0x3327, 0xf6},
{0x3328, 0xb4},
{0x3329, 0x00},
{0x332a, 0x0d},
{0x332b, 0x87},
{0x332c, 0x00},
{0x332d, 0x08},
{0x332e, 0x1e},
{0x332f, 0x0f},
{0x3330, 0xfa},
{0x3331, 0x6e},
{0x3332, 0x0f},
{0x3333, 0xff},
{0x3334, 0xaa},
{0x3335, 0x0f},
{0x3336, 0xf2},
{0x3337, 0xc0},
{0x3338, 0x00},
{0x3339, 0x1d},
{0x333a, 0x18},
{0x333b, 0x0f},
{0x333c, 0xef},
{0x333d, 0xed},
{0x333e, 0x0f},
{0x333f, 0xec},
{0x3340, 0xf6},
{0x3341, 0x00},
{0x3342, 0x16},
{0x3343, 0x8e},
{0x3344, 0x00},
{0x3345, 0x9c},
{0x3346, 0x52},
{0x3347, 0x0f},
{0x3348, 0xcf},
{0x3349, 0xb9},
{0x334a, 0x00},
{0x334b, 0x29},
{0x334c, 0xe9},
{0x334d, 0x0f},
{0x334e, 0xe2},
{0x334f, 0x83},
{0x3350, 0x00},
{0x3351, 0x11},
{0x3352, 0xcc},
{0x3353, 0x0f},
{0x3354, 0xff},
{0x3355, 0xf4},
{0x3356, 0x0f},
{0x3357, 0xc1},
{0x3358, 0xa4},
{0x3359, 0x00},
{0x335a, 0x2f},
{0x335b, 0xce},
{0x335c, 0x0f},
{0x335d, 0xc5},
{0x335e, 0xbb},
{0x335f, 0x00},
{0x3360, 0x35},
{0x3361, 0x2a},
{0x3362, 0x0f},
{0x3363, 0xe6},
{0x3364, 0x2a},
{0x3365, 0x0f},
{0x3366, 0xf7},
{0x3367, 0x44},
{0x3368, 0x00},
{0x3369, 0x31},
{0x336a, 0xfe},
{0x336b, 0x0f},
{0x336c, 0xb6},
{0x336d, 0x84},
{0x336e, 0x00},
{0x336f, 0x3c},
{0x3370, 0x71},
{0x3371, 0x0f},
{0x3372, 0xe5},
{0x3373, 0xfe},
{0x3374, 0x0f},
{0x3375, 0xf2},
{0x3376, 0x87},
{0x3377, 0x00},
{0x3378, 0x29},
{0x3379, 0x2b},
{0x337a, 0x0f},
{0x337b, 0xe5},
{0x337c, 0x3f},
{0x337d, 0x00},
{0x337e, 0x45},
{0x337f, 0xc6},
{0x3380, 0x0f},
{0x3381, 0xdf},
{0x3382, 0xe6},
{0x3383, 0x0f},
{0x3384, 0xfb},
{0x3385, 0x0f},
{0x3386, 0x00},
{0x3387, 0x0f},
{0x3388, 0xf4},
{0x3389, 0x0f},
{0x338a, 0xdf},
{0x338b, 0x72},
{0x338c, 0x00},
{0x338d, 0x0e},
{0x338e, 0xaf},
{0x338f, 0x0f},
{0x3390, 0xed},
{0x3391, 0x7a},
{0x3392, 0x0f},
{0x3393, 0xe5},
{0x3394, 0xab},
{0x3395, 0x00},
{0x3396, 0x18},
{0x3397, 0x43},
{0x3398, 0x00},
{0x3399, 0x1b},
{0x339a, 0x41},
{0x339b, 0x0f},
{0x339c, 0xea},
{0x339d, 0x84},
{0x339e, 0x0f},
{0x339f, 0xfd},
{0x33a0, 0xdb},
{0x33a1, 0x0f},
{0x33a2, 0xe9},
{0x33a3, 0xbd},
{0x33a4, 0x00},
{0x33a5, 0x30},
{0x33a6, 0x77},
{0x33a7, 0x0f},
{0x33a8, 0xe9},
{0x33a9, 0x93},
{0x33aa, 0x0f},
{0x33ab, 0xd7},
{0x33ac, 0xde},
{0x33ad, 0x00},
{0x33ae, 0x2a},
{0x33af, 0x14},
{0x309D, 0x62},
{0x309d, 0x22}, /* shading enable */
/*LC setting End */
}
}; /* lc_setting} */
static struct wake_lock s5k3e2fx_wake_lock;
static inline void init_suspend(void)
{
wake_lock_init(&s5k3e2fx_wake_lock, WAKE_LOCK_IDLE, "s5k3e2fx");
}
static inline void deinit_suspend(void)
{
wake_lock_destroy(&s5k3e2fx_wake_lock);
}
static inline void prevent_suspend(void)
{
wake_lock(&s5k3e2fx_wake_lock);
}
static inline void allow_suspend(void)
{
wake_unlock(&s5k3e2fx_wake_lock);
}
struct reg_struct {
/* PLL setting */
uint8_t pre_pll_clk_div; /* 0x0305 */
uint8_t pll_multiplier_msb; /* 0x0306 */
uint8_t pll_multiplier_lsb; /* 0x0307 */
uint8_t vt_pix_clk_div; /* 0x0301 */
uint8_t vt_sys_clk_div; /* 0x0303 */
uint8_t op_pix_clk_div; /* 0x0309 */
uint8_t op_sys_clk_div; /* 0x030B */
/* Data Format */
uint8_t ccp_data_format_msb; /* 0x0112 */
uint8_t ccp_data_format_lsb; /* 0x0113 */
/* Preview Output Size */
uint8_t x_output_size_msb; /* 0x034C */
uint8_t x_output_size_lsb; /* 0x034D */
uint8_t y_output_size_msb; /* 0x034E */
uint8_t y_output_size_lsb; /* 0x034F */
/* add the X-Y addr setting position */
uint8_t x_addr_start_MSB; /* 0x0344 */
uint8_t x_addr_start_LSB; /* 0x0345 */
uint8_t y_addr_start_MSB; /* 0x0346 */
uint8_t y_addr_start_LSB; /* 0x0347 */
uint8_t x_addr_end_MSB; /* 0x0348 */
uint8_t x_addr_end_LSB; /* 0x0349 */
uint8_t y_addr_end_MSB; /* 0x034A */
uint8_t y_addr_end_LSB; /* 0x034B */
/* change the setting position */
/* Frame format */
uint8_t frame_length_lines_msb; /* 0x0340 */
uint8_t frame_length_lines_lsb; /* 0x0341 */
uint8_t line_length_pck_msb; /* 0x0342 */
uint8_t line_length_pck_lsb; /* 0x0343 */
/* binning */
uint8_t x_even_inc; /* 0x0381 */
uint8_t x_odd_inc; /* 0x0383 */
uint8_t y_even_inc; /* 0x0385 */
uint8_t y_odd_inc; /* 0x0387 */
uint8_t binning_enable; /* 0x3014 */
/* Samsung MSR Setting */
uint8_t sel_ccp; /* 0x30C4 */
uint8_t ld_start; /* 0x3000 */
uint8_t ld_end; /* 0x3001 */
uint8_t sl_start; /* 0x3002 */
uint8_t sl_end; /* 0x3003 */
uint8_t rx_start; /* 0x3004 */
uint8_t s1_start; /* 0x3005 */
uint8_t s1_end; /* 0x3006 */
uint8_t s1s_start; /* 0x3007 */
uint8_t s1s_end; /* 0x3008 */
uint8_t s3_start; /* 0x3009 */
uint8_t s3_end; /* 0x300A */
uint8_t cmp_en_start; /* 0x300B */
uint8_t clp_sl_start; /* 0x300C */
uint8_t clp_sl_end; /* 0x300D */
uint8_t off_start; /* 0x300E */
uint8_t rmp_en_start; /* 0x300F */
uint8_t tx_start; /* 0x3010 */
uint8_t tx_end; /* 0x3011 */
uint8_t stx_width; /* 0x3012 */
/* Samsung other MSR setting */
uint8_t clamp_on; /* 0x3015 */
uint8_t reg_301d_reserved; /* 0x301D */
uint8_t vpix; /* 0x3024 */
uint8_t reg_3028_reserved; /* 0x3028 */
uint8_t reg_3070_reserved; /* 0x3070 */
uint8_t reg_3072_reserved; /* 0x3072 */
uint8_t reg_301b_reserved; /* 0x301B */
uint8_t offset; /* 0x307E */
uint8_t reg_30bd_reserved; /* 0x30BD */
uint8_t reg_30c2_reserved; /* 0x30C2 */
uint8_t shade_clk_enable; /* 0x30AC */
uint8_t reg_3051_reserved; /* 0x3051 */
uint8_t reg_3029_reserved; /* 0x3029 */
uint8_t reg_30bf_reserved; /* 0x30BF */
uint8_t reg_3022_reserved; /* 0x3022 */
uint8_t reg_3019_reserved; /* 0x3019 */
/* end: Samsung other MSR setting */
uint8_t reg_3152_reserved; /* 0x3152 */
/* Samsung signal output setting */
uint8_t reg_3150_reserved; /* 0x3150 */
uint8_t reg_3157_reserved; /* 0x3157 */
uint8_t reg_3159_reserved; /* 0x3159 */
/* end: Samsung signal output setting */
uint8_t reg_315A_reserved; /* 0x315A */
/* AEC Setting */
uint8_t analogue_gain_code_global_msb; /* 0x0204 */
uint8_t analogue_gain_code_global_lsb; /* 0x0205 */
uint8_t fine_integration_time; /* 0x0200 */
uint8_t coarse_integration_time; /* 0x0202 */
/* LC Preview/Snapshot difference register */
/* Preview LC Setting */
uint8_t sh4ch_blk_width_r; /* 0x309E */
uint8_t sh4ch_blk_height_r; /* 0x309F */
uint8_t sh4ch_step_x_r_MSB; /* 0x30A0 */
uint8_t sh4ch_step_x_r_LSB; /* 0x30A1 */
uint8_t sh4ch_step_y_r_MSB; /* 0x30A2 */
uint8_t sh4ch_step_y_r_LSB; /* 0x30A3 */
uint8_t sh4ch_start_blk_cnt_x_r; /* 0x30A4 */
uint8_t sh4ch_start_blk_int_x_r; /* 0x30A5 */
uint8_t sh4ch_start_frac_x_r_MSB; /* 0x30A6 */
uint8_t sh4ch_start_frac_x_r_LSB; /* 0x30A7 */
uint8_t sh4ch_start_blk_cnt_y_r; /* 0x30A8 */
uint8_t sh4ch_start_blk_int_y_r; /* 0x30A9 */
uint8_t sh4ch_start_frac_y_r_MSB; /* 0x30AA */
uint8_t sh4ch_start_frac_y_r_LSB; /* 0x30AB */
/* end: LC Preview/Snapshot difference register */
uint32_t size_h;
uint32_t blk_l;
uint32_t size_w;
uint32_t blk_p;
};
struct reg_struct s5k3e2fx_reg_pat[2] = {
{ /* Preview */
/* PLL setting */
0x06, /* pre_pll_clk_div REG=0x0305 */
0x00, /* pll_multiplier_msb REG=0x0306 */
REG_PLL_MULTIPLIER_LSB_VALUE,
/* pll_multiplier_lsb REG=0x0307 */
0x08, /* vt_pix_clk_div REG=0x0301 */
0x01, /* vt_sys_clk_div REG=0x0303 */
0x08, /* op_pix_clk_div REG=0x0309 */
0x01, /* op_sys_clk_div REG=0x030B */
/* Data Format */
0x0a, /* ccp_data_format_msb REG=0x0112 */
0x0a, /* ccp_data_format_lsb REG=0x0113 */
/* Preview Output Size */
0x05, /* x_output_size_msb REG=0x034C */
0x10, /* x_output_size_lsb REG=0x034D */
0x03, /* y_output_size_msb REG=0x034E */
0xcc, /* y_output_size_lsb REG=0x034F */
/* X-Y addr setting position. Start */
0x00, /* x_addr_start_MSB REG=0x0344 */
0x08, /* x_addr_start_LSB REG=0x0345 */
0x00, /* y_addr_start_MSB REG=0x0346 */
0x08, /* y_addr_start_LSB REG=0x0347 */
0x0a, /* x_addr_end_MSB REG=0x0348 */
0x27, /* x_addr_end_LSB REG=0x0349 */
0x07, /* y_addr_end_MSB REG=0x034A */
0x9f, /* y_addr_end_LSB REG=0x034B */
/* change the setting position */
/* Frame format */
0x03, /* frame_length_lines_msb REG=0x0340 */
0xe2, /* frame_length_lines_lsb REG=0x0341 */
0x0a, /* line_length_pck_msb REG=0x0342 */
0xac, /* line_length_pck_lsb REG=0x0343 */
/* enable binning for preview */
0x01, /* x_even_inc REG=0x0381 */
0x01, /* x_odd_inc REG=0x0383 */
0x01, /* y_even_inc REG=0x0385 */
0x03, /* y_odd_inc REG=0x0387 */
0x06, /* binning_enable REG=0x3014 */
/* Samsung MSR Setting */
0x01, /* sel_ccp REG=0x30C4 */
0x03, /* ld_start REG=0x3000 */
0x94, /* ld_end REG=0x3001 */
0x02, /* sl_start REG=0x3002 */
0x95, /* sl_end REG=0x3003 */
0x0f, /* rx_start REG=0x3004 */
0x05, /* s1_start REG=0x3005 */
0x3c, /* s1_end REG=0x3006 */
0x8c, /* s1s_start REG=0x3007 */
0x93, /* s1s_end REG=0x3008 */
0x05, /* s3_start REG=0x3009 */
0x3a, /* s3_end REG=0x300A */
0x10, /* cmp_en_start REG=0x300B */
0x02, /* clp_sl_start REG=0x300C */
0x3e, /* clp_sl_end REG=0x300D */
0x02, /* off_start REG=0x300E */
0x0e, /* rmp_en_start REG=0x300F */
0x46, /* tx_start REG=0x3010 */
0x64, /* tx_end REG=0x3011 */
0x1e, /* stx_width REG=0x3012 */
/* Samsung other MSR setting. */
0x00, /* clamp_on REG=0x3015 */
0x3f, /* reg_301d_reserved REG=0x301D */
0x04, /* vpix REG=0x3024 */
0x40, /* reg_3028_reserved REG=0x3028 */
0xdf, /* reg_3070_reserved REG=0x3070 */
0x20, /* reg_3072_reserved REG=0x3072 */
0x73, /* reg_3073_reserved REG=0x301B */
0x02, /* offset REG=0x307E */
0x06, /* reg_30bd_reserved REG=0x30BD */
0x0b, /* reg_30c2_reserved REG=0x30C2 */
0x81, /* shade_clk_enable REG=0x30AC */
0xe6, /* reg_3051_reserved REG=0x3051 */
0x02, /* reg_3029_reserved REG=0x3029 */
0x00, /* reg_30bf_reserved REG=0x30BF */
0x87, /* reg_3022_reserved REG=0x3022 */
0x60, /* reg_3019_reserved REG=0x3019 */
/* end: Samsung other MSR setting. */
0x08, /* reg_3152_reserved REG=0x3152 */
0x50, /* reg_3150_reserved REG=0x3150 */
/* Inverse PCLK */
0x04, /* reg_3157_reserved REG=0x3157 */
/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
0x0f, /* reg_3159_reserved REG=0x3159 */
/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
* 11:8mA
*/
0xf0, /* reg_315A_reserved REG=0x315A */
/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA, 10:6mA,
* 11:8mA
*/
/* AEC Setting */
0x00, /* analogue_gain_code_global_msb REG=0x0204 */
REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE,
/* analogue_gain_code_global_lsb REG=0x0205 */
0x02, /* fine_integration_time REG=0x0200 */
0x03, /* coarse_integration_time REG=0x0202 */
/* LC Preview/Snapshot difference register. */
/* Preview LC config Setting */
0x52, /* sh4ch_blk_width_r REG=0x309E */
0x3e, /* sh4ch_blk_height_r REG=0x309F */
0x03, /* sh4ch_step_x_r_MSB REG=0x30A0 */
0x1f, /* sh4ch_step_x_r_LSB REG=0x30A1 */
0x04, /* sh4ch_step_y_r_MSB REG=0x30A2 */
0x21, /* sh4ch_step_y_r_LSB REG=0x30A3 */
0x04, /* sh4ch_start_blk_cnt_x_r REG=0x30A4 */
0x00, /* sh4ch_start_blk_int_x_r REG=0x30A5 */
0x0c, /* sh4ch_start_frac_x_r_MSB REG=0x30A6 */
0x7c, /* sh4ch_start_frac_x_r_LSB REG=0x30A7 */
0x04, /* sh4ch_start_blk_cnt_y_r REG=0x30A8 */
0x00, /* sh4ch_start_blk_int_y_r REG=0x30A9 */
0x10, /* sh4ch_start_frac_y_r_MSB REG=0x30AA */
0x84, /* sh4ch_start_frac_y_r_LSB REG=0x30AB */
/* end: LC Preview/Snapshot difference register. */
S5K3E2FX_QTR_SIZE_HEIGHT,
18,
S5K3E2FX_QTR_SIZE_WIDTH,
1436},
{ /* Snapshot */
/* PLL setting */
0x06, /* pre_pll_clk_div REG=0x0305 */
0x00, /* pll_multiplier_msb REG=0x0306 */
REG_PLL_MULTIPLIER_LSB_VALUE,
/* pll_multiplier_lsb REG=0x0307 */
0x08, /* vt_pix_clk_div REG=0x0301 */
0x01, /* vt_sys_clk_div REG=0x0303 */
0x08, /* op_pix_clk_div REG=0x0309 */
0x01, /* op_sys_clk_div REG=0x030B */
/* Data Format */
0x0a, /* ccp_data_format_msb REG=0x0112 */
0x0a, /* ccp_data_format_lsb REG=0x0113 */
/* Snapshot Output Size */
0x0a, /* x_output_size_msb REG=0x034C */
0x30, /* x_output_size_lsb REG=0x034D */
0x07, /* y_output_size_msb REG=0x034E */
0xa8, /* y_output_size_lsb REG=0x034F */
/* add the X-Y addr setting position. */
0x00, /* x_addr_start_MSB REG=0x0344 */
0x00, /* x_addr_start_LSB REG=0x0345 */
0x00, /* y_addr_start_MSB REG=0x0346 */
0x00, /* y_addr_start_LSB REG=0x0347 */
0x0a, /* x_addr_end_MSB REG=0x0348 */
0x2F, /* x_addr_end_LSB REG=0x0349 */
0x07, /* y_addr_end_MSB REG=0x034A */
0xA7, /* y_addr_end_LSB REG=0x034B */
/* Change the setting position. */
/* Frame format */
0x07, /* frame_length_lines_msb REG=0x0340 */
0xb6, /* frame_length_lines_lsb REG=0x0341 */
0x0a, /* line_length_pck_msb REG=0x0342 */
0xac, /* line_length_pck_lsb REG=0x0343 */
/* disable binning for snapshot */
0x01, /* x_even_inc REG=0x0381 */
0x01, /* x_odd_inc REG=0x0383 */
0x01, /* y_even_inc REG=0x0385 */
0x01, /* y_odd_inc REG=0x0387 */
0x00, /* binning_enable REG=0x3014 */
/* Samsung MSR Setting */
0x01, /* sel_ccp REG=0x30C4 */
0x03, /* ld_start REG=0x3000 */
0x94, /* ld_end REG=0x3001 */
0x02, /* sl_start REG=0x3002 */
0x95, /* sl_end REG=0x3003 */
0x0f, /* rx_start REG=0x3004 */
0x05, /* s1_start REG=0x3005 */
0x3c, /* s1_end REG=0x3006 */
0x8c, /* s1s_start REG=0x3007 */
0x93, /* s1s_end REG=0x3008 */
0x05, /* s3_start REG=0x3009 */
0x3a, /* s3_end REG=0x300A */
0x10, /* cmp_en_start REG=0x300B */
0x02, /* clp_sl_start REG=0x300C */
0x3e, /* clp_sl_end REG=0x300D */
0x02, /* off_start REG=0x300E */
0x0e, /* rmp_en_start REG=0x300F */
0x46, /* tx_start REG=0x3010 */
0x64, /* tx_end REG=0x3011 */
0x1e, /* stx_width REG=0x3012 */
/* Add Samsung other MSR setting. */
0x00, /* clamp_on REG=0x3015 */
0x3f, /* reg_301d_reserved REG=0x301D */
0x04, /* vpix REG=0x3024 */
0x40, /* reg_3028_reserved REG=0x3028 */
0xdf, /* reg_3070_reserved REG=0x3070 */
0x20, /* reg_3072_reserved REG=0x3072 */
0x73, /* reg_3073_reserved REG=0x301B */
0x02, /* offset REG=0x307E */
0x06, /* reg_30bd_reserved REG=0x30BD */
0x0b, /* reg_30c2_reserved REG=0x30C2 */
0x81, /* shade_clk_enable REG=0x30AC */
0xe6, /* reg_3051_reserved REG=0x3051 */
0x02, /* reg_3029_reserved REG=0x3029 */
0x00, /* reg_30bf_reserved REG=0x30BF */
0x87, /* reg_3022_reserved REG=0x3022 */
0x60, /* reg_3019_reserved REG=0x3019 */
/* end: Add Samsung other MSR setting. */
0x08, /* reg_3152_reserved REG=0x3152 */
/* Add Samsung signal output setting. */
0x50, /* reg_3150_reserved REG=0x3150 */
/* Inverse PCLK = 0x50 */
0x04, /* reg_3157_reserved REG=0x3157 */
/* PCLK Delay offset; 0x0a will delay around 4ns at 80MHz */
0x0f, /* reg_3159_reserved REG=0x3159 */
/* HS, VS driving strength [3:2]=>VS, [1:0]=>HS 00:2mA, 01:4mA, 10:6mA,
* 11:8mA
*/
0xf0, /* reg_315A_reserved REG=0x315A */
/* PCLK, DATA driving strength [7:6]=>data, [5:4]=>PCLK 00:2mA, 01:4mA, 10:6mA,
* 11:8mA
*/
/* AEC Setting */
0x00, /* analogue_gain_code_global_msb REG=0x0204 */
REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB_VALUE,
/* analogue_gain_code_global_lsb REG=0x0205 */
0x02, /* fine_integration_time REG=0x0200 */
0x03, /* coarse_integration_time REG=0x0202 */
/* Add LC Preview/Snapshot diff register. */
/* Snapshot LC config Setting */
0x52, /* sh4ch_blk_width_r REG=0x309E */
0x7b, /* sh4ch_blk_height_r REG=0x309F */
0x03, /* sh4ch_step_x_r_MSB REG=0x30A0 */
0x1f, /* sh4ch_step_x_r_LSB REG=0x30A1 */
0x02, /* sh4ch_step_y_r_MSB REG=0x30A2 */
0x15, /* sh4ch_step_y_r_LSB REG=0x30A3 */
0x00, /* sh4ch_start_blk_cnt_x_r REG=0x30A4 */
0x00, /* sh4ch_start_blk_int_x_r REG=0x30A5 */
0x00, /* sh4ch_start_frac_x_r_MSB REG=0x30A6 */
0x00, /* sh4ch_start_frac_x_r_LSB REG=0x30A7 */
0x00, /* sh4ch_start_blk_cnt_y_r REG=0x30A8 */
0x00, /* sh4ch_start_blk_int_y_r REG=0x30A9 */
0x00, /* sh4ch_start_frac_y_r_MSB REG=0x30AA */
0x00, /* sh4ch_start_frac_y_r_LSB REG=0x30AB */
/* diff: Add LC Preview/Snapshot diff register. */
S5K3E2FX_FULL_SIZE_HEIGHT,
14,
S5K3E2FX_FULL_SIZE_WIDTH,
124}
};
struct s5k3e2fx_work {
struct work_struct work;
};
static struct s5k3e2fx_work *s5k3e2fx_sensorw;
static struct i2c_client *s5k3e2fx_client;
struct s5k3e2fx_ctrl {
const struct msm_camera_sensor_info *sensordata;
int sensormode;
uint32_t fps_divider; /* init to 1 * 0x00000400 */
uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */
uint16_t curr_lens_pos;
uint16_t init_curr_lens_pos;
uint16_t my_reg_gain;
uint32_t my_reg_line_count;
enum msm_s_resolution prev_res;
enum msm_s_resolution pict_res;
enum msm_s_resolution curr_res;
enum msm_s_test_mode set_test;
};
static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl;
static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue);
#define MAX_I2C_RETRIES 20
static int i2c_transfer_retry(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int len)
{
int i2c_retry = 0;
int ns; /* number sent */
while (i2c_retry++ < MAX_I2C_RETRIES) {
ns = i2c_transfer(adap, msgs, len);
if (ns == len)
break;
pr_err("%s: try %d/%d: i2c_transfer sent: %d, len %d\n",
__func__,
i2c_retry, MAX_I2C_RETRIES, ns, len);
msleep(10);
}
return ns == len ? 0 : -EIO;
}
static inline int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata,
int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 2,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
return i2c_transfer_retry(s5k3e2fx_client->adapter, msgs, 2);
}
static inline int s5k3e2fx_i2c_txdata(unsigned short saddr,
unsigned char *txdata, int length)
{
struct i2c_msg msg[] = {
{
.addr = saddr,
.flags = 0,
.len = length,
.buf = txdata,
},
};
return i2c_transfer_retry(s5k3e2fx_client->adapter, msg, 1);
}
static int s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr,
unsigned char bdata)
{
int rc = -EFAULT;
unsigned char buf[4];
memset(buf, 0, sizeof(buf));
buf[0] = (waddr & 0xFF00) >> 8;
buf[1] = (waddr & 0x00FF);
buf[2] = bdata;
rc = s5k3e2fx_i2c_txdata(saddr, buf, 3);
if (rc < 0)
pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
waddr, bdata);
return rc;
}
static int s5k3e2fx_i2c_write_table(struct s5k3e2fx_i2c_reg_conf
*reg_cfg_tbl, int num)
{
int i;
int rc = -EFAULT;
CDBG("s5k3e2fx_i2c_write_table starts\n");
for (i = 0; i < num; i++) {
CDBG("%d: waddr = 0x%x, bdata = 0x%x\n", i,
(int)reg_cfg_tbl->waddr, (int)reg_cfg_tbl->bdata);
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
reg_cfg_tbl->waddr,
reg_cfg_tbl->bdata);
if (rc < 0)
break;
reg_cfg_tbl++;
}
CDBG("s5k3e2fx_i2c_write_table ends\n");
return rc;
}
static int s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr,
unsigned short *rdata)
{
int rc = 0;
unsigned char buf[4];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = (raddr & 0xFF00) >> 8;
buf[1] = (raddr & 0x00FF);
rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2);
if (rc < 0)
return rc;
*rdata = buf[0] << 8 | buf[1];
if (rc < 0)
pr_err("s5k3e2fx_i2c_read failed!\n");
return rc;
}
static int s5k3e2fx_i2c_read_b(unsigned short saddr, unsigned short raddr,
unsigned short *rdata)
{
int rc = 0;
unsigned char buf[4];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = (raddr & 0xFF00) >> 8;
buf[1] = (raddr & 0x00FF);
rc = s5k3e2fx_i2c_rxdata(saddr, buf, 1);
if (rc < 0)
return rc;
*rdata = buf[0];
if (rc < 0)
pr_err("s5k3e2fx_i2c_read failed!\n");
return rc;
}
static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data)
{
int rc;
uint16_t chipid = 0;
uint16_t modulever = 0;
CDBG("s5k3e2fx: gpio_request: %d\n", data->sensor_reset);
rc = gpio_request(data->sensor_reset, "s5k3e2fx");
if (!rc)
gpio_direction_output(data->sensor_reset, 1);
else {
pr_err("s5k3e2fx: request GPIO(sensor_reset): %d failed\n",
data->sensor_reset);
goto init_probe_fail;
}
CDBG("s5k3e2fx: gpio_free: %d\n", data->sensor_reset);
gpio_free(data->sensor_reset);
msleep(20);
CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n");
rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr, S5K3E2FX_REG_MODEL_ID,
&chipid);
if (rc < 0) {
pr_err("s5k3e2fx: read model_id failed: %d\n", rc);
goto init_probe_fail;
}
CDBG("s5k3e2fx_sensor_init(): model_id=0x%X\n", chipid);
if (chipid != S5K3E2FX_MODEL_ID) {
pr_err("S5K3E2FX wrong model_id = 0x%x\n", chipid);
rc = -ENODEV;
goto init_probe_fail;
}
rc = s5k3e2fx_i2c_read_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODULE_VER, &modulever);
if (rc < 0) {
pr_err("S5K3E2FX read module version failed, line=%d\n",
__LINE__);
goto init_probe_fail;
}
/* modulever = (0xF000 & modulever) >> 8; */
modulever = 0x00F0 & modulever;
CDBG("s5k3e2fx_sensor_init(): module version=0x%X\n", modulever);
if (modulever == 0x40)
g_usModuleVersion = 0;
else if (modulever == 0x50)
g_usModuleVersion = 1;
goto init_probe_done;
init_probe_fail:
pr_err("s5k3e2fx: prob init sensor failed\n");
init_probe_done:
return rc;
}
static int s5k3e2fx_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&s5k3e2fx_wait_queue);
return 0;
}
static const struct i2c_device_id s5k3e2fx_i2c_id[] = {
{"s5k3e2fx", 0},
{}
};
static int s5k3e2fx_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
CDBG("s5k3e2fx_probe called!\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
pr_err("i2c_check_functionality failed\n");
goto probe_failure;
}
s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL);
if (!s5k3e2fx_sensorw) {
pr_err("kzalloc failed\n");
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, s5k3e2fx_sensorw);
s5k3e2fx_init_client(client);
s5k3e2fx_client = client;
msleep(50);
CDBG("s5k3e2fx_probe successed! rc = %d\n", rc);
return 0;
probe_failure:
pr_err("s5k3e2fx_probe failed! rc = %d\n", rc);
return rc;
}
static struct i2c_driver s5k3e2fx_i2c_driver = {
.id_table = s5k3e2fx_i2c_id,
.probe = s5k3e2fx_i2c_probe,
.driver = {
.name = "s5k3e2fx",
},
};
#if 0
static int s5k3e2fx_test(enum msm_s_test_mode mo)
{
int rc = 0;
if (mo == S_TEST_OFF)
rc = 0;
else
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_TEST_PATTERN_MODE, (uint16_t) mo);
return rc;
}
#endif
static int s5k3e2fx_setting(enum msm_s_reg_update rupdate,
enum msm_s_setting rt)
{
int rc = 0;
uint16_t num_lperf;
switch (rupdate) {
case S_UPDATE_PERIODIC:{
if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
struct s5k3e2fx_i2c_reg_conf tbl_1[] = {
{REG_X_OUTPUT_SIZE_MSB,
s5k3e2fx_reg_pat[rt].
x_output_size_msb},
{REG_X_OUTPUT_SIZE_LSB,
s5k3e2fx_reg_pat[rt].
x_output_size_lsb},
{REG_Y_OUTPUT_SIZE_MSB,
s5k3e2fx_reg_pat[rt].
y_output_size_msb},
{REG_Y_OUTPUT_SIZE_LSB,
s5k3e2fx_reg_pat[rt].
y_output_size_lsb},
/* Start-End address */
{REG_X_ADDR_START_MSB,
s5k3e2fx_reg_pat[rt].x_addr_start_MSB},
{REG_X_ADDR_START_LSB,
s5k3e2fx_reg_pat[rt].x_addr_start_LSB},
{REG_Y_ADDR_START_MSB,
s5k3e2fx_reg_pat[rt].y_addr_start_MSB},
{REG_Y_ADDR_START_LSB,
s5k3e2fx_reg_pat[rt].y_addr_start_LSB},
{REG_X_ADDR_END_MSB,
s5k3e2fx_reg_pat[rt].x_addr_end_MSB},
{REG_X_ADDR_END_LSB,
s5k3e2fx_reg_pat[rt].x_addr_end_LSB},
{REG_Y_ADDR_END_MSB,
s5k3e2fx_reg_pat[rt].y_addr_end_MSB},
{REG_Y_ADDR_END_LSB,
s5k3e2fx_reg_pat[rt].y_addr_end_LSB},
/* Binning */
{REG_X_EVEN_INC,
s5k3e2fx_reg_pat[rt].x_even_inc},
{REG_X_ODD_INC,
s5k3e2fx_reg_pat[rt].x_odd_inc},
{REG_Y_EVEN_INC,
s5k3e2fx_reg_pat[rt].y_even_inc},
{REG_Y_ODD_INC,
s5k3e2fx_reg_pat[rt].y_odd_inc},
{REG_BINNING_ENABLE,
s5k3e2fx_reg_pat[rt].binning_enable},
};
struct s5k3e2fx_i2c_reg_conf tbl_2[] = {
{REG_FRAME_LENGTH_LINES_MSB, 0},
{REG_FRAME_LENGTH_LINES_LSB, 0},
{REG_LINE_LENGTH_PCK_MSB,
s5k3e2fx_reg_pat[rt].
line_length_pck_msb},
{REG_LINE_LENGTH_PCK_LSB,
s5k3e2fx_reg_pat[rt].
line_length_pck_lsb},
{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
s5k3e2fx_reg_pat[rt].
analogue_gain_code_global_msb},
{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
s5k3e2fx_reg_pat[rt].
analogue_gain_code_global_lsb},
{REG_FINE_INTEGRATION_TIME,
s5k3e2fx_reg_pat[rt].
fine_integration_time},
{REG_COARSE_INTEGRATION_TIME,
s5k3e2fx_reg_pat[rt].
coarse_integration_time},
/* LC Preview/Snapshot difference
* register
*/
{REG_SH4CH_BLK_WIDTH_R,
s5k3e2fx_reg_pat[rt].
sh4ch_blk_width_r},
{REG_SH4CH_BLK_HEIGHT_R,
s5k3e2fx_reg_pat[rt].
sh4ch_blk_height_r},
{REG_SH4CH_STEP_X_R_MSB,
s5k3e2fx_reg_pat[rt].
sh4ch_step_x_r_MSB},
{REG_SH4CH_STEP_X_R_LSB,
s5k3e2fx_reg_pat[rt].
sh4ch_step_x_r_LSB},
{REG_SH4CH_STEP_Y_R_MSB,
s5k3e2fx_reg_pat[rt].
sh4ch_step_y_r_MSB},
{REG_SH4CH_STEP_Y_R_LSB,
s5k3e2fx_reg_pat[rt].
sh4ch_step_y_r_LSB},
{REG_SH4CH_START_BLK_CNT_X_R,
s5k3e2fx_reg_pat[rt].
sh4ch_start_blk_cnt_x_r},
{REG_SH4CH_START_BLK_INT_X_R,
s5k3e2fx_reg_pat[rt].
sh4ch_start_blk_int_x_r},
{REG_SH4CH_START_FRAC_X_R_MSB,
s5k3e2fx_reg_pat[rt].
sh4ch_start_frac_x_r_MSB},
{REG_SH4CH_START_FRAC_X_R_LSB,
s5k3e2fx_reg_pat[rt].
sh4ch_start_frac_x_r_LSB},
{REG_SH4CH_START_BLK_CNT_Y_R,
s5k3e2fx_reg_pat[rt].
sh4ch_start_blk_cnt_y_r},
{REG_SH4CH_START_BLK_INT_Y_R,
s5k3e2fx_reg_pat[rt].
sh4ch_start_blk_int_y_r},
{REG_SH4CH_START_FRAC_Y_R_MSB,
s5k3e2fx_reg_pat[rt].
sh4ch_start_frac_y_r_MSB},
{REG_SH4CH_START_FRAC_Y_R_LSB,
s5k3e2fx_reg_pat[rt].
sh4ch_start_frac_y_r_LSB},
};
/* add EVT5 sensor Samsung difference MSR setting between Preview and Capture */
struct s5k3e2fx_i2c_reg_conf
tbl_only_for_EVT5[2][2] = {
{ /* S_RES_PREVIEW */
{0x3062, 0x00},
{0x3063, 0xD6},
},
{ /* S_RES_CAPTURE */
{0x3062, 0x01},
{0x3063, 0x16},
}
};
/* Most registers are directly applied at next frame after
writing except shutter and analog gain. Shutter and gain are
applied at 2nd or 1st frame later depending on register
writing time. When the camera is switched from preview to
snapshot, the first frame may have wrong shutter/gain and
should be discarded. The register REG_MASK_CORRUPTED_FRAMES
can discard the frame that has wrong shutter/gain. But in
preview mode, the frames should not be dropped. Otherwise
the preview will not be smooth. */
if (rt == S_RES_PREVIEW) {
/* Frames will be not discarded after exposure and gain are
written. */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_MASK_CORRUPTED_FRAMES, NO_MASK);
} else {
/* Solve greenish in lowlight. Prevent corrupted frame */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_MASK_CORRUPTED_FRAMES, MASK);
}
/* solve greenish: hold for both */
rc = s5k3e2fx_i2c_write_b(
s5k3e2fx_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return rc;
CDBG("Binning_enable = 0x %2x"
"[s5k3e2fx.c s5k3e2fx_setting]\r\n",
s5k3e2fx_reg_pat[rt].binning_enable);
rc = s5k3e2fx_i2c_write_table(&tbl_1[0],
ARRAY_SIZE
(tbl_1));
if (rc < 0) {
pr_err("UPDATE_PERIODIC, tb1_1 failed");
return rc;
}
num_lperf =
(uint16_t) ((s5k3e2fx_reg_pat[rt].
frame_length_lines_msb
<< 8) & 0xFF00) +
s5k3e2fx_reg_pat[rt].
frame_length_lines_lsb;
num_lperf =
num_lperf *
s5k3e2fx_ctrl->fps_divider / 0x0400;
tbl_2[0] =
(struct s5k3e2fx_i2c_reg_conf) {
REG_FRAME_LENGTH_LINES_MSB,
(num_lperf & 0xFF00) >> 8};
tbl_2[1] =
(struct s5k3e2fx_i2c_reg_conf) {
REG_FRAME_LENGTH_LINES_LSB,
(num_lperf & 0x00FF)};
rc = s5k3e2fx_i2c_write_table(&tbl_2[0],
ARRAY_SIZE
(tbl_2));
if (rc < 0) {
pr_err("UPDATE_PERIODIC, tb1_2 failed");
return rc;
}
/* only for evt5 */
if (g_usModuleVersion == 1) {
rc = s5k3e2fx_i2c_write_table
(&tbl_only_for_EVT5[rt][0],
2);
if (rc < 0)
return rc;
}
/* solve greenish: only release for preview */
if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE)
{
rc = s5k3e2fx_i2c_write_b(
s5k3e2fx_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0)
return rc;
}
rc = s5k3e2fx_i2c_write_b
(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_STREAM);
if (rc < 0)
return rc;
}
break; /* UPDATE_PERIODIC */
}
case S_REG_INIT:{
if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) {
struct s5k3e2fx_i2c_reg_conf tbl_3[] = {
/* {S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET},*/
{S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_SW_STANDBY},
/*Output Size */
{REG_X_OUTPUT_SIZE_MSB,
s5k3e2fx_reg_pat[rt].
x_output_size_msb},
{REG_X_OUTPUT_SIZE_LSB,
s5k3e2fx_reg_pat[rt].
x_output_size_lsb},
{REG_Y_OUTPUT_SIZE_MSB,
s5k3e2fx_reg_pat[rt].
y_output_size_msb},
{REG_Y_OUTPUT_SIZE_LSB,
s5k3e2fx_reg_pat[rt].
y_output_size_lsb},
/* Start-End address */
{REG_X_ADDR_START_MSB,
s5k3e2fx_reg_pat[rt].x_addr_start_MSB},
{REG_X_ADDR_START_LSB,
s5k3e2fx_reg_pat[rt].x_addr_start_LSB},
{REG_Y_ADDR_START_MSB,
s5k3e2fx_reg_pat[rt].y_addr_start_MSB},
{REG_Y_ADDR_START_LSB,
s5k3e2fx_reg_pat[rt].y_addr_start_LSB},
{REG_X_ADDR_END_MSB,
s5k3e2fx_reg_pat[rt].x_addr_end_MSB},
{REG_X_ADDR_END_LSB,
s5k3e2fx_reg_pat[rt].x_addr_end_LSB},
{REG_Y_ADDR_END_MSB,
s5k3e2fx_reg_pat[rt].y_addr_end_MSB},
{REG_Y_ADDR_END_LSB,
s5k3e2fx_reg_pat[rt].y_addr_end_LSB},
/* Binning */
{REG_X_EVEN_INC,
s5k3e2fx_reg_pat[rt].x_even_inc},
{REG_X_ODD_INC,
s5k3e2fx_reg_pat[rt].x_odd_inc},
{REG_Y_EVEN_INC,
s5k3e2fx_reg_pat[rt].y_even_inc},
{REG_Y_ODD_INC,
s5k3e2fx_reg_pat[rt].y_odd_inc},
{REG_BINNING_ENABLE,
s5k3e2fx_reg_pat[rt].binning_enable},
/* Frame format */
{REG_FRAME_LENGTH_LINES_MSB,
s5k3e2fx_reg_pat[rt].
frame_length_lines_msb},
{REG_FRAME_LENGTH_LINES_LSB,
s5k3e2fx_reg_pat[rt].
frame_length_lines_lsb},
{REG_LINE_LENGTH_PCK_MSB,
s5k3e2fx_reg_pat[rt].
line_length_pck_msb},
{REG_LINE_LENGTH_PCK_LSB,
s5k3e2fx_reg_pat[rt].
line_length_pck_lsb},
/* MSR setting */
{REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
s5k3e2fx_reg_pat[rt].
analogue_gain_code_global_msb},
{REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
s5k3e2fx_reg_pat[rt].
analogue_gain_code_global_lsb},
{REG_FINE_INTEGRATION_TIME,
s5k3e2fx_reg_pat[rt].
fine_integration_time},
{REG_COARSE_INTEGRATION_TIME,
s5k3e2fx_reg_pat[rt].
coarse_integration_time},
{S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_STREAM},
};
unsigned short rData = 0;
mdelay(1);
s5k3e2fx_i2c_read_b(s5k3e2fx_client->
addr,
REG_3150_RESERVED,
&rData);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->
addr,
REG_3150_RESERVED,
(rData & 0xFFFE));
mdelay(1);
s5k3e2fx_i2c_read_b(s5k3e2fx_client->
addr,
REG_TYPE1_AF_ENABLE,
&rData);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->
addr,
REG_TYPE1_AF_ENABLE,
(rData | 0x0001));
mdelay(1);
/* reset fps_divider */
s5k3e2fx_ctrl->fps_divider = 1 * 0x0400;
/* write REG_INIT registers */
rc = s5k3e2fx_i2c_write_table(&tbl_3[0],
ARRAY_SIZE
(tbl_3));
if (rc < 0) {
pr_err("REG_INIT failed, rc=%d\n", rc);
return rc;
}
}
}
break; /* REG_INIT */
default:
rc = -EFAULT;
break;
} /* switch (rupdate) */
return rc;
}
static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data)
{
int rc;
CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL);
if (!s5k3e2fx_ctrl) {
pr_err("s5k3e2fx_init failed!\n");
rc = -ENOMEM;
goto init_done;
}
s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400;
s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400;
s5k3e2fx_ctrl->set_test = S_TEST_OFF;
s5k3e2fx_ctrl->prev_res = S_QTR_SIZE;
s5k3e2fx_ctrl->pict_res = S_FULL_SIZE;
if (data)
s5k3e2fx_ctrl->sensordata = data;
/* enable mclk first */
msm_camio_clk_rate_set(S5K3E2FX_DEF_MCLK);
msleep(20);
msm_camio_camif_pad_reg_reset();
msleep(20);
rc = s5k3e2fx_probe_init_sensor(data);
if (rc < 0)
goto init_fail1;
if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE)
rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW);
else
rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE);
if (rc < 0) {
pr_err("s5k3e2fx_setting failed. rc = %d\n", rc);
goto init_fail1;
}
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
0x3130, 0x03);
if (rc < 0)
goto init_fail1;
goto init_done;
init_fail1:
kfree(s5k3e2fx_ctrl);
init_done:
return rc;
}
static void s5k3e2fx_suspend_sensor(void)
{
unsigned short rData = 0;
/*AF*/
s5k3e2fx_i2c_read_b(s5k3e2fx_client->addr,
REG_TYPE1_AF_ENABLE, &rData);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_TYPE1_AF_ENABLE, (rData & 0xFFFE));
mdelay(1);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_SW_STANDBY);
msleep(210); /*for 5FPS */
/* hi z */
s5k3e2fx_i2c_read_b(s5k3e2fx_client->addr, REG_3150_RESERVED, &rData);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_3150_RESERVED, (rData | 0x0001));
mdelay(1);
}
static int s5k3e2fx_power_down(void)
{
int rc = -EBADF;
s5k3e2fx_suspend_sensor();
return rc;
}
static int s5k3e2fx_sensor_release(void)
{
int rc = -EBADF;
s5k3e2fx_suspend_sensor();
kfree(s5k3e2fx_ctrl);
s5k3e2fx_ctrl = NULL;
allow_suspend();
CDBG("s5k3e2fx_release completed\n");
return rc;
}
static int s5k3e2fx_probe_init_lens_correction(
const struct msm_camera_sensor_info *data)
{
int rc = 0;
/* LC setting */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_SOFTWARE_RESET,
S5K3E2FX_SOFTWARE_RESET);
mdelay(2);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_SW_STANDBY);
/*20090811 separates the EVT4/EVT5 sensor init and LC setting start */
s5k3e2fx_i2c_write_table(&Init_setting[g_usModuleVersion][0],
NUM_INIT_REG);
/* 090911 Add for Samsung VCM calibration current Start */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3112, 0x0A);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3112, 0x09);
mdelay(5);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3145, 0x04);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x80);
/* 090911 Add for Samsung VCM calibration current End */
s5k3e2fx_i2c_write_table(&lc_setting[g_usModuleVersion][0], NUM_LC_REG);
/*20090811 separates the EVT4/EVT5 sensor init and LC setting end */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_STREAM);
msleep(10);
s5k3e2fx_suspend_sensor();
return rc;
}
static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps)
{
/* input fps is preview fps in Q8 format */
uint32_t divider; /* Q10 */
divider = (uint32_t)
((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
(s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 /
((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) *
(s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p));
/* Verify PCLK settings and frame sizes. */
*pfps = (uint16_t) (fps * divider / 0x00000400);
}
static uint16_t s5k3e2fx_get_prev_lines_pf(void)
{
return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
}
static uint16_t s5k3e2fx_get_prev_pixels_pl(void)
{
return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
}
static uint16_t s5k3e2fx_get_pict_lines_pf(void)
{
return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
}
static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
{
return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
}
static uint32_t s5k3e2fx_get_pict_max_exp_lc(void)
{
uint32_t snapshot_lines_per_frame;
if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE)
snapshot_lines_per_frame =
s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
else
snapshot_lines_per_frame = 3961 * 3;
return snapshot_lines_per_frame;
}
static int s5k3e2fx_set_fps(struct fps_cfg *fps)
{
/* input is new fps in Q10 format */
int rc = 0;
s5k3e2fx_ctrl->fps_divider = fps->fps_div;
CDBG("s5k3e2fx_ctrl->fps_divider = %d\n",
s5k3e2fx_ctrl->fps_divider);
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_FRAME_LENGTH_LINES_MSB,
(((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
s5k3e2fx_ctrl->fps_divider /
0x400) & 0xFF00) >> 8);
if (rc < 0)
goto set_fps_done;
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_FRAME_LENGTH_LINES_LSB,
(((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) *
s5k3e2fx_ctrl->fps_divider /
0x400) & 0xFF00));
set_fps_done:
return rc;
}
static int s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line)
{
int rc = 0;
uint16_t max_legal_gain = 0x0200;
uint32_t ll_ratio; /* Q10 */
uint32_t ll_pck, fl_lines;
uint16_t offset = 4;
uint32_t gain_msb, gain_lsb;
uint32_t intg_t_msb, intg_t_lsb;
uint32_t ll_pck_msb, ll_pck_lsb;
struct s5k3e2fx_i2c_reg_conf tbl[2];
CDBG("Line:%d s5k3e2fx_write_exp_gain gain %d line %d\n",
__LINE__, gain, line);
if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
s5k3e2fx_ctrl->my_reg_gain = gain;
s5k3e2fx_ctrl->my_reg_line_count = (uint16_t) line;
fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l;
ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
} else {
fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
}
if (gain > max_legal_gain)
gain = max_legal_gain;
/* in Q10 */
line = (line * s5k3e2fx_ctrl->fps_divider);
if (fl_lines < (line / 0x400))
ll_ratio = (line / (fl_lines - offset));
else
ll_ratio = 0x400;
/* solve greenish: only release for preview */
if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0) {
pr_err("s5k3e2fx_i2c_write_b failed on line %d\n",
__LINE__);
return rc;
}
}
/* update gain registers */
gain_msb = (gain & 0xFF00) >> 8;
gain_lsb = gain & 0x00FF;
tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB;
tbl[0].bdata = gain_msb;
tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB;
tbl[1].bdata = gain_lsb;
rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
if (rc < 0)
goto write_gain_done;
#if 1 /* Solve EVT5 greenish in lowlight*/
ll_pck = ll_pck * ll_ratio;
ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8;
ll_pck_lsb = (ll_pck / 0x400) & 0x00FF;
tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB;
tbl[0].bdata = ll_pck_msb;
tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB;
tbl[1].bdata = ll_pck_lsb;
rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
if (rc < 0)
goto write_gain_done;
#else
if (line / 0x400 + offset > fl_lines)
ll_pck = line / 0x400 + offset;
else
ll_pck = fl_lines;
ll_pck_msb = ((ll_pck) & 0xFF00) >> 8;
ll_pck_lsb = (ll_pck) & 0x00FF;
tbl[0].waddr = REG_FRAME_LENGTH_LINES_MSB;
tbl[0].bdata = ll_pck_msb;
tbl[1].waddr = REG_FRAME_LENGTH_LINES_LSB;
tbl[1].bdata = ll_pck_lsb;
rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
if (rc < 0)
goto write_gain_done;
#endif
line = line / 0x400;
intg_t_msb = (line & 0xFF00) >> 8;
intg_t_lsb = (line & 0x00FF);
tbl[0].waddr = REG_COARSE_INTEGRATION_TIME;
tbl[0].bdata = intg_t_msb;
tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB;
tbl[1].bdata = intg_t_lsb;
rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl));
/* solve greenish: release for both */
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0) {
pr_err("s5k3e2fx_i2c_write_b failed on line %d\n",
__LINE__);
return rc;
}
write_gain_done:
return rc;
}
static int s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line)
{
pr_info("s5k3e2fx_set_pict_exp_gain gain %d line %d\n",
gain, line);
return s5k3e2fx_write_exp_gain(gain, line);
}
static int s5k3e2fx_video_config(int mode, int res)
{
int rc;
switch (res) {
case S_QTR_SIZE:
pr_info("start sensor S_RES_PREVIEW config: %d\n", __LINE__);
rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW);
if (rc < 0)
return rc;
/* only apply my_reg for returning preview*/
rc = s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain,
s5k3e2fx_ctrl->my_reg_line_count);
break;
case S_FULL_SIZE:
rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE);
if (rc < 0)
return rc;
break;
default:
return 0;
}
s5k3e2fx_ctrl->prev_res = res;
s5k3e2fx_ctrl->curr_res = res;
s5k3e2fx_ctrl->sensormode = mode;
return rc;
}
static int s5k3e2fx_set_default_focus(void)
{
int rc = 0;
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131, 0);
if (rc < 0)
return rc;
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132, 0);
if (rc < 0)
return rc;
s5k3e2fx_ctrl->curr_lens_pos = 0;
return rc;
}
static int s5k3e2fx_move_focus(int direction, int num_steps)
{
int rc = 0;
int i;
int16_t step_direction;
int16_t actual_step;
int16_t next_pos, pos_offset;
int16_t init_code = 0;
uint8_t next_pos_msb, next_pos_lsb;
int16_t s_move[5];
uint32_t gain; /* Q10 format */
if (direction == MOVE_NEAR)
step_direction = 20;
else if (direction == MOVE_FAR)
step_direction = -20;
else {
pr_err("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__);
return -EINVAL;
}
actual_step = step_direction * (int16_t) num_steps;
pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos;
gain = actual_step * 0x400 / 5;
for (i = 0; i <= 4; i++) {
if (actual_step >= 0)
s_move[i] =
((((i + 1) * gain + 0x200) -
(i * gain + 0x200)) / 0x400);
else
s_move[i] =
((((i + 1) * gain - 0x200) -
(i * gain - 0x200)) / 0x400);
}
/* Ring Damping Code */
for (i = 0; i <= 4; i++) {
next_pos = (int16_t) (pos_offset + s_move[i]);
if (next_pos > (738 + init_code))
next_pos = 738 + init_code;
else if (next_pos < 0)
next_pos = 0;
CDBG("next_position in damping mode = %d\n", next_pos);
/* Writing the Values to the actuator */
if (next_pos == init_code)
next_pos = 0x00;
next_pos_msb = next_pos >> 8;
next_pos_lsb = next_pos & 0x00FF;
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131,
next_pos_msb);
if (rc < 0)
break;
rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132,
next_pos_lsb);
if (rc < 0)
break;
pos_offset = next_pos;
s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code;
if (num_steps > 1)
mdelay(6);
else
mdelay(4);
}
return rc;
}
static int s5k3e2fx_sensor_config(void __user *argp)
{
struct sensor_cfg_data cdata;
long rc = 0;
if (copy_from_user(&cdata,
(void *)argp, sizeof(struct sensor_cfg_data)))
return -EFAULT;
CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype);
switch (cdata.cfgtype) {
case CFG_GET_PICT_FPS:
s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps,
&(cdata.cfg.gfps.pictfps));
if (copy_to_user((void *)argp, &cdata,
sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_GET_PREV_L_PF:
cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf();
if (copy_to_user((void *)argp,
&cdata, sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_GET_PREV_P_PL:
cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl();
if (copy_to_user((void *)argp,
&cdata, sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_GET_PICT_L_PF:
cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf();
if (copy_to_user((void *)argp,
&cdata, sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_GET_PICT_P_PL:
cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl();
if (copy_to_user((void *)argp,
&cdata, sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_GET_PICT_MAX_EXP_LC:
cdata.cfg.pict_max_exp_lc = s5k3e2fx_get_pict_max_exp_lc();
if (copy_to_user((void *)argp,
&cdata, sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_SET_FPS:
case CFG_SET_PICT_FPS:
rc = s5k3e2fx_set_fps(&(cdata.cfg.fps));
break;
case CFG_SET_EXP_GAIN:
rc = s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_PICT_EXP_GAIN:
rc = s5k3e2fx_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_MODE:
rc = s5k3e2fx_video_config(cdata.mode, cdata.rs);
break;
case CFG_PWR_DOWN:
rc = s5k3e2fx_power_down();
break;
case CFG_MOVE_FOCUS:
rc = s5k3e2fx_move_focus(cdata.cfg.focus.dir,
cdata.cfg.focus.steps);
break;
case CFG_SET_DEFAULT_FOCUS:
rc = s5k3e2fx_set_default_focus();
break;
/* case CFG_GET_AF_MAX_STEPS: */
case CFG_SET_EFFECT:
rc = s5k3e2fx_set_default_focus();
break;
case CFG_SET_LENS_SHADING:
default:
rc = -EFAULT;
break;
}
prevent_suspend();
return rc;
}
static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info,
struct msm_sensor_ctrl *s)
{
int rc = 0;
pr_info("%s\n", __func__);
rc = i2c_add_driver(&s5k3e2fx_i2c_driver);
if (rc < 0 || s5k3e2fx_client == NULL) {
rc = -ENOTSUPP;
goto probe_fail;
}
msm_camio_clk_rate_set(S5K3E2FX_DEF_MCLK);
msleep(20);
rc = s5k3e2fx_probe_init_sensor(info);
if (rc < 0)
goto probe_fail;
/* lens correction */
s5k3e2fx_probe_init_lens_correction(info);
init_suspend();
s->s_init = s5k3e2fx_sensor_open_init;
s->s_release = s5k3e2fx_sensor_release;
s->s_config = s5k3e2fx_sensor_config;
return rc;
probe_fail:
pr_err("SENSOR PROBE FAILS!\n");
return rc;
}
static int s5k3e2fx_suspend(struct platform_device *pdev, pm_message_t state)
{
int rc;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
if (!sinfo->need_suspend)
return 0;
CDBG("s5k3e2fx: camera suspend\n");
rc = gpio_request(sinfo->sensor_reset, "s5k3e2fx");
if (!rc)
gpio_direction_output(sinfo->sensor_reset, 0);
else {
pr_err("s5k3e2fx: request GPIO(sensor_reset) :%d faile\n",
sinfo->sensor_reset);
goto suspend_fail;
}
CDBG("s5k3e2fx: gpio_free:%d line:%d\n", sinfo->sensor_reset,
__LINE__);
gpio_free(sinfo->sensor_reset);
suspend_fail:
return rc;
}
static void s5k3e2fx_sensor_resume_setting(void)
{
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_SOFTWARE_RESET,
S5K3E2FX_SOFTWARE_RESET);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0100, 0x00);
/*--------------PLL setting for 80Mhz*/
/* PLL setting */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0305, 0x06);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0306, 0x00);
/*88 54.4Mhz */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0307, 0x83);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0301, 0x08);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0303, 0x01);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0309, 0x08);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x030b, 0x01);
/*--------------output size*/
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034c, 0x05);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034d, 0x10);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034e, 0x03);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x034f, 0xcc);
/*--------------frame format (min blanking)*/
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0340, 0x03);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0341, 0xe2);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0342, 0x0a);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0343, 0xac);
/*--------------Binning */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0381, 0x01);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0383, 0x01);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0385, 0x01);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0387, 0x03);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3014, 0x06);
/*--------------MSR setting*/
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30c4, 0x01);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3000, 0x03);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3001, 0x94);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3002, 0x02);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3003, 0x95);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3004, 0x0f);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3005, 0x05);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3006, 0x3c);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3007, 0x8c);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3008, 0x93);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3009, 0x05);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300a, 0x3a);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300c, 0x02);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300d, 0x3e);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x300f, 0x0e);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3010, 0x46);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3011, 0x64);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3012, 0x1e);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x301d, 0x3f);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3024, 0x04);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3028, 0x40);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3070, 0xdf);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x301b, 0x73);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x307e, 0x02);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30bd, 0x06);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30c2, 0x0b);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30ac, 0x81);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3151, 0xe6);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3029, 0x02);
/*--------------EVT4 setting*/
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x30bf, 0x00);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3022, 0x87);
/*tune ADC to got batter yield rate in EDS */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3019, 0x60);
/*AF driving strength */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3c);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3152, 0x08);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x315a, 0xaa);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3159, 0x0a);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0205, 0x80);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0202, 0x03);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x0200, 0x02);
}
static int s5k3e2fx_resume(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
if (!sinfo->need_suspend)
return 0;
CDBG("s5k3e2fx_resume\n");
/*init msm,clk ,GPIO,enable */
msm_camio_probe_on(pdev);
msm_camio_clk_enable(CAMIO_MDC_CLK);
CDBG("msm_camio_probe_on\n");
/*read sensor ID and pull down reset */
msm_camio_clk_rate_set(S5K3E2FX_DEF_MCLK);
CDBG("msm_camio_clk_rate_set\n");
msleep(20);
s5k3e2fx_probe_init_sensor(sinfo);
CDBG("s5k3e2fx_probe_init_sensor\n");
/*init sensor,streaming on, SW init streaming off */
s5k3e2fx_sensor_resume_setting();
/*lens sharding */
s5k3e2fx_probe_init_lens_correction(sinfo);
/*stream on */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_STREAM);
/*software standby */
msleep(25);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x00);
mdelay(1);
/*stream off */
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr,
S5K3E2FX_REG_MODE_SELECT,
S5K3E2FX_MODE_SELECT_SW_STANDBY);
mdelay(1);
s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3150, 0x51);
msleep(240);
/*set RST to low */
msm_camio_probe_off(pdev);
msm_camio_clk_disable(CAMIO_MDC_CLK);
CDBG("s5k3e2fx:resume done\n");
return rc;
}
static int __s5k3e2fx_probe(struct platform_device *pdev)
{
return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __s5k3e2fx_probe,
.driver = {
.name = "msm_camera_s5k3e2fx",
.owner = THIS_MODULE,
},
.suspend = s5k3e2fx_suspend,
.resume = s5k3e2fx_resume,
};
static int __init s5k3e2fx_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(s5k3e2fx_init);