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
32
33
34
35
36
37
38#include <linux/module.h>
39#include <linux/init.h>
40#include <linux/kernel.h>
41#include <linux/string.h>
42#include <linux/timer.h>
43#include <linux/delay.h>
44#include <linux/errno.h>
45#include <linux/slab.h>
46#include <linux/videodev.h>
47#include <linux/i2c.h>
48
49#include <media/v4l2-common.h>
50#include <media/i2c-addr.h>
51
52#ifndef VIDEO_AUDIO_BALANCE
53# define VIDEO_AUDIO_BALANCE 32
54#endif
55
56MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
57MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
58MODULE_LICENSE("GPL");
59
60static int maxvol;
61static int loudness;
62static int debug;
63module_param(debug, int, S_IRUGO | S_IWUSR);
64module_param(loudness, int, S_IRUGO);
65MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
66module_param(maxvol, int, S_IRUGO | S_IWUSR);
67
68
69
70static unsigned short normal_i2c[] = {
71 I2C_ADDR_TDA7432 >> 1,
72 I2C_CLIENT_END,
73};
74I2C_CLIENT_INSMOD;
75
76
77
78struct tda7432 {
79 int addr;
80 int input;
81 int volume;
82 int muted;
83 int bass, treble;
84 int lf, lr, rf, rr;
85 int loud;
86 struct i2c_client c;
87};
88static struct i2c_driver driver;
89static struct i2c_client client_template;
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106#define TDA7432_IN 0x00
107#define TDA7432_VL 0x01
108#define TDA7432_TN 0x02
109#define TDA7432_LF 0x03
110#define TDA7432_LR 0x04
111#define TDA7432_RF 0x05
112#define TDA7432_RR 0x06
113#define TDA7432_LD 0x07
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135#define TDA7432_STEREO_IN 0
136#define TDA7432_MONO_IN 2
137#define TDA7432_BASS_SYM 1 << 3
138#define TDA7432_BASS_NORM 1 << 4
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153#define TDA7432_VOL_0DB 0x20
154#define TDA7432_LD_ON 1 << 7
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178#define TDA7432_TREBLE_0DB 0xf
179#define TDA7432_TREBLE 7
180#define TDA7432_TREBLE_GAIN 1 << 3
181#define TDA7432_BASS_0DB 0xf
182#define TDA7432_BASS 7 << 4
183#define TDA7432_BASS_GAIN 1 << 7
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202#define TDA7432_ATTEN_0DB 0x00
203#define TDA7432_MUTE 0x1 << 5
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224static int tda7432_write(struct i2c_client *client, int subaddr, int val)
225{
226 unsigned char buffer[2];
227 v4l_dbg(2, debug,client,"In tda7432_write\n");
228 v4l_dbg(1, debug,client,"Writing %d 0x%x\n", subaddr, val);
229 buffer[0] = subaddr;
230 buffer[1] = val;
231 if (2 != i2c_master_send(client,buffer,2)) {
232 v4l_err(client,"I/O error, trying (write %d 0x%x)\n",
233 subaddr, val);
234 return -1;
235 }
236 return 0;
237}
238
239
240
241static int tda7432_set(struct i2c_client *client)
242{
243 struct tda7432 *t = i2c_get_clientdata(client);
244 unsigned char buf[16];
245 v4l_dbg(2, debug,client,"In tda7432_set\n");
246
247 v4l_dbg(1, debug,client,
248 "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
249 t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
250 buf[0] = TDA7432_IN;
251 buf[1] = t->input;
252 buf[2] = t->volume;
253 buf[3] = t->bass;
254 buf[4] = t->treble;
255 buf[5] = t->lf;
256 buf[6] = t->lr;
257 buf[7] = t->rf;
258 buf[8] = t->rr;
259 buf[9] = t->loud;
260 if (10 != i2c_master_send(client,buf,10)) {
261 v4l_err(client,"I/O error, trying tda7432_set\n");
262 return -1;
263 }
264
265 return 0;
266}
267
268static void do_tda7432_init(struct i2c_client *client)
269{
270 struct tda7432 *t = i2c_get_clientdata(client);
271 v4l_dbg(2, debug,client,"In tda7432_init\n");
272
273 t->input = TDA7432_STEREO_IN |
274 TDA7432_BASS_SYM |
275 TDA7432_BASS_NORM;
276 t->volume = 0x3b ;
277 if (loudness)
278 t->volume |= TDA7432_LD_ON;
279 t->muted = VIDEO_AUDIO_MUTE;
280 t->treble = TDA7432_TREBLE_0DB;
281 t->bass = TDA7432_BASS_0DB;
282 t->lf = TDA7432_ATTEN_0DB;
283 t->lr = TDA7432_ATTEN_0DB;
284 t->rf = TDA7432_ATTEN_0DB;
285 t->rr = TDA7432_ATTEN_0DB;
286 t->loud = loudness;
287
288 tda7432_set(client);
289}
290
291
292
293
294
295static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
296{
297 struct tda7432 *t;
298 struct i2c_client *client;
299
300 t = kzalloc(sizeof *t,GFP_KERNEL);
301 if (!t)
302 return -ENOMEM;
303
304 client = &t->c;
305 memcpy(client,&client_template,sizeof(struct i2c_client));
306 client->adapter = adap;
307 client->addr = addr;
308 i2c_set_clientdata(client, t);
309
310 do_tda7432_init(client);
311 i2c_attach_client(client);
312
313 v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
314 return 0;
315}
316
317static int tda7432_probe(struct i2c_adapter *adap)
318{
319 if (adap->class & I2C_CLASS_TV_ANALOG)
320 return i2c_probe(adap, &addr_data, tda7432_attach);
321 return 0;
322}
323
324static int tda7432_detach(struct i2c_client *client)
325{
326 struct tda7432 *t = i2c_get_clientdata(client);
327
328 do_tda7432_init(client);
329 i2c_detach_client(client);
330
331 kfree(t);
332 return 0;
333}
334
335static int tda7432_command(struct i2c_client *client,
336 unsigned int cmd, void *arg)
337{
338 struct tda7432 *t = i2c_get_clientdata(client);
339 v4l_dbg(2, debug,client,"In tda7432_command\n");
340 if (debug>1)
341 v4l_i2c_print_ioctl(client,cmd);
342
343 switch (cmd) {
344
345
346
347
348
349 case VIDIOCGAUDIO:
350 {
351 struct video_audio *va = arg;
352
353 va->flags |= VIDEO_AUDIO_VOLUME |
354 VIDEO_AUDIO_BASS |
355 VIDEO_AUDIO_TREBLE |
356 VIDEO_AUDIO_MUTABLE;
357 if (t->muted)
358 va->flags |= VIDEO_AUDIO_MUTE;
359 va->mode |= VIDEO_SOUND_STEREO;
360
361
362
363
364
365
366
367
368 if (!maxvol){
369 va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
370 } else {
371 va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
372 }
373
374
375
376
377
378
379
380
381
382 if ( (t->lf) < (t->rf) )
383
384 va->balance = (32768 - 1057*(t->rf));
385 else
386
387 va->balance = (32768 + 1057*(t->lf));
388
389
390 va->bass=t->bass;
391 if(va->bass >= 0x8)
392 va->bass = ~(va->bass - 0x8) & 0xf;
393 va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
394 va->treble=t->treble;
395 if(va->treble >= 0x8)
396 va->treble = ~(va->treble - 0x8) & 0xf;
397 va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
398
399 break;
400 }
401
402
403 case VIDIOCSAUDIO:
404 {
405 struct video_audio *va = arg;
406
407 if(va->flags & VIDEO_AUDIO_VOLUME){
408 if(!maxvol){
409 t->volume = 0x6f - ((va->volume)/630);
410 } else {
411 t->volume = 0x6f - ((va->volume)/829);
412 }
413
414 if (loudness)
415 t->volume |= TDA7432_LD_ON;
416
417 tda7432_write(client,TDA7432_VL, t->volume);
418 }
419
420 if(va->flags & VIDEO_AUDIO_BASS)
421 {
422 t->bass = va->bass >> 12;
423 if(t->bass>= 0x8)
424 t->bass = (~t->bass & 0xf) + 0x8 ;
425 }
426 if(va->flags & VIDEO_AUDIO_TREBLE)
427 {
428 t->treble= va->treble >> 12;
429 if(t->treble>= 0x8)
430 t->treble = (~t->treble & 0xf) + 0x8 ;
431 }
432 if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
433 tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
434
435 if(va->flags & VIDEO_AUDIO_BALANCE) {
436 if (va->balance < 32768)
437 {
438
439 t->rr = (32768 - va->balance)/1057;
440 t->rf = t->rr;
441 t->lr = TDA7432_ATTEN_0DB;
442 t->lf = TDA7432_ATTEN_0DB;
443 }
444 else if(va->balance > 32769)
445 {
446
447 t->lf = (va->balance - 32768)/1057;
448 t->lr = t->lf;
449 t->rr = TDA7432_ATTEN_0DB;
450 t->rf = TDA7432_ATTEN_0DB;
451 }
452 else
453 {
454
455 t->rr = TDA7432_ATTEN_0DB;
456 t->rf = TDA7432_ATTEN_0DB;
457 t->lf = TDA7432_ATTEN_0DB;
458 t->lr = TDA7432_ATTEN_0DB;
459 }
460 }
461
462 t->muted=(va->flags & VIDEO_AUDIO_MUTE);
463 if (t->muted)
464 {
465
466 tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
467 tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
468 tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
469 tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
470 } else {
471 tda7432_write(client,TDA7432_LF, t->lf);
472 tda7432_write(client,TDA7432_LR, t->lr);
473 tda7432_write(client,TDA7432_RF, t->rf);
474 tda7432_write(client,TDA7432_RR, t->rr);
475 }
476
477 break;
478
479 }
480
481 }
482
483 return 0;
484}
485
486static struct i2c_driver driver = {
487 .driver = {
488 .name = "tda7432",
489 },
490 .id = I2C_DRIVERID_TDA7432,
491 .attach_adapter = tda7432_probe,
492 .detach_client = tda7432_detach,
493 .command = tda7432_command,
494};
495
496static struct i2c_client client_template =
497{
498 .name = "tda7432",
499 .driver = &driver,
500};
501
502static int __init tda7432_init(void)
503{
504 if ( (loudness < 0) || (loudness > 15) ) {
505 printk(KERN_ERR "loudness parameter must be between 0 and 15\n");
506 return -EINVAL;
507 }
508
509 return i2c_add_driver(&driver);
510}
511
512static void __exit tda7432_fini(void)
513{
514 i2c_del_driver(&driver);
515}
516
517module_init(tda7432_init);
518module_exit(tda7432_fini);
519
520
521
522
523
524
525