diff options
Diffstat (limited to 'sound/oss/dmasound/tas3004.c')
-rw-r--r-- | sound/oss/dmasound/tas3004.c | 1138 |
1 files changed, 0 insertions, 1138 deletions
diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c deleted file mode 100644 index 678bf0ff6da2..000000000000 --- a/sound/oss/dmasound/tas3004.c +++ /dev/null | |||
@@ -1,1138 +0,0 @@ | |||
1 | /* | ||
2 | * Driver for the i2c/i2s based TA3004 sound chip used | ||
3 | * on some Apple hardware. Also known as "snapper". | ||
4 | * | ||
5 | * Tobias Sargeant <tobias.sargeant@bigpond.com> | ||
6 | * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>: | ||
7 | * | ||
8 | * Input support by Renzo Davoli <renzo@cs.unibo.it> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/proc_fs.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/sysctl.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/soundcard.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/workqueue.h> | ||
23 | |||
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/errno.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/prom.h> | ||
28 | |||
29 | #include "dmasound.h" | ||
30 | #include "tas_common.h" | ||
31 | #include "tas3004.h" | ||
32 | |||
33 | #include "tas_ioctl.h" | ||
34 | |||
35 | /* #define DEBUG_DRCE */ | ||
36 | |||
37 | #define TAS3004_BIQUAD_FILTER_COUNT 7 | ||
38 | #define TAS3004_BIQUAD_CHANNEL_COUNT 2 | ||
39 | |||
40 | #define VOL_DEFAULT (100 * 4 / 5) | ||
41 | #define INPUT_DEFAULT (100 * 4 / 5) | ||
42 | #define BASS_DEFAULT (100 / 2) | ||
43 | #define TREBLE_DEFAULT (100 / 2) | ||
44 | |||
45 | struct tas3004_data_t { | ||
46 | struct tas_data_t super; | ||
47 | int device_id; | ||
48 | int output_id; | ||
49 | int speaker_id; | ||
50 | struct tas_drce_t drce_state; | ||
51 | struct work_struct change; | ||
52 | }; | ||
53 | |||
54 | #define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000) | ||
55 | |||
56 | #define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000)) | ||
57 | |||
58 | |||
59 | static const union tas_biquad_t tas3004_eq_unity = { | ||
60 | .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 }, | ||
61 | }; | ||
62 | |||
63 | |||
64 | static const struct tas_drce_t tas3004_drce_min = { | ||
65 | .enable = 1, | ||
66 | .above = { .val = MAKE_RATIO(16,0), .expand = 0 }, | ||
67 | .below = { .val = MAKE_RATIO(2,0), .expand = 0 }, | ||
68 | .threshold = -0x59a0, | ||
69 | .energy = MAKE_TIME(0, 1700), | ||
70 | .attack = MAKE_TIME(0, 1700), | ||
71 | .decay = MAKE_TIME(0, 1700), | ||
72 | }; | ||
73 | |||
74 | |||
75 | static const struct tas_drce_t tas3004_drce_max = { | ||
76 | .enable = 1, | ||
77 | .above = { .val = MAKE_RATIO(1,500), .expand = 1 }, | ||
78 | .below = { .val = MAKE_RATIO(2,0), .expand = 1 }, | ||
79 | .threshold = -0x0, | ||
80 | .energy = MAKE_TIME(2,400000), | ||
81 | .attack = MAKE_TIME(2,400000), | ||
82 | .decay = MAKE_TIME(2,400000), | ||
83 | }; | ||
84 | |||
85 | |||
86 | static const unsigned short time_constants[]={ | ||
87 | MAKE_TIME(0, 1700), | ||
88 | MAKE_TIME(0, 3500), | ||
89 | MAKE_TIME(0, 6700), | ||
90 | MAKE_TIME(0, 13000), | ||
91 | MAKE_TIME(0, 26000), | ||
92 | MAKE_TIME(0, 53000), | ||
93 | MAKE_TIME(0,106000), | ||
94 | MAKE_TIME(0,212000), | ||
95 | MAKE_TIME(0,425000), | ||
96 | MAKE_TIME(0,850000), | ||
97 | MAKE_TIME(1,700000), | ||
98 | MAKE_TIME(2,400000), | ||
99 | }; | ||
100 | |||
101 | static const unsigned short above_threshold_compression_ratio[]={ | ||
102 | MAKE_RATIO( 1, 70), | ||
103 | MAKE_RATIO( 1,140), | ||
104 | MAKE_RATIO( 1,230), | ||
105 | MAKE_RATIO( 1,330), | ||
106 | MAKE_RATIO( 1,450), | ||
107 | MAKE_RATIO( 1,600), | ||
108 | MAKE_RATIO( 1,780), | ||
109 | MAKE_RATIO( 2, 0), | ||
110 | MAKE_RATIO( 2,290), | ||
111 | MAKE_RATIO( 2,670), | ||
112 | MAKE_RATIO( 3,200), | ||
113 | MAKE_RATIO( 4, 0), | ||
114 | MAKE_RATIO( 5,330), | ||
115 | MAKE_RATIO( 8, 0), | ||
116 | MAKE_RATIO(16, 0), | ||
117 | }; | ||
118 | |||
119 | static const unsigned short above_threshold_expansion_ratio[]={ | ||
120 | MAKE_RATIO(1, 60), | ||
121 | MAKE_RATIO(1,130), | ||
122 | MAKE_RATIO(1,190), | ||
123 | MAKE_RATIO(1,250), | ||
124 | MAKE_RATIO(1,310), | ||
125 | MAKE_RATIO(1,380), | ||
126 | MAKE_RATIO(1,440), | ||
127 | MAKE_RATIO(1,500) | ||
128 | }; | ||
129 | |||
130 | static const unsigned short below_threshold_compression_ratio[]={ | ||
131 | MAKE_RATIO(1, 70), | ||
132 | MAKE_RATIO(1,140), | ||
133 | MAKE_RATIO(1,230), | ||
134 | MAKE_RATIO(1,330), | ||
135 | MAKE_RATIO(1,450), | ||
136 | MAKE_RATIO(1,600), | ||
137 | MAKE_RATIO(1,780), | ||
138 | MAKE_RATIO(2, 0) | ||
139 | }; | ||
140 | |||
141 | static const unsigned short below_threshold_expansion_ratio[]={ | ||
142 | MAKE_RATIO(1, 60), | ||
143 | MAKE_RATIO(1,130), | ||
144 | MAKE_RATIO(1,190), | ||
145 | MAKE_RATIO(1,250), | ||
146 | MAKE_RATIO(1,310), | ||
147 | MAKE_RATIO(1,380), | ||
148 | MAKE_RATIO(1,440), | ||
149 | MAKE_RATIO(1,500), | ||
150 | MAKE_RATIO(1,560), | ||
151 | MAKE_RATIO(1,630), | ||
152 | MAKE_RATIO(1,690), | ||
153 | MAKE_RATIO(1,750), | ||
154 | MAKE_RATIO(1,810), | ||
155 | MAKE_RATIO(1,880), | ||
156 | MAKE_RATIO(1,940), | ||
157 | MAKE_RATIO(2, 0) | ||
158 | }; | ||
159 | |||
160 | static inline int | ||
161 | search( unsigned short val, | ||
162 | const unsigned short *arr, | ||
163 | const int arrsize) { | ||
164 | /* | ||
165 | * This could be a binary search, but for small tables, | ||
166 | * a linear search is likely to be faster | ||
167 | */ | ||
168 | |||
169 | int i; | ||
170 | |||
171 | for (i=0; i < arrsize; i++) | ||
172 | if (arr[i] >= val) | ||
173 | goto _1; | ||
174 | return arrsize-1; | ||
175 | _1: | ||
176 | if (i == 0) | ||
177 | return 0; | ||
178 | return (arr[i]-val < val-arr[i-1]) ? i : i-1; | ||
179 | } | ||
180 | |||
181 | #define SEARCH(a, b) search(a, b, ARRAY_SIZE(b)) | ||
182 | |||
183 | static inline int | ||
184 | time_index(unsigned short time) | ||
185 | { | ||
186 | return SEARCH(time, time_constants); | ||
187 | } | ||
188 | |||
189 | |||
190 | static inline int | ||
191 | above_threshold_compression_index(unsigned short ratio) | ||
192 | { | ||
193 | return SEARCH(ratio, above_threshold_compression_ratio); | ||
194 | } | ||
195 | |||
196 | |||
197 | static inline int | ||
198 | above_threshold_expansion_index(unsigned short ratio) | ||
199 | { | ||
200 | return SEARCH(ratio, above_threshold_expansion_ratio); | ||
201 | } | ||
202 | |||
203 | |||
204 | static inline int | ||
205 | below_threshold_compression_index(unsigned short ratio) | ||
206 | { | ||
207 | return SEARCH(ratio, below_threshold_compression_ratio); | ||
208 | } | ||
209 | |||
210 | |||
211 | static inline int | ||
212 | below_threshold_expansion_index(unsigned short ratio) | ||
213 | { | ||
214 | return SEARCH(ratio, below_threshold_expansion_ratio); | ||
215 | } | ||
216 | |||
217 | static inline unsigned char db_to_regval(short db) { | ||
218 | int r=0; | ||
219 | |||
220 | r=(db+0x59a0) / 0x60; | ||
221 | |||
222 | if (r < 0x91) return 0x91; | ||
223 | if (r > 0xef) return 0xef; | ||
224 | return r; | ||
225 | } | ||
226 | |||
227 | static inline short quantize_db(short db) | ||
228 | { | ||
229 | return db_to_regval(db) * 0x60 - 0x59a0; | ||
230 | } | ||
231 | |||
232 | static inline int | ||
233 | register_width(enum tas3004_reg_t r) | ||
234 | { | ||
235 | switch(r) { | ||
236 | case TAS3004_REG_MCR: | ||
237 | case TAS3004_REG_TREBLE: | ||
238 | case TAS3004_REG_BASS: | ||
239 | case TAS3004_REG_ANALOG_CTRL: | ||
240 | case TAS3004_REG_TEST1: | ||
241 | case TAS3004_REG_TEST2: | ||
242 | case TAS3004_REG_MCR2: | ||
243 | return 1; | ||
244 | |||
245 | case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN: | ||
246 | case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN: | ||
247 | return 3; | ||
248 | |||
249 | case TAS3004_REG_DRC: | ||
250 | case TAS3004_REG_VOLUME: | ||
251 | return 6; | ||
252 | |||
253 | case TAS3004_REG_LEFT_MIXER: | ||
254 | case TAS3004_REG_RIGHT_MIXER: | ||
255 | return 9; | ||
256 | |||
257 | case TAS3004_REG_TEST: | ||
258 | return 10; | ||
259 | |||
260 | case TAS3004_REG_LEFT_BIQUAD0: | ||
261 | case TAS3004_REG_LEFT_BIQUAD1: | ||
262 | case TAS3004_REG_LEFT_BIQUAD2: | ||
263 | case TAS3004_REG_LEFT_BIQUAD3: | ||
264 | case TAS3004_REG_LEFT_BIQUAD4: | ||
265 | case TAS3004_REG_LEFT_BIQUAD5: | ||
266 | case TAS3004_REG_LEFT_BIQUAD6: | ||
267 | |||
268 | case TAS3004_REG_RIGHT_BIQUAD0: | ||
269 | case TAS3004_REG_RIGHT_BIQUAD1: | ||
270 | case TAS3004_REG_RIGHT_BIQUAD2: | ||
271 | case TAS3004_REG_RIGHT_BIQUAD3: | ||
272 | case TAS3004_REG_RIGHT_BIQUAD4: | ||
273 | case TAS3004_REG_RIGHT_BIQUAD5: | ||
274 | case TAS3004_REG_RIGHT_BIQUAD6: | ||
275 | |||
276 | case TAS3004_REG_LEFT_LOUD_BIQUAD: | ||
277 | case TAS3004_REG_RIGHT_LOUD_BIQUAD: | ||
278 | return 15; | ||
279 | |||
280 | default: | ||
281 | return 0; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static int | ||
286 | tas3004_write_register( struct tas3004_data_t *self, | ||
287 | enum tas3004_reg_t reg_num, | ||
288 | char *data, | ||
289 | uint write_mode) | ||
290 | { | ||
291 | if (reg_num==TAS3004_REG_MCR || | ||
292 | reg_num==TAS3004_REG_BASS || | ||
293 | reg_num==TAS3004_REG_TREBLE || | ||
294 | reg_num==TAS3004_REG_ANALOG_CTRL) { | ||
295 | return tas_write_byte_register(&self->super, | ||
296 | (uint)reg_num, | ||
297 | *data, | ||
298 | write_mode); | ||
299 | } else { | ||
300 | return tas_write_register(&self->super, | ||
301 | (uint)reg_num, | ||
302 | register_width(reg_num), | ||
303 | data, | ||
304 | write_mode); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static int | ||
309 | tas3004_sync_register( struct tas3004_data_t *self, | ||
310 | enum tas3004_reg_t reg_num) | ||
311 | { | ||
312 | if (reg_num==TAS3004_REG_MCR || | ||
313 | reg_num==TAS3004_REG_BASS || | ||
314 | reg_num==TAS3004_REG_TREBLE || | ||
315 | reg_num==TAS3004_REG_ANALOG_CTRL) { | ||
316 | return tas_sync_byte_register(&self->super, | ||
317 | (uint)reg_num, | ||
318 | register_width(reg_num)); | ||
319 | } else { | ||
320 | return tas_sync_register(&self->super, | ||
321 | (uint)reg_num, | ||
322 | register_width(reg_num)); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | static int | ||
327 | tas3004_read_register( struct tas3004_data_t *self, | ||
328 | enum tas3004_reg_t reg_num, | ||
329 | char *data, | ||
330 | uint write_mode) | ||
331 | { | ||
332 | return tas_read_register(&self->super, | ||
333 | (uint)reg_num, | ||
334 | register_width(reg_num), | ||
335 | data); | ||
336 | } | ||
337 | |||
338 | static inline int | ||
339 | tas3004_fast_load(struct tas3004_data_t *self, int fast) | ||
340 | { | ||
341 | if (fast) | ||
342 | self->super.shadow[TAS3004_REG_MCR][0] |= 0x80; | ||
343 | else | ||
344 | self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f; | ||
345 | return tas3004_sync_register(self,TAS3004_REG_MCR); | ||
346 | } | ||
347 | |||
348 | static uint | ||
349 | tas3004_supported_mixers(struct tas3004_data_t *self) | ||
350 | { | ||
351 | return SOUND_MASK_VOLUME | | ||
352 | SOUND_MASK_PCM | | ||
353 | SOUND_MASK_ALTPCM | | ||
354 | SOUND_MASK_IMIX | | ||
355 | SOUND_MASK_TREBLE | | ||
356 | SOUND_MASK_BASS | | ||
357 | SOUND_MASK_MIC | | ||
358 | SOUND_MASK_LINE; | ||
359 | } | ||
360 | |||
361 | static int | ||
362 | tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer) | ||
363 | { | ||
364 | switch(mixer) { | ||
365 | case SOUND_MIXER_VOLUME: | ||
366 | case SOUND_MIXER_PCM: | ||
367 | case SOUND_MIXER_ALTPCM: | ||
368 | case SOUND_MIXER_IMIX: | ||
369 | return 1; | ||
370 | default: | ||
371 | return 0; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | static uint | ||
376 | tas3004_stereo_mixers(struct tas3004_data_t *self) | ||
377 | { | ||
378 | uint r = tas3004_supported_mixers(self); | ||
379 | uint i; | ||
380 | |||
381 | for (i=1; i<SOUND_MIXER_NRDEVICES; i++) | ||
382 | if (r&(1<<i) && !tas3004_mixer_is_stereo(self,i)) | ||
383 | r &= ~(1<<i); | ||
384 | return r; | ||
385 | } | ||
386 | |||
387 | static int | ||
388 | tas3004_get_mixer_level(struct tas3004_data_t *self, int mixer, uint *level) | ||
389 | { | ||
390 | if (!self) | ||
391 | return -1; | ||
392 | |||
393 | *level = self->super.mixer[mixer]; | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int | ||
399 | tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) | ||
400 | { | ||
401 | int rc; | ||
402 | tas_shadow_t *shadow; | ||
403 | uint temp; | ||
404 | uint offset=0; | ||
405 | |||
406 | if (!self) | ||
407 | return -1; | ||
408 | |||
409 | shadow = self->super.shadow; | ||
410 | |||
411 | if (!tas3004_mixer_is_stereo(self,mixer)) | ||
412 | level = tas_mono_to_stereo(level); | ||
413 | switch(mixer) { | ||
414 | case SOUND_MIXER_VOLUME: | ||
415 | temp = tas3004_gain.master[level&0xff]; | ||
416 | SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp); | ||
417 | temp = tas3004_gain.master[(level>>8)&0xff]; | ||
418 | SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp); | ||
419 | rc = tas3004_sync_register(self,TAS3004_REG_VOLUME); | ||
420 | break; | ||
421 | case SOUND_MIXER_IMIX: | ||
422 | offset += 3; | ||
423 | case SOUND_MIXER_ALTPCM: | ||
424 | offset += 3; | ||
425 | case SOUND_MIXER_PCM: | ||
426 | /* | ||
427 | * Don't load these in fast mode. The documentation | ||
428 | * says it can be done in either mode, but testing it | ||
429 | * shows that fast mode produces ugly clicking. | ||
430 | */ | ||
431 | /* tas3004_fast_load(self,1); */ | ||
432 | temp = tas3004_gain.mixer[level&0xff]; | ||
433 | SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp); | ||
434 | temp = tas3004_gain.mixer[(level>>8)&0xff]; | ||
435 | SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp); | ||
436 | rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); | ||
437 | if (rc == 0) | ||
438 | rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); | ||
439 | /* tas3004_fast_load(self,0); */ | ||
440 | break; | ||
441 | case SOUND_MIXER_TREBLE: | ||
442 | temp = tas3004_gain.treble[level&0xff]; | ||
443 | shadow[TAS3004_REG_TREBLE][0]=temp&0xff; | ||
444 | rc = tas3004_sync_register(self,TAS3004_REG_TREBLE); | ||
445 | break; | ||
446 | case SOUND_MIXER_BASS: | ||
447 | temp = tas3004_gain.bass[level&0xff]; | ||
448 | shadow[TAS3004_REG_BASS][0]=temp&0xff; | ||
449 | rc = tas3004_sync_register(self,TAS3004_REG_BASS); | ||
450 | break; | ||
451 | case SOUND_MIXER_MIC: | ||
452 | if ((level&0xff)>0) { | ||
453 | software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff); | ||
454 | if (self->super.mixer[mixer] == 0) { | ||
455 | self->super.mixer[SOUND_MIXER_LINE] = 0; | ||
456 | shadow[TAS3004_REG_ANALOG_CTRL][0]=0xc2; | ||
457 | rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); | ||
458 | } else rc=0; | ||
459 | } else { | ||
460 | self->super.mixer[SOUND_MIXER_LINE] = SW_INPUT_VOLUME_DEFAULT; | ||
461 | software_input_volume = SW_INPUT_VOLUME_SCALE * | ||
462 | (self->super.mixer[SOUND_MIXER_LINE]&0xff); | ||
463 | shadow[TAS3004_REG_ANALOG_CTRL][0]=0x00; | ||
464 | rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); | ||
465 | } | ||
466 | break; | ||
467 | case SOUND_MIXER_LINE: | ||
468 | if (self->super.mixer[SOUND_MIXER_MIC] == 0) { | ||
469 | software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff); | ||
470 | rc=0; | ||
471 | } | ||
472 | break; | ||
473 | default: | ||
474 | rc = -1; | ||
475 | break; | ||
476 | } | ||
477 | if (rc < 0) | ||
478 | return rc; | ||
479 | self->super.mixer[mixer] = level; | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int | ||
485 | tas3004_leave_sleep(struct tas3004_data_t *self) | ||
486 | { | ||
487 | unsigned char mcr = (1<<6)+(2<<4)+(2<<2); | ||
488 | |||
489 | if (!self) | ||
490 | return -1; | ||
491 | |||
492 | /* Make sure something answers on the i2c bus */ | ||
493 | if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, | ||
494 | WRITE_NORMAL | FORCE_WRITE) < 0) | ||
495 | return -1; | ||
496 | |||
497 | tas3004_fast_load(self, 1); | ||
498 | |||
499 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); | ||
500 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); | ||
501 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); | ||
502 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); | ||
503 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); | ||
504 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); | ||
505 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); | ||
506 | |||
507 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); | ||
508 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); | ||
509 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); | ||
510 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); | ||
511 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); | ||
512 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); | ||
513 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); | ||
514 | |||
515 | tas3004_fast_load(self, 0); | ||
516 | |||
517 | (void)tas3004_sync_register(self,TAS3004_REG_VOLUME); | ||
518 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); | ||
519 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); | ||
520 | (void)tas3004_sync_register(self,TAS3004_REG_TREBLE); | ||
521 | (void)tas3004_sync_register(self,TAS3004_REG_BASS); | ||
522 | (void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | tas3004_enter_sleep(struct tas3004_data_t *self) | ||
529 | { | ||
530 | if (!self) | ||
531 | return -1; | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int | ||
536 | tas3004_sync_biquad( struct tas3004_data_t *self, | ||
537 | u_int channel, | ||
538 | u_int filter) | ||
539 | { | ||
540 | enum tas3004_reg_t reg; | ||
541 | |||
542 | if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || | ||
543 | filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; | ||
544 | |||
545 | reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; | ||
546 | |||
547 | return tas3004_sync_register(self,reg); | ||
548 | } | ||
549 | |||
550 | static int | ||
551 | tas3004_write_biquad_shadow( struct tas3004_data_t *self, | ||
552 | u_int channel, | ||
553 | u_int filter, | ||
554 | const union tas_biquad_t *biquad) | ||
555 | { | ||
556 | tas_shadow_t *shadow=self->super.shadow; | ||
557 | enum tas3004_reg_t reg; | ||
558 | |||
559 | if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || | ||
560 | filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; | ||
561 | |||
562 | reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; | ||
563 | |||
564 | SET_4_20(shadow[reg], 0,biquad->coeff.b0); | ||
565 | SET_4_20(shadow[reg], 3,biquad->coeff.b1); | ||
566 | SET_4_20(shadow[reg], 6,biquad->coeff.b2); | ||
567 | SET_4_20(shadow[reg], 9,biquad->coeff.a1); | ||
568 | SET_4_20(shadow[reg],12,biquad->coeff.a2); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int | ||
574 | tas3004_write_biquad( struct tas3004_data_t *self, | ||
575 | u_int channel, | ||
576 | u_int filter, | ||
577 | const union tas_biquad_t *biquad) | ||
578 | { | ||
579 | int rc; | ||
580 | |||
581 | rc=tas3004_write_biquad_shadow(self, channel, filter, biquad); | ||
582 | if (rc < 0) return rc; | ||
583 | |||
584 | return tas3004_sync_biquad(self, channel, filter); | ||
585 | } | ||
586 | |||
587 | static int | ||
588 | tas3004_write_biquad_list( struct tas3004_data_t *self, | ||
589 | u_int filter_count, | ||
590 | u_int flags, | ||
591 | struct tas_biquad_ctrl_t *biquads) | ||
592 | { | ||
593 | int i; | ||
594 | int rc; | ||
595 | |||
596 | if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); | ||
597 | |||
598 | for (i=0; i<filter_count; i++) { | ||
599 | rc=tas3004_write_biquad(self, | ||
600 | biquads[i].channel, | ||
601 | biquads[i].filter, | ||
602 | &biquads[i].data); | ||
603 | if (rc < 0) break; | ||
604 | } | ||
605 | |||
606 | if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,0); | ||
607 | |||
608 | return rc; | ||
609 | } | ||
610 | |||
611 | static int | ||
612 | tas3004_read_biquad( struct tas3004_data_t *self, | ||
613 | u_int channel, | ||
614 | u_int filter, | ||
615 | union tas_biquad_t *biquad) | ||
616 | { | ||
617 | tas_shadow_t *shadow=self->super.shadow; | ||
618 | enum tas3004_reg_t reg; | ||
619 | |||
620 | if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || | ||
621 | filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; | ||
622 | |||
623 | reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; | ||
624 | |||
625 | biquad->coeff.b0=GET_4_20(shadow[reg], 0); | ||
626 | biquad->coeff.b1=GET_4_20(shadow[reg], 3); | ||
627 | biquad->coeff.b2=GET_4_20(shadow[reg], 6); | ||
628 | biquad->coeff.a1=GET_4_20(shadow[reg], 9); | ||
629 | biquad->coeff.a2=GET_4_20(shadow[reg],12); | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int | ||
635 | tas3004_eq_rw( struct tas3004_data_t *self, | ||
636 | u_int cmd, | ||
637 | u_long arg) | ||
638 | { | ||
639 | void __user *argp = (void __user *)arg; | ||
640 | int rc; | ||
641 | struct tas_biquad_ctrl_t biquad; | ||
642 | |||
643 | if (copy_from_user((void *)&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) { | ||
644 | return -EFAULT; | ||
645 | } | ||
646 | |||
647 | if (cmd & SIOC_IN) { | ||
648 | rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); | ||
649 | if (rc != 0) return rc; | ||
650 | } | ||
651 | |||
652 | if (cmd & SIOC_OUT) { | ||
653 | rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); | ||
654 | if (rc != 0) return rc; | ||
655 | |||
656 | if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) { | ||
657 | return -EFAULT; | ||
658 | } | ||
659 | |||
660 | } | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int | ||
665 | tas3004_eq_list_rw( struct tas3004_data_t *self, | ||
666 | u_int cmd, | ||
667 | u_long arg) | ||
668 | { | ||
669 | int rc = 0; | ||
670 | int filter_count; | ||
671 | int flags; | ||
672 | int i,j; | ||
673 | char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT]; | ||
674 | struct tas_biquad_ctrl_t biquad; | ||
675 | struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg; | ||
676 | |||
677 | memset(sync_required,0,sizeof(sync_required)); | ||
678 | |||
679 | if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int))) | ||
680 | return -EFAULT; | ||
681 | |||
682 | if (copy_from_user(&flags, &argp->flags, sizeof(int))) | ||
683 | return -EFAULT; | ||
684 | |||
685 | if (cmd & SIOC_IN) { | ||
686 | } | ||
687 | |||
688 | for (i=0; i < filter_count; i++) { | ||
689 | if (copy_from_user(&biquad, &argp->biquads[i], | ||
690 | sizeof(struct tas_biquad_ctrl_t))) { | ||
691 | return -EFAULT; | ||
692 | } | ||
693 | |||
694 | if (cmd & SIOC_IN) { | ||
695 | sync_required[biquad.channel][biquad.filter]=1; | ||
696 | rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); | ||
697 | if (rc != 0) return rc; | ||
698 | } | ||
699 | |||
700 | if (cmd & SIOC_OUT) { | ||
701 | rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); | ||
702 | if (rc != 0) return rc; | ||
703 | |||
704 | if (copy_to_user(&argp->biquads[i], &biquad, | ||
705 | sizeof(struct tas_biquad_ctrl_t))) { | ||
706 | return -EFAULT; | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | |||
711 | if (cmd & SIOC_IN) { | ||
712 | /* | ||
713 | * This is OK for the tas3004. For the | ||
714 | * tas3001c, going into fast load mode causes | ||
715 | * the treble and bass to be reset to 0dB, and | ||
716 | * volume controls to be muted. | ||
717 | */ | ||
718 | if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); | ||
719 | for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) { | ||
720 | for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) { | ||
721 | if (sync_required[i][j]) { | ||
722 | rc=tas3004_sync_biquad(self, i, j); | ||
723 | if (rc < 0) goto out; | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | out: | ||
728 | if (flags & TAS_BIQUAD_FAST_LOAD) | ||
729 | tas3004_fast_load(self,0); | ||
730 | } | ||
731 | |||
732 | return rc; | ||
733 | } | ||
734 | |||
735 | static int | ||
736 | tas3004_update_drce( struct tas3004_data_t *self, | ||
737 | int flags, | ||
738 | struct tas_drce_t *drce) | ||
739 | { | ||
740 | tas_shadow_t *shadow; | ||
741 | int i; | ||
742 | shadow=self->super.shadow; | ||
743 | |||
744 | if (flags & TAS_DRCE_ABOVE_RATIO) { | ||
745 | self->drce_state.above.expand = drce->above.expand; | ||
746 | if (drce->above.val == (1<<8)) { | ||
747 | self->drce_state.above.val = 1<<8; | ||
748 | shadow[TAS3004_REG_DRC][0] = 0x02; | ||
749 | |||
750 | } else if (drce->above.expand) { | ||
751 | i=above_threshold_expansion_index(drce->above.val); | ||
752 | self->drce_state.above.val=above_threshold_expansion_ratio[i]; | ||
753 | shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3); | ||
754 | } else { | ||
755 | i=above_threshold_compression_index(drce->above.val); | ||
756 | self->drce_state.above.val=above_threshold_compression_ratio[i]; | ||
757 | shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3); | ||
758 | } | ||
759 | } | ||
760 | |||
761 | if (flags & TAS_DRCE_BELOW_RATIO) { | ||
762 | self->drce_state.below.expand = drce->below.expand; | ||
763 | if (drce->below.val == (1<<8)) { | ||
764 | self->drce_state.below.val = 1<<8; | ||
765 | shadow[TAS3004_REG_DRC][1] = 0x02; | ||
766 | |||
767 | } else if (drce->below.expand) { | ||
768 | i=below_threshold_expansion_index(drce->below.val); | ||
769 | self->drce_state.below.val=below_threshold_expansion_ratio[i]; | ||
770 | shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3); | ||
771 | } else { | ||
772 | i=below_threshold_compression_index(drce->below.val); | ||
773 | self->drce_state.below.val=below_threshold_compression_ratio[i]; | ||
774 | shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3); | ||
775 | } | ||
776 | } | ||
777 | |||
778 | if (flags & TAS_DRCE_THRESHOLD) { | ||
779 | self->drce_state.threshold=quantize_db(drce->threshold); | ||
780 | shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold); | ||
781 | } | ||
782 | |||
783 | if (flags & TAS_DRCE_ENERGY) { | ||
784 | i=time_index(drce->energy); | ||
785 | self->drce_state.energy=time_constants[i]; | ||
786 | shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4); | ||
787 | } | ||
788 | |||
789 | if (flags & TAS_DRCE_ATTACK) { | ||
790 | i=time_index(drce->attack); | ||
791 | self->drce_state.attack=time_constants[i]; | ||
792 | shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4); | ||
793 | } | ||
794 | |||
795 | if (flags & TAS_DRCE_DECAY) { | ||
796 | i=time_index(drce->decay); | ||
797 | self->drce_state.decay=time_constants[i]; | ||
798 | shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4); | ||
799 | } | ||
800 | |||
801 | if (flags & TAS_DRCE_ENABLE) { | ||
802 | self->drce_state.enable = drce->enable; | ||
803 | } | ||
804 | |||
805 | if (!self->drce_state.enable) { | ||
806 | shadow[TAS3004_REG_DRC][0] |= 0x01; | ||
807 | } | ||
808 | |||
809 | #ifdef DEBUG_DRCE | ||
810 | printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", | ||
811 | self->drce_state.enable, | ||
812 | self->drce_state.above.expand,self->drce_state.above.val, | ||
813 | self->drce_state.below.expand,self->drce_state.below.val, | ||
814 | self->drce_state.threshold, | ||
815 | self->drce_state.energy, | ||
816 | self->drce_state.attack, | ||
817 | self->drce_state.decay); | ||
818 | |||
819 | printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n", | ||
820 | (unsigned char)shadow[TAS3004_REG_DRC][0], | ||
821 | (unsigned char)shadow[TAS3004_REG_DRC][1], | ||
822 | (unsigned char)shadow[TAS3004_REG_DRC][2], | ||
823 | (unsigned char)shadow[TAS3004_REG_DRC][3], | ||
824 | (unsigned char)shadow[TAS3004_REG_DRC][4], | ||
825 | (unsigned char)shadow[TAS3004_REG_DRC][5]); | ||
826 | #endif | ||
827 | |||
828 | return tas3004_sync_register(self, TAS3004_REG_DRC); | ||
829 | } | ||
830 | |||
831 | static int | ||
832 | tas3004_drce_rw( struct tas3004_data_t *self, | ||
833 | u_int cmd, | ||
834 | u_long arg) | ||
835 | { | ||
836 | int rc; | ||
837 | struct tas_drce_ctrl_t drce_ctrl; | ||
838 | void __user *argp = (void __user *)arg; | ||
839 | |||
840 | if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t))) | ||
841 | return -EFAULT; | ||
842 | |||
843 | #ifdef DEBUG_DRCE | ||
844 | printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", | ||
845 | drce_ctrl.flags, | ||
846 | drce_ctrl.data.enable, | ||
847 | drce_ctrl.data.above.expand,drce_ctrl.data.above.val, | ||
848 | drce_ctrl.data.below.expand,drce_ctrl.data.below.val, | ||
849 | drce_ctrl.data.threshold, | ||
850 | drce_ctrl.data.energy, | ||
851 | drce_ctrl.data.attack, | ||
852 | drce_ctrl.data.decay); | ||
853 | #endif | ||
854 | |||
855 | if (cmd & SIOC_IN) { | ||
856 | rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); | ||
857 | if (rc < 0) return rc; | ||
858 | } | ||
859 | |||
860 | if (cmd & SIOC_OUT) { | ||
861 | if (drce_ctrl.flags & TAS_DRCE_ENABLE) | ||
862 | drce_ctrl.data.enable = self->drce_state.enable; | ||
863 | if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) | ||
864 | drce_ctrl.data.above = self->drce_state.above; | ||
865 | if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) | ||
866 | drce_ctrl.data.below = self->drce_state.below; | ||
867 | if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) | ||
868 | drce_ctrl.data.threshold = self->drce_state.threshold; | ||
869 | if (drce_ctrl.flags & TAS_DRCE_ENERGY) | ||
870 | drce_ctrl.data.energy = self->drce_state.energy; | ||
871 | if (drce_ctrl.flags & TAS_DRCE_ATTACK) | ||
872 | drce_ctrl.data.attack = self->drce_state.attack; | ||
873 | if (drce_ctrl.flags & TAS_DRCE_DECAY) | ||
874 | drce_ctrl.data.decay = self->drce_state.decay; | ||
875 | |||
876 | if (copy_to_user(argp, &drce_ctrl, | ||
877 | sizeof(struct tas_drce_ctrl_t))) { | ||
878 | return -EFAULT; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static void | ||
886 | tas3004_update_device_parameters(struct tas3004_data_t *self) | ||
887 | { | ||
888 | char data; | ||
889 | int i; | ||
890 | |||
891 | if (!self) return; | ||
892 | |||
893 | if (self->output_id == TAS_OUTPUT_HEADPHONES) { | ||
894 | /* turn on allPass when headphones are plugged in */ | ||
895 | data = 0x02; | ||
896 | } else { | ||
897 | data = 0x00; | ||
898 | } | ||
899 | |||
900 | tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE); | ||
901 | |||
902 | for (i=0; tas3004_eq_prefs[i]; i++) { | ||
903 | struct tas_eq_pref_t *eq = tas3004_eq_prefs[i]; | ||
904 | |||
905 | if (eq->device_id == self->device_id && | ||
906 | (eq->output_id == 0 || eq->output_id == self->output_id) && | ||
907 | (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { | ||
908 | |||
909 | tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce); | ||
910 | tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); | ||
911 | |||
912 | break; | ||
913 | } | ||
914 | } | ||
915 | } | ||
916 | |||
917 | static void | ||
918 | tas3004_device_change_handler(struct work_struct *work) | ||
919 | { | ||
920 | struct tas3004_data_t *self; | ||
921 | self = container_of(work, struct tas3004_data_t, change); | ||
922 | tas3004_update_device_parameters(self); | ||
923 | } | ||
924 | |||
925 | static int | ||
926 | tas3004_output_device_change( struct tas3004_data_t *self, | ||
927 | int device_id, | ||
928 | int output_id, | ||
929 | int speaker_id) | ||
930 | { | ||
931 | self->device_id=device_id; | ||
932 | self->output_id=output_id; | ||
933 | self->speaker_id=speaker_id; | ||
934 | |||
935 | schedule_work(&self->change); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static int | ||
941 | tas3004_device_ioctl( struct tas3004_data_t *self, | ||
942 | u_int cmd, | ||
943 | u_long arg) | ||
944 | { | ||
945 | uint __user *argp = (void __user *)arg; | ||
946 | switch (cmd) { | ||
947 | case TAS_READ_EQ: | ||
948 | case TAS_WRITE_EQ: | ||
949 | return tas3004_eq_rw(self, cmd, arg); | ||
950 | |||
951 | case TAS_READ_EQ_LIST: | ||
952 | case TAS_WRITE_EQ_LIST: | ||
953 | return tas3004_eq_list_rw(self, cmd, arg); | ||
954 | |||
955 | case TAS_READ_EQ_FILTER_COUNT: | ||
956 | put_user(TAS3004_BIQUAD_FILTER_COUNT, argp); | ||
957 | return 0; | ||
958 | |||
959 | case TAS_READ_EQ_CHANNEL_COUNT: | ||
960 | put_user(TAS3004_BIQUAD_CHANNEL_COUNT, argp); | ||
961 | return 0; | ||
962 | |||
963 | case TAS_READ_DRCE: | ||
964 | case TAS_WRITE_DRCE: | ||
965 | return tas3004_drce_rw(self, cmd, arg); | ||
966 | |||
967 | case TAS_READ_DRCE_CAPS: | ||
968 | put_user(TAS_DRCE_ENABLE | | ||
969 | TAS_DRCE_ABOVE_RATIO | | ||
970 | TAS_DRCE_BELOW_RATIO | | ||
971 | TAS_DRCE_THRESHOLD | | ||
972 | TAS_DRCE_ENERGY | | ||
973 | TAS_DRCE_ATTACK | | ||
974 | TAS_DRCE_DECAY, | ||
975 | argp); | ||
976 | return 0; | ||
977 | |||
978 | case TAS_READ_DRCE_MIN: | ||
979 | case TAS_READ_DRCE_MAX: { | ||
980 | struct tas_drce_ctrl_t drce_ctrl; | ||
981 | const struct tas_drce_t *drce_copy; | ||
982 | |||
983 | if (copy_from_user(&drce_ctrl, argp, | ||
984 | sizeof(struct tas_drce_ctrl_t))) { | ||
985 | return -EFAULT; | ||
986 | } | ||
987 | |||
988 | if (cmd == TAS_READ_DRCE_MIN) { | ||
989 | drce_copy=&tas3004_drce_min; | ||
990 | } else { | ||
991 | drce_copy=&tas3004_drce_max; | ||
992 | } | ||
993 | |||
994 | if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) { | ||
995 | drce_ctrl.data.above=drce_copy->above; | ||
996 | } | ||
997 | if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) { | ||
998 | drce_ctrl.data.below=drce_copy->below; | ||
999 | } | ||
1000 | if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { | ||
1001 | drce_ctrl.data.threshold=drce_copy->threshold; | ||
1002 | } | ||
1003 | if (drce_ctrl.flags & TAS_DRCE_ENERGY) { | ||
1004 | drce_ctrl.data.energy=drce_copy->energy; | ||
1005 | } | ||
1006 | if (drce_ctrl.flags & TAS_DRCE_ATTACK) { | ||
1007 | drce_ctrl.data.attack=drce_copy->attack; | ||
1008 | } | ||
1009 | if (drce_ctrl.flags & TAS_DRCE_DECAY) { | ||
1010 | drce_ctrl.data.decay=drce_copy->decay; | ||
1011 | } | ||
1012 | |||
1013 | if (copy_to_user(argp, &drce_ctrl, | ||
1014 | sizeof(struct tas_drce_ctrl_t))) { | ||
1015 | return -EFAULT; | ||
1016 | } | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | return -EINVAL; | ||
1021 | } | ||
1022 | |||
1023 | static int | ||
1024 | tas3004_init_mixer(struct tas3004_data_t *self) | ||
1025 | { | ||
1026 | unsigned char mcr = (1<<6)+(2<<4)+(2<<2); | ||
1027 | |||
1028 | /* Make sure something answers on the i2c bus */ | ||
1029 | if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, | ||
1030 | WRITE_NORMAL | FORCE_WRITE) < 0) | ||
1031 | return -1; | ||
1032 | |||
1033 | tas3004_fast_load(self, 1); | ||
1034 | |||
1035 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); | ||
1036 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); | ||
1037 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); | ||
1038 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); | ||
1039 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); | ||
1040 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); | ||
1041 | (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); | ||
1042 | |||
1043 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); | ||
1044 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); | ||
1045 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); | ||
1046 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); | ||
1047 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); | ||
1048 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); | ||
1049 | (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); | ||
1050 | |||
1051 | tas3004_sync_register(self, TAS3004_REG_DRC); | ||
1052 | |||
1053 | tas3004_sync_register(self, TAS3004_REG_MCR2); | ||
1054 | |||
1055 | tas3004_fast_load(self, 0); | ||
1056 | |||
1057 | tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); | ||
1058 | tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); | ||
1059 | tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); | ||
1060 | tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); | ||
1061 | |||
1062 | tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); | ||
1063 | tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); | ||
1064 | |||
1065 | tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT); | ||
1066 | |||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int | ||
1071 | tas3004_uninit_mixer(struct tas3004_data_t *self) | ||
1072 | { | ||
1073 | tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); | ||
1074 | tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0); | ||
1075 | tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); | ||
1076 | tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); | ||
1077 | |||
1078 | tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0); | ||
1079 | tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); | ||
1080 | |||
1081 | tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0); | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static int | ||
1087 | tas3004_init(struct i2c_client *client) | ||
1088 | { | ||
1089 | struct tas3004_data_t *self; | ||
1090 | size_t sz = sizeof(*self) + (TAS3004_REG_MAX*sizeof(tas_shadow_t)); | ||
1091 | char drce_init[] = { 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 }; | ||
1092 | char mcr2 = 0; | ||
1093 | int i, j; | ||
1094 | |||
1095 | self = kzalloc(sz, GFP_KERNEL); | ||
1096 | if (!self) | ||
1097 | return -ENOMEM; | ||
1098 | |||
1099 | self->super.client = client; | ||
1100 | self->super.shadow = (tas_shadow_t *)(self+1); | ||
1101 | self->output_id = TAS_OUTPUT_HEADPHONES; | ||
1102 | |||
1103 | dev_set_drvdata(&client->dev, self); | ||
1104 | |||
1105 | for (i = 0; i < TAS3004_BIQUAD_CHANNEL_COUNT; i++) | ||
1106 | for (j = 0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) | ||
1107 | tas3004_write_biquad_shadow(self, i, j, | ||
1108 | &tas3004_eq_unity); | ||
1109 | |||
1110 | tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW); | ||
1111 | tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW); | ||
1112 | |||
1113 | INIT_WORK(&self->change, tas3004_device_change_handler); | ||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static void | ||
1118 | tas3004_uninit(struct tas3004_data_t *self) | ||
1119 | { | ||
1120 | tas3004_uninit_mixer(self); | ||
1121 | kfree(self); | ||
1122 | } | ||
1123 | |||
1124 | |||
1125 | struct tas_driver_hooks_t tas3004_hooks = { | ||
1126 | .init = (tas_hook_init_t)tas3004_init, | ||
1127 | .post_init = (tas_hook_post_init_t)tas3004_init_mixer, | ||
1128 | .uninit = (tas_hook_uninit_t)tas3004_uninit, | ||
1129 | .get_mixer_level = (tas_hook_get_mixer_level_t)tas3004_get_mixer_level, | ||
1130 | .set_mixer_level = (tas_hook_set_mixer_level_t)tas3004_set_mixer_level, | ||
1131 | .enter_sleep = (tas_hook_enter_sleep_t)tas3004_enter_sleep, | ||
1132 | .leave_sleep = (tas_hook_leave_sleep_t)tas3004_leave_sleep, | ||
1133 | .supported_mixers = (tas_hook_supported_mixers_t)tas3004_supported_mixers, | ||
1134 | .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3004_mixer_is_stereo, | ||
1135 | .stereo_mixers = (tas_hook_stereo_mixers_t)tas3004_stereo_mixers, | ||
1136 | .output_device_change = (tas_hook_output_device_change_t)tas3004_output_device_change, | ||
1137 | .device_ioctl = (tas_hook_device_ioctl_t)tas3004_device_ioctl | ||
1138 | }; | ||