1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/delay.h>
34#include <linux/errno.h>
35#include <linux/fs.h>
36#include <linux/kernel.h>
37#include <linux/major.h>
38#include <linux/slab.h>
39#include <linux/mm.h>
40#include <linux/signal.h>
41#include <linux/types.h>
42#include <linux/i2c.h>
43#include <asm/io.h>
44#include <asm/pgtable.h>
45#include <asm/page.h>
46#include <asm/uaccess.h>
47
48#include <linux/videodev.h>
49#include <linux/video_encoder.h>
50
51MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
52MODULE_AUTHOR("Maxim Yevtyushkin");
53MODULE_LICENSE("GPL");
54
55
56#define I2C_NAME(x) (x)->name
57
58
59static int debug = 0;
60module_param(debug, int, 0);
61MODULE_PARM_DESC(debug, "Debug level (0-1)");
62
63#define dprintk(num, format, args...) \
64 do { \
65 if (debug >= num) \
66 printk(format, ##args); \
67 } while (0)
68
69
70
71struct adv7170 {
72 unsigned char reg[128];
73
74 int norm;
75 int input;
76 int enable;
77 int bright;
78 int contrast;
79 int hue;
80 int sat;
81};
82
83#define I2C_ADV7170 0xd4
84#define I2C_ADV7171 0x54
85
86static char adv7170_name[] = "adv7170";
87static char adv7171_name[] = "adv7171";
88
89static char *inputs[] = { "pass_through", "play_back" };
90static char *norms[] = { "PAL", "NTSC" };
91
92
93
94static inline int
95adv7170_write (struct i2c_client *client,
96 u8 reg,
97 u8 value)
98{
99 struct adv7170 *encoder = i2c_get_clientdata(client);
100
101 encoder->reg[reg] = value;
102 return i2c_smbus_write_byte_data(client, reg, value);
103}
104
105static inline int
106adv7170_read (struct i2c_client *client,
107 u8 reg)
108{
109 return i2c_smbus_read_byte_data(client, reg);
110}
111
112static int
113adv7170_write_block (struct i2c_client *client,
114 const u8 *data,
115 unsigned int len)
116{
117 int ret = -1;
118 u8 reg;
119
120
121
122 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
123
124 struct adv7170 *encoder = i2c_get_clientdata(client);
125 u8 block_data[32];
126 int block_len;
127
128 while (len >= 2) {
129 block_len = 0;
130 block_data[block_len++] = reg = data[0];
131 do {
132 block_data[block_len++] =
133 encoder->reg[reg++] = data[1];
134 len -= 2;
135 data += 2;
136 } while (len >= 2 && data[0] == reg &&
137 block_len < 32);
138 if ((ret = i2c_master_send(client, block_data,
139 block_len)) < 0)
140 break;
141 }
142 } else {
143
144 while (len >= 2) {
145 reg = *data++;
146 if ((ret = adv7170_write(client, reg,
147 *data++)) < 0)
148 break;
149 len -= 2;
150 }
151 }
152
153 return ret;
154}
155
156
157
158
159#define MR050 0x11
160#define MR060 0x14
161
162
163
164#define TR0MODE 0x4c
165#define TR0RST 0x80
166
167#define TR1CAPT 0x00
168#define TR1PLAY 0x00
169
170
171static const unsigned char init_NTSC[] = {
172 0x00, 0x10,
173 0x01, 0x20,
174 0x02, 0x0e,
175 0x03, 0x80,
176 0x04, 0x30,
177 0x05, 0x00,
178 0x06, 0x00,
179 0x07, TR0MODE,
180 0x08, TR1CAPT,
181 0x09, 0x16,
182 0x0a, 0x7c,
183 0x0b, 0xf0,
184 0x0c, 0x21,
185 0x0d, 0x00,
186 0x0e, 0x00,
187 0x0f, 0x00,
188 0x10, 0x00,
189 0x11, 0x00,
190 0x12, 0x00,
191 0x13, 0x00,
192 0x14, 0x00,
193 0x15, 0x00,
194 0x16, 0x00,
195 0x17, 0x00,
196 0x18, 0x00,
197 0x19, 0x00,
198};
199
200static const unsigned char init_PAL[] = {
201 0x00, 0x71,
202 0x01, 0x20,
203 0x02, 0x0e,
204 0x03, 0x80,
205 0x04, 0x30,
206 0x05, 0x00,
207 0x06, 0x00,
208 0x07, TR0MODE,
209 0x08, TR1CAPT,
210 0x09, 0xcb,
211 0x0a, 0x8a,
212 0x0b, 0x09,
213 0x0c, 0x2a,
214 0x0d, 0x00,
215 0x0e, 0x00,
216 0x0f, 0x00,
217 0x10, 0x00,
218 0x11, 0x00,
219 0x12, 0x00,
220 0x13, 0x00,
221 0x14, 0x00,
222 0x15, 0x00,
223 0x16, 0x00,
224 0x17, 0x00,
225 0x18, 0x00,
226 0x19, 0x00,
227};
228
229
230static int
231adv7170_command (struct i2c_client *client,
232 unsigned int cmd,
233 void * arg)
234{
235 struct adv7170 *encoder = i2c_get_clientdata(client);
236
237 switch (cmd) {
238
239 case 0:
240#if 0
241
242 adv7170_write_block(client, init_common,
243 sizeof(init_common));
244 adv7170_write(client, 0x07, TR0MODE | TR0RST);
245 adv7170_write(client, 0x07, TR0MODE);
246#endif
247 break;
248
249 case ENCODER_GET_CAPABILITIES:
250 {
251 struct video_encoder_capability *cap = arg;
252
253 cap->flags = VIDEO_ENCODER_PAL |
254 VIDEO_ENCODER_NTSC;
255 cap->inputs = 2;
256 cap->outputs = 1;
257 }
258 break;
259
260 case ENCODER_SET_NORM:
261 {
262 int iarg = *(int *) arg;
263
264 dprintk(1, KERN_DEBUG "%s_command: set norm %d",
265 I2C_NAME(client), iarg);
266
267 switch (iarg) {
268
269 case VIDEO_MODE_NTSC:
270 adv7170_write_block(client, init_NTSC,
271 sizeof(init_NTSC));
272 if (encoder->input == 0)
273 adv7170_write(client, 0x02, 0x0e);
274 adv7170_write(client, 0x07, TR0MODE | TR0RST);
275 adv7170_write(client, 0x07, TR0MODE);
276 break;
277
278 case VIDEO_MODE_PAL:
279 adv7170_write_block(client, init_PAL,
280 sizeof(init_PAL));
281 if (encoder->input == 0)
282 adv7170_write(client, 0x02, 0x0e);
283 adv7170_write(client, 0x07, TR0MODE | TR0RST);
284 adv7170_write(client, 0x07, TR0MODE);
285 break;
286
287 default:
288 dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
289 I2C_NAME(client), iarg);
290 return -EINVAL;
291
292 }
293 dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
294 norms[iarg]);
295 encoder->norm = iarg;
296 }
297 break;
298
299 case ENCODER_SET_INPUT:
300 {
301 int iarg = *(int *) arg;
302
303
304
305
306
307 dprintk(1, KERN_DEBUG "%s_command: set input from %s\n",
308 I2C_NAME(client),
309 iarg == 0 ? "decoder" : "ZR36060");
310
311 switch (iarg) {
312
313 case 0:
314 adv7170_write(client, 0x01, 0x20);
315 adv7170_write(client, 0x08, TR1CAPT);
316 adv7170_write(client, 0x02, 0x0e);
317 adv7170_write(client, 0x07, TR0MODE | TR0RST);
318 adv7170_write(client, 0x07, TR0MODE);
319
320 break;
321
322 case 1:
323 adv7170_write(client, 0x01, 0x00);
324 adv7170_write(client, 0x08, TR1PLAY);
325 adv7170_write(client, 0x02, 0x08);
326 adv7170_write(client, 0x07, TR0MODE | TR0RST);
327 adv7170_write(client, 0x07, TR0MODE);
328
329 break;
330
331 default:
332 dprintk(1, KERN_ERR "%s: illegal input: %d\n",
333 I2C_NAME(client), iarg);
334 return -EINVAL;
335
336 }
337 dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
338 inputs[iarg]);
339 encoder->input = iarg;
340 }
341 break;
342
343 case ENCODER_SET_OUTPUT:
344 {
345 int *iarg = arg;
346
347
348 if (*iarg != 0) {
349 return -EINVAL;
350 }
351 }
352 break;
353
354 case ENCODER_ENABLE_OUTPUT:
355 {
356 int *iarg = arg;
357
358 encoder->enable = !!*iarg;
359 }
360 break;
361
362 default:
363 return -EINVAL;
364 }
365
366 return 0;
367}
368
369
370
371
372
373
374
375static unsigned short normal_i2c[] =
376 { I2C_ADV7170 >> 1, (I2C_ADV7170 >> 1) + 1,
377 I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
378 I2C_CLIENT_END
379};
380
381static unsigned short ignore = I2C_CLIENT_END;
382
383static struct i2c_client_address_data addr_data = {
384 .normal_i2c = normal_i2c,
385 .probe = &ignore,
386 .ignore = &ignore,
387};
388
389static struct i2c_driver i2c_driver_adv7170;
390
391static int
392adv7170_detect_client (struct i2c_adapter *adapter,
393 int address,
394 int kind)
395{
396 int i;
397 struct i2c_client *client;
398 struct adv7170 *encoder;
399 char *dname;
400
401 dprintk(1,
402 KERN_INFO
403 "adv7170.c: detecting adv7170 client on address 0x%x\n",
404 address << 1);
405
406
407 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
408 return 0;
409
410 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
411 if (client == 0)
412 return -ENOMEM;
413 client->addr = address;
414 client->adapter = adapter;
415 client->driver = &i2c_driver_adv7170;
416 if ((client->addr == I2C_ADV7170 >> 1) ||
417 (client->addr == (I2C_ADV7170 >> 1) + 1)) {
418 dname = adv7170_name;
419 } else if ((client->addr == I2C_ADV7171 >> 1) ||
420 (client->addr == (I2C_ADV7171 >> 1) + 1)) {
421 dname = adv7171_name;
422 } else {
423
424 kfree(client);
425 return 0;
426 }
427 strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
428
429 encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
430 if (encoder == NULL) {
431 kfree(client);
432 return -ENOMEM;
433 }
434 encoder->norm = VIDEO_MODE_NTSC;
435 encoder->input = 0;
436 encoder->enable = 1;
437 i2c_set_clientdata(client, encoder);
438
439 i = i2c_attach_client(client);
440 if (i) {
441 kfree(client);
442 kfree(encoder);
443 return i;
444 }
445
446 i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
447 if (i >= 0) {
448 i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
449 i = adv7170_write(client, 0x07, TR0MODE);
450 i = adv7170_read(client, 0x12);
451 dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%02x\n",
452 I2C_NAME(client), i & 1, client->addr << 1);
453 }
454 if (i < 0) {
455 dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
456 I2C_NAME(client), i);
457 }
458
459 return 0;
460}
461
462static int
463adv7170_attach_adapter (struct i2c_adapter *adapter)
464{
465 dprintk(1,
466 KERN_INFO
467 "adv7170.c: starting probe for adapter %s (0x%x)\n",
468 I2C_NAME(adapter), adapter->id);
469 return i2c_probe(adapter, &addr_data, &adv7170_detect_client);
470}
471
472static int
473adv7170_detach_client (struct i2c_client *client)
474{
475 struct adv7170 *encoder = i2c_get_clientdata(client);
476 int err;
477
478 err = i2c_detach_client(client);
479 if (err) {
480 return err;
481 }
482
483 kfree(encoder);
484 kfree(client);
485
486 return 0;
487}
488
489
490
491static struct i2c_driver i2c_driver_adv7170 = {
492 .driver = {
493 .name = "adv7170",
494 },
495
496 .id = I2C_DRIVERID_ADV7170,
497
498 .attach_adapter = adv7170_attach_adapter,
499 .detach_client = adv7170_detach_client,
500 .command = adv7170_command,
501};
502
503static int __init
504adv7170_init (void)
505{
506 return i2c_add_driver(&i2c_driver_adv7170);
507}
508
509static void __exit
510adv7170_exit (void)
511{
512 i2c_del_driver(&i2c_driver_adv7170);
513}
514
515module_init(adv7170_init);
516module_exit(adv7170_exit);
517