123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850 |
- /*
- * 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>:
- *
- * TODO:
- * -----
- * * Enable control over input line 2 (is this connected?)
- * * Implement sleep support (at least mute everything and
- * * set gains to minimum during sleep)
- * * Look into some of Darwin's tweaks regarding the mute
- * * lines (delays & different behaviour on some HW)
- *
- */
- #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/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 "tas3001c.h"
- #include "tas_ioctl.h"
- #define TAS3001C_BIQUAD_FILTER_COUNT 6
- #define TAS3001C_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 tas3001c_data_t {
- struct tas_data_t super;
- int device_id;
- int output_id;
- int speaker_id;
- struct tas_drce_t drce_state;
- };
- static const union tas_biquad_t
- tas3001c_eq_unity={
- .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 }
- };
- 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 tas3001c_reg_t r)
- {
- switch(r) {
- case TAS3001C_REG_MCR:
- case TAS3001C_REG_TREBLE:
- case TAS3001C_REG_BASS:
- return 1;
- case TAS3001C_REG_DRC:
- return 2;
- case TAS3001C_REG_MIXER1:
- case TAS3001C_REG_MIXER2:
- return 3;
- case TAS3001C_REG_VOLUME:
- return 6;
- case TAS3001C_REG_LEFT_BIQUAD0:
- case TAS3001C_REG_LEFT_BIQUAD1:
- case TAS3001C_REG_LEFT_BIQUAD2:
- case TAS3001C_REG_LEFT_BIQUAD3:
- case TAS3001C_REG_LEFT_BIQUAD4:
- case TAS3001C_REG_LEFT_BIQUAD5:
- case TAS3001C_REG_LEFT_BIQUAD6:
- case TAS3001C_REG_RIGHT_BIQUAD0:
- case TAS3001C_REG_RIGHT_BIQUAD1:
- case TAS3001C_REG_RIGHT_BIQUAD2:
- case TAS3001C_REG_RIGHT_BIQUAD3:
- case TAS3001C_REG_RIGHT_BIQUAD4:
- case TAS3001C_REG_RIGHT_BIQUAD5:
- case TAS3001C_REG_RIGHT_BIQUAD6:
- return 15;
- default:
- return 0;
- }
- }
- static int
- tas3001c_write_register( struct tas3001c_data_t *self,
- enum tas3001c_reg_t reg_num,
- char *data,
- uint write_mode)
- {
- if (reg_num==TAS3001C_REG_MCR ||
- reg_num==TAS3001C_REG_BASS ||
- reg_num==TAS3001C_REG_TREBLE) {
- 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
- tas3001c_sync_register( struct tas3001c_data_t *self,
- enum tas3001c_reg_t reg_num)
- {
- if (reg_num==TAS3001C_REG_MCR ||
- reg_num==TAS3001C_REG_BASS ||
- reg_num==TAS3001C_REG_TREBLE) {
- 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
- tas3001c_read_register( struct tas3001c_data_t *self,
- enum tas3001c_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
- tas3001c_fast_load(struct tas3001c_data_t *self, int fast)
- {
- if (fast)
- self->super.shadow[TAS3001C_REG_MCR][0] |= 0x80;
- else
- self->super.shadow[TAS3001C_REG_MCR][0] &= 0x7f;
- return tas3001c_sync_register(self,TAS3001C_REG_MCR);
- }
- static uint
- tas3001c_supported_mixers(struct tas3001c_data_t *self)
- {
- return SOUND_MASK_VOLUME |
- SOUND_MASK_PCM |
- SOUND_MASK_ALTPCM |
- SOUND_MASK_TREBLE |
- SOUND_MASK_BASS;
- }
- static int
- tas3001c_mixer_is_stereo(struct tas3001c_data_t *self,int mixer)
- {
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- return 1;
- default:
- return 0;
- }
- }
- static uint
- tas3001c_stereo_mixers(struct tas3001c_data_t *self)
- {
- uint r=tas3001c_supported_mixers(self);
- uint i;
-
- for (i=1; i<SOUND_MIXER_NRDEVICES; i++)
- if (r&(1<<i) && !tas3001c_mixer_is_stereo(self,i))
- r &= ~(1<<i);
- return r;
- }
- static int
- tas3001c_get_mixer_level(struct tas3001c_data_t *self,int mixer,uint *level)
- {
- if (!self)
- return -1;
-
- *level=self->super.mixer[mixer];
-
- return 0;
- }
- static int
- tas3001c_set_mixer_level(struct tas3001c_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 (!tas3001c_mixer_is_stereo(self,mixer))
- level = tas_mono_to_stereo(level);
- switch(mixer) {
- case SOUND_MIXER_VOLUME:
- temp = tas3001c_gain.master[level&0xff];
- shadow[TAS3001C_REG_VOLUME][0] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_VOLUME][1] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_VOLUME][2] = (temp >> 0) & 0xff;
- temp = tas3001c_gain.master[(level>>8)&0xff];
- shadow[TAS3001C_REG_VOLUME][3] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_VOLUME][4] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_VOLUME][5] = (temp >> 0) & 0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- break;
- case SOUND_MIXER_ALTPCM:
- /* tas3001c_fast_load(self, 1); */
- level = tas_mono_to_stereo(level);
- temp = tas3001c_gain.mixer[level&0xff];
- shadow[TAS3001C_REG_MIXER2][offset+0] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_MIXER2][offset+1] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_MIXER2][offset+2] = (temp >> 0) & 0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- /* tas3001c_fast_load(self, 0); */
- break;
- case SOUND_MIXER_PCM:
- /* tas3001c_fast_load(self, 1); */
- level = tas_mono_to_stereo(level);
- temp = tas3001c_gain.mixer[level&0xff];
- shadow[TAS3001C_REG_MIXER1][offset+0] = (temp >> 16) & 0xff;
- shadow[TAS3001C_REG_MIXER1][offset+1] = (temp >> 8) & 0xff;
- shadow[TAS3001C_REG_MIXER1][offset+2] = (temp >> 0) & 0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- /* tas3001c_fast_load(self, 0); */
- break;
- case SOUND_MIXER_TREBLE:
- temp = tas3001c_gain.treble[level&0xff];
- shadow[TAS3001C_REG_TREBLE][0]=temp&0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- break;
- case SOUND_MIXER_BASS:
- temp = tas3001c_gain.bass[level&0xff];
- shadow[TAS3001C_REG_BASS][0]=temp&0xff;
- rc = tas3001c_sync_register(self,TAS3001C_REG_BASS);
- break;
- default:
- rc = -1;
- break;
- }
- if (rc < 0)
- return rc;
- self->super.mixer[mixer]=level;
- return 0;
- }
- static int
- tas3001c_leave_sleep(struct tas3001c_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 (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr,
- WRITE_NORMAL|FORCE_WRITE) < 0)
- return -1;
- tas3001c_fast_load(self, 1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5);
- tas3001c_fast_load(self, 0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- return 0;
- }
- static int
- tas3001c_enter_sleep(struct tas3001c_data_t *self)
- {
- /* Stub for now, but I have the details on low-power mode */
- if (!self)
- return -1;
- return 0;
- }
- static int
- tas3001c_sync_biquad( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter)
- {
- enum tas3001c_reg_t reg;
- if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;
- reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter;
- return tas3001c_sync_register(self,reg);
- }
- static int
- tas3001c_write_biquad_shadow( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
- {
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3001c_reg_t reg;
- if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;
- reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_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
- tas3001c_write_biquad( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter,
- const union tas_biquad_t *biquad)
- {
- int rc;
- rc=tas3001c_write_biquad_shadow(self, channel, filter, biquad);
- if (rc < 0) return rc;
- return tas3001c_sync_biquad(self, channel, filter);
- }
- static int
- tas3001c_write_biquad_list( struct tas3001c_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) tas3001c_fast_load(self,1);
- for (i=0; i<filter_count; i++) {
- rc=tas3001c_write_biquad(self,
- biquads[i].channel,
- biquads[i].filter,
- &biquads[i].data);
- if (rc < 0) break;
- }
- if (flags & TAS_BIQUAD_FAST_LOAD) {
- tas3001c_fast_load(self,0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- }
- return rc;
- }
- static int
- tas3001c_read_biquad( struct tas3001c_data_t *self,
- u_int channel,
- u_int filter,
- union tas_biquad_t *biquad)
- {
- tas_shadow_t *shadow=self->super.shadow;
- enum tas3001c_reg_t reg;
- if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT ||
- filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL;
- reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_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
- tas3001c_eq_rw( struct tas3001c_data_t *self,
- u_int cmd,
- u_long arg)
- {
- int rc;
- struct tas_biquad_ctrl_t biquad;
- void __user *argp = (void __user *)arg;
- if (copy_from_user(&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) {
- return -EFAULT;
- }
- if (cmd & SIOC_IN) {
- rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
- if (cmd & SIOC_OUT) {
- rc=tas3001c_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
- tas3001c_eq_list_rw( struct tas3001c_data_t *self,
- u_int cmd,
- u_long arg)
- {
- int rc;
- int filter_count;
- int flags;
- int i,j;
- char sync_required[2][6];
- 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=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data);
- if (rc != 0) return rc;
- }
- if (cmd & SIOC_OUT) {
- rc=tas3001c_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) {
- if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1);
- for (i=0; i<2; i++) {
- for (j=0; j<6; j++) {
- if (sync_required[i][j]) {
- rc=tas3001c_sync_biquad(self, i, j);
- if (rc < 0) return rc;
- }
- }
- }
- if (flags & TAS_BIQUAD_FAST_LOAD) {
- tas3001c_fast_load(self,0);
- /* now we need to set up the mixers again,
- because leaving fast mode resets them. */
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- }
- }
- return 0;
- }
- static int
- tas3001c_update_drce( struct tas3001c_data_t *self,
- int flags,
- struct tas_drce_t *drce)
- {
- tas_shadow_t *shadow;
- shadow=self->super.shadow;
- shadow[TAS3001C_REG_DRC][1] = 0xc1;
- if (flags & TAS_DRCE_THRESHOLD) {
- self->drce_state.threshold=quantize_db(drce->threshold);
- shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold);
- }
- if (flags & TAS_DRCE_ENABLE) {
- self->drce_state.enable = drce->enable;
- }
- if (!self->drce_state.enable) {
- shadow[TAS3001C_REG_DRC][0] = 0xf0;
- }
- #ifdef DEBUG_DRCE
- printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n",
- self->drce_state.enable,
- self->drce_state.threshold);
- printk("DRCE IOCTL: reg [ %02x %02x ]\n",
- (unsigned char)shadow[TAS3001C_REG_DRC][0],
- (unsigned char)shadow[TAS3001C_REG_DRC][1]);
- #endif
- return tas3001c_sync_register(self, TAS3001C_REG_DRC);
- }
- static int
- tas3001c_drce_rw( struct tas3001c_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 IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n",
- drce_ctrl.flags,
- drce_ctrl.data.enable,
- drce_ctrl.data.threshold);
- #endif
- if (cmd & SIOC_IN) {
- rc = tas3001c_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_THRESHOLD)
- drce_ctrl.data.threshold = self->drce_state.threshold;
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
- return 0;
- }
- static void
- tas3001c_update_device_parameters(struct tas3001c_data_t *self)
- {
- int i,j;
- if (!self) return;
- if (self->output_id == TAS_OUTPUT_HEADPHONES) {
- tas3001c_fast_load(self, 1);
- for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) {
- for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) {
- tas3001c_write_biquad(self, i, j, &tas3001c_eq_unity);
- }
- }
- tas3001c_fast_load(self, 0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_BASS);
- (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME);
- return;
- }
- for (i=0; tas3001c_eq_prefs[i]; i++) {
- struct tas_eq_pref_t *eq = tas3001c_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)) {
- tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce);
- tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads);
- break;
- }
- }
- }
- static void
- tas3001c_device_change_handler(void *self)
- {
- if (self)
- tas3001c_update_device_parameters(self);
- }
- static struct work_struct device_change;
- static int
- tas3001c_output_device_change( struct tas3001c_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(&device_change);
- return 0;
- }
- static int
- tas3001c_device_ioctl( struct tas3001c_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 tas3001c_eq_rw(self, cmd, arg);
- case TAS_READ_EQ_LIST:
- case TAS_WRITE_EQ_LIST:
- return tas3001c_eq_list_rw(self, cmd, arg);
- case TAS_READ_EQ_FILTER_COUNT:
- put_user(TAS3001C_BIQUAD_FILTER_COUNT, argp);
- return 0;
- case TAS_READ_EQ_CHANNEL_COUNT:
- put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, argp);
- return 0;
- case TAS_READ_DRCE:
- case TAS_WRITE_DRCE:
- return tas3001c_drce_rw(self, cmd, arg);
- case TAS_READ_DRCE_CAPS:
- put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, argp);
- return 0;
- case TAS_READ_DRCE_MIN:
- case TAS_READ_DRCE_MAX: {
- struct tas_drce_ctrl_t drce_ctrl;
- if (copy_from_user(&drce_ctrl, argp,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) {
- if (cmd == TAS_READ_DRCE_MIN) {
- drce_ctrl.data.threshold=-36<<8;
- } else {
- drce_ctrl.data.threshold=-6<<8;
- }
- }
- if (copy_to_user(argp, &drce_ctrl,
- sizeof(struct tas_drce_ctrl_t))) {
- return -EFAULT;
- }
- }
- }
- return -EINVAL;
- }
- static int
- tas3001c_init_mixer(struct tas3001c_data_t *self)
- {
- unsigned char mcr = (1<<6)+(2<<4)+(2<<2);
- /* Make sure something answers on the i2c bus */
- if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr,
- WRITE_NORMAL|FORCE_WRITE) < 0)
- return -1;
- tas3001c_fast_load(self, 1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5);
- (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5);
- (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6);
- tas3001c_fast_load(self, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT);
- tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT);
- tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT);
- tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT);
- return 0;
- }
- static int
- tas3001c_uninit_mixer(struct tas3001c_data_t *self)
- {
- tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, 0);
- tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0);
- return 0;
- }
- static int
- tas3001c_init(struct i2c_client *client)
- {
- struct tas3001c_data_t *self;
- size_t sz = sizeof(*self) + (TAS3001C_REG_MAX*sizeof(tas_shadow_t));
- int i, j;
- self = kmalloc(sz, GFP_KERNEL);
- if (!self)
- return -ENOMEM;
- memset(self, 0, sz);
- 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 < TAS3001C_BIQUAD_CHANNEL_COUNT; i++)
- for (j = 0; j < TAS3001C_BIQUAD_FILTER_COUNT; j++)
- tas3001c_write_biquad_shadow(self, i, j,
- &tas3001c_eq_unity);
- INIT_WORK(&device_change, tas3001c_device_change_handler, self);
- return 0;
- }
- static void
- tas3001c_uninit(struct tas3001c_data_t *self)
- {
- tas3001c_uninit_mixer(self);
- kfree(self);
- }
- struct tas_driver_hooks_t tas3001c_hooks = {
- .init = (tas_hook_init_t)tas3001c_init,
- .post_init = (tas_hook_post_init_t)tas3001c_init_mixer,
- .uninit = (tas_hook_uninit_t)tas3001c_uninit,
- .get_mixer_level = (tas_hook_get_mixer_level_t)tas3001c_get_mixer_level,
- .set_mixer_level = (tas_hook_set_mixer_level_t)tas3001c_set_mixer_level,
- .enter_sleep = (tas_hook_enter_sleep_t)tas3001c_enter_sleep,
- .leave_sleep = (tas_hook_leave_sleep_t)tas3001c_leave_sleep,
- .supported_mixers = (tas_hook_supported_mixers_t)tas3001c_supported_mixers,
- .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3001c_mixer_is_stereo,
- .stereo_mixers = (tas_hook_stereo_mixers_t)tas3001c_stereo_mixers,
- .output_device_change = (tas_hook_output_device_change_t)tas3001c_output_device_change,
- .device_ioctl = (tas_hook_device_ioctl_t)tas3001c_device_ioctl
- };
|