📄 adv7180.c
字号:
1 /*
2 * ADV7180 Analog decoder driver for S3C2443X
3 *
4 * Jaecheol Lee <jc.lee@samsung.com>
5 * 2007.08.08
6 */
7
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/i2c.h>
12 #include <linux/i2c-id.h>
13 #include <linux/slab.h>
14 #include <linux/string.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/video_decoder.h>
18 #include <media/v4l2-dev.h>
19
20 //#include <asm/arch/registers.h>
21 #include "../s3c_camif.h"
22 #include "adv7180.h"
23
24
25
26 static const char *sensor_version =
27 "adv7180.c, v 1.00 2007/08/08 jc.lee@samsung.com";
28
29
30 static struct i2c_driver i2c_driver_adv7180;
31
32 /* This is an abstract CIS sensor for MSDMA input. */
33
34 camif_cis_t msdma_input = {
35 itu_fmt: CAMIF_ITU601,
36 order422: CAMIF_YCBYCR, /* YCRYCB */
37 camclk: 32000000, /* No effect */
38 source_x: 800,
39 source_y: 480,
40 win_hor_ofst: 0,
41 win_ver_ofst: 0,
42 win_hor_ofst2: 0,
43 win_ver_ofst2: 0,
44 polarity_pclk: 0,
45 polarity_vsync:1,
46 polarity_href: 0,
47 reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */
48 reset_udelay: 20000,
49 };
50
51 camif_cis_t interlace_input = {
52 itu_fmt: CAMIF_ITU656,
53 order422: CAMIF_CBYCRY, /* YCRYCB */
54 camclk: 32000000, /* No effect */
55 source_x: 720,
56 source_y: 243,
57 win_hor_ofst: 0,
58 win_ver_ofst: 0,
59 win_hor_ofst2: 0,
60 win_ver_ofst2: 0,
61 polarity_pclk: 0,
62 polarity_vsync:0,
63 polarity_href: 0,
64 reset_type:CAMIF_EX_RESET_AH, /* Ref board has inverted signal */
65 reset_udelay: 20000,
66 };
67
68
69 extern camif_cis_t* get_initialized_cis();
70 camif_cis_t* get_initialized_cis() {
71 if(interlace_input.init_sensor == 0) return NULL;
72 return &interlace_input;
73
74 }
75
76 static unsigned short ignore[] = { I2C_CLIENT_END };
77 static unsigned short normal_addr[] = { (I2C_ADV7180 >> 1), I2C_CLIENT_END };
78 static unsigned short *forces[] = { NULL };
79
80 static struct i2c_client_address_data addr_data = {
81 normal_i2c:normal_addr,
82 //normal_i2c_range:ignore,
83 probe:ignore,
84 //probe_range:ignore,
85 ignore:ignore,
86 //ignore_range:ignore,
87 forces:forces,
88 };
89
90
91 static inline int
92 adv7180_write (struct i2c_client *client,
93 u8 reg,
94 u8 value)
95 {
96 struct adv7180 *decoder = i2c_get_clientdata(client);
97 decoder->reg[reg] = value;
98 return i2c_smbus_write_byte_data(client, reg, value);
99 }
100
101 static inline int
102 adv7180_read (struct i2c_client *client,
103 u8 reg)
104 {
105 return i2c_smbus_read_byte_data(client, reg);
106 }
107
108 static int
109 adv7180_write_block (struct i2c_client *client,
110 const u8 *data,
111 unsigned int len)
112 {
113 int ret = -1;
114 u8 reg;
115
116 /* the adv7180 has an autoincrement function, use it if
117 * the adapter understands raw I2C */
118 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
119 /* do raw I2C, not smbus compatible */
120 struct adv7180 *decoder = i2c_get_clientdata(client);
121 struct i2c_msg msg;
122 u8 block_data[32];
123
124 msg.addr = client->addr;
125 msg.flags = 0;
126 while (len >= 2) {
127 msg.buf = (char *) block_data;
128 msg.len = 0;
129 block_data[msg.len++] = reg = data[0];
130 do {
131 block_data[msg.len++] =
132 decoder->reg[reg++] = data[1];
133 len -= 2;
134 data += 2;
135 } while (len >= 2 && data[0] == reg &&
136 msg.len < 32);
137 if ((ret = i2c_transfer(client->adapter,
138 &msg, 1)) < 0)
139 break;
140 }
141 } else {
142 /* do some slow I2C emulation kind of thing */
143 while (len >= 2) {
144 reg = *data++;
145 if ((ret = adv7180_write(client, reg,
146 *data++)) < 0)
147 break;
148 len -= 2;
149 }
150 }
151
152 return ret;
153 }
154
155
156 static int
157 adv7180_detect_client (struct i2c_adapter *adapter,
158 int address,
159 int kind)
160 {
161 int i;
162 struct i2c_client *client;
163 struct adv7180 *decoder;
164 char *dname;
165
166 /* Check if the adapter supports the needed features */
167 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_EMUL))
168 return 0;
169
170 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
171 if (client == 0)
172 return -ENOMEM;
173 client->addr = address;
174 client->adapter = adapter;
175 client->driver = &i2c_driver_adv7180;
176 if ((client->addr == I2C_ADV7180 >> 1) ||
177 (client->addr == (I2C_ADV7180 >> 1) + 1)) {
178 dname = adv7180_name;
179 } else {
180 /* We should never get here!!! */
181 kfree(client);
182 return 0;
183 }
184
185 client->data = &interlace_input;
186 interlace_input.sensor = client;
187 camif_register_cis(client);
188
189 strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
190
191 decoder = kzalloc(sizeof(struct adv7180), GFP_KERNEL);
192 if (decoder == NULL) {
193 kfree(client);
194 return -ENOMEM;
195 }
196 decoder->norm = VIDEO_MODE_NTSC;
197 decoder->input = 0;
198 decoder->enable = 1;
199 i2c_set_clientdata(client, decoder);
200
201 i = i2c_attach_client(client);
202 if (i) {
203 kfree(client);
204 kfree(decoder);
205 return i;
206 }
207
208 i = adv7180_write_block(client, init_composite, sizeof(init_composite));
209 if (i >= 0) {
210
211 }
212 if (i < 0) {
213 }
214
215 return 0;
216 }
217
218
219
220 static int adv7180_attach_adapter(struct i2c_adapter *adap)
221 {
222 return i2c_probe(adap, &addr_data, adv7180_detect_client);
223 }
224
225 static int adv7180_detach_client(struct i2c_client *client)
226 {
227 int err;
228 err = i2c_detach_client(client);
229 if(err) {
230 return err;
231 }
232 camif_unregister_cis(client);
233
234 kfree(client);
235 return 0;
236 }
237
238 static int
239 adv7180_command (struct i2c_client *client,
240 unsigned int cmd,
241 void *arg)
242 {
243 int tmp;
244 u64 endtime;
245
246 struct adv7180 *decoder = i2c_get_clientdata(client);
247
248 switch (cmd) {
249
250 case 0:
251 /* This is just for testing!!! */
252 adv7180_write_block(client, init_composite,
253 sizeof(init_composite));
254 break;
255
256 case USER_ADD:
257 adv7180_write(client, 0x0f, (1<<7)); // Reset
258 endtime = get_jiffies_64() + RESET_DELAY;
259 while(jiffies < endtime); // Delay for a 5 ms
260 break;
261
262 case USER_EXIT:
263 adv7180_write(client, 0x0f, (1<<5)); // PWRDWN : 1
264 break;
265
266 case DECODER_INIT:
267 break;
268
269 case DECODER_GET_STATUS:
270 {
271 int *iarg = arg;
272
273 tmp = adv7180_read(client, 0x10) & 0x000000ff; // STATUS1
274 tmp = (tmp | (adv7180_read(client, 0x11) & 0x000000ff)<<8); // + IDENTIFICATION
275 tmp = (tmp | (adv7180_read(client, 0x12) & 0x000000ff)<<16); // + STATUS2
276 tmp = (tmp | (adv7180_read(client, 0x13) & 0x000000ff)<<24); // + STATUS3
277
278 *iarg = tmp;
279 }
280 break;
281
282 case DECODER_GET_CAPABILITIES:
283 {
284 struct video_decoder_capability *cap = arg;
285
286 cap->flags = VIDEO_DECODER_NTSC |
287 VIDEO_DECODER_PAL; /* well, hacky */
288 cap->inputs = 2;
289 cap->outputs = 1;
290 }
291 break;
292
293 case DECODER_SET_NORM:
294 {
295 int iarg = *(int *) arg;
296 switch (iarg) {
297
298 case 0: // Composite
299 adv7180_write_block(client, init_composite,
300 sizeof(init_composite));
301 break;
302
303 case 1: //S-VIDEO
304 adv7180_write_block(client, init_svideo,
305 sizeof(init_svideo));
306 break;
307
308 case 2: // Component
309 adv7180_write_block(client, init_component,
310 sizeof(init_component));
311 break;
312 default:
313 return -EINVAL;
314
315 }
316
317 decoder->norm = iarg;
318 }
319 break;
320
321 case DECODER_SET_INPUT:
322 {
323 int iarg = *(int *) arg;
324 decoder->input = iarg;
325
326 switch(decoder->input) {
327
328 case CVBS:
329 adv7180_write_block(client, init_composite,
330 sizeof(init_composite));
331 break;
332
333 case SVIDEO:
334 adv7180_write_block(client, init_svideo,
335 sizeof(init_svideo));
336 break;
337
338 case YPbPr:
339 adv7180_write_block(client, init_component,
340 sizeof(init_component));
341 break;
342
343 default:
344 return -EINVAL;
345
346 }
347 }
348 break;
349
350 case DECODER_SET_OUTPUT:
351 {
352 int *iarg = arg;
353
354 if (*iarg != 0) {
355 return -EINVAL;
356 }
357 }
358 break;
359
360 case DECODER_ENABLE_OUTPUT:
361 {
362 int *iarg = arg;
363
364 decoder->enable = !!*iarg;
365 }
366 break;
367
368 case DECODER_SET_GPIO:
369 {
370 int *iarg = arg;
371 switch(*iarg) {
372 case 0: // Pin 37 output is Field signal
373 adv7180_write(client, 0x58, 0x00);
374 break;
375
376 case 1: // Output is Vsync signal
377 adv7180_write(client, 0x58, (1<<0));
378 break;
379
380 default:
381 return -EINVAL;
382 }
383 }
384 break;
385
386 default:
387 return -EINVAL;
388 }
389
390 return 0;
391 }
392
393 static struct i2c_driver i2c_driver_adv7180 = {
394 .driver = {
395 .name = "adv7180",
396 },
397 .id = I2C_DRIVERID_ADV7170, /* Must be fixed!!! */
398
399 .attach_adapter = adv7180_attach_adapter,
400 .detach_client = adv7180_detach_client,
401 .command = adv7180_command
402 };
403
404 static __init int adv7180_init(void)
405 {
406 return i2c_add_driver(&i2c_driver_adv7180);
407 }
408
409
410 static __init void adv7180_exit(void)
411 {
412 i2c_del_driver(&i2c_driver_adv7180);
413 }
414
415 module_init(adv7180_init)
416 module_exit(adv7180_exit)
417
418 MODULE_AUTHOR("JaeCheol Lee <jc.lee@samsung.com>");
419 MODULE_DESCRIPTION("I2C Client Driver For ADV7180 video decoder");
420 MODULE_LICENSE("GPL");
421
422
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -