]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/camera/s5k3e2fx.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[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>
5a0e3ad6 6#include <linux/slab.h>
eb7b797b
BS
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 */
b94c765a 747 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3A);
13a21ad1 748 if (rc < 0)
eb7b797b
BS
749 goto init_fail1;
750
b94c765a 751 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x03);
13a21ad1 752 if (rc < 0)
eb7b797b
BS
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{
13a21ad1
JM
818 return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
819 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
eb7b797b
BS
820}
821
822static uint16_t s5k3e2fx_get_pict_lines_pf(void)
823{
13a21ad1
JM
824 return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
825 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
eb7b797b
BS
826}
827
828static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
829{
13a21ad1
JM
830 return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
831 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
eb7b797b
BS
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;
8c172dde 1097 gain = ((actual_step << 10) / 5) >> 10;
eb7b797b 1098
8c172dde
JM
1099 for (i = 0; i <= 4; i++)
1100 s_move[i] = gain;
eb7b797b
BS
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