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#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/delay.h>
30#include <linux/errno.h>
31#include <linux/fs.h>
32#include <linux/kernel.h>
33#include <linux/major.h>
34#include <linux/slab.h>
35#include <linux/mm.h>
36#include <linux/signal.h>
37#include <linux/types.h>
38#include <linux/i2c.h>
39#include <asm/io.h>
40#include <asm/pgtable.h>
41#include <asm/page.h>
42#include <asm/uaccess.h>
43
44#include <linux/videodev.h>
45#include <linux/video_encoder.h>
46
47MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
48MODULE_AUTHOR("Dave Perks");
49MODULE_LICENSE("GPL");
50
51
52#define I2C_NAME(s) (s)->name
53
54
55static int debug = 0;
56module_param(debug, int, 0);
57MODULE_PARM_DESC(debug, "Debug level (0-1)");
58
59#define dprintk(num, format, args...) \
60 do { \
61 if (debug >= num) \
62 printk(format, ##args); \
63 } while (0)
64
65
66
67struct saa7185 {
68 unsigned char reg[128];
69
70 int norm;
71 int enable;
72 int bright;
73 int contrast;
74 int hue;
75 int sat;
76};
77
78#define I2C_SAA7185 0x88
79
80
81
82static inline int
83saa7185_read (struct i2c_client *client)
84{
85 return i2c_smbus_read_byte(client);
86}
87
88static int
89saa7185_write (struct i2c_client *client,
90 u8 reg,
91 u8 value)
92{
93 struct saa7185 *encoder = i2c_get_clientdata(client);
94
95 dprintk(1, KERN_DEBUG "SAA7185: %02x set to %02x\n", reg, value);
96 encoder->reg[reg] = value;
97 return i2c_smbus_write_byte_data(client, reg, value);
98}
99
100static int
101saa7185_write_block (struct i2c_client *client,
102 const u8 *data,
103 unsigned int len)
104{
105 int ret = -1;
106 u8 reg;
107
108
109
110 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
111
112 struct saa7185 *encoder = i2c_get_clientdata(client);
113 u8 block_data[32];
114 int block_len;
115
116 while (len >= 2) {
117 block_len = 0;
118 block_data[block_len++] = reg = data[0];
119 do {
120 block_data[block_len++] =
121 encoder->reg[reg++] = data[1];
122 len -= 2;
123 data += 2;
124 } while (len >= 2 && data[0] == reg &&
125 block_len < 32);
126 if ((ret = i2c_master_send(client, block_data,
127 block_len)) < 0)
128 break;
129 }
130 } else {
131
132 while (len >= 2) {
133 reg = *data++;
134 if ((ret = saa7185_write(client, reg,
135 *data++)) < 0)
136 break;
137 len -= 2;
138 }
139 }
140
141 return ret;
142}
143
144
145
146static const unsigned char init_common[] = {
147 0x3a, 0x0f,
148
149
150 0x42, 0x6b,
151 0x43, 0x00,
152 0x44, 0x00,
153 0x45, 0x22,
154 0x46, 0xac,
155 0x47, 0x0e,
156 0x48, 0x03,
157 0x49, 0x1d,
158 0x4a, 0xac,
159 0x4b, 0xf0,
160 0x4c, 0xc8,
161 0x4d, 0xb9,
162 0x4e, 0xd4,
163 0x4f, 0x38,
164 0x50, 0x47,
165 0x51, 0xc1,
166 0x52, 0xe3,
167 0x53, 0x54,
168 0x54, 0xa3,
169 0x55, 0x54,
170 0x56, 0xf2,
171 0x57, 0x90,
172 0x58, 0x00,
173 0x59, 0x00,
174
175 0x5a, 0x00,
176 0x5b, 0x76,
177 0x5c, 0xa5,
178 0x5d, 0x3c,
179 0x5e, 0x3a,
180 0x5f, 0x3a,
181 0x60, 0x00,
182
183
184
185 0x67, 0x00,
186 0x68, 0x00,
187 0x69, 0x00,
188 0x6a, 0x00,
189
190 0x6b, 0x91,
191 0x6c, 0x20,
192
193 0x6d, 0x00,
194
195 0x6e, 0x0e,
196
197 0x6f, 0x00,
198 0x70, 0x20,
199
200
201
202 0x71, 0x15,
203 0x72, 0x90,
204 0x73, 0x61,
205 0x74, 0x00,
206 0x75, 0x00,
207 0x76, 0x00,
208 0x77, 0x15,
209 0x78, 0x90,
210 0x79, 0x61,
211
212
213
214 0x7a, 0x70,
215
216
217
218 0x7b, 0x16,
219 0x7c, 0x35,
220 0x7d, 0x20,
221};
222
223static const unsigned char init_pal[] = {
224 0x61, 0x1e,
225
226 0x62, 0xc8,
227 0x63, 0xcb,
228 0x64, 0x8a,
229 0x65, 0x09,
230 0x66, 0x2a,
231};
232
233static const unsigned char init_ntsc[] = {
234 0x61, 0x1d,
235
236 0x62, 0xe6,
237 0x63, 0x1f,
238 0x64, 0x7c,
239 0x65, 0xf0,
240 0x66, 0x21,
241};
242
243static int
244saa7185_command (struct i2c_client *client,
245 unsigned int cmd,
246 void *arg)
247{
248 struct saa7185 *encoder = i2c_get_clientdata(client);
249
250 switch (cmd) {
251
252 case 0:
253 saa7185_write_block(client, init_common,
254 sizeof(init_common));
255 switch (encoder->norm) {
256
257 case VIDEO_MODE_NTSC:
258 saa7185_write_block(client, init_ntsc,
259 sizeof(init_ntsc));
260 break;
261
262 case VIDEO_MODE_PAL:
263 saa7185_write_block(client, init_pal,
264 sizeof(init_pal));
265 break;
266 }
267
268 break;
269
270 case ENCODER_GET_CAPABILITIES:
271 {
272 struct video_encoder_capability *cap = arg;
273
274 cap->flags =
275 VIDEO_ENCODER_PAL | VIDEO_ENCODER_NTSC |
276 VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
277 cap->inputs = 1;
278 cap->outputs = 1;
279 }
280 break;
281
282 case ENCODER_SET_NORM:
283 {
284 int *iarg = arg;
285
286
287
288 switch (*iarg) {
289
290 case VIDEO_MODE_NTSC:
291 saa7185_write_block(client, init_ntsc,
292 sizeof(init_ntsc));
293 break;
294
295 case VIDEO_MODE_PAL:
296 saa7185_write_block(client, init_pal,
297 sizeof(init_pal));
298 break;
299
300 case VIDEO_MODE_SECAM:
301 default:
302 return -EINVAL;
303
304 }
305 encoder->norm = *iarg;
306 }
307 break;
308
309 case ENCODER_SET_INPUT:
310 {
311 int *iarg = arg;
312
313
314
315
316 switch (*iarg) {
317
318 case 0:
319
320 saa7185_write(client, 0x61,
321 (encoder->reg[0x61] & 0xf7) | 0x08);
322 saa7185_write(client, 0x6e, 0x01);
323 break;
324
325 case 1:
326
327 saa7185_write(client, 0x61,
328 (encoder->reg[0x61] & 0xf7) | 0x00);
329
330 saa7185_write(client, 0x6e, 0x00);
331 break;
332
333 default:
334 return -EINVAL;
335
336 }
337 }
338 break;
339
340 case ENCODER_SET_OUTPUT:
341 {
342 int *iarg = arg;
343
344
345 if (*iarg != 0) {
346 return -EINVAL;
347 }
348 }
349 break;
350
351 case ENCODER_ENABLE_OUTPUT:
352 {
353 int *iarg = arg;
354
355 encoder->enable = !!*iarg;
356 saa7185_write(client, 0x61,
357 (encoder->reg[0x61] & 0xbf) |
358 (encoder->enable ? 0x00 : 0x40));
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[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
376
377static unsigned short ignore = I2C_CLIENT_END;
378
379static struct i2c_client_address_data addr_data = {
380 .normal_i2c = normal_i2c,
381 .probe = &ignore,
382 .ignore = &ignore,
383};
384
385static struct i2c_driver i2c_driver_saa7185;
386
387static int
388saa7185_detect_client (struct i2c_adapter *adapter,
389 int address,
390 int kind)
391{
392 int i;
393 struct i2c_client *client;
394 struct saa7185 *encoder;
395
396 dprintk(1,
397 KERN_INFO
398 "saa7185.c: detecting saa7185 client on address 0x%x\n",
399 address << 1);
400
401
402 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
403 return 0;
404
405 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
406 if (client == 0)
407 return -ENOMEM;
408 client->addr = address;
409 client->adapter = adapter;
410 client->driver = &i2c_driver_saa7185;
411 strlcpy(I2C_NAME(client), "saa7185", sizeof(I2C_NAME(client)));
412
413 encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
414 if (encoder == NULL) {
415 kfree(client);
416 return -ENOMEM;
417 }
418 encoder->norm = VIDEO_MODE_NTSC;
419 encoder->enable = 1;
420 i2c_set_clientdata(client, encoder);
421
422 i = i2c_attach_client(client);
423 if (i) {
424 kfree(client);
425 kfree(encoder);
426 return i;
427 }
428
429 i = saa7185_write_block(client, init_common, sizeof(init_common));
430 if (i >= 0) {
431 i = saa7185_write_block(client, init_ntsc,
432 sizeof(init_ntsc));
433 }
434 if (i < 0) {
435 dprintk(1, KERN_ERR "%s_attach: init error %d\n",
436 I2C_NAME(client), i);
437 } else {
438 dprintk(1,
439 KERN_INFO
440 "%s_attach: chip version %d at address 0x%x\n",
441 I2C_NAME(client), saa7185_read(client) >> 5,
442 client->addr << 1);
443 }
444
445 return 0;
446}
447
448static int
449saa7185_attach_adapter (struct i2c_adapter *adapter)
450{
451 dprintk(1,
452 KERN_INFO
453 "saa7185.c: starting probe for adapter %s (0x%x)\n",
454 I2C_NAME(adapter), adapter->id);
455 return i2c_probe(adapter, &addr_data, &saa7185_detect_client);
456}
457
458static int
459saa7185_detach_client (struct i2c_client *client)
460{
461 struct saa7185 *encoder = i2c_get_clientdata(client);
462 int err;
463
464 err = i2c_detach_client(client);
465 if (err) {
466 return err;
467 }
468
469 saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40);
470
471
472 kfree(encoder);
473 kfree(client);
474
475 return 0;
476}
477
478
479
480static struct i2c_driver i2c_driver_saa7185 = {
481 .driver = {
482 .name = "saa7185",
483 },
484
485 .id = I2C_DRIVERID_SAA7185B,
486
487 .attach_adapter = saa7185_attach_adapter,
488 .detach_client = saa7185_detach_client,
489 .command = saa7185_command,
490};
491
492static int __init
493saa7185_init (void)
494{
495 return i2c_add_driver(&i2c_driver_saa7185);
496}
497
498static void __exit
499saa7185_exit (void)
500{
501 i2c_del_driver(&i2c_driver_saa7185);
502}
503
504module_init(saa7185_init);
505module_exit(saa7185_exit);
506