📄 3xa_sensor.c
字号:
1 /*
2 * Copyright (C) 2004 Samsung Electronics
3 * SW.LEE <hitchcar@samsung.com>
4 * - based on Russell King : pcf8583.c
5 * - added smdk24a0, smdk2440
6 * - added poseidon (s3c24a0+wavecom)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Driver for FIMC2.x Camera Decoder
13 *
14 */
15
16 //#include <linux/config.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/i2c.h>
21 #include <linux/i2c-id.h>
22 #include <linux/slab.h>
23 #include <linux/string.h>
24 #include <linux/init.h>
25 #include <linux/delay.h>
26
27 //#define CAMIF_DEBUG
28
29 //#include <asm/arch/registers.h>
30 #include "../s3c_camif.h"
31 #include "3xa_sensor.h"
32
33 static const char *sensor_version =
34 "$Id: 3xa_sensor.c,v 1.3 2007/09/07 01:11:37 yreom Exp $";
35
36
37 static struct i2c_driver sensor_driver;
38
39 /* This is an abstract CIS sensor for MSDMA input. */
40
41 camif_cis_t msdma_input = {
42 itu_fmt: CAMIF_ITU601,
43 order422: CAMIF_YCBYCR, /* YCRYCB */
44 camclk: 32000000, /* No effect */
45 source_x: 800,
46 source_y: 480,
47 win_hor_ofst: 0,
48 win_ver_ofst: 0,
49 win_hor_ofst2: 0,
50 win_ver_ofst2: 0,
51 polarity_pclk: 0,
52 polarity_vsync:1,
53 polarity_href: 0,
54 reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */
55 reset_udelay: 20000,
56 };
57
58 camif_cis_t interlace_input = {
59 itu_fmt: CAMIF_ITU601,
60 order422: CAMIF_YCBYCR, /* YCRYCB */
61 camclk: 32000000, /* No effect */
62 source_x: 720,
63 source_y: 243,
64 win_hor_ofst: 0,
65 win_ver_ofst: 0,
66 win_hor_ofst2: 0,
67 win_ver_ofst2: 0,
68 polarity_pclk: 1,
69 polarity_vsync:0,
70 polarity_href: 0,
71 reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */
72 reset_udelay: 20000,
73 };
74
75 #if defined(CONFIG_VIDEO_SAMSUNG_S5K3AA)
76 /* This is SXGA(1280x1024) camera but start from VGA(640x480) mode */
77 static camif_cis_t data = {
78 itu_fmt: CAMIF_ITU601,
79 order422: CAMIF_CBYCRY, /* YCRYCB */
80 camclk: 32000000, /* No effect */
81 source_x: 640,
82 source_y: 480,
83 win_hor_ofst: 112,
84 win_ver_ofst: 20,
85 win_hor_ofst2: 112,
86 win_ver_ofst2: 20,
87 polarity_pclk: 1,
88 polarity_vsync:0,
89 polarity_href: 0,
90
91 #ifdef CONFIG_CPU_S3C24A0A
92 reset_type:CAMIF_EX_RESET_AL, /* Active Low */
93 #else
94 reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */
95 #endif
96 reset_udelay: 20000,
97 };
98
99 s5k3xa_t s5k3aa_regs_mirror[S5K3AA_REGS];
100
101 #elif defined(CONFIG_VIDEO_SAMSUNG_S5K3BA)
102 /* This is UXGA(1600x1200) camera but start from SVGA(800x600) mode */
103 static camif_cis_t data = {
104 itu_fmt: CAMIF_ITU601,
105 order422: CAMIF_YCBYCR, /* YCRYCB */
106 camclk: 32000000, /* No effect */
107 source_x: 640,
108 source_y: 480,
109 win_hor_ofst: 112,
110 win_ver_ofst: 20,
111 win_hor_ofst2: 112,
112 win_ver_ofst2: 20,
113 polarity_pclk: 1,
114 polarity_vsync:1,
115 polarity_href: 0,
116 reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */
117 reset_udelay: 20000,
118 };
119
120 s5k3xa_t s5k3ba_regs_mirror[S5K3BA_REGS];
121 #else
122 #error No samsung CIS moudule here !
123 #endif
124
125 extern camif_cis_t* get_initialized_cis();
126 camif_cis_t* get_initialized_cis() {
127 if(data.init_sensor == 0) return NULL;
128 return &data;
129
130 }
131
132 #define CAM_ID 0x5a
133
134 static unsigned short ignore[] = { I2C_CLIENT_END };
135 static unsigned short normal_addr[] = { (CAM_ID >> 1), I2C_CLIENT_END };
136 static unsigned short *forces[] = { NULL };
137
138 static struct i2c_client_address_data addr_data = {
139 normal_i2c:normal_addr,
140 //normal_i2c_range:ignore,
141 probe:ignore,
142 //probe_range:ignore,
143 ignore:ignore,
144 //ignore_range:ignore,
145 forces:forces,
146 };
147
148
149 unsigned char sensor_read(struct i2c_client *client, unsigned char subaddr)
150 {
151 int ret;
152 unsigned char buf[1];
153 struct i2c_msg msg = { client->addr, 0, 1, buf };
154 buf[0] = subaddr;
155
156 ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
157 if (ret == -EIO) {
158 printk(" I2C write Error \n");
159 return -EIO;
160 }
161
162 msg.flags = I2C_M_RD;
163 ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
164
165 return buf[0];
166 }
167
168
169 static int
170 sensor_write(struct i2c_client *client,
171 unsigned char subaddr, unsigned char val)
172 {
173 unsigned char buf[2];
174 struct i2c_msg msg = { client->addr, 0, 2, buf };
175
176 buf[0] = subaddr;
177 buf[1] = val;
178
179 return i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
180 }
181
182 #if defined(CONFIG_VIDEO_SAMSUNG_S5K3AA)
183 void inline sensor_init(struct i2c_client *sam_client)
184 {
185 int i;
186 i = (sizeof(s5k3aa_reg)/sizeof(s5k3aa_reg[0]));
187
188 for (i = 0; i < S5K3AA_INIT_REGS; i++) {
189 sensor_write(sam_client,
190 s5k3aa_reg[i].subaddr, s5k3aa_reg[i].value);
191 #if 0
192 printk(KERN_ERR "Page:[%03d] Subaddr %02x = 0x%02x\n",i,
193 s5k3aa_reg[i].subaddr,
194 s5k3aa_reg[i].value);
195 #endif
196 }
197
198 #ifdef YOU_WANT_TO_CHECK_IMG_SENSOR
199 for (i = 0; i < S5K3AA_INIT_REGS; i++) {
200 if (s5k3aa_reg[i].subaddr == PAGE_ADDRESS) {
201 sensor_write(sam_client,
202 s5k3aa_reg[i].subaddr,
203 s5k3aa_reg[i].value);
204
205 printk(KERN_ERR "Page: Subaddr %02x = 0x%02x\n",
206 s5k3aa_reg[i].subaddr,
207 s5k3aa_reg[i].value);
208
209
210 } else {
211 s5k3aa_regs_mirror[i].subaddr =
212 s5k3aa_reg[i].subaddr;
213 s5k3aa_regs_mirror[i].value =
214 s5k3aa_read(sam_client, s5k3aa_reg[i].subaddr);
215 printk(KERN_ERR "Subaddr %02x = 0x%02x\n",
216 s5k3aa_reg[i].subaddr,
217 s5k3aa_regs_mirror[i].value);
218 }
219 }
220 #endif
221 }
222
223 #elif defined(CONFIG_VIDEO_SAMSUNG_S5K3BA)
224 void inline sensor_init(struct i2c_client *sam_client)
225 {
226 int i;
227 i = (sizeof(s5k3ba_reg)/sizeof(s5k3ba_reg[0]));
228
229 for (i = 0; i < S5K3BA_INIT_REGS; i++) {
230 sensor_write(sam_client,
231 s5k3ba_reg[i].subaddr, s5k3ba_reg[i].value);
232 }
233 }
234 #else
235 #error No samsung CIS moudule !
236 #endif
237
238 static int
239 s5k3xa_attach(struct i2c_adapter *adap, int addr, unsigned short flags,
240 int kind)
241 {
242 struct i2c_client *c;
243
244 c = kmalloc(sizeof(*c), GFP_KERNEL);
245 if (!c)
246 return -ENOMEM;
247
248 memset(c, 0, sizeof(struct i2c_client));
249
250 strcpy(c->name, "S5K3XA");
251 //c->id = sensor_driver.id;
252 //c->flags = I2C_CLIENT_ALLOW_USE;
253 c->addr = addr;
254 c->adapter = adap;
255 c->driver = &sensor_driver;
256 c->data = &data;
257 data.sensor = c;
258
259 camif_register_cis(c);
260 return i2c_attach_client(c);
261 }
262
263 static int sensor_attach_adapter(struct i2c_adapter *adap)
264 {
265 return i2c_probe(adap, &addr_data, s5k3xa_attach);
266 }
267
268 static int sensor_detach(struct i2c_client *client)
269 {
270 i2c_detach_client(client);
271 camif_unregister_cis(client);
272 return 0;
273 }
274
275 /* Purpose:
276 This fucntion only for SXGA Camera : 3AA
277 This fucntion only for UXGA Camera : 3BA
278 */
279 static int change_sensor_size(struct i2c_client *client, int size)
280 {
281 int i;
282
283 switch (size) {
284 #if defined(CONFIG_VIDEO_SAMSUNG_S5K3AA)
285 case SENSOR_VGA:
286 for (i = 0; i < S5K3AA_VGA_REGS; i++) {
287 sensor_write(client, s5k3aa_reg_vga[i].subaddr,
288 s5k3aa_reg_vga[i].value);
289 }
290 break;
291 case SENSOR_SXGA:
292 for (i = 0; i < S5K3AA_SXGA_REGS; i++) {
293 sensor_write(client, s5k3aa_reg_sxga[i].subaddr,
294 s5k3aa_reg_sxga[i].value);
295 }
296 break;
297
298 #elif defined(CONFIG_VIDEO_SAMSUNG_S5K3BA)
299 case SENSOR_VGA:
300 for (i = 0; i < S5K3BA_VGA_REGS; i++) {
301 sensor_write(client, s5k3ba_reg_vga[i].subaddr,
302 s5k3ba_reg_vga[i].value);
303 }
304 break;
305
306 case SENSOR_SVGA:
307 for (i = 0; i < S5K3BA_INIT_REGS; i++) {
308 sensor_write(client, s5k3ba_reg[i].subaddr,
309 s5k3ba_reg[i].value);
310 }
311 break;
312 case SENSOR_UXGA:
313 for (i = 0; i < S5K3BA_UXGA_REGS; i++) {
314 sensor_write(client, s5k3ba_reg_uxga[i].subaddr,
315 s5k3ba_reg_uxga[i].value);
316 }
317 break;
318 #else
319 #error No samsung CIS moudule !
320 #endif
321 default:
322 panic("3xa_sensor.c: unexpect value \n");
323 }
324
325 return 0;
326 }
327
328 static int change_sensor_wb(struct i2c_client *client, int type)
329 {
330 printk("[ *** Page 0, 3XA Sensor White Balance Mode ***]\n");
331
332 #if defined(CONFIG_VIDEO_SAMSUNG_S5K3AA)
333 sensor_write(client, 0xEC, 0x0);
334 sensor_write(client, 0x30, type);
335 #elif defined(CONFIG_VIDEO_SAMSUNG_S5K3BA)
336 sensor_write(client, 0xFC, 0x0);
337 sensor_write(client, 0x30, type);
338 #endif
339
340 switch(type){
341 case 0:
342 default:
343 printk(" -> AWB auto mode ]\n");
344 break;
345 case 1:
346 printk(" -> Indoor 3100 mode ]\n");
347 break;
348 case 2:
349 printk(" -> Outdoor 5100 mode ]\n");
350 break;
351 case 3:
352 printk(" -> Indoor 2000 mode ]\n");
353 break;
354 case 4:
355 printk(" -> AE/AWB halt ]\n");
356 break;
357 case 5:
358 printk(" -> Cloudy(6000) mode ]\n");
359 break;
360 case 6:
361 printk(" -> Sunny(8000) mode ]\n");
362 break;
363 }
364
365 return 0;
366 }
367
368 static int
369 sensor_command(struct i2c_client *client, unsigned int cmd, void *arg)
370 {
371 switch (cmd) {
372 case SENSOR_INIT:
373 sensor_init(client);
374 printk(KERN_INFO "External Camera initialized\n");
375 break;
376
377 case USER_ADD:
378 //MOD_INC_USE_COUNT;
379 break;
380
381 case USER_EXIT:
382 //MOD_DEC_USE_COUNT;
383 break;
384
385 case SENSOR_VGA:
386 change_sensor_size(client, SENSOR_VGA);
387 break;
388
389 case SENSOR_SVGA:
390 change_sensor_size(client, SENSOR_SVGA);
391 break;
392
393 case SENSOR_SXGA:
394 change_sensor_size(client, SENSOR_SXGA);
395 break;
396
397 case SENSOR_UXGA:
398 change_sensor_size(client, SENSOR_UXGA);
399 break;
400 /* Todo
401 case SENSOR_BRIGHTNESS:
402 change_sensor_setting();
403 break;
404 */
405 case SENSOR_WB:
406 printk("[ *** 3XA Sensor White Balance , No mode ***]\n");
407 change_sensor_wb(client, arg);
408 break;
409
410 default:
411 panic("3xa_sensor.c : Unexpect Sensor Command \n");
412 break;
413 }
414
415 return 0;
416 }
417
418 static struct i2c_driver sensor_driver = {
419 .driver = {
420 .name = "s5k3xa",
421 },
422 //name:"S5K3XA",
423 .id = I2C_DRIVERID_S5K_3XA,
424 //flags:I2C_DF_NOTIFY,
425 .attach_adapter = sensor_attach_adapter,
426 .detach_client = sensor_detach,
427 .command = sensor_command
428 };
429
430 static __init int camif_sensor_init(void)
431 {
432 return i2c_add_driver(&sensor_driver);
433 }
434
435
436 static __init void camif_sensor_exit(void)
437 {
438 i2c_del_driver(&sensor_driver);
439 }
440
441 module_init(camif_sensor_init)
442 module_exit(camif_sensor_exit)
443
444 MODULE_AUTHOR("Yeom, Youngran <yeom@samsung.com>");
445 MODULE_DESCRIPTION("I2C Client Driver For Fimc3.x V4L2 Driver");
446 MODULE_LICENSE("GPL");
447
448
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -