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