staging: Final semaphore cleanup
[pandora-kernel.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/slab.h>
7 #include <linux/types.h>
8 #include <linux/i2c.h>
9 #include <linux/uaccess.h>
10 #include <linux/miscdevice.h>
11 #include <media/msm_camera.h>
12 #include <mach/gpio.h>
13 #include <mach/camera.h>
14 #include "s5k3e2fx.h"
15
16 #define S5K3E2FX_REG_MODEL_ID   0x0000
17 #define S5K3E2FX_MODEL_ID               0x3E2F
18
19 /* PLL Registers */
20 #define REG_PRE_PLL_CLK_DIV                     0x0305
21 #define REG_PLL_MULTIPLIER_MSB                  0x0306
22 #define REG_PLL_MULTIPLIER_LSB                  0x0307
23 #define REG_VT_PIX_CLK_DIV                      0x0301
24 #define REG_VT_SYS_CLK_DIV                      0x0303
25 #define REG_OP_PIX_CLK_DIV                      0x0309
26 #define REG_OP_SYS_CLK_DIV                      0x030B
27
28 /* Data Format Registers */
29 #define REG_CCP_DATA_FORMAT_MSB                 0x0112
30 #define REG_CCP_DATA_FORMAT_LSB                 0x0113
31
32 /* Output Size */
33 #define REG_X_OUTPUT_SIZE_MSB                   0x034C
34 #define REG_X_OUTPUT_SIZE_LSB                   0x034D
35 #define REG_Y_OUTPUT_SIZE_MSB                   0x034E
36 #define REG_Y_OUTPUT_SIZE_LSB                   0x034F
37
38 /* Binning */
39 #define REG_X_EVEN_INC                          0x0381
40 #define REG_X_ODD_INC                           0x0383
41 #define REG_Y_EVEN_INC                          0x0385
42 #define REG_Y_ODD_INC                           0x0387
43 /*Reserved register */
44 #define REG_BINNING_ENABLE                      0x3014
45
46 /* Frame Fotmat */
47 #define REG_FRAME_LENGTH_LINES_MSB              0x0340
48 #define REG_FRAME_LENGTH_LINES_LSB              0x0341
49 #define REG_LINE_LENGTH_PCK_MSB                 0x0342
50 #define REG_LINE_LENGTH_PCK_LSB                 0x0343
51
52 /* MSR setting */
53 /* Reserved registers */
54 #define REG_SHADE_CLK_ENABLE                    0x30AC
55 #define REG_SEL_CCP                             0x30C4
56 #define REG_VPIX                                0x3024
57 #define REG_CLAMP_ON                            0x3015
58 #define REG_OFFSET                              0x307E
59
60 /* CDS timing settings */
61 /* Reserved registers */
62 #define REG_LD_START                            0x3000
63 #define REG_LD_END                              0x3001
64 #define REG_SL_START                            0x3002
65 #define REG_SL_END                              0x3003
66 #define REG_RX_START                            0x3004
67 #define REG_S1_START                            0x3005
68 #define REG_S1_END                              0x3006
69 #define REG_S1S_START                           0x3007
70 #define REG_S1S_END                             0x3008
71 #define REG_S3_START                            0x3009
72 #define REG_S3_END                              0x300A
73 #define REG_CMP_EN_START                        0x300B
74 #define REG_CLP_SL_START                        0x300C
75 #define REG_CLP_SL_END                          0x300D
76 #define REG_OFF_START                           0x300E
77 #define REG_RMP_EN_START                        0x300F
78 #define REG_TX_START                            0x3010
79 #define REG_TX_END                              0x3011
80 #define REG_STX_WIDTH                           0x3012
81 #define REG_TYPE1_AF_ENABLE                     0x3130
82 #define DRIVER_ENABLED                          0x0001
83 #define AUTO_START_ENABLED                      0x0010
84 #define REG_NEW_POSITION                        0x3131
85 #define REG_3152_RESERVED                       0x3152
86 #define REG_315A_RESERVED                       0x315A
87 #define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204
88 #define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205
89 #define REG_FINE_INTEGRATION_TIME               0x0200
90 #define REG_COARSE_INTEGRATION_TIME             0x0202
91 #define REG_COARSE_INTEGRATION_TIME_LSB   0x0203
92
93 /* Mode select register */
94 #define S5K3E2FX_REG_MODE_SELECT                0x0100
95 #define S5K3E2FX_MODE_SELECT_STREAM             0x01   /* start streaming */
96 #define S5K3E2FX_MODE_SELECT_SW_STANDBY 0x00   /* software standby */
97 #define S5K3E2FX_REG_SOFTWARE_RESET   0x0103
98 #define S5K3E2FX_SOFTWARE_RESET                 0x01
99 #define REG_TEST_PATTERN_MODE                   0x0601
100
101 struct 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
160 struct 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
285 struct s5k3e2fx_work {
286         struct work_struct work;
287 };
288 static struct s5k3e2fx_work *s5k3e2fx_sensorw;
289 static struct i2c_client *s5k3e2fx_client;
290
291 struct 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
309 struct s5k3e2fx_i2c_reg_conf {
310         unsigned short waddr;
311         unsigned char  bdata;
312 };
313
314 static struct s5k3e2fx_ctrl *s5k3e2fx_ctrl;
315 static DECLARE_WAIT_QUEUE_HEAD(s5k3e2fx_wait_queue);
316 DEFINE_SEMAPHORE(s5k3e2fx_sem);
317
318 static 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
344 static 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
364 static 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
384 static 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
398 static 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
424 static 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
431 static 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
459 init_probe_fail:
460         s5k3e2fx_probe_init_done(data);
461 init_probe_done:
462         return rc;
463 }
464
465 static 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
472 static const struct i2c_device_id s5k3e2fx_i2c_id[] = {
473         { "s5k3e2fx", 0},
474         { }
475 };
476
477 static 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
504 probe_failure:
505         CDBG("s5k3e2fx_probe failed! rc = %d\n", rc);
506         return rc;
507 }
508
509 static 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
518 static 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
531 static 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
705 static int s5k3e2fx_sensor_open_init(const struct msm_camera_sensor_info *data)
706 {
707         int32_t  rc;
708
709         s5k3e2fx_ctrl = kzalloc(sizeof(struct s5k3e2fx_ctrl), GFP_KERNEL);
710         if (!s5k3e2fx_ctrl) {
711                 CDBG("s5k3e2fx_init failed!\n");
712                 rc = -ENOMEM;
713                 goto init_done;
714         }
715
716         s5k3e2fx_ctrl->fps_divider = 1 * 0x00000400;
717         s5k3e2fx_ctrl->pict_fps_divider = 1 * 0x00000400;
718         s5k3e2fx_ctrl->set_test = S_TEST_OFF;
719         s5k3e2fx_ctrl->prev_res = S_QTR_SIZE;
720         s5k3e2fx_ctrl->pict_res = S_FULL_SIZE;
721
722         if (data)
723                 s5k3e2fx_ctrl->sensordata = data;
724
725         /* enable mclk first */
726         msm_camio_clk_rate_set(24000000);
727         mdelay(20);
728
729         msm_camio_camif_pad_reg_reset();
730         mdelay(20);
731
732         rc = s5k3e2fx_probe_init_sensor(data);
733         if (rc < 0)
734                 goto init_fail1;
735
736         if (s5k3e2fx_ctrl->prev_res == S_QTR_SIZE)
737                 rc = s5k3e2fx_setting(S_REG_INIT, S_RES_PREVIEW);
738         else
739                 rc = s5k3e2fx_setting(S_REG_INIT, S_RES_CAPTURE);
740
741         if (rc < 0) {
742                 CDBG("s5k3e2fx_setting failed. rc = %d\n", rc);
743                 goto init_fail1;
744         }
745
746         /* initialize AF */
747         rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3146, 0x3A);
748         if (rc < 0)
749                 goto init_fail1;
750
751         rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3130, 0x03);
752         if (rc < 0)
753                 goto init_fail1;
754
755         goto init_done;
756
757 init_fail1:
758         s5k3e2fx_probe_init_done(data);
759         kfree(s5k3e2fx_ctrl);
760 init_done:
761         return rc;
762 }
763
764 static int32_t s5k3e2fx_power_down(void)
765 {
766         int32_t rc = 0;
767         return rc;
768 }
769
770 static 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
791 static 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
810 static 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
816 static uint16_t s5k3e2fx_get_prev_pixels_pl(void)
817 {
818         return s5k3e2fx_reg_pat[S_RES_PREVIEW].size_w +
819                 s5k3e2fx_reg_pat[S_RES_PREVIEW].blk_p;
820 }
821
822 static uint16_t s5k3e2fx_get_pict_lines_pf(void)
823 {
824         return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_h +
825                 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_l;
826 }
827
828 static uint16_t s5k3e2fx_get_pict_pixels_pl(void)
829 {
830         return s5k3e2fx_reg_pat[S_RES_CAPTURE].size_w +
831                 s5k3e2fx_reg_pat[S_RES_CAPTURE].blk_p;
832 }
833
834 static 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
848 static 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
869 set_fps_done:
870         return rc;
871 }
872
873 static 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
951 write_gain_done:
952         return rc;
953 }
954
955 static 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
967 static 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
1002 static 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
1016 static 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
1030 static 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
1055 static 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
1074 static int32_t s5k3e2fx_move_focus(int direction, int32_t num_steps)
1075 {
1076         int32_t rc = 0;
1077         int32_t i;
1078         int16_t step_direction;
1079         int16_t actual_step;
1080         int16_t next_pos, pos_offset;
1081         int16_t init_code = 50;
1082         uint8_t next_pos_msb, next_pos_lsb;
1083         int16_t s_move[5];
1084         uint32_t gain; /* Q10 format */
1085
1086         if (direction == MOVE_NEAR)
1087                 step_direction = 20;
1088         else if (direction == MOVE_FAR)
1089                 step_direction = -20;
1090         else {
1091                 CDBG("s5k3e2fx_move_focus failed at line %d ...\n", __LINE__);
1092                 return -EINVAL;
1093         }
1094
1095         actual_step = step_direction * (int16_t)num_steps;
1096         pos_offset = init_code + s5k3e2fx_ctrl->curr_lens_pos;
1097         gain = ((actual_step << 10) / 5) >> 10;
1098
1099         for (i = 0; i <= 4; i++)
1100                 s_move[i] = gain;
1101
1102         /* Ring Damping Code */
1103         for (i = 0; i <= 4; i++) {
1104                 next_pos = (int16_t)(pos_offset + s_move[i]);
1105
1106                 if (next_pos > (738 + init_code))
1107                         next_pos = 738 + init_code;
1108                 else if (next_pos < 0)
1109                         next_pos = 0;
1110
1111                 CDBG("next_position in damping mode = %d\n", next_pos);
1112                 /* Writing the Values to the actuator */
1113                 if (next_pos == init_code)
1114                         next_pos = 0x00;
1115
1116                 next_pos_msb = next_pos >> 8;
1117                 next_pos_lsb = next_pos & 0x00FF;
1118
1119                 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3131, next_pos_msb);
1120                 if (rc < 0)
1121                         break;
1122
1123                 rc = s5k3e2fx_i2c_write_b(s5k3e2fx_client->addr, 0x3132, next_pos_lsb);
1124                 if (rc < 0)
1125                         break;
1126
1127                 pos_offset = next_pos;
1128                 s5k3e2fx_ctrl->curr_lens_pos = pos_offset - init_code;
1129                 if (i < 4)
1130                         mdelay(3);
1131         }
1132
1133         return rc;
1134 }
1135
1136 static 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
1258 static 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
1283 probe_fail:
1284         CDBG("SENSOR PROBE FAILS!\n");
1285         return rc;
1286 }
1287
1288 static int __s5k3e2fx_probe(struct platform_device *pdev)
1289 {
1290         return msm_camera_drv_start(pdev, s5k3e2fx_sensor_probe);
1291 }
1292
1293 static struct platform_driver msm_camera_driver = {
1294         .probe = __s5k3e2fx_probe,
1295         .driver = {
1296                 .name = "msm_camera_s5k3e2fx",
1297                 .owner = THIS_MODULE,
1298         },
1299 };
1300
1301 static int __init s5k3e2fx_init(void)
1302 {
1303         return platform_driver_register(&msm_camera_driver);
1304 }
1305
1306 module_init(s5k3e2fx_init);
1307