1/* 2 * Copyright (C) 2008-2009 QUALCOMM Incorporated. 3 */ 4 5#include <linux/delay.h> 6#include <linux/slab.h> 7#include <linux/types.h> 8#include <linux/i2c.h> 9#include <linux/uaccess.h> 10#include <linux/miscdevice.h> 11#include <media/msm_camera.h> 12#include <mach/gpio.h> 13#include <mach/camera.h> 14#include "s5k3e2fx.h" 15 16#define S5K3E2FX_REG_MODEL_ID 0x0000 17#define S5K3E2FX_MODEL_ID 0x3E2F 18 19/* PLL Registers */ 20#define REG_PRE_PLL_CLK_DIV 0x0305 21#define REG_PLL_MULTIPLIER_MSB 0x0306 22#define REG_PLL_MULTIPLIER_LSB 0x0307 23#define REG_VT_PIX_CLK_DIV 0x0301 24#define REG_VT_SYS_CLK_DIV 0x0303 25#define REG_OP_PIX_CLK_DIV 0x0309 26#define REG_OP_SYS_CLK_DIV 0x030B 27 28/* Data Format Registers */ 29#define REG_CCP_DATA_FORMAT_MSB 0x0112 30#define REG_CCP_DATA_FORMAT_LSB 0x0113 31 32/* Output Size */ 33#define REG_X_OUTPUT_SIZE_MSB 0x034C 34#define REG_X_OUTPUT_SIZE_LSB 0x034D 35#define REG_Y_OUTPUT_SIZE_MSB 0x034E 36#define REG_Y_OUTPUT_SIZE_LSB 0x034F 37 38/* Binning */ 39#define REG_X_EVEN_INC 0x0381 40#define REG_X_ODD_INC 0x0383 41#define REG_Y_EVEN_INC 0x0385 42#define REG_Y_ODD_INC 0x0387 43/*Reserved register */ 44#define REG_BINNING_ENABLE 0x3014 45 46/* Frame Fotmat */ 47#define REG_FRAME_LENGTH_LINES_MSB 0x0340 48#define REG_FRAME_LENGTH_LINES_LSB 0x0341 49#define REG_LINE_LENGTH_PCK_MSB 0x0342 50#define REG_LINE_LENGTH_PCK_LSB 0x0343 51 52/* MSR setting */ 53/* Reserved registers */ 54#define REG_SHADE_CLK_ENABLE 0x30AC 55#define REG_SEL_CCP 0x30C4 56#define REG_VPIX 0x3024 57#define REG_CLAMP_ON 0x3015 58#define REG_OFFSET 0x307E 59 60/* CDS timing settings */ 61/* Reserved registers */ 62#define REG_LD_START 0x3000 63#define REG_LD_END 0x3001 64#define REG_SL_START 0x3002 65#define REG_SL_END 0x3003 66#define REG_RX_START 0x3004 67#define REG_S1_START 0x3005 68#define REG_S1_END 0x3006 69#define REG_S1S_START 0x3007 70#define REG_S1S_END 0x3008 71#define REG_S3_START 0x3009 72#define REG_S3_END 0x300A 73#define REG_CMP_EN_START 0x300B 74#define REG_CLP_SL_START 0x300C 75#define REG_CLP_SL_END 0x300D 76#define REG_OFF_START 0x300E 77#define REG_RMP_EN_START 0x300F 78#define REG_TX_START 0x3010 79#define REG_TX_END 0x3011 80#define REG_STX_WIDTH 0x3012 81#define REG_TYPE1_AF_ENABLE 0x3130 82#define DRIVER_ENABLED 0x0001 83#define AUTO_START_ENABLED 0x0010 84#define REG_NEW_POSITION 0x3131 85#define REG_3152_RESERVED 0x3152 86#define REG_315A_RESERVED 0x315A 87#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204 88#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205 89#define REG_FINE_INTEGRATION_TIME 0x0200 90#define REG_COARSE_INTEGRATION_TIME 0x0202 91#define REG_COARSE_INTEGRATION_TIME_LSB 0x0203 92 93/* Mode select register */ 94#define S5K3E2FX_REG_MODE_SELECT 0x0100 95#define S5K3E2FX_MODE_SELECT_STREAM 0x01 /* start streaming */ 96#define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00 /* software standby */ 97#define S5K3E2FX_REG_SOFTWARE_RESET 0x0103 98#define S5K3E2FX_SOFTWARE_RESET 0x01 99#define REG_TEST_PATTERN_MODE 0x0601 100 101struct reg_struct { 102 uint8_t pre_pll_clk_div; /* 0x0305 */ 103 uint8_t pll_multiplier_msb; /* 0x0306 */ 104 uint8_t pll_multiplier_lsb; /* 0x0307 */ 105 uint8_t vt_pix_clk_div; /* 0x0301 */ 106 uint8_t vt_sys_clk_div; /* 0x0303 */ 107 uint8_t op_pix_clk_div; /* 0x0309 */ 108 uint8_t op_sys_clk_div; /* 0x030B */ 109 uint8_t ccp_data_format_msb; /* 0x0112 */ 110 uint8_t ccp_data_format_lsb; /* 0x0113 */ 111 uint8_t x_output_size_msb; /* 0x034C */ 112 uint8_t x_output_size_lsb; /* 0x034D */ 113 uint8_t y_output_size_msb; /* 0x034E */ 114 uint8_t y_output_size_lsb; /* 0x034F */ 115 uint8_t x_even_inc; /* 0x0381 */ 116 uint8_t x_odd_inc; /* 0x0383 */ 117 uint8_t y_even_inc; /* 0x0385 */ 118 uint8_t y_odd_inc; /* 0x0387 */ 119 uint8_t binning_enable; /* 0x3014 */ 120 uint8_t frame_length_lines_msb; /* 0x0340 */ 121 uint8_t frame_length_lines_lsb; /* 0x0341 */ 122 uint8_t line_length_pck_msb; /* 0x0342 */ 123 uint8_t line_length_pck_lsb; /* 0x0343 */ 124 uint8_t shade_clk_enable ; /* 0x30AC */ 125 uint8_t sel_ccp; /* 0x30C4 */ 126 uint8_t vpix; /* 0x3024 */ 127 uint8_t clamp_on; /* 0x3015 */ 128 uint8_t offset; /* 0x307E */ 129 uint8_t ld_start; /* 0x3000 */ 130 uint8_t ld_end; /* 0x3001 */ 131 uint8_t sl_start; /* 0x3002 */ 132 uint8_t sl_end; /* 0x3003 */ 133 uint8_t rx_start; /* 0x3004 */ 134 uint8_t s1_start; /* 0x3005 */ 135 uint8_t s1_end; /* 0x3006 */ 136 uint8_t s1s_start; /* 0x3007 */ 137 uint8_t s1s_end; /* 0x3008 */ 138 uint8_t s3_start; /* 0x3009 */ 139 uint8_t s3_end; /* 0x300A */ 140 uint8_t cmp_en_start; /* 0x300B */ 141 uint8_t clp_sl_start; /* 0x300C */ 142 uint8_t clp_sl_end; /* 0x300D */ 143 uint8_t off_start; /* 0x300E */ 144 uint8_t rmp_en_start; /* 0x300F */ 145 uint8_t tx_start; /* 0x3010 */ 146 uint8_t tx_end; /* 0x3011 */ 147 uint8_t stx_width; /* 0x3012 */ 148 uint8_t reg_3152_reserved; /* 0x3152 */ 149 uint8_t reg_315A_reserved; /* 0x315A */ 150 uint8_t analogue_gain_code_global_msb; /* 0x0204 */ 151 uint8_t analogue_gain_code_global_lsb; /* 0x0205 */ 152 uint8_t fine_integration_time; /* 0x0200 */ 153 uint8_t coarse_integration_time; /* 0x0202 */ 154 uint32_t size_h; 155 uint32_t blk_l; 156 uint32_t size_w; 157 uint32_t blk_p; 158}; 159 160struct reg_struct s5k3e2fx_reg_pat[2] = { 161 { /* Preview */ 162 0x06, /* pre_pll_clk_div REG=0x0305 */ 163 0x00, /* pll_multiplier_msb REG=0x0306 */ 164 0x88, /* pll_multiplier_lsb REG=0x0307 */ 165 0x0a, /* vt_pix_clk_div REG=0x0301 */ 166 0x01, /* vt_sys_clk_div REG=0x0303 */ 167 0x0a, /* op_pix_clk_div REG=0x0309 */ 168 0x01, /* op_sys_clk_div REG=0x030B */ 169 0x0a, /* ccp_data_format_msb REG=0x0112 */ 170 0x0a, /* ccp_data_format_lsb REG=0x0113 */ 171 0x05, /* x_output_size_msb REG=0x034C */ 172 0x10, /* x_output_size_lsb REG=0x034D */ 173 0x03, /* y_output_size_msb REG=0x034E */ 174 0xcc, /* y_output_size_lsb REG=0x034F */ 175 176 /* enable binning for preview */ 177 0x01, /* x_even_inc REG=0x0381 */ 178 0x01, /* x_odd_inc REG=0x0383 */ 179 0x01, /* y_even_inc REG=0x0385 */ 180 0x03, /* y_odd_inc REG=0x0387 */ 181 0x06, /* binning_enable REG=0x3014 */ 182 183 0x03, /* frame_length_lines_msb REG=0x0340 */ 184 0xde, /* frame_length_lines_lsb REG=0x0341 */ 185 0x0a, /* line_length_pck_msb REG=0x0342 */ 186 0xac, /* line_length_pck_lsb REG=0x0343 */ 187 0x81, /* shade_clk_enable REG=0x30AC */ 188 0x01, /* sel_ccp REG=0x30C4 */ 189 0x04, /* vpix REG=0x3024 */ 190 0x00, /* clamp_on REG=0x3015 */ 191 0x02, /* offset REG=0x307E */ 192 0x03, /* ld_start REG=0x3000 */ 193 0x9c, /* ld_end REG=0x3001 */ 194 0x02, /* sl_start REG=0x3002 */ 195 0x9e, /* sl_end REG=0x3003 */ 196 0x05, /* rx_start REG=0x3004 */ 197 0x0f, /* s1_start REG=0x3005 */ 198 0x24, /* s1_end REG=0x3006 */ 199 0x7c, /* s1s_start REG=0x3007 */ 200 0x9a, /* s1s_end REG=0x3008 */ 201 0x10, /* s3_start REG=0x3009 */ 202 0x14, /* s3_end REG=0x300A */ 203 0x10, /* cmp_en_start REG=0x300B */ 204 0x04, /* clp_sl_start REG=0x300C */ 205 0x26, /* clp_sl_end REG=0x300D */ 206 0x02, /* off_start REG=0x300E */ 207 0x0e, /* rmp_en_start REG=0x300F */ 208 0x30, /* tx_start REG=0x3010 */ 209 0x4e, /* tx_end REG=0x3011 */ 210 0x1E, /* stx_width REG=0x3012 */ 211 0x08, /* reg_3152_reserved REG=0x3152 */ 212 0x10, /* reg_315A_reserved REG=0x315A */ 213 0x00, /* analogue_gain_code_global_msb REG=0x0204 */ 214 0x80, /* analogue_gain_code_global_lsb REG=0x0205 */ 215 0x02, /* fine_integration_time REG=0x0200 */ 216 0x03, /* coarse_integration_time REG=0x0202 */ 217 972, 218 18, 219 1296, 220 1436 221 }, 222 { /* Snapshot */ 223 0x06, /* pre_pll_clk_div REG=0x0305 */ 224 0x00, /* pll_multiplier_msb REG=0x0306 */ 225 0x88, /* pll_multiplier_lsb REG=0x0307 */ 226 0x0a, /* vt_pix_clk_div REG=0x0301 */ 227 0x01, /* vt_sys_clk_div REG=0x0303 */ 228 0x0a, /* op_pix_clk_div REG=0x0309 */ 229 0x01, /* op_sys_clk_div REG=0x030B */ 230 0x0a, /* ccp_data_format_msb REG=0x0112 */ 231 0x0a, /* ccp_data_format_lsb REG=0x0113 */ 232 0x0a, /* x_output_size_msb REG=0x034C */ 233 0x30, /* x_output_size_lsb REG=0x034D */ 234 0x07, /* y_output_size_msb REG=0x034E */ 235 0xa8, /* y_output_size_lsb REG=0x034F */ 236 237 /* disable binning for snapshot */ 238 0x01, /* x_even_inc REG=0x0381 */ 239 0x01, /* x_odd_inc REG=0x0383 */ 240 0x01, /* y_even_inc REG=0x0385 */ 241 0x01, /* y_odd_inc REG=0x0387 */ 242 0x00, /* binning_enable REG=0x3014 */ 243 244 0x07, /* frame_length_lines_msb REG=0x0340 */ 245 0xb6, /* frame_length_lines_lsb REG=0x0341 */ 246 0x0a, /* line_length_pck_msb REG=0x0342 */ 247 0xac, /* line_length_pck_lsb REG=0x0343 */ 248 0x81, /* shade_clk_enable REG=0x30AC */ 249 0x01, /* sel_ccp REG=0x30C4 */ 250 0x04, /* vpix REG=0x3024 */ 251 0x00, /* clamp_on REG=0x3015 */ 252 0x02, /* offset REG=0x307E */ 253 0x03, /* ld_start REG=0x3000 */ 254 0x9c, /* ld_end REG=0x3001 */ 255 0x02, /* sl_start REG=0x3002 */ 256 0x9e, /* sl_end REG=0x3003 */ 257 0x05, /* rx_start REG=0x3004 */ 258 0x0f, /* s1_start REG=0x3005 */ 259 0x24, /* s1_end REG=0x3006 */ 260 0x7c, /* s1s_start REG=0x3007 */ 261 0x9a, /* s1s_end REG=0x3008 */ 262 0x10, /* s3_start REG=0x3009 */ 263 0x14, /* s3_end REG=0x300A */ 264 0x10, /* cmp_en_start REG=0x300B */ 265 0x04, /* clp_sl_start REG=0x300C */ 266 0x26, /* clp_sl_end REG=0x300D */ 267 0x02, /* off_start REG=0x300E */ 268 0x0e, /* rmp_en_start REG=0x300F */ 269 0x30, /* tx_start REG=0x3010 */ 270 0x4e, /* tx_end REG=0x3011 */ 271 0x1E, /* stx_width REG=0x3012 */ 272 0x08, /* reg_3152_reserved REG=0x3152 */ 273 0x10, /* reg_315A_reserved REG=0x315A */ 274 0x00, /* analogue_gain_code_global_msb REG=0x0204 */ 275 0x80, /* analogue_gain_code_global_lsb REG=0x0205 */ 276 0x02, /* fine_integration_time REG=0x0200 */ 277 0x03, /* coarse_integration_time REG=0x0202 */ 278 1960, 279 14, 280 2608, 281 124 282 } 283}; 284 285struct s5k3e2fx_work { 286 struct work_struct work; 287}; 288static struct s5k3e2fx_work *s5k3e2fx_sensorw; 289static struct i2c_client *s5k3e2fx_client; 290 291struct s5k3e2fx_ctrl { 292 const struct msm_camera_sensor_info *sensordata; 293 294 int sensormode; 295 uint32_t fps_divider; /* init to 1 * 0x00000400 */ 296 uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */ 297 298 uint16_t curr_lens_pos; 299 uint16_t init_curr_lens_pos; 300 uint16_t my_reg_gain; 301 uint32_t my_reg_line_count; 302 303 enum msm_s_resolution prev_res; 304 enum msm_s_resolution pict_res; 305 enum msm_s_resolution curr_res; 306 enum msm_s_test_mode set_test; 307}; 308 309struct s5k3e2fx_i2c_reg_conf { 310 unsigned short waddr; 311 unsigned char bdata; 312}; 313 314static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl; 315static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue); 316DECLARE_MUTEX(s5k3e2fx_sem); 317 318static int s5k3e2fx_i2c_rxdata(unsigned short saddr, unsigned char *rxdata, 319 int length) 320{ 321 struct i2c_msg msgs[] = { 322 { 323 .addr = saddr, 324 .flags = 0, 325 .len = 2, 326 .buf = rxdata, 327 }, 328 { 329 .addr = saddr, 330 .flags = I2C_M_RD, 331 .len = length, 332 .buf = rxdata, 333 }, 334 }; 335 336 if (i2c_transfer(s5k3e2fx_client->adapter, msgs, 2) < 0) { 337 CDBG("s5k3e2fx_i2c_rxdata failed!\n"); 338 return -EIO; 339 } 340 341 return 0; 342} 343 344static int32_t s5k3e2fx_i2c_txdata(unsigned short saddr, 345 unsigned char *txdata, int length) 346{ 347 struct i2c_msg msg[] = { 348 { 349 .addr = saddr, 350 .flags = 0, 351 .len = length, 352 .buf = txdata, 353 }, 354 }; 355 356 if (i2c_transfer(s5k3e2fx_client->adapter, msg, 1) < 0) { 357 CDBG("s5k3e2fx_i2c_txdata failed\n"); 358 return -EIO; 359 } 360 361 return 0; 362} 363 364static int32_t s5k3e2fx_i2c_write_b(unsigned short saddr, unsigned short waddr, 365 unsigned char bdata) 366{ 367 int32_t rc = -EIO; 368 unsigned char buf[4]; 369 370 memset(buf, 0, sizeof(buf)); 371 buf[0] = (waddr & 0xFF00)>>8; 372 buf[1] = (waddr & 0x00FF); 373 buf[2] = bdata; 374 375 rc = s5k3e2fx_i2c_txdata(saddr, buf, 3); 376 377 if (rc < 0) 378 CDBG("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n", 379 waddr, bdata); 380 381 return rc; 382} 383 384static int32_t s5k3e2fx_i2c_write_table( 385 struct s5k3e2fx_i2c_reg_conf *reg_cfg_tbl, int num) 386{ 387 int i; 388 int32_t rc = -EIO; 389 for (i = 0; i < num; i++) { 390 if (rc < 0) 391 break; 392 reg_cfg_tbl++; 393 } 394 395 return rc; 396} 397 398static int32_t s5k3e2fx_i2c_read_w(unsigned short saddr, unsigned short raddr, 399 unsigned short *rdata) 400{ 401 int32_t rc = 0; 402 unsigned char buf[4]; 403 404 if (!rdata) 405 return -EIO; 406 407 memset(buf, 0, sizeof(buf)); 408 409 buf[0] = (raddr & 0xFF00)>>8; 410 buf[1] = (raddr & 0x00FF); 411 412 rc = s5k3e2fx_i2c_rxdata(saddr, buf, 2); 413 if (rc < 0) 414 return rc; 415 416 *rdata = buf[0] << 8 | buf[1]; 417 418 if (rc < 0) 419 CDBG("s5k3e2fx_i2c_read failed!\n"); 420 421 return rc; 422} 423 424static int s5k3e2fx_probe_init_done(const struct msm_camera_sensor_info *data) 425{ 426 gpio_direction_output(data->sensor_reset, 0); 427 gpio_free(data->sensor_reset); 428 return 0; 429} 430 431static int s5k3e2fx_probe_init_sensor(const struct msm_camera_sensor_info *data) 432{ 433 int32_t rc; 434 uint16_t chipid = 0; 435 436 rc = gpio_request(data->sensor_reset, "s5k3e2fx"); 437 if (!rc) 438 gpio_direction_output(data->sensor_reset, 1); 439 else 440 goto init_probe_done; 441 442 mdelay(20); 443 444 CDBG("s5k3e2fx_sensor_init(): reseting sensor.\n"); 445 446 rc = s5k3e2fx_i2c_read_w(s5k3e2fx_client->addr, 447 S5K3E2FX_REG_MODEL_ID, &chipid); 448 if (rc < 0) 449 goto init_probe_fail; 450 451 if (chipid != S5K3E2FX_MODEL_ID) { 452 CDBG("S5K3E2FX wrong model_id = 0x%x\n", chipid); 453 rc = -ENODEV; 454 goto init_probe_fail; 455 } 456 457 goto init_probe_done; 458 459init_probe_fail: 460 s5k3e2fx_probe_init_done(data); 461init_probe_done: 462 return rc; 463} 464 465static int s5k3e2fx_init_client(struct i2c_client *client) 466{ 467 /* Initialize the MSM_CAMI2C Chip */ 468 init_waitqueue_head(&s5k3e2fx_wait_queue); 469 return 0; 470} 471 472static const struct i2c_device_id s5k3e2fx_i2c_id[] = { 473 { "s5k3e2fx", 0}, 474 { } 475}; 476 477static int s5k3e2fx_i2c_probe(struct i2c_client *client, 478 const struct i2c_device_id *id) 479{ 480 int rc = 0; 481 CDBG("s5k3e2fx_probe called!\n"); 482 483 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 484 CDBG("i2c_check_functionality failed\n"); 485 goto probe_failure; 486 } 487 488 s5k3e2fx_sensorw = kzalloc(sizeof(struct s5k3e2fx_work), GFP_KERNEL); 489 if (!s5k3e2fx_sensorw) { 490 CDBG("kzalloc failed.\n"); 491 rc = -ENOMEM; 492 goto probe_failure; 493 } 494 495 i2c_set_clientdata(client, s5k3e2fx_sensorw); 496 s5k3e2fx_init_client(client); 497 s5k3e2fx_client = client; 498 499 mdelay(50); 500 501 CDBG("s5k3e2fx_probe successed! rc = %d\n", rc); 502 return 0; 503 504probe_failure: 505 CDBG("s5k3e2fx_probe failed! rc = %d\n", rc); 506 return rc; 507} 508 509static struct i2c_driver s5k3e2fx_i2c_driver = { 510 .id_table = s5k3e2fx_i2c_id, 511 .probe = s5k3e2fx_i2c_probe, 512 .remove = __exit_p(s5k3e2fx_i2c_remove), 513 .driver = { 514 .name = "s5k3e2fx", 515 }, 516}; 517 518static int32_t s5k3e2fx_test(enum msm_s_test_mode mo) 519{ 520 int32_t rc = 0; 521 522 if (mo == S_TEST_OFF) 523 rc = 0; 524 else 525 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 526 REG_TEST_PATTERN_MODE, (uint16_t)mo); 527 528 return rc; 529} 530 531static int32_t s5k3e2fx_setting(enum msm_s_reg_update rupdate, 532 enum msm_s_setting rt) 533{ 534 int32_t rc = 0; 535 uint16_t num_lperf; 536 537 switch (rupdate) { 538 case S_UPDATE_PERIODIC: 539 if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) { 540 541 struct s5k3e2fx_i2c_reg_conf tbl_1[] = { 542 {REG_CCP_DATA_FORMAT_MSB, s5k3e2fx_reg_pat[rt].ccp_data_format_msb}, 543 {REG_CCP_DATA_FORMAT_LSB, s5k3e2fx_reg_pat[rt].ccp_data_format_lsb}, 544 {REG_X_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].x_output_size_msb}, 545 {REG_X_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].x_output_size_lsb}, 546 {REG_Y_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].y_output_size_msb}, 547 {REG_Y_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].y_output_size_lsb}, 548 {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc}, 549 {REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc}, 550 {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc}, 551 {REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc}, 552 {REG_BINNING_ENABLE, s5k3e2fx_reg_pat[rt].binning_enable}, 553 }; 554 555 struct s5k3e2fx_i2c_reg_conf tbl_2[] = { 556 {REG_FRAME_LENGTH_LINES_MSB, 0}, 557 {REG_FRAME_LENGTH_LINES_LSB, 0}, 558 {REG_LINE_LENGTH_PCK_MSB, s5k3e2fx_reg_pat[rt].line_length_pck_msb}, 559 {REG_LINE_LENGTH_PCK_LSB, s5k3e2fx_reg_pat[rt].line_length_pck_lsb}, 560 {REG_SHADE_CLK_ENABLE, s5k3e2fx_reg_pat[rt].shade_clk_enable}, 561 {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp}, 562 {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix}, 563 {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on}, 564 {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset}, 565 {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start}, 566 {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end}, 567 {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start}, 568 {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end}, 569 {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start}, 570 {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start}, 571 {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end}, 572 {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start}, 573 {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end}, 574 {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start}, 575 {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end}, 576 {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start}, 577 {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start}, 578 {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end}, 579 {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start}, 580 {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start}, 581 {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start}, 582 {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end}, 583 {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width}, 584 {REG_3152_RESERVED, s5k3e2fx_reg_pat[rt].reg_3152_reserved}, 585 {REG_315A_RESERVED, s5k3e2fx_reg_pat[rt].reg_315A_reserved}, 586 {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_msb}, 587 {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_lsb}, 588 {REG_FINE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].fine_integration_time}, 589 {REG_COARSE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].coarse_integration_time}, 590 {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM}, 591 }; 592 593 rc = s5k3e2fx_i2c_write_table(&tbl_1[0], 594 ARRAY_SIZE(tbl_1)); 595 if (rc < 0) 596 return rc; 597 598 num_lperf = 599 (uint16_t)((s5k3e2fx_reg_pat[rt].frame_length_lines_msb << 8) & 0xFF00) + 600 s5k3e2fx_reg_pat[rt].frame_length_lines_lsb; 601 602 num_lperf = num_lperf * s5k3e2fx_ctrl->fps_divider / 0x0400; 603 604 tbl_2[0] = (struct s5k3e2fx_i2c_reg_conf) {REG_FRAME_LENGTH_LINES_MSB, (num_lperf & 0xFF00) >> 8}; 605 tbl_2[1] = (struct s5k3e2fx_i2c_reg_conf) {REG_FRAME_LENGTH_LINES_LSB, (num_lperf & 0x00FF)}; 606 607 rc = s5k3e2fx_i2c_write_table(&tbl_2[0], 608 ARRAY_SIZE(tbl_2)); 609 if (rc < 0) 610 return rc; 611 612 mdelay(5); 613 614 rc = s5k3e2fx_test(s5k3e2fx_ctrl->set_test); 615 if (rc < 0) 616 return rc; 617 } 618 break; /* UPDATE_PERIODIC */ 619 620 case S_REG_INIT: 621 if (rt == S_RES_PREVIEW || rt == S_RES_CAPTURE) { 622 623 struct s5k3e2fx_i2c_reg_conf tbl_3[] = { 624 {S5K3E2FX_REG_SOFTWARE_RESET, S5K3E2FX_SOFTWARE_RESET}, 625 {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_SW_STANDBY}, 626 /* PLL setting */ 627 {REG_PRE_PLL_CLK_DIV, s5k3e2fx_reg_pat[rt].pre_pll_clk_div}, 628 {REG_PLL_MULTIPLIER_MSB, s5k3e2fx_reg_pat[rt].pll_multiplier_msb}, 629 {REG_PLL_MULTIPLIER_LSB, s5k3e2fx_reg_pat[rt].pll_multiplier_lsb}, 630 {REG_VT_PIX_CLK_DIV, s5k3e2fx_reg_pat[rt].vt_pix_clk_div}, 631 {REG_VT_SYS_CLK_DIV, s5k3e2fx_reg_pat[rt].vt_sys_clk_div}, 632 {REG_OP_PIX_CLK_DIV, s5k3e2fx_reg_pat[rt].op_pix_clk_div}, 633 {REG_OP_SYS_CLK_DIV, s5k3e2fx_reg_pat[rt].op_sys_clk_div}, 634 /*Data Format */ 635 {REG_CCP_DATA_FORMAT_MSB, s5k3e2fx_reg_pat[rt].ccp_data_format_msb}, 636 {REG_CCP_DATA_FORMAT_LSB, s5k3e2fx_reg_pat[rt].ccp_data_format_lsb}, 637 /*Output Size */ 638 {REG_X_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].x_output_size_msb}, 639 {REG_X_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].x_output_size_lsb}, 640 {REG_Y_OUTPUT_SIZE_MSB, s5k3e2fx_reg_pat[rt].y_output_size_msb}, 641 {REG_Y_OUTPUT_SIZE_LSB, s5k3e2fx_reg_pat[rt].y_output_size_lsb}, 642 /* Binning */ 643 {REG_X_EVEN_INC, s5k3e2fx_reg_pat[rt].x_even_inc}, 644 {REG_X_ODD_INC, s5k3e2fx_reg_pat[rt].x_odd_inc }, 645 {REG_Y_EVEN_INC, s5k3e2fx_reg_pat[rt].y_even_inc}, 646 {REG_Y_ODD_INC, s5k3e2fx_reg_pat[rt].y_odd_inc}, 647 {REG_BINNING_ENABLE, s5k3e2fx_reg_pat[rt].binning_enable}, 648 /* Frame format */ 649 {REG_FRAME_LENGTH_LINES_MSB, s5k3e2fx_reg_pat[rt].frame_length_lines_msb}, 650 {REG_FRAME_LENGTH_LINES_LSB, s5k3e2fx_reg_pat[rt].frame_length_lines_lsb}, 651 {REG_LINE_LENGTH_PCK_MSB, s5k3e2fx_reg_pat[rt].line_length_pck_msb}, 652 {REG_LINE_LENGTH_PCK_LSB, s5k3e2fx_reg_pat[rt].line_length_pck_lsb}, 653 /* MSR setting */ 654 {REG_SHADE_CLK_ENABLE, s5k3e2fx_reg_pat[rt].shade_clk_enable}, 655 {REG_SEL_CCP, s5k3e2fx_reg_pat[rt].sel_ccp}, 656 {REG_VPIX, s5k3e2fx_reg_pat[rt].vpix}, 657 {REG_CLAMP_ON, s5k3e2fx_reg_pat[rt].clamp_on}, 658 {REG_OFFSET, s5k3e2fx_reg_pat[rt].offset}, 659 /* CDS timing setting */ 660 {REG_LD_START, s5k3e2fx_reg_pat[rt].ld_start}, 661 {REG_LD_END, s5k3e2fx_reg_pat[rt].ld_end}, 662 {REG_SL_START, s5k3e2fx_reg_pat[rt].sl_start}, 663 {REG_SL_END, s5k3e2fx_reg_pat[rt].sl_end}, 664 {REG_RX_START, s5k3e2fx_reg_pat[rt].rx_start}, 665 {REG_S1_START, s5k3e2fx_reg_pat[rt].s1_start}, 666 {REG_S1_END, s5k3e2fx_reg_pat[rt].s1_end}, 667 {REG_S1S_START, s5k3e2fx_reg_pat[rt].s1s_start}, 668 {REG_S1S_END, s5k3e2fx_reg_pat[rt].s1s_end}, 669 {REG_S3_START, s5k3e2fx_reg_pat[rt].s3_start}, 670 {REG_S3_END, s5k3e2fx_reg_pat[rt].s3_end}, 671 {REG_CMP_EN_START, s5k3e2fx_reg_pat[rt].cmp_en_start}, 672 {REG_CLP_SL_START, s5k3e2fx_reg_pat[rt].clp_sl_start}, 673 {REG_CLP_SL_END, s5k3e2fx_reg_pat[rt].clp_sl_end}, 674 {REG_OFF_START, s5k3e2fx_reg_pat[rt].off_start}, 675 {REG_RMP_EN_START, s5k3e2fx_reg_pat[rt].rmp_en_start}, 676 {REG_TX_START, s5k3e2fx_reg_pat[rt].tx_start}, 677 {REG_TX_END, s5k3e2fx_reg_pat[rt].tx_end}, 678 {REG_STX_WIDTH, s5k3e2fx_reg_pat[rt].stx_width}, 679 {REG_3152_RESERVED, s5k3e2fx_reg_pat[rt].reg_3152_reserved}, 680 {REG_315A_RESERVED, s5k3e2fx_reg_pat[rt].reg_315A_reserved}, 681 {REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_msb}, 682 {REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB, s5k3e2fx_reg_pat[rt].analogue_gain_code_global_lsb}, 683 {REG_FINE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].fine_integration_time}, 684 {REG_COARSE_INTEGRATION_TIME, s5k3e2fx_reg_pat[rt].coarse_integration_time}, 685 {S5K3E2FX_REG_MODE_SELECT, S5K3E2FX_MODE_SELECT_STREAM}, 686 }; 687 688 /* reset fps_divider */ 689 s5k3e2fx_ctrl->fps_divider = 1 * 0x0400; 690 rc = s5k3e2fx_i2c_write_table(&tbl_3[0], 691 ARRAY_SIZE(tbl_3)); 692 if (rc < 0) 693 return rc; 694 } 695 break; /* case REG_INIT: */ 696 697 default: 698 rc = -EINVAL; 699 break; 700 } /* switch (rupdate) */ 701 702 return rc; 703} 704 705static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data) 706{ 707 int32_t rc; 708 709 s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL); 710 if (!s5k3e2fx_ctrl) { 711 CDBG("s5k3e2fx_init failed!\n"); 712 rc = -ENOMEM; 713 goto init_done; 714 } 715 716 s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400; 717 s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400; 718 s5k3e2fx_ctrl->set_test = S_TEST_OFF; 719 s5k3e2fx_ctrl->prev_res = S_QTR_SIZE; 720 s5k3e2fx_ctrl->pict_res = S_FULL_SIZE; 721 722 if (data) 723 s5k3e2fx_ctrl->sensordata = data; 724 725 /* enable mclk first */ 726 msm_camio_clk_rate_set(24000000); 727 mdelay(20); 728 729 msm_camio_camif_pad_reg_reset(); 730 mdelay(20); 731 732 rc = s5k3e2fx_probe_init_sensor(data); 733 if (rc < 0) 734 goto init_fail1; 735 736 if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE) 737 rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW); 738 else 739 rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE); 740 741 if (rc < 0) { 742 CDBG("s5k3e2fx_setting failed. rc = %d\n", rc); 743 goto init_fail1; 744 } 745 746 /* initialize AF */ 747 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3A); 748 if (rc < 0) 749 goto init_fail1; 750 751 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x03); 752 if (rc < 0) 753 goto init_fail1; 754 755 goto init_done; 756 757init_fail1: 758 s5k3e2fx_probe_init_done(data); 759 kfree(s5k3e2fx_ctrl); 760init_done: 761 return rc; 762} 763 764static int32_t s5k3e2fx_power_down(void) 765{ 766 int32_t rc = 0; 767 return rc; 768} 769 770static int s5k3e2fx_sensor_release(void) 771{ 772 int rc = -EBADF; 773 774 down(&s5k3e2fx_sem); 775 776 s5k3e2fx_power_down(); 777 778 gpio_direction_output(s5k3e2fx_ctrl->sensordata->sensor_reset, 779 0); 780 gpio_free(s5k3e2fx_ctrl->sensordata->sensor_reset); 781 782 kfree(s5k3e2fx_ctrl); 783 s5k3e2fx_ctrl = NULL; 784 785 CDBG("s5k3e2fx_release completed\n"); 786 787 up(&s5k3e2fx_sem); 788 return rc; 789} 790 791static void s5k3e2fx_get_pict_fps(uint16_t fps, uint16_t *pfps) 792{ 793 /* input fps is preview fps in Q8 format */ 794 uint32_t divider; /* Q10 */ 795 796 divider = (uint32_t) 797 ((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + 798 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * 799 (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + 800 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p)) * 0x00000400 / 801 ((s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + 802 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l) * 803 (s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + 804 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p)); 805 806 /* Verify PCLK settings and frame sizes. */ 807 *pfps = (uint16_t)(fps * divider / 0x00000400); 808} 809 810static uint16_t s5k3e2fx_get_prev_lines_pf(void) 811{ 812 return (s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + 813 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l); 814} 815 816static uint16_t s5k3e2fx_get_prev_pixels_pl(void) 817{ 818 return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + 819 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p; 820} 821 822static uint16_t s5k3e2fx_get_pict_lines_pf(void) 823{ 824 return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + 825 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; 826} 827 828static uint16_t s5k3e2fx_get_pict_pixels_pl(void) 829{ 830 return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + 831 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; 832} 833 834static uint32_t s5k3e2fx_get_pict_max_exp_lc(void) 835{ 836 uint32_t snapshot_lines_per_frame; 837 838 if (s5k3e2fx_ctrl->pict_res == S_QTR_SIZE) 839 snapshot_lines_per_frame = 840 s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + 841 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l; 842 else 843 snapshot_lines_per_frame = 3961 * 3; 844 845 return snapshot_lines_per_frame; 846} 847 848static int32_t s5k3e2fx_set_fps(struct fps_cfg *fps) 849{ 850 /* input is new fps in Q10 format */ 851 int32_t rc = 0; 852 853 s5k3e2fx_ctrl->fps_divider = fps->fps_div; 854 855 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 856 REG_FRAME_LENGTH_LINES_MSB, 857 (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + 858 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * 859 s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00) >> 8); 860 if (rc < 0) 861 goto set_fps_done; 862 863 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 864 REG_FRAME_LENGTH_LINES_LSB, 865 (((s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + 866 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_l) * 867 s5k3e2fx_ctrl->fps_divider / 0x400) & 0xFF00)); 868 869set_fps_done: 870 return rc; 871} 872 873static int32_t s5k3e2fx_write_exp_gain(uint16_t gain, uint32_t line) 874{ 875 int32_t rc = 0; 876 877 uint16_t max_legal_gain = 0x0200; 878 uint32_t ll_ratio; /* Q10 */ 879 uint16_t ll_pck, fl_lines; 880 uint16_t offset = 4; 881 uint8_t gain_msb, gain_lsb; 882 uint8_t intg_t_msb, intg_t_lsb; 883 uint8_t ll_pck_msb, ll_pck_lsb, tmp; 884 885 struct s5k3e2fx_i2c_reg_conf tbl[2]; 886 887 CDBG("Line:%d s5k3e2fx_write_exp_gain \n", __LINE__); 888 889 if (s5k3e2fx_ctrl->sensormode == SENSOR_PREVIEW_MODE) { 890 891 s5k3e2fx_ctrl->my_reg_gain = gain; 892 s5k3e2fx_ctrl->my_reg_line_count = (uint16_t)line; 893 894 fl_lines = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_h + 895 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; 896 897 ll_pck = s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w + 898 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; 899 900 } else { 901 902 fl_lines = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h + 903 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l; 904 905 ll_pck = s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w + 906 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p; 907 } 908 909 if (gain > max_legal_gain) 910 gain = max_legal_gain; 911 912 /* in Q10 */ 913 line = (line * s5k3e2fx_ctrl->fps_divider); 914 915 if (fl_lines < (line / 0x400)) 916 ll_ratio = (line / (fl_lines - offset)); 917 else 918 ll_ratio = 0x400; 919 920 /* update gain registers */ 921 gain_msb = (gain & 0xFF00) >> 8; 922 gain_lsb = gain & 0x00FF; 923 tbl[0].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB; 924 tbl[0].bdata = gain_msb; 925 tbl[1].waddr = REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB; 926 tbl[1].bdata = gain_lsb; 927 rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); 928 if (rc < 0) 929 goto write_gain_done; 930 931 ll_pck = ll_pck * ll_ratio; 932 ll_pck_msb = ((ll_pck / 0x400) & 0xFF00) >> 8; 933 ll_pck_lsb = (ll_pck / 0x400) & 0x00FF; 934 tbl[0].waddr = REG_LINE_LENGTH_PCK_MSB; 935 tbl[0].bdata = s5k3e2fx_reg_pat[S_RES_PREVIEW].line_length_pck_msb; 936 tbl[1].waddr = REG_LINE_LENGTH_PCK_LSB; 937 tbl[1].bdata = s5k3e2fx_reg_pat[S_RES_PREVIEW].line_length_pck_lsb; 938 rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); 939 if (rc < 0) 940 goto write_gain_done; 941 942 tmp = (ll_pck * 0x400) / ll_ratio; 943 intg_t_msb = (tmp & 0xFF00) >> 8; 944 intg_t_lsb = (tmp & 0x00FF); 945 tbl[0].waddr = REG_COARSE_INTEGRATION_TIME; 946 tbl[0].bdata = intg_t_msb; 947 tbl[1].waddr = REG_COARSE_INTEGRATION_TIME_LSB; 948 tbl[1].bdata = intg_t_lsb; 949 rc = s5k3e2fx_i2c_write_table(&tbl[0], ARRAY_SIZE(tbl)); 950 951write_gain_done: 952 return rc; 953} 954 955static int32_t s5k3e2fx_set_pict_exp_gain(uint16_t gain, uint32_t line) 956{ 957 int32_t rc = 0; 958 959 CDBG("Line:%d s5k3e2fx_set_pict_exp_gain \n", __LINE__); 960 961 rc = 962 s5k3e2fx_write_exp_gain(gain, line); 963 964 return rc; 965} 966 967static int32_t s5k3e2fx_video_config(int mode, int res) 968{ 969 int32_t rc; 970 971 switch (res) { 972 case S_QTR_SIZE: 973 rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_PREVIEW); 974 if (rc < 0) 975 return rc; 976 977 CDBG("s5k3e2fx sensor configuration done!\n"); 978 break; 979 980 case S_FULL_SIZE: 981 rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); 982 if (rc < 0) 983 return rc; 984 985 break; 986 987 default: 988 return 0; 989 } /* switch */ 990 991 s5k3e2fx_ctrl->prev_res = res; 992 s5k3e2fx_ctrl->curr_res = res; 993 s5k3e2fx_ctrl->sensormode = mode; 994 995 rc = 996 s5k3e2fx_write_exp_gain(s5k3e2fx_ctrl->my_reg_gain, 997 s5k3e2fx_ctrl->my_reg_line_count); 998 999 return rc; 1000} 1001 1002static int32_t s5k3e2fx_snapshot_config(int mode) 1003{ 1004 int32_t rc = 0; 1005 1006 rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); 1007 if (rc < 0) 1008 return rc; 1009 1010 s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res; 1011 s5k3e2fx_ctrl->sensormode = mode; 1012 1013 return rc; 1014} 1015 1016static int32_t s5k3e2fx_raw_snapshot_config(int mode) 1017{ 1018 int32_t rc = 0; 1019 1020 rc = s5k3e2fx_setting(S_UPDATE_PERIODIC, S_RES_CAPTURE); 1021 if (rc < 0) 1022 return rc; 1023 1024 s5k3e2fx_ctrl->curr_res = s5k3e2fx_ctrl->pict_res; 1025 s5k3e2fx_ctrl->sensormode = mode; 1026 1027 return rc; 1028} 1029 1030static int32_t s5k3e2fx_set_sensor_mode(int mode, int res) 1031{ 1032 int32_t rc = 0; 1033 1034 switch (mode) { 1035 case SENSOR_PREVIEW_MODE: 1036 rc = s5k3e2fx_video_config(mode, res); 1037 break; 1038 1039 case SENSOR_SNAPSHOT_MODE: 1040 rc = s5k3e2fx_snapshot_config(mode); 1041 break; 1042 1043 case SENSOR_RAW_SNAPSHOT_MODE: 1044 rc = s5k3e2fx_raw_snapshot_config(mode); 1045 break; 1046 1047 default: 1048 rc = -EINVAL; 1049 break; 1050 } 1051 1052 return rc; 1053} 1054 1055static int32_t s5k3e2fx_set_default_focus(void) 1056{ 1057 int32_t rc = 0; 1058 1059 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 1060 0x3131, 0); 1061 if (rc < 0) 1062 return rc; 1063 1064 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 1065 0x3132, 0); 1066 if (rc < 0) 1067 return rc; 1068 1069 s5k3e2fx_ctrl->curr_lens_pos = 0; 1070 1071 return rc; 1072} 1073 1074static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps) 1075{ 1076 int32_t rc = 0; 1077 int32_t i; 1078 int16_t step_direction; 1079 int16_t actual_step; 1080 int16_t next_pos, pos_offset; 1081 int16_t init_code = 50; 1082 uint8_t next_pos_msb, next_pos_lsb; 1083 int16_t s_move[5]; 1084 uint32_t gain; /* Q10 format */ 1085 1086 if (direction == MOVE_NEAR) 1087 step_direction = 20; 1088 else if (direction == MOVE_FAR) 1089 step_direction = -20; 1090 else { 1091 CDBG("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__); 1092 return -EINVAL; 1093 } 1094 1095 actual_step = step_direction * (int16_t)num_steps; 1096 pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos; 1097 gain = ((actual_step << 10) / 5) >> 10; 1098 1099 for (i = 0; i <= 4; i++) 1100 s_move[i] = gain; 1101 1102 /* Ring Damping Code */ 1103 for (i = 0; i <= 4; i++) { 1104 next_pos = (int16_t)(pos_offset + s_move[i]); 1105 1106 if (next_pos > (738 + init_code)) 1107 next_pos = 738 + init_code; 1108 else if (next_pos < 0) 1109 next_pos = 0; 1110 1111 CDBG("next_position in damping mode = %d\n", next_pos); 1112 /* Writing the Values to the actuator */ 1113 if (next_pos == init_code) 1114 next_pos = 0x00; 1115 1116 next_pos_msb = next_pos >> 8; 1117 next_pos_lsb = next_pos & 0x00FF; 1118 1119 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131, next_pos_msb); 1120 if (rc < 0) 1121 break; 1122 1123 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132, next_pos_lsb); 1124 if (rc < 0) 1125 break; 1126 1127 pos_offset = next_pos; 1128 s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code; 1129 if (i < 4) 1130 mdelay(3); 1131 } 1132 1133 return rc; 1134} 1135 1136static int s5k3e2fx_sensor_config(void __user *argp) 1137{ 1138 struct sensor_cfg_data cdata; 1139 long rc = 0; 1140 1141 if (copy_from_user(&cdata, 1142 (void *)argp, 1143 sizeof(struct sensor_cfg_data))) 1144 return -EFAULT; 1145 1146 down(&s5k3e2fx_sem); 1147 1148 CDBG("%s: cfgtype = %d\n", __func__, cdata.cfgtype); 1149 switch (cdata.cfgtype) { 1150 case CFG_GET_PICT_FPS: 1151 s5k3e2fx_get_pict_fps(cdata.cfg.gfps.prevfps, 1152 &(cdata.cfg.gfps.pictfps)); 1153 1154 if (copy_to_user((void *)argp, &cdata, 1155 sizeof(struct sensor_cfg_data))) 1156 rc = -EFAULT; 1157 break; 1158 1159 case CFG_GET_PREV_L_PF: 1160 cdata.cfg.prevl_pf = s5k3e2fx_get_prev_lines_pf(); 1161 1162 if (copy_to_user((void *)argp, 1163 &cdata, 1164 sizeof(struct sensor_cfg_data))) 1165 rc = -EFAULT; 1166 break; 1167 1168 case CFG_GET_PREV_P_PL: 1169 cdata.cfg.prevp_pl = s5k3e2fx_get_prev_pixels_pl(); 1170 1171 if (copy_to_user((void *)argp, 1172 &cdata, 1173 sizeof(struct sensor_cfg_data))) 1174 rc = -EFAULT; 1175 break; 1176 1177 case CFG_GET_PICT_L_PF: 1178 cdata.cfg.pictl_pf = s5k3e2fx_get_pict_lines_pf(); 1179 1180 if (copy_to_user((void *)argp, 1181 &cdata, 1182 sizeof(struct sensor_cfg_data))) 1183 rc = -EFAULT; 1184 break; 1185 1186 case CFG_GET_PICT_P_PL: 1187 cdata.cfg.pictp_pl = s5k3e2fx_get_pict_pixels_pl(); 1188 1189 if (copy_to_user((void *)argp, 1190 &cdata, 1191 sizeof(struct sensor_cfg_data))) 1192 rc = -EFAULT; 1193 break; 1194 1195 case CFG_GET_PICT_MAX_EXP_LC: 1196 cdata.cfg.pict_max_exp_lc = 1197 s5k3e2fx_get_pict_max_exp_lc(); 1198 1199 if (copy_to_user((void *)argp, 1200 &cdata, 1201 sizeof(struct sensor_cfg_data))) 1202 rc = -EFAULT; 1203 break; 1204 1205 case CFG_SET_FPS: 1206 case CFG_SET_PICT_FPS: 1207 rc = s5k3e2fx_set_fps(&(cdata.cfg.fps)); 1208 break; 1209 1210 case CFG_SET_EXP_GAIN: 1211 rc = 1212 s5k3e2fx_write_exp_gain(cdata.cfg.exp_gain.gain, 1213 cdata.cfg.exp_gain.line); 1214 break; 1215 1216 case CFG_SET_PICT_EXP_GAIN: 1217 CDBG("Line:%d CFG_SET_PICT_EXP_GAIN \n", __LINE__); 1218 rc = 1219 s5k3e2fx_set_pict_exp_gain( 1220 cdata.cfg.exp_gain.gain, 1221 cdata.cfg.exp_gain.line); 1222 break; 1223 1224 case CFG_SET_MODE: 1225 rc = 1226 s5k3e2fx_set_sensor_mode( 1227 cdata.mode, cdata.rs); 1228 break; 1229 1230 case CFG_PWR_DOWN: 1231 rc = s5k3e2fx_power_down(); 1232 break; 1233 1234 case CFG_MOVE_FOCUS: 1235 rc = 1236 s5k3e2fx_move_focus( 1237 cdata.cfg.focus.dir, 1238 cdata.cfg.focus.steps); 1239 break; 1240 1241 case CFG_SET_DEFAULT_FOCUS: 1242 rc = 1243 s5k3e2fx_set_default_focus(); 1244 break; 1245 1246 case CFG_GET_AF_MAX_STEPS: 1247 case CFG_SET_EFFECT: 1248 case CFG_SET_LENS_SHADING: 1249 default: 1250 rc = -EINVAL; 1251 break; 1252 } 1253 1254 up(&s5k3e2fx_sem); 1255 return rc; 1256} 1257 1258static int s5k3e2fx_sensor_probe(const struct msm_camera_sensor_info *info, 1259 struct msm_sensor_ctrl *s) 1260{ 1261 int rc = 0; 1262 1263 rc = i2c_add_driver(&s5k3e2fx_i2c_driver); 1264 if (rc < 0 || s5k3e2fx_client == NULL) { 1265 rc = -ENOTSUPP; 1266 goto probe_fail; 1267 } 1268 1269 msm_camio_clk_rate_set(24000000); 1270 mdelay(20); 1271 1272 rc = s5k3e2fx_probe_init_sensor(info); 1273 if (rc < 0) 1274 goto probe_fail; 1275 1276 s->s_init = s5k3e2fx_sensor_open_init; 1277 s->s_release = s5k3e2fx_sensor_release; 1278 s->s_config = s5k3e2fx_sensor_config; 1279 s5k3e2fx_probe_init_done(info); 1280 1281 return rc; 1282 1283probe_fail: 1284 CDBG("SENSOR PROBE FAILS!\n"); 1285 return rc; 1286} 1287 1288static int __s5k3e2fx_probe(struct platform_device *pdev) 1289{ 1290 return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe); 1291} 1292 1293static struct platform_driver msm_camera_driver = { 1294 .probe = __s5k3e2fx_probe, 1295 .driver = { 1296 .name = "msm_camera_s5k3e2fx", 1297 .owner = THIS_MODULE, 1298 }, 1299}; 1300 1301static int __init s5k3e2fx_init(void) 1302{ 1303 return platform_driver_register(&msm_camera_driver); 1304} 1305 1306module_init(s5k3e2fx_init); 1307