1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138 |
- /*
- * Driver for the i2c/i2s based TA3004 sound chip used
- * on some Apple hardware. Also known as "snapper".
- *
- * Tobias Sargeant <tobias.sargeant@bigpond.com>
- * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>:
- *
- * Input support by Renzo Davoli <renzo@cs.unibo.it>
- *
- */
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/proc_fs.h>
- #include <linux/ioport.h>
- #include <linux/sysctl.h>
- #include <linux/types.h>
- #include <linux/i2c.h>
- #include <linux/init.h>
- #include <linux/soundcard.h>
- #include <linux/interrupt.h>
- #include <linux/workqueue.h>
- #include <asm/uaccess.h>
- #include <asm/errno.h>
- #include <asm/io.h>
- #include <asm/prom.h>
- #include "dmasound.h"
- #include "tas_common.h"
- #include "tas3004.h"
- #include "tas_ioctl.h"
- /* #define DEBUG_DRCE */
- #define TAS3004_BIQUAD_FILTER_COUNT 7
- #define TAS3004_BIQUAD_CHANNEL_COUNT 2
- #define VOL_DEFAULT (100 * 4 / 5)
- #define INPUT_DEFAULT (100 * 4 / 5)
- #define BASS_DEFAULT (100 / 2)
- #define TREBLE_DEFAULT (100 / 2)
- struct tas3004_data_t {
- struct tas_data_t super;
- int device_id;
- int output_id;
- int speaker_id;
- struct tas_drce_t drce_state;
- struct work_struct change;
- };
- #define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000)
- #define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000))
- static const union tas_biquad_t tas3004_eq_unity = {
- .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 },
- };
- static const struct tas_drce_t tas3004_drce_min = {
- .enable = 1,
- .above = { .val = MAKE_RATIO(16,0), .expand = 0 },
- .below = { .val = MAKE_RATIO(2,0), .expand = 0 },
- .threshold = -0x59a0,
- .energy = MAKE_TIME(0, 1700),
- .attack = MAKE_TIME(0, 1700),
- .decay = MAKE_TIME(0, 1700),
- };
- static const struct tas_drce_t tas3004_drce_max = {
- .enable = 1,
- .above = { .val = MAKE_RATIO(1,500), .expand = 1 },
- .below = { .val = MAKE_RATIO(2,0), .expand = 1 },
- .threshold = -0x0,
- .energy = MAKE_TIME(2,400000),
- .attack = MAKE_TIME(2,400000),
- .decay = MAKE_TIME(2,400000),
- };
- static const unsigned short time_constants[]={
- MAKE_TIME(0, 1700),
- MAKE_TIME(0, 3500),
- MAKE_TIME(0, 6700),
- MAKE_TIME(0, 13000),
- MAKE_TIME(0, 26000),
- MAKE_TIME(0, 53000),
- MAKE_TIME(0,106000),
- MAKE_TIME(0,212000),
- MAKE_TIME(0,425000),
- MAKE_TIME(0,850000),
- MAKE_TIME(1,700000),
- MAKE_TIME(2,400000),
- };
- static const unsigned short above_threshold_compression_ratio[]={
- MAKE_RATIO( 1, 70),
- MAKE_RATIO( 1,140),
- MAKE_RATIO( 1,230),
- MAKE_RATIO( 1,330),
- MAKE_RATIO( 1,450),
- MAKE_RATIO( 1,600),
- MAKE_RATIO( 1,780),
- MAKE_RATIO( 2, 0),
- MAKE_RATIO( 2,290),
- MAKE_RATIO( 2,670),
- MAKE_RATIO( 3,200),
- MAKE_RATIO( 4, 0),
- MAKE_RATIO( 5,330),
- MAKE_RATIO( 8, 0),
- MAKE_RATIO(16, 0),
- };
- static const unsigned short above_threshold_expansion_ratio[]={
- MAKE_RATIO(1, 60),
- MAKE_RATIO(1,130),
- MAKE_RATIO(1,190),
- MAKE_RATIO(1,250),
- MAKE_RATIO(1,310),
- MAKE_RATIO(1,380),
- MAKE_RATIO(1,440),
- MAKE_RATIO(1,500)
- };
- static const unsigned short below_threshold_compression_ratio[]={
- MAKE_RATIO(1, 70),
- MAKE_RATIO(1,140),
- MAKE_RATIO(1,230),
- MAKE_RATIO(1,330),
- MAKE_RATIO(1,450),
- MAKE_RATIO(1,600),
- MAKE_RATIO(1,780),
- MAKE_RATIO(2, 0)
- };
- static const unsigned short below_threshold_expansion_ratio[]={
- MAKE_RATIO(1, 60),
- MAKE_RATIO(1,130),
- MAKE_RATIO(1,190),
- MAKE_RATIO(1,250),
- MAKE_RATIO(1,310),
- MAKE_RATIO(1,380),
- MAKE_RATIO(1,440),
- MAKE_RATIO(1,500),
- MAKE_RATIO(1,560),
- MAKE_RATIO(1,630),
- MAKE_RATIO(1,690),
- MAKE_RATIO(1,750),
- MAKE_RATIO(1,810),
- MAKE_RATIO(1,880),
- MAKE_RATIO(1,940),
- MAKE_RATIO(2, 0)
- };
- static inline int
- search( unsigned short val,
- const unsigned short *arr,
- const int arrsize) {
- /*
- * This could be a binary search, but for small tables,
- * a linear search is likely to be faster
- */
- int i;
- for (i=0; i < arrsize; i++)
- if (arr[i] >= val)
- goto _1;
- return arrsize-1;
- _1:
- if (i == 0)
- return 0;
- return (arr[i]-val < val-arr[i-1]) ? i : i-1;
- }
- #define SEARCH(a, b) search(a, b, ARRAY_SIZE(b))
- static inline int
- time_index(unsigned short time)
- {
- return SEARCH(time, time_constants);
- }
- static inline int
- above_threshold_compression_index(unsigned short ratio)
- {
- return SEARCH(ratio, above_threshold_compression_ratio);
- }
- static inline int
- above_threshold_expansion_index(unsigned short ratio)
- {
- return SEARCH(ratio, above_threshold_expansion_ratio);
- }
- static inline int
- below_threshold_compression_index(unsigned short ratio)
- {
- return SEARCH(ratio, below_threshold_compression_ratio);
- }
- static inline int
- below_threshold_expansion_index(unsigned short ratio)
- {
- return SEARCH(ratio, below_threshold_expansion_ratio);
- }
- static inline unsigned char db_to_regval(short db) {
- int r=0;
- r=(db+0x59a0) / 0x60;
- if (r < 0x91) return 0x91;
- if (r > 0xef) return 0xef;
- return r;
- }
- static inline short quantize_db(short db)
- {
- return db_to_regval(db) * 0x60 - 0x59a0;
- }
- static inline int
- register_width(enum tas3004_reg_t r)
- {
- switch(r) {
- case TAS3004_REG_MCR:
- case TAS3004_REG_TREBLE:
- case TAS3004_REG_BASS:
- case TAS3004_REG_ANALOG_CTRL:
- case TAS3004_REG_TEST1:
- case TAS3004_REG_TEST2:
- case TAS3004_REG_MCR2:
- return 1;
- case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN:
- case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN:
- return 3;
- case TAS3004_REG_DRC:
- case TAS3004_REG_VOLUME:
- return 6;
- case TAS3004_REG_LEFT_MIXER:
- case TAS3004_REG_RIGHT_MIXER:
- return 9;
- case TAS3004_REG_TEST:
- return 10;
- case TAS3004_REG_LEFT_BIQUAD0:
- case TAS3004_REG_LEFT_BIQUAD1:
- case TAS3004_REG_LEFT_BIQUAD2:
- case TAS3004_REG_LEFT_BIQUAD3:
- case TAS3004_REG_LEFT_BIQUAD4:
- case TAS3004_REG_LEFT_BIQUAD5:
- case TAS3004_REG_LEFT_BIQUAD6:
- case TAS3004_REG_RIGHT_BIQUAD0:
- case TAS3004_REG_RIGHT_BIQUAD1:
- case TAS3004_REG_RIGHT_BIQUAD2:
- case TAS3004_REG_RIGHT_BIQUAD3:
- case TAS3004_REG_RIGHT_BIQUAD4:
- case TAS3004_REG_RIGHT_BIQUAD5:
- case TAS3004_REG_RIGHT_BIQUAD6:
- case TAS3004_REG_LEFT_LOUD_BIQUAD:
- case TAS3004_REG_RIGHT_LOUD_BIQUAD:
- return 15;
- default:
- return 0;
- }
- }
- static int
- tas3004_write_register( struct tas3004_data_t *self,
- enum tas3004_reg_t reg_num,
- char *data,
- uint write_mode)
- {
- if (reg_num==TAS3004_REG_MCR ||
- reg_num==TAS3004_REG_BASS ||
- reg_num==TAS3004_REG_TREBLE ||
- reg_num==TAS3004_REG_ANALOG_CTRL) {
- return tas_write_byte_register(&self->super,
- (uint)reg_num,
- *data,
- write_mode);
- } else {
- return tas_write_register(&self->super,
- (uint)reg_num,
- register_width(reg_num),
- data,
- write_mode);
- }
- }
- static int
- tas3004_sync_register( struct tas3004_data_t *self,
- enum tas3004_reg_t reg_num)
- {
- if (reg_num==TAS3004_REG_MCR ||
- reg_num==TAS3004_REG_BASS ||
- reg_num==TAS3004_REG_TREBLE ||
- reg_num==TAS3004_REG_ANALOG_CTRL) {
- return tas_sync_byte_register(&self->super,
- (uint)reg_num,
- register_width(reg_num));
- } else {
- return tas_sync_register(&self->super,
- (uint)reg_num,
- register_width(reg_num));
- }
- }
- static int
- tas3004_read_register( struct tas3004_data_t *self,
- enum tas3004_reg_t reg_num,
- char *data,
- uint write_mode)
- {
- return tas_read_register(&self->super,
- (uint)reg_num,
- register_width(reg_num),
- data);
- }
- static inline int
- tas3004_fast_load(struct tas3004_data_t *self, int fast)
- {
- if (fast)
- self->super.shadow[TAS3004_REG_MCR][0] |= 0x80;
- else
- self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f;
- return tas3004_sync_register(self,TAS3004_REG_MCR);
- }
- static uint
- tas3004_supported_mixers(struct tas3004_data_t *self)
- {
- return SOUND_MASK_VOLUME |
- SOUND_MASK_PCM |
- SOUND_MASK_ALTPCM |
- SOUND_MASK_IMIX |
- SOUND_MASK_TREBLE |
- SOUND_MASK_BASS |
- SOUND_MASK_MIC |
- SOUND_MASK_LINE;
- }
- static int
- tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer)
- {
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- case SOUND_MIXER_PCM:
- case SOUND_MIXER_ALTPCM:
- case SOUND_MIXER_IMIX:
- return 1;
- default:
- return 0;
- }
- }
- static uint
- tas3004_stereo_mixers(struct tas3004_data_t *self)
- {
- uint r = tas3004_supported_mixers(self);
- uint i;
-
- for (i=1; i<SOUND_MIXER_NRDEVICES; i++)
- if (r&(1<<i) && !tas3004_mixer_is_stereo(self,i))
- r &= ~(1<<i);
- return r;
- }
- static int
- tas3004_get_mixer_level(struct tas3004_data_t *self, int mixer, uint *level)
- {
- if (!self)
- return -1;
- *level = self->super.mixer[mixer];
- return 0;
- }
- static int
- tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level)
- {
- int rc;
- tas_shadow_t *shadow;
- uint temp;
- uint offset=0;
- if (!self)
- return -1;
- shadow = self->super.shadow;
- if (!tas3004_mixer_is_stereo(self,mixer))
- level = tas_mono_to_stereo(level);
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- temp = tas3004_gain.master[level&0xff];
- SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp);
- temp = tas3004_gain.master[(level>>8)&0xff];
- SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp);
- rc = tas3004_sync_register(self,TAS3004_REG_VOLUME);
- break;
- case SOUND_MIXER_IMIX:
- offset += 3;
- case SOUND_MIXER_ALTPCM:
- offset += 3;
- case SOUND_MIXER_PCM:
- /*
- * Don't load these in fast mode. The documentation
- * says it can be done in either mode, but testing it
- * shows that fast mode produces ugly clicking.
- */
- /* tas3004_fast_load(self,1); */
- temp = tas3004_gain.mixer[level&0xff];
- SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp);
- temp = tas3004_gain.mixer[(level>>8)&0xff];
- SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp);
- rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER);
- if (rc == 0)
- rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER);
- /* tas3004_fast_load(self,0); */
- break;
- case SOUND_MIXER_TREBLE:
- temp = tas3004_gain.treble[level&0xff];
- shadow[TAS3004_REG_TREBLE][0]=temp&0xff;
- rc = tas3004_sync_register(self,TAS3004_REG_TREBLE);
- break;
- case SOUND_MIXER_BASS:
- temp = tas3004_gain.bass[level&0xff];
- shadow[TAS3004_REG_BASS][0]=temp&0xff;
- rc = tas3004_sync_register(self,TAS3004_REG_BASS);
- break;
- case SOUND_MIXER_MIC:
- if ((level&0xff)>0) {
- software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff);
- if (self->super.mixer[mixer] == 0) {
- self->super.mixer[SOUND_MIXER_LINE] = 0;
- shadow[TAS3004_REG_ANALOG_CTRL][0]=0xc2;
- rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
- } else rc=0;
- } else {
- self->super.mixer[SOUND_MIXER_LINE] = SW_INPUT_VOLUME_DEFAULT;
- software_input_volume = SW_INPUT_VOLUME_SCALE *
- (self->super.mixer[SOUND_MIXER_LINE]&0xff);
- shadow[TAS3004_REG_ANALOG_CTRL][0]=0x00;
- rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
- }
- break;
- case SOUND_MIXER_LINE:
- if (self->super.mixer[SOUND_MIXER_MIC] == 0) {
- software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff);
- rc=0;
- }
- break;
- default:
- rc = -1;
- break;
- }
- if (rc < 0)
- return rc;
- self->super.mixer[mixer] = level;
-
- return 0;
- }
- static int
- tas3004_leave_sleep(struct tas3004_data_t *self)
- {
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
- if (!self)
- return -1;
- /* Make sure something answers on the i2c bus */
- if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr,
- WRITE_NORMAL | FORCE_WRITE) < 0)
- return -1;
- tas3004_fast_load(self, 1);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6);
- tas3004_fast_load(self, 0);
- (void)tas3004_sync_register(self,TAS3004_REG_VOLUME);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER);
- (void)tas3004_sync_register(self,TAS3004_REG_TREBLE);
- (void)tas3004_sync_register(self,TAS3004_REG_BASS);
- (void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL);
- return 0;
- }
- static int
- tas3004_enter_sleep(struct tas3004_data_t *self)
- {
- if (!self)
- return -1;
- return 0;
- }
- static int
- tas3004_sync_biquad( struct tas3004_data_t *self,
- u_int channel,
- u_int filter)
- {
- enum tas3004_reg_t reg;
- if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL;
- reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter;
- return tas3004_sync_register(self,reg);
- }
- static int
- tas3004_write_biquad_shadow( struct tas3004_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
- {
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3004_reg_t reg;
- if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL;
- reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter;
- SET_4_20(shadow[reg], 0,biquad->coeff.b0);
- SET_4_20(shadow[reg], 3,biquad->coeff.b1);
- SET_4_20(shadow[reg], 6,biquad->coeff.b2);
- SET_4_20(shadow[reg], 9,biquad->coeff.a1);
- SET_4_20(shadow[reg],12,biquad->coeff.a2);
- return 0;
- }
- static int
- tas3004_write_biquad( struct tas3004_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
- {
- int rc;
- rc=tas3004_write_biquad_shadow(self, channel, filter, biquad);
- if (rc < 0) return rc;
- return tas3004_sync_biquad(self, channel, filter);
- }
- static int
- tas3004_write_biquad_list( struct tas3004_data_t *self,
- u_int filter_count,
- u_int flags,
- struct tas_biquad_ctrl_t *biquads)
- {
- int i;
- int rc;
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1);
- for (i=0; i<filter_count; i++) {
- rc=tas3004_write_biquad(self,
- biquads[i].channel,
- biquads[i].filter,
- &biquads[i].data);
- if (rc < 0) break;
- }
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,0);
- return rc;
- }
- static int
- tas3004_read_biquad( struct tas3004_data_t *self,
- u_int channel,
- u_int filter,
- union tas_biquad_t *biquad)
- {
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3004_reg_t reg;
- if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL;
- reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter;
- biquad->coeff.b0=GET_4_20(shadow[reg], 0);
- biquad->coeff.b1=GET_4_20(shadow[reg], 3);
- biquad->coeff.b2=GET_4_20(shadow[reg], 6);
- biquad->coeff.a1=GET_4_20(shadow[reg], 9);
- biquad->coeff.a2=GET_4_20(shadow[reg],12);
-
- return 0;
- }
- static int
- tas3004_eq_rw( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
- {
- void __user *argp = (void __user *)arg;
- int rc;
- struct tas_biquad_ctrl_t biquad;
- if (copy_from_user((void *)&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- if (cmd & SIOC_IN) {
- rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
- if (cmd & SIOC_OUT) {
- rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- }
- return 0;
- }
- static int
- tas3004_eq_list_rw( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
- {
- int rc = 0;
- int filter_count;
- int flags;
- int i,j;
- char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT];
- struct tas_biquad_ctrl_t biquad;
- struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg;
- memset(sync_required,0,sizeof(sync_required));
- if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int)))
- return -EFAULT;
- if (copy_from_user(&flags, &argp->flags, sizeof(int)))
- return -EFAULT;
- if (cmd & SIOC_IN) {
- }
- for (i=0; i < filter_count; i++) {
- if (copy_from_user(&biquad, &argp->biquads[i],
- sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- if (cmd & SIOC_IN) {
- sync_required[biquad.channel][biquad.filter]=1;
- rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
- if (cmd & SIOC_OUT) {
- rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- if (copy_to_user(&argp->biquads[i], &biquad,
- sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
- if (cmd & SIOC_IN) {
- /*
- * This is OK for the tas3004. For the
- * tas3001c, going into fast load mode causes
- * the treble and bass to be reset to 0dB, and
- * volume controls to be muted.
- */
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1);
- for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) {
- for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) {
- if (sync_required[i][j]) {
- rc=tas3004_sync_biquad(self, i, j);
- if (rc < 0) goto out;
- }
- }
- }
- out:
- if (flags & TAS_BIQUAD_FAST_LOAD)
- tas3004_fast_load(self,0);
- }
- return rc;
- }
- static int
- tas3004_update_drce( struct tas3004_data_t *self,
- int flags,
- struct tas_drce_t *drce)
- {
- tas_shadow_t *shadow;
- int i;
- shadow=self->super.shadow;
- if (flags & TAS_DRCE_ABOVE_RATIO) {
- self->drce_state.above.expand = drce->above.expand;
- if (drce->above.val == (1<<8)) {
- self->drce_state.above.val = 1<<8;
- shadow[TAS3004_REG_DRC][0] = 0x02;
-
- } else if (drce->above.expand) {
- i=above_threshold_expansion_index(drce->above.val);
- self->drce_state.above.val=above_threshold_expansion_ratio[i];
- shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3);
- } else {
- i=above_threshold_compression_index(drce->above.val);
- self->drce_state.above.val=above_threshold_compression_ratio[i];
- shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3);
- }
- }
- if (flags & TAS_DRCE_BELOW_RATIO) {
- self->drce_state.below.expand = drce->below.expand;
- if (drce->below.val == (1<<8)) {
- self->drce_state.below.val = 1<<8;
- shadow[TAS3004_REG_DRC][1] = 0x02;
-
- } else if (drce->below.expand) {
- i=below_threshold_expansion_index(drce->below.val);
- self->drce_state.below.val=below_threshold_expansion_ratio[i];
- shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3);
- } else {
- i=below_threshold_compression_index(drce->below.val);
- self->drce_state.below.val=below_threshold_compression_ratio[i];
- shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3);
- }
- }
- if (flags & TAS_DRCE_THRESHOLD) {
- self->drce_state.threshold=quantize_db(drce->threshold);
- shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold);
- }
- if (flags & TAS_DRCE_ENERGY) {
- i=time_index(drce->energy);
- self->drce_state.energy=time_constants[i];
- shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4);
- }
- if (flags & TAS_DRCE_ATTACK) {
- i=time_index(drce->attack);
- self->drce_state.attack=time_constants[i];
- shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4);
- }
- if (flags & TAS_DRCE_DECAY) {
- i=time_index(drce->decay);
- self->drce_state.decay=time_constants[i];
- shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4);
- }
- if (flags & TAS_DRCE_ENABLE) {
- self->drce_state.enable = drce->enable;
- }
- if (!self->drce_state.enable) {
- shadow[TAS3004_REG_DRC][0] |= 0x01;
- }
- #ifdef DEBUG_DRCE
- printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n",
- self->drce_state.enable,
- self->drce_state.above.expand,self->drce_state.above.val,
- self->drce_state.below.expand,self->drce_state.below.val,
- self->drce_state.threshold,
- self->drce_state.energy,
- self->drce_state.attack,
- self->drce_state.decay);
- printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n",
- (unsigned char)shadow[TAS3004_REG_DRC][0],
- (unsigned char)shadow[TAS3004_REG_DRC][1],
- (unsigned char)shadow[TAS3004_REG_DRC][2],
- (unsigned char)shadow[TAS3004_REG_DRC][3],
- (unsigned char)shadow[TAS3004_REG_DRC][4],
- (unsigned char)shadow[TAS3004_REG_DRC][5]);
- #endif
- return tas3004_sync_register(self, TAS3004_REG_DRC);
- }
- static int
- tas3004_drce_rw( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
- {
- int rc;
- struct tas_drce_ctrl_t drce_ctrl;
- void __user *argp = (void __user *)arg;
- if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t)))
- return -EFAULT;
- #ifdef DEBUG_DRCE
- printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n",
- drce_ctrl.flags,
- drce_ctrl.data.enable,
- drce_ctrl.data.above.expand,drce_ctrl.data.above.val,
- drce_ctrl.data.below.expand,drce_ctrl.data.below.val,
- drce_ctrl.data.threshold,
- drce_ctrl.data.energy,
- drce_ctrl.data.attack,
- drce_ctrl.data.decay);
- #endif
- if (cmd & SIOC_IN) {
- rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data);
- if (rc < 0) return rc;
- }
- if (cmd & SIOC_OUT) {
- if (drce_ctrl.flags & TAS_DRCE_ENABLE)
- drce_ctrl.data.enable = self->drce_state.enable;
- if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO)
- drce_ctrl.data.above = self->drce_state.above;
- if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO)
- drce_ctrl.data.below = self->drce_state.below;
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD)
- drce_ctrl.data.threshold = self->drce_state.threshold;
- if (drce_ctrl.flags & TAS_DRCE_ENERGY)
- drce_ctrl.data.energy = self->drce_state.energy;
- if (drce_ctrl.flags & TAS_DRCE_ATTACK)
- drce_ctrl.data.attack = self->drce_state.attack;
- if (drce_ctrl.flags & TAS_DRCE_DECAY)
- drce_ctrl.data.decay = self->drce_state.decay;
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
- return 0;
- }
- static void
- tas3004_update_device_parameters(struct tas3004_data_t *self)
- {
- char data;
- int i;
- if (!self) return;
- if (self->output_id == TAS_OUTPUT_HEADPHONES) {
- /* turn on allPass when headphones are plugged in */
- data = 0x02;
- } else {
- data = 0x00;
- }
- tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE);
- for (i=0; tas3004_eq_prefs[i]; i++) {
- struct tas_eq_pref_t *eq = tas3004_eq_prefs[i];
- if (eq->device_id == self->device_id &&
- (eq->output_id == 0 || eq->output_id == self->output_id) &&
- (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) {
- tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce);
- tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads);
- break;
- }
- }
- }
- static void
- tas3004_device_change_handler(struct work_struct *work)
- {
- struct tas3004_data_t *self;
- self = container_of(work, struct tas3004_data_t, change);
- tas3004_update_device_parameters(self);
- }
- static int
- tas3004_output_device_change( struct tas3004_data_t *self,
- int device_id,
- int output_id,
- int speaker_id)
- {
- self->device_id=device_id;
- self->output_id=output_id;
- self->speaker_id=speaker_id;
- schedule_work(&self->change);
- return 0;
- }
- static int
- tas3004_device_ioctl( struct tas3004_data_t *self,
- u_int cmd,
- u_long arg)
- {
- uint __user *argp = (void __user *)arg;
- switch (cmd) {
- case TAS_READ_EQ:
- case TAS_WRITE_EQ:
- return tas3004_eq_rw(self, cmd, arg);
- case TAS_READ_EQ_LIST:
- case TAS_WRITE_EQ_LIST:
- return tas3004_eq_list_rw(self, cmd, arg);
- case TAS_READ_EQ_FILTER_COUNT:
- put_user(TAS3004_BIQUAD_FILTER_COUNT, argp);
- return 0;
- case TAS_READ_EQ_CHANNEL_COUNT:
- put_user(TAS3004_BIQUAD_CHANNEL_COUNT, argp);
- return 0;
- case TAS_READ_DRCE:
- case TAS_WRITE_DRCE:
- return tas3004_drce_rw(self, cmd, arg);
- case TAS_READ_DRCE_CAPS:
- put_user(TAS_DRCE_ENABLE |
- TAS_DRCE_ABOVE_RATIO |
- TAS_DRCE_BELOW_RATIO |
- TAS_DRCE_THRESHOLD |
- TAS_DRCE_ENERGY |
- TAS_DRCE_ATTACK |
- TAS_DRCE_DECAY,
- argp);
- return 0;
- case TAS_READ_DRCE_MIN:
- case TAS_READ_DRCE_MAX: {
- struct tas_drce_ctrl_t drce_ctrl;
- const struct tas_drce_t *drce_copy;
- if (copy_from_user(&drce_ctrl, argp,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- if (cmd == TAS_READ_DRCE_MIN) {
- drce_copy=&tas3004_drce_min;
- } else {
- drce_copy=&tas3004_drce_max;
- }
- if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) {
- drce_ctrl.data.above=drce_copy->above;
- }
- if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) {
- drce_ctrl.data.below=drce_copy->below;
- }
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) {
- drce_ctrl.data.threshold=drce_copy->threshold;
- }
- if (drce_ctrl.flags & TAS_DRCE_ENERGY) {
- drce_ctrl.data.energy=drce_copy->energy;
- }
- if (drce_ctrl.flags & TAS_DRCE_ATTACK) {
- drce_ctrl.data.attack=drce_copy->attack;
- }
- if (drce_ctrl.flags & TAS_DRCE_DECAY) {
- drce_ctrl.data.decay=drce_copy->decay;
- }
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
- return -EINVAL;
- }
- static int
- tas3004_init_mixer(struct tas3004_data_t *self)
- {
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
- /* Make sure something answers on the i2c bus */
- if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr,
- WRITE_NORMAL | FORCE_WRITE) < 0)
- return -1;
- tas3004_fast_load(self, 1);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5);
- (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6);
- tas3004_sync_register(self, TAS3004_REG_DRC);
- tas3004_sync_register(self, TAS3004_REG_MCR2);
- tas3004_fast_load(self, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT);
- tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT);
- return 0;
- }
- static int
- tas3004_uninit_mixer(struct tas3004_data_t *self)
- {
- tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0);
- tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0);
- return 0;
- }
- static int
- tas3004_init(struct i2c_client *client)
- {
- struct tas3004_data_t *self;
- size_t sz = sizeof(*self) + (TAS3004_REG_MAX*sizeof(tas_shadow_t));
- char drce_init[] = { 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 };
- char mcr2 = 0;
- int i, j;
- self = kzalloc(sz, GFP_KERNEL);
- if (!self)
- return -ENOMEM;
- self->super.client = client;
- self->super.shadow = (tas_shadow_t *)(self+1);
- self->output_id = TAS_OUTPUT_HEADPHONES;
- dev_set_drvdata(&client->dev, self);
- for (i = 0; i < TAS3004_BIQUAD_CHANNEL_COUNT; i++)
- for (j = 0; j<TAS3004_BIQUAD_FILTER_COUNT; j++)
- tas3004_write_biquad_shadow(self, i, j,
- &tas3004_eq_unity);
- tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW);
- tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW);
- INIT_WORK(&self->change, tas3004_device_change_handler);
- return 0;
- }
- static void
- tas3004_uninit(struct tas3004_data_t *self)
- {
- tas3004_uninit_mixer(self);
- kfree(self);
- }
- struct tas_driver_hooks_t tas3004_hooks = {
- .init = (tas_hook_init_t)tas3004_init,
- .post_init = (tas_hook_post_init_t)tas3004_init_mixer,
- .uninit = (tas_hook_uninit_t)tas3004_uninit,
- .get_mixer_level = (tas_hook_get_mixer_level_t)tas3004_get_mixer_level,
- .set_mixer_level = (tas_hook_set_mixer_level_t)tas3004_set_mixer_level,
- .enter_sleep = (tas_hook_enter_sleep_t)tas3004_enter_sleep,
- .leave_sleep = (tas_hook_leave_sleep_t)tas3004_leave_sleep,
- .supported_mixers = (tas_hook_supported_mixers_t)tas3004_supported_mixers,
- .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3004_mixer_is_stereo,
- .stereo_mixers = (tas_hook_stereo_mixers_t)tas3004_stereo_mixers,
- .output_device_change = (tas_hook_output_device_change_t)tas3004_output_device_change,
- .device_ioctl = (tas_hook_device_ioctl_t)tas3004_device_ioctl
- };
|