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