841792e2624b23bda21cb28fc21bd5843d752cf2
[linux-flexiantxendom0-natty.git] / drivers / staging / dream / camera / s5k3e2fx.c
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
100 struct 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
159 struct 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
284 struct s5k3e2fx_work {
285         struct work_struct work;
286 };
287 static struct s5k3e2fx_work *s5k3e2fx_sensorw;
288 static struct i2c_client *s5k3e2fx_client;
289
290 struct 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
308 struct s5k3e2fx_i2c_reg_conf {
309         unsigned short waddr;
310         unsigned char  bdata;
311 };
312
313 static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl;
314 static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue);
315 DECLARE_MUTEX(s5k3e2fx_sem);
316
317 static 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
343 static 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
363 static 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
383 static 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
397 static 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
423 static 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
430 static 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
458 init_probe_fail:
459         s5k3e2fx_probe_init_done(data);
460 init_probe_done:
461         return rc;
462 }
463
464 static 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
471 static const struct i2c_device_id s5k3e2fx_i2c_id[] = {
472         { "s5k3e2fx", 0},
473         { }
474 };
475
476 static 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
503 probe_failure:
504         CDBG("s5k3e2fx_probe failed! rc = %d\n", rc);
505         return rc;
506 }
507
508 static 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
517 static 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
530 static 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
704 static 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         rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3A);
747         if (rc < 0)
748                 goto init_fail1;
749
750         rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x03);
751         if (rc < 0)
752                 goto init_fail1;
753
754         goto init_done;
755
756 init_fail1:
757         s5k3e2fx_probe_init_done(data);
758         kfree(s5k3e2fx_ctrl);
759 init_done:
760         return rc;
761 }
762
763 static int32_t s5k3e2fx_power_down(void)
764 {
765         int32_t rc = 0;
766         return rc;
767 }
768
769 static 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
790 static 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
809 static 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
815 static 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
821 static 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
827 static 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
833 static 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
847 static 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
868 set_fps_done:
869         return rc;
870 }
871
872 static 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
950 write_gain_done:
951         return rc;
952 }
953
954 static 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
966 static 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
1001 static 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
1015 static 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
1029 static 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
1054 static 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
1073 static 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;
1096         gain = ((actual_step << 10) / 5) >> 10;
1097
1098         for (i = 0; i <= 4; i++)
1099                 s_move[i] = gain;
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
1135 static 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
1257 static 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
1282 probe_fail:
1283         CDBG("SENSOR PROBE FAILS!\n");
1284         return rc;
1285 }
1286
1287 static int __s5k3e2fx_probe(struct platform_device *pdev)
1288 {
1289         return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe);
1290 }
1291
1292 static struct platform_driver msm_camera_driver = {
1293         .probe = __s5k3e2fx_probe,
1294         .driver = {
1295                 .name = "msm_camera_s5k3e2fx",
1296                 .owner = THIS_MODULE,
1297         },
1298 };
1299
1300 static int __init s5k3e2fx_init(void)
1301 {
1302         return platform_driver_register(&msm_camera_driver);
1303 }
1304
1305 module_init(s5k3e2fx_init);
1306