2 * Driver for the i2c/i2s based TA3004 sound chip used
3 * on some Apple hardware. Also known as "snapper".
5 * Tobias Sargeant <tobias.sargeant@bigpond.com>
6 * Based upon, tas3001c.c by Christopher C. Chimelis <chris@debian.org>:
10 * * Enable control over input line 2 (is this connected?)
11 * * Implement sleep support (at least mute everything and
12 * * set gains to minimum during sleep)
13 * * Look into some of Darwin's tweaks regarding the mute
14 * * lines (delays & different behaviour on some HW)
18 #include <linux/module.h>
19 #include <linux/slab.h>
20 #include <linux/proc_fs.h>
21 #include <linux/ioport.h>
22 #include <linux/sysctl.h>
23 #include <linux/types.h>
24 #include <linux/i2c.h>
25 #include <linux/init.h>
26 #include <linux/soundcard.h>
27 #include <linux/workqueue.h>
28 #include <asm/uaccess.h>
29 #include <asm/errno.h>
34 #include "tas_common.h"
37 #include "tas_ioctl.h"
39 #define TAS3001C_BIQUAD_FILTER_COUNT 6
40 #define TAS3001C_BIQUAD_CHANNEL_COUNT 2
42 #define VOL_DEFAULT (100 * 4 / 5)
43 #define INPUT_DEFAULT (100 * 4 / 5)
44 #define BASS_DEFAULT (100 / 2)
45 #define TREBLE_DEFAULT (100 / 2)
47 struct tas3001c_data_t
{
48 struct tas_data_t super
;
52 struct tas_drce_t drce_state
;
53 struct work_struct change
;
57 static const union tas_biquad_t
59 .buf
= { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 }
63 static inline unsigned char db_to_regval(short db
) {
68 if (r
< 0x91) return 0x91;
69 if (r
> 0xef) return 0xef;
73 static inline short quantize_db(short db
) {
74 return db_to_regval(db
) * 0x60 - 0x59a0;
79 register_width(enum tas3001c_reg_t r
)
82 case TAS3001C_REG_MCR
:
83 case TAS3001C_REG_TREBLE
:
84 case TAS3001C_REG_BASS
:
87 case TAS3001C_REG_DRC
:
90 case TAS3001C_REG_MIXER1
:
91 case TAS3001C_REG_MIXER2
:
94 case TAS3001C_REG_VOLUME
:
97 case TAS3001C_REG_LEFT_BIQUAD0
:
98 case TAS3001C_REG_LEFT_BIQUAD1
:
99 case TAS3001C_REG_LEFT_BIQUAD2
:
100 case TAS3001C_REG_LEFT_BIQUAD3
:
101 case TAS3001C_REG_LEFT_BIQUAD4
:
102 case TAS3001C_REG_LEFT_BIQUAD5
:
103 case TAS3001C_REG_LEFT_BIQUAD6
:
105 case TAS3001C_REG_RIGHT_BIQUAD0
:
106 case TAS3001C_REG_RIGHT_BIQUAD1
:
107 case TAS3001C_REG_RIGHT_BIQUAD2
:
108 case TAS3001C_REG_RIGHT_BIQUAD3
:
109 case TAS3001C_REG_RIGHT_BIQUAD4
:
110 case TAS3001C_REG_RIGHT_BIQUAD5
:
111 case TAS3001C_REG_RIGHT_BIQUAD6
:
120 tas3001c_write_register( struct tas3001c_data_t
*self
,
121 enum tas3001c_reg_t reg_num
,
125 if (reg_num
==TAS3001C_REG_MCR
||
126 reg_num
==TAS3001C_REG_BASS
||
127 reg_num
==TAS3001C_REG_TREBLE
) {
128 return tas_write_byte_register(&self
->super
,
133 return tas_write_register(&self
->super
,
135 register_width(reg_num
),
142 tas3001c_sync_register( struct tas3001c_data_t
*self
,
143 enum tas3001c_reg_t reg_num
)
145 if (reg_num
==TAS3001C_REG_MCR
||
146 reg_num
==TAS3001C_REG_BASS
||
147 reg_num
==TAS3001C_REG_TREBLE
) {
148 return tas_sync_byte_register(&self
->super
,
150 register_width(reg_num
));
152 return tas_sync_register(&self
->super
,
154 register_width(reg_num
));
159 tas3001c_read_register( struct tas3001c_data_t
*self
,
160 enum tas3001c_reg_t reg_num
,
164 return tas_read_register(&self
->super
,
166 register_width(reg_num
),
171 tas3001c_fast_load(struct tas3001c_data_t
*self
, int fast
)
174 self
->super
.shadow
[TAS3001C_REG_MCR
][0] |= 0x80;
176 self
->super
.shadow
[TAS3001C_REG_MCR
][0] &= 0x7f;
177 return tas3001c_sync_register(self
,TAS3001C_REG_MCR
);
181 tas3001c_supported_mixers(struct tas3001c_data_t
*self
)
183 return SOUND_MASK_VOLUME
|
191 tas3001c_mixer_is_stereo(struct tas3001c_data_t
*self
,int mixer
)
194 case SOUND_MIXER_VOLUME
:
202 tas3001c_stereo_mixers(struct tas3001c_data_t
*self
)
204 uint r
=tas3001c_supported_mixers(self
);
207 for (i
=1; i
<SOUND_MIXER_NRDEVICES
; i
++)
208 if (r
&(1<<i
) && !tas3001c_mixer_is_stereo(self
,i
))
214 tas3001c_get_mixer_level(struct tas3001c_data_t
*self
,int mixer
,uint
*level
)
219 *level
=self
->super
.mixer
[mixer
];
225 tas3001c_set_mixer_level(struct tas3001c_data_t
*self
,int mixer
,uint level
)
228 tas_shadow_t
*shadow
;
236 shadow
=self
->super
.shadow
;
238 if (!tas3001c_mixer_is_stereo(self
,mixer
))
239 level
= tas_mono_to_stereo(level
);
242 case SOUND_MIXER_VOLUME
:
243 temp
= tas3001c_gain
.master
[level
&0xff];
244 shadow
[TAS3001C_REG_VOLUME
][0] = (temp
>> 16) & 0xff;
245 shadow
[TAS3001C_REG_VOLUME
][1] = (temp
>> 8) & 0xff;
246 shadow
[TAS3001C_REG_VOLUME
][2] = (temp
>> 0) & 0xff;
247 temp
= tas3001c_gain
.master
[(level
>>8)&0xff];
248 shadow
[TAS3001C_REG_VOLUME
][3] = (temp
>> 16) & 0xff;
249 shadow
[TAS3001C_REG_VOLUME
][4] = (temp
>> 8) & 0xff;
250 shadow
[TAS3001C_REG_VOLUME
][5] = (temp
>> 0) & 0xff;
251 rc
= tas3001c_sync_register(self
,TAS3001C_REG_VOLUME
);
253 case SOUND_MIXER_ALTPCM
:
254 /* tas3001c_fast_load(self, 1); */
255 level
= tas_mono_to_stereo(level
);
256 temp
= tas3001c_gain
.mixer
[level
&0xff];
257 shadow
[TAS3001C_REG_MIXER2
][offset
+0] = (temp
>> 16) & 0xff;
258 shadow
[TAS3001C_REG_MIXER2
][offset
+1] = (temp
>> 8) & 0xff;
259 shadow
[TAS3001C_REG_MIXER2
][offset
+2] = (temp
>> 0) & 0xff;
260 rc
= tas3001c_sync_register(self
,TAS3001C_REG_MIXER2
);
261 /* tas3001c_fast_load(self, 0); */
263 case SOUND_MIXER_PCM
:
264 /* tas3001c_fast_load(self, 1); */
265 level
= tas_mono_to_stereo(level
);
266 temp
= tas3001c_gain
.mixer
[level
&0xff];
267 shadow
[TAS3001C_REG_MIXER1
][offset
+0] = (temp
>> 16) & 0xff;
268 shadow
[TAS3001C_REG_MIXER1
][offset
+1] = (temp
>> 8) & 0xff;
269 shadow
[TAS3001C_REG_MIXER1
][offset
+2] = (temp
>> 0) & 0xff;
270 rc
= tas3001c_sync_register(self
,TAS3001C_REG_MIXER1
);
271 /* tas3001c_fast_load(self, 0); */
273 case SOUND_MIXER_TREBLE
:
274 temp
= tas3001c_gain
.treble
[level
&0xff];
275 shadow
[TAS3001C_REG_TREBLE
][0]=temp
&0xff;
276 rc
= tas3001c_sync_register(self
,TAS3001C_REG_TREBLE
);
278 case SOUND_MIXER_BASS
:
279 temp
= tas3001c_gain
.bass
[level
&0xff];
280 shadow
[TAS3001C_REG_BASS
][0]=temp
&0xff;
281 rc
= tas3001c_sync_register(self
,TAS3001C_REG_BASS
);
289 self
->super
.mixer
[mixer
]=level
;
294 tas3001c_leave_sleep(struct tas3001c_data_t
*self
)
296 unsigned char mcr
= (1<<6)+(2<<4)+(2<<2);
301 /* Make sure something answers on the i2c bus */
302 if (tas3001c_write_register(self
, TAS3001C_REG_MCR
, &mcr
,
303 WRITE_NORMAL
|FORCE_WRITE
) < 0)
306 tas3001c_fast_load(self
, 1);
308 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD0
);
309 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD1
);
310 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD2
);
311 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD3
);
312 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD4
);
313 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD5
);
315 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD0
);
316 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD1
);
317 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD2
);
318 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD3
);
319 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD4
);
320 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD5
);
322 tas3001c_fast_load(self
, 0);
324 (void)tas3001c_sync_register(self
,TAS3001C_REG_BASS
);
325 (void)tas3001c_sync_register(self
,TAS3001C_REG_TREBLE
);
326 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER1
);
327 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER2
);
328 (void)tas3001c_sync_register(self
,TAS3001C_REG_VOLUME
);
334 tas3001c_enter_sleep(struct tas3001c_data_t
*self
)
336 /* Stub for now, but I have the details on low-power mode */
343 tas3001c_sync_biquad( struct tas3001c_data_t
*self
,
347 enum tas3001c_reg_t reg
;
349 if (channel
>= TAS3001C_BIQUAD_CHANNEL_COUNT
||
350 filter
>= TAS3001C_BIQUAD_FILTER_COUNT
) return -EINVAL
;
352 reg
=( channel
? TAS3001C_REG_RIGHT_BIQUAD0
: TAS3001C_REG_LEFT_BIQUAD0
) + filter
;
354 return tas3001c_sync_register(self
,reg
);
358 tas3001c_write_biquad_shadow( struct tas3001c_data_t
*self
,
361 const union tas_biquad_t
*biquad
)
363 tas_shadow_t
*shadow
=self
->super
.shadow
;
364 enum tas3001c_reg_t reg
;
366 if (channel
>= TAS3001C_BIQUAD_CHANNEL_COUNT
||
367 filter
>= TAS3001C_BIQUAD_FILTER_COUNT
) return -EINVAL
;
369 reg
=( channel
? TAS3001C_REG_RIGHT_BIQUAD0
: TAS3001C_REG_LEFT_BIQUAD0
) + filter
;
371 SET_4_20(shadow
[reg
], 0,biquad
->coeff
.b0
);
372 SET_4_20(shadow
[reg
], 3,biquad
->coeff
.b1
);
373 SET_4_20(shadow
[reg
], 6,biquad
->coeff
.b2
);
374 SET_4_20(shadow
[reg
], 9,biquad
->coeff
.a1
);
375 SET_4_20(shadow
[reg
],12,biquad
->coeff
.a2
);
381 tas3001c_write_biquad( struct tas3001c_data_t
*self
,
384 const union tas_biquad_t
*biquad
)
388 rc
=tas3001c_write_biquad_shadow(self
, channel
, filter
, biquad
);
389 if (rc
< 0) return rc
;
391 return tas3001c_sync_biquad(self
, channel
, filter
);
395 tas3001c_write_biquad_list( struct tas3001c_data_t
*self
,
398 struct tas_biquad_ctrl_t
*biquads
)
403 if (flags
& TAS_BIQUAD_FAST_LOAD
) tas3001c_fast_load(self
,1);
405 for (i
=0; i
<filter_count
; i
++) {
406 rc
=tas3001c_write_biquad(self
,
413 if (flags
& TAS_BIQUAD_FAST_LOAD
) {
414 tas3001c_fast_load(self
,0);
416 (void)tas3001c_sync_register(self
,TAS3001C_REG_BASS
);
417 (void)tas3001c_sync_register(self
,TAS3001C_REG_TREBLE
);
418 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER1
);
419 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER2
);
420 (void)tas3001c_sync_register(self
,TAS3001C_REG_VOLUME
);
427 tas3001c_read_biquad( struct tas3001c_data_t
*self
,
430 union tas_biquad_t
*biquad
)
432 tas_shadow_t
*shadow
=self
->super
.shadow
;
433 enum tas3001c_reg_t reg
;
435 if (channel
>= TAS3001C_BIQUAD_CHANNEL_COUNT
||
436 filter
>= TAS3001C_BIQUAD_FILTER_COUNT
) return -EINVAL
;
438 reg
=( channel
? TAS3001C_REG_RIGHT_BIQUAD0
: TAS3001C_REG_LEFT_BIQUAD0
) + filter
;
440 biquad
->coeff
.b0
=GET_4_20(shadow
[reg
], 0);
441 biquad
->coeff
.b1
=GET_4_20(shadow
[reg
], 3);
442 biquad
->coeff
.b2
=GET_4_20(shadow
[reg
], 6);
443 biquad
->coeff
.a1
=GET_4_20(shadow
[reg
], 9);
444 biquad
->coeff
.a2
=GET_4_20(shadow
[reg
],12);
450 tas3001c_eq_rw( struct tas3001c_data_t
*self
,
455 struct tas_biquad_ctrl_t biquad
;
456 void __user
*argp
= (void __user
*)arg
;
458 if (copy_from_user(&biquad
, argp
, sizeof(struct tas_biquad_ctrl_t
))) {
463 rc
=tas3001c_write_biquad(self
, biquad
.channel
, biquad
.filter
, &biquad
.data
);
464 if (rc
!= 0) return rc
;
467 if (cmd
& SIOC_OUT
) {
468 rc
=tas3001c_read_biquad(self
, biquad
.channel
, biquad
.filter
, &biquad
.data
);
469 if (rc
!= 0) return rc
;
471 if (copy_to_user(argp
, &biquad
, sizeof(struct tas_biquad_ctrl_t
))) {
480 tas3001c_eq_list_rw( struct tas3001c_data_t
*self
,
488 char sync_required
[2][6];
489 struct tas_biquad_ctrl_t biquad
;
490 struct tas_biquad_ctrl_list_t __user
*argp
= (void __user
*)arg
;
492 memset(sync_required
,0,sizeof(sync_required
));
494 if (copy_from_user(&filter_count
, &argp
->filter_count
, sizeof(int)))
497 if (copy_from_user(&flags
, &argp
->flags
, sizeof(int)))
503 for (i
=0; i
< filter_count
; i
++) {
504 if (copy_from_user(&biquad
, &argp
->biquads
[i
],
505 sizeof(struct tas_biquad_ctrl_t
))) {
510 sync_required
[biquad
.channel
][biquad
.filter
]=1;
511 rc
=tas3001c_write_biquad_shadow(self
, biquad
.channel
, biquad
.filter
, &biquad
.data
);
512 if (rc
!= 0) return rc
;
515 if (cmd
& SIOC_OUT
) {
516 rc
=tas3001c_read_biquad(self
, biquad
.channel
, biquad
.filter
, &biquad
.data
);
517 if (rc
!= 0) return rc
;
519 if (copy_to_user(&argp
->biquads
[i
], &biquad
,
520 sizeof(struct tas_biquad_ctrl_t
))) {
527 if (flags
& TAS_BIQUAD_FAST_LOAD
) tas3001c_fast_load(self
,1);
528 for (i
=0; i
<2; i
++) {
529 for (j
=0; j
<6; j
++) {
530 if (sync_required
[i
][j
]) {
531 rc
=tas3001c_sync_biquad(self
, i
, j
);
532 if (rc
< 0) return rc
;
536 if (flags
& TAS_BIQUAD_FAST_LOAD
) {
537 tas3001c_fast_load(self
,0);
538 /* now we need to set up the mixers again,
539 because leaving fast mode resets them. */
540 (void)tas3001c_sync_register(self
,TAS3001C_REG_BASS
);
541 (void)tas3001c_sync_register(self
,TAS3001C_REG_TREBLE
);
542 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER1
);
543 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER2
);
544 (void)tas3001c_sync_register(self
,TAS3001C_REG_VOLUME
);
552 tas3001c_update_drce( struct tas3001c_data_t
*self
,
554 struct tas_drce_t
*drce
)
556 tas_shadow_t
*shadow
;
557 shadow
=self
->super
.shadow
;
559 shadow
[TAS3001C_REG_DRC
][1] = 0xc1;
561 if (flags
& TAS_DRCE_THRESHOLD
) {
562 self
->drce_state
.threshold
=quantize_db(drce
->threshold
);
563 shadow
[TAS3001C_REG_DRC
][2] = db_to_regval(self
->drce_state
.threshold
);
566 if (flags
& TAS_DRCE_ENABLE
) {
567 self
->drce_state
.enable
= drce
->enable
;
570 if (!self
->drce_state
.enable
) {
571 shadow
[TAS3001C_REG_DRC
][0] = 0xf0;
575 printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n",
576 self
->drce_state
.enable
,
577 self
->drce_state
.threshold
);
579 printk("DRCE IOCTL: reg [ %02x %02x ]\n",
580 (unsigned char)shadow
[TAS3001C_REG_DRC
][0],
581 (unsigned char)shadow
[TAS3001C_REG_DRC
][1]);
584 return tas3001c_sync_register(self
, TAS3001C_REG_DRC
);
588 tas3001c_drce_rw( struct tas3001c_data_t
*self
,
593 struct tas_drce_ctrl_t drce_ctrl
;
594 void __user
*argp
= (void __user
*)arg
;
596 if (copy_from_user(&drce_ctrl
, argp
, sizeof(struct tas_drce_ctrl_t
)))
600 printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n",
602 drce_ctrl
.data
.enable
,
603 drce_ctrl
.data
.threshold
);
607 rc
= tas3001c_update_drce(self
, drce_ctrl
.flags
, &drce_ctrl
.data
);
612 if (cmd
& SIOC_OUT
) {
613 if (drce_ctrl
.flags
& TAS_DRCE_ENABLE
)
614 drce_ctrl
.data
.enable
= self
->drce_state
.enable
;
616 if (drce_ctrl
.flags
& TAS_DRCE_THRESHOLD
)
617 drce_ctrl
.data
.threshold
= self
->drce_state
.threshold
;
619 if (copy_to_user(argp
, &drce_ctrl
,
620 sizeof(struct tas_drce_ctrl_t
))) {
629 tas3001c_update_device_parameters(struct tas3001c_data_t
*self
)
635 if (self
->output_id
== TAS_OUTPUT_HEADPHONES
) {
636 tas3001c_fast_load(self
, 1);
638 for (i
=0; i
<TAS3001C_BIQUAD_CHANNEL_COUNT
; i
++) {
639 for (j
=0; j
<TAS3001C_BIQUAD_FILTER_COUNT
; j
++) {
640 tas3001c_write_biquad(self
, i
, j
, &tas3001c_eq_unity
);
644 tas3001c_fast_load(self
, 0);
646 (void)tas3001c_sync_register(self
,TAS3001C_REG_BASS
);
647 (void)tas3001c_sync_register(self
,TAS3001C_REG_TREBLE
);
648 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER1
);
649 (void)tas3001c_sync_register(self
,TAS3001C_REG_MIXER2
);
650 (void)tas3001c_sync_register(self
,TAS3001C_REG_VOLUME
);
655 for (i
=0; tas3001c_eq_prefs
[i
]; i
++) {
656 struct tas_eq_pref_t
*eq
= tas3001c_eq_prefs
[i
];
658 if (eq
->device_id
== self
->device_id
&&
659 (eq
->output_id
== 0 || eq
->output_id
== self
->output_id
) &&
660 (eq
->speaker_id
== 0 || eq
->speaker_id
== self
->speaker_id
)) {
662 tas3001c_update_drce(self
, TAS_DRCE_ALL
, eq
->drce
);
663 tas3001c_write_biquad_list(self
, eq
->filter_count
, TAS_BIQUAD_FAST_LOAD
, eq
->biquads
);
671 tas3001c_device_change_handler(struct work_struct
*work
)
673 struct tas3001c_data_t
*self
;
674 self
= container_of(work
, struct tas3001c_data_t
, change
);
675 tas3001c_update_device_parameters(self
);
679 tas3001c_output_device_change( struct tas3001c_data_t
*self
,
684 self
->device_id
=device_id
;
685 self
->output_id
=output_id
;
686 self
->speaker_id
=speaker_id
;
688 schedule_work(&self
->change
);
693 tas3001c_device_ioctl( struct tas3001c_data_t
*self
,
697 uint __user
*argp
= (void __user
*)arg
;
701 return tas3001c_eq_rw(self
, cmd
, arg
);
703 case TAS_READ_EQ_LIST
:
704 case TAS_WRITE_EQ_LIST
:
705 return tas3001c_eq_list_rw(self
, cmd
, arg
);
707 case TAS_READ_EQ_FILTER_COUNT
:
708 put_user(TAS3001C_BIQUAD_FILTER_COUNT
, argp
);
711 case TAS_READ_EQ_CHANNEL_COUNT
:
712 put_user(TAS3001C_BIQUAD_CHANNEL_COUNT
, argp
);
717 return tas3001c_drce_rw(self
, cmd
, arg
);
719 case TAS_READ_DRCE_CAPS
:
720 put_user(TAS_DRCE_ENABLE
| TAS_DRCE_THRESHOLD
, argp
);
723 case TAS_READ_DRCE_MIN
:
724 case TAS_READ_DRCE_MAX
: {
725 struct tas_drce_ctrl_t drce_ctrl
;
727 if (copy_from_user(&drce_ctrl
, argp
,
728 sizeof(struct tas_drce_ctrl_t
))) {
732 if (drce_ctrl
.flags
& TAS_DRCE_THRESHOLD
) {
733 if (cmd
== TAS_READ_DRCE_MIN
) {
734 drce_ctrl
.data
.threshold
=-36<<8;
736 drce_ctrl
.data
.threshold
=-6<<8;
740 if (copy_to_user(argp
, &drce_ctrl
,
741 sizeof(struct tas_drce_ctrl_t
))) {
751 tas3001c_init_mixer(struct tas3001c_data_t
*self
)
753 unsigned char mcr
= (1<<6)+(2<<4)+(2<<2);
755 /* Make sure something answers on the i2c bus */
756 if (tas3001c_write_register(self
, TAS3001C_REG_MCR
, &mcr
,
757 WRITE_NORMAL
|FORCE_WRITE
) < 0)
760 tas3001c_fast_load(self
, 1);
762 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD0
);
763 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD1
);
764 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD2
);
765 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD3
);
766 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD4
);
767 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD5
);
768 (void)tas3001c_sync_register(self
,TAS3001C_REG_RIGHT_BIQUAD6
);
770 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD0
);
771 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD1
);
772 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD2
);
773 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD3
);
774 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD4
);
775 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD5
);
776 (void)tas3001c_sync_register(self
,TAS3001C_REG_LEFT_BIQUAD6
);
778 tas3001c_fast_load(self
, 0);
780 tas3001c_set_mixer_level(self
, SOUND_MIXER_VOLUME
, VOL_DEFAULT
<<8 | VOL_DEFAULT
);
781 tas3001c_set_mixer_level(self
, SOUND_MIXER_PCM
, INPUT_DEFAULT
<<8 | INPUT_DEFAULT
);
782 tas3001c_set_mixer_level(self
, SOUND_MIXER_ALTPCM
, 0);
784 tas3001c_set_mixer_level(self
, SOUND_MIXER_BASS
, BASS_DEFAULT
);
785 tas3001c_set_mixer_level(self
, SOUND_MIXER_TREBLE
, TREBLE_DEFAULT
);
791 tas3001c_uninit_mixer(struct tas3001c_data_t
*self
)
793 tas3001c_set_mixer_level(self
, SOUND_MIXER_VOLUME
, 0);
794 tas3001c_set_mixer_level(self
, SOUND_MIXER_PCM
, 0);
795 tas3001c_set_mixer_level(self
, SOUND_MIXER_ALTPCM
, 0);
797 tas3001c_set_mixer_level(self
, SOUND_MIXER_BASS
, 0);
798 tas3001c_set_mixer_level(self
, SOUND_MIXER_TREBLE
, 0);
804 tas3001c_init(struct i2c_client
*client
)
806 struct tas3001c_data_t
*self
;
807 size_t sz
= sizeof(*self
) + (TAS3001C_REG_MAX
*sizeof(tas_shadow_t
));
810 self
= kzalloc(sz
, GFP_KERNEL
);
814 self
->super
.client
= client
;
815 self
->super
.shadow
= (tas_shadow_t
*)(self
+1);
816 self
->output_id
= TAS_OUTPUT_HEADPHONES
;
818 dev_set_drvdata(&client
->dev
, self
);
820 for (i
= 0; i
< TAS3001C_BIQUAD_CHANNEL_COUNT
; i
++)
821 for (j
= 0; j
< TAS3001C_BIQUAD_FILTER_COUNT
; j
++)
822 tas3001c_write_biquad_shadow(self
, i
, j
,
825 INIT_WORK(&self
->change
, tas3001c_device_change_handler
);
830 tas3001c_uninit(struct tas3001c_data_t
*self
)
832 tas3001c_uninit_mixer(self
);
836 struct tas_driver_hooks_t tas3001c_hooks
= {
837 .init
= (tas_hook_init_t
)tas3001c_init
,
838 .post_init
= (tas_hook_post_init_t
)tas3001c_init_mixer
,
839 .uninit
= (tas_hook_uninit_t
)tas3001c_uninit
,
840 .get_mixer_level
= (tas_hook_get_mixer_level_t
)tas3001c_get_mixer_level
,
841 .set_mixer_level
= (tas_hook_set_mixer_level_t
)tas3001c_set_mixer_level
,
842 .enter_sleep
= (tas_hook_enter_sleep_t
)tas3001c_enter_sleep
,
843 .leave_sleep
= (tas_hook_leave_sleep_t
)tas3001c_leave_sleep
,
844 .supported_mixers
= (tas_hook_supported_mixers_t
)tas3001c_supported_mixers
,
845 .mixer_is_stereo
= (tas_hook_mixer_is_stereo_t
)tas3001c_mixer_is_stereo
,
846 .stereo_mixers
= (tas_hook_stereo_mixers_t
)tas3001c_stereo_mixers
,
847 .output_device_change
= (tas_hook_output_device_change_t
)tas3001c_output_device_change
,
848 .device_ioctl
= (tas_hook_device_ioctl_t
)tas3001c_device_ioctl