diff options
author | joel <joel@FreeBSD.org> | 2007-05-27 19:58:39 +0000 |
---|---|---|
committer | joel <joel@FreeBSD.org> | 2007-05-27 19:58:39 +0000 |
commit | 885b989283f427208d97559528312bd1d42aed6b (patch) | |
tree | 5347304834b0c0a40cf5f467f89016ee96d33b53 | |
parent | ef37256e5e0ee3cea7da9704d99c342be1bbfa30 (diff) | |
download | FreeBSD-src-885b989283f427208d97559528312bd1d42aed6b.zip FreeBSD-src-885b989283f427208d97559528312bd1d42aed6b.tar.gz |
Bring in a bunch of bug fixes and some code to support more chipsets.
Neither me nor Ariff have access to any of this hardware, so all tests
have been made by Konstantin and Artem. Commit message mostly written
by Konstantin.
envy24:
- Add test code to support rear line-in input on 'Terratec DMX 6fire'
audio card. This code is also intended to be used in the future for
support of cards, that have I2C-to-GPIO expanders wired between the
control line of the audio codec and the Envy24, however such cards
are too complex and i can't add that support without hardware sample
of such board, i've already tried and failed.
envy24ht:
- Add support for 'AudioTrak Prodigy HD2'.
- Add support for 'AudioTrak Prodigy 7.1 XT'.
- Add support for 'ESI Juli@' (Works ok, DAC volume is hard-coded for
the time being, so 'mixer vol ...' doesn't work, only 'mixer pcm
...' works). [1]
- Fix bug in the init data for M-Audio Revolution 5.1, that
results in distorted sound.
- Add software volume control (now 'mixer pcm' works, thanks to Ariff).
- Add support for more samples rates - 176.4kHz and 192kHz.
- Fix problem with the 192kHz samples rate playback when 24.576MHz
crystal is used on the board instead of 49.152MHz crystal.
spicds:
- Add support for Asahi Kasei flagship DAC - AK4396 (used in AudioTrak
Prodigy HD2).
Submitted by: Konstantin Dimitrov <kosio.dimitrov@gmail.com>
Tested by: Artem Antonov [1]
Reviewed by: ariff
-rw-r--r-- | sys/dev/sound/pci/envy24.c | 135 | ||||
-rw-r--r-- | sys/dev/sound/pci/envy24.h | 13 | ||||
-rw-r--r-- | sys/dev/sound/pci/envy24ht.c | 81 | ||||
-rw-r--r-- | sys/dev/sound/pci/envy24ht.h | 5 | ||||
-rw-r--r-- | sys/dev/sound/pci/spicds.c | 26 | ||||
-rw-r--r-- | sys/dev/sound/pci/spicds.h | 5 |
6 files changed, 246 insertions, 19 deletions
diff --git a/sys/dev/sound/pci/envy24.c b/sys/dev/sound/pci/envy24.c index 9344231..136477b 100644 --- a/sys/dev/sound/pci/envy24.c +++ b/sys/dev/sound/pci/envy24.c @@ -55,6 +55,9 @@ struct sc_info; #define ENVY24_NAMELEN 32 +#define SDA_GPIO 0x10 +#define SCL_GPIO 0x20 + struct envy24_sample { volatile u_int32_t buffer; }; @@ -740,7 +743,7 @@ envy24_gpiosetdir(struct sc_info *sc, u_int32_t dir) /* -------------------------------------------------------------------- */ -/* M-Audio Delta series AK4524 access interface routine */ +/* Envy24 I2C through GPIO bit-banging */ struct envy24_delta_ak4524_codec { struct spicds_info *info; @@ -751,6 +754,110 @@ struct envy24_delta_ak4524_codec { }; static void +envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda) +{ + u_int32_t data = 0; + struct envy24_delta_ak4524_codec *ptr = codec; +#if(0) + device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda); +#endif + data = envy24_gpiord(ptr->parent); + data &= ~(SDA_GPIO | SCL_GPIO); + if (scl) data += SCL_GPIO; + if (sda) data += SDA_GPIO; + envy24_gpiowr(ptr->parent, data); + return; +} + +static void +i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + unsigned int sda; + + if (bit) + sda = 1; + else + sda = 0; + + ctrl(ptr, 0, sda); + DELAY(I2C_DELAY); + ctrl(ptr, 1, sda); + DELAY(I2C_DELAY); + ctrl(ptr, 0, sda); + DELAY(I2C_DELAY); +} + +static void +i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + + ctrl(ptr, 1, 1); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 0); + DELAY(I2C_DELAY); + ctrl(ptr, 0, 0); + DELAY(I2C_DELAY); +} + +static void +i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + + ctrl(ptr, 0, 0); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 0); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 1); + DELAY(I2C_DELAY); +} + +static void +i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + + ctrl(ptr, 0, 1); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 1); + DELAY(I2C_DELAY); + /* dummy, need routine to change gpio direction */ + ctrl(ptr, 0, 1); + DELAY(I2C_DELAY); +} + +static void +i2c_wr(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + int mask; + + i2c_start(ptr, ctrl); + + for (mask = 0x80; mask != 0; mask >>= 1) + i2c_wrbit(ptr, ctrl, dev & mask); + i2c_ack(ptr, ctrl); + + if (reg != 0xff) { + for (mask = 0x80; mask != 0; mask >>= 1) + i2c_wrbit(ptr, ctrl, reg & mask); + i2c_ack(ptr, ctrl); + } + + for (mask = 0x80; mask != 0; mask >>= 1) + i2c_wrbit(ptr, ctrl, val & mask); + i2c_ack(ptr, ctrl); + + i2c_stop(ptr, ctrl); +} + +/* -------------------------------------------------------------------- */ + +/* M-Audio Delta series AK4524 access interface routine */ + +static void envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) { u_int32_t data = 0; @@ -863,6 +970,18 @@ envy24_delta_ak4524_init(void *codec) /* for the time being, init only first codec */ if (ptr->num == 0) spicds_init(ptr->info); + + /* 6fire rear input init test, set ptr->num to 1 for test */ + if (ptr->parent->cfg->subvendor == 0x153b && \ + ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) { + ptr->cs = 0x02; + spicds_init(ptr->info); + device_printf(ptr->parent->dev, "6fire rear input init\n"); + i2c_wr(ptr, envy24_gpio_i2c_ctl, \ + PCA9554_I2CDEV, PCA9554_DIR, 0x80); + i2c_wr(ptr, envy24_gpio_i2c_ctl, \ + PCA9554_I2CDEV, PCA9554_OUT, 0x02); + } } static void @@ -1219,6 +1338,9 @@ envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev) device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg); #endif envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4); + + /* 6fire rear input init test */ + envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4); } return 0; @@ -1664,6 +1786,7 @@ envy24chan_trigger(kobj_t obj, void *data, int go) ch->emldma(ch); break; case PCMTRIG_ABORT: + if (ch->run) { #if(0) device_printf(sc->dev, "envy24chan_trigger(): abort\n"); #endif @@ -1688,6 +1811,7 @@ envy24chan_trigger(kobj_t obj, void *data, int go) envy24_updintr(sc, ch->dir); } #endif + } break; } snd_mtxunlock(sc->lock); @@ -2411,16 +2535,15 @@ envy24_pci_attach(device_t dev) mixer_init(dev, &envy24mixer_class, sc); /* set channel information */ - err = pcm_register(dev, sc, sc->dacn, sc->adcn); + err = pcm_register(dev, sc, 5, 2 + sc->adcn); if (err) goto bad; - sc->chnum = ENVY24_CHAN_PLAY_DAC1; - for (i = 0; i < sc->dacn; i++) { + sc->chnum = 0; + for (i = 0; i < 5; i++) { pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); sc->chnum++; } - sc->chnum = ENVY24_CHAN_REC_ADC1; - for (i = 0; i < sc->adcn; i++) { + for (i = 0; i < 2 + sc->adcn; i++) { pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); sc->chnum++; } diff --git a/sys/dev/sound/pci/envy24.h b/sys/dev/sound/pci/envy24.h index 8830145..b6dad28 100644 --- a/sys/dev/sound/pci/envy24.h +++ b/sys/dev/sound/pci/envy24.h @@ -479,4 +479,17 @@ /* M-Audio Delta series parameter */ #define ENVY24_DELTA_AK4524_CIF 0 +#define I2C_DELAY 1000 + +/* PCA9554 registers */ +#define PCA9554_I2CDEV 0x40 /* I2C device address */ +#define PCA9554_IN 0x00 /* input port */ +#define PCA9554_OUT 0x01 /* output port */ +#define PCA9554_INVERT 0x02 /* polarity invert */ +#define PCA9554_DIR 0x03 /* port directions */ + +/* PCF8574 registers */ +#define PCF8574_I2CDEV_DAC 0x48 +#define PCF8574_SENSE_MASK 0x40 + /* end of file */ diff --git a/sys/dev/sound/pci/envy24ht.c b/sys/dev/sound/pci/envy24ht.c index bcd463e..0f85701 100644 --- a/sys/dev/sound/pci/envy24ht.c +++ b/sys/dev/sound/pci/envy24ht.c @@ -26,6 +26,17 @@ * */ +/* + * Konstantin Dimitrov's thanks list: + * + * A huge thanks goes to Spas Filipov for his friendship, support and his + * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to + * thank Keiichi Iwasaki and his parents, because they helped Spas to get + * the card from Japan! Having hardware sample of Prodigy HD2 made adding + * support for that great card very easy and real fun and pleasure. + * + */ + #include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/ac97.h> #include <dev/sound/pci/spicds.h> @@ -247,7 +258,7 @@ static int envy24ht_mixmap[] = { /* variable rate audio */ static u_int32_t envy24ht_speed[] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, + 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000, 0 }; @@ -319,13 +330,22 @@ static struct cfg_info cfg_table[] = { { "Envy24HT audio (AudioTrak Prodigy 7.1 LT)", 0x3132, 0x4154, - 0x0b, 0x80, 0xfc, 0xc3, + 0x4b, 0x80, 0xfc, 0xc3, 0x7ff8ff, 0x7fffff, 0x700, 0x400, 0x200, 0x100, 0x00, 0x02, 0, &spi_codec, }, { + "Envy24HT audio (AudioTrak Prodigy 7.1 XT)", + 0x3136, 0x4154, + 0x4b, 0x80, 0xfc, 0xc3, + 0x7ff8ff, 0x7fffff, 0x700, + 0x400, 0x200, 0x100, 0x00, 0x02, + 0, + &spi_codec, + }, + { "Envy24HT audio (M-Audio Revolution 7.1)", 0x1412, 0x3630, 0x43, 0x80, 0xf8, 0xc1, @@ -339,7 +359,7 @@ static struct cfg_info cfg_table[] = { 0x1412, 0x3631, 0x42, 0x80, 0xf8, 0xc1, 0x3fff85, 0x72, 0x4000fa, - 0x08, 0x02, 0x20, 0x00, 0x03, + 0x08, 0x02, 0x10, 0x00, 0x03, 0, &spi_codec, }, @@ -352,6 +372,24 @@ static struct cfg_info cfg_table[] = { 0, &spi_codec, }, + { + "Envy24HT audio (AudioTrak Prodigy HD2)", + 0x3137, 0x4154, + 0x68, 0x80, 0x78, 0xc3, + 0xfff8ff, 0x200700, 0xdfffff, + 0x400, 0x200, 0x100, 0x00, 0x05, + 0, + &spi_codec, + }, + { + "Envy24HT audio (ESI Juli@)", + 0x3031, 0x4553, + 0x20, 0x80, 0xf8, 0xc3, + 0x7fff9f, 0x8016, 0x7fff9f, + 0x08, 0x02, 0x10, 0x00, 0x03, + 0, + &spi_codec, + }, { "Envy24HT audio (Generic)", 0, 0, @@ -377,7 +415,7 @@ static u_int32_t envy24ht_playfmt[] = { 0 }; -static struct pcmchan_caps envy24ht_playcaps = {8000, 96000, envy24ht_playfmt, 0}; +static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0}; struct envy24ht_emldma { u_int32_t format; @@ -505,7 +543,6 @@ envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr) return (int)data; } -#if 0 static int envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data) { @@ -540,7 +577,6 @@ envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data return 0; } -#endif static int envy24ht_rdrom(struct sc_info *sc, u_int32_t addr) @@ -572,7 +608,7 @@ envy24ht_rom2cfg(struct sc_info *sc) device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n"); #endif size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE); - if (size < ENVY24HT_E2PROM_GPIOSTATE + 3) { + if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) { #if(0) device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size); #endif @@ -816,7 +852,7 @@ envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask) static u_int32_t envy24ht_gpiogetdir(struct sc_info *sc) { - return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4; + return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4); } #endif @@ -982,17 +1018,19 @@ static struct { {16000, ENVY24HT_MT_RATE_16000}, {8000, ENVY24HT_MT_RATE_8000}, {96000, ENVY24HT_MT_RATE_96000}, + {192000, ENVY24HT_MT_RATE_192000}, {64000, ENVY24HT_MT_RATE_64000}, {44100, ENVY24HT_MT_RATE_44100}, {22050, ENVY24HT_MT_RATE_22050}, {11025, ENVY24HT_MT_RATE_11025}, {88200, ENVY24HT_MT_RATE_88200}, + {176400, ENVY24HT_MT_RATE_176400}, {0, 0x10} }; static int envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) { - u_int32_t code; + u_int32_t code, i2sfmt; int i = 0; #if(0) @@ -1014,6 +1052,17 @@ envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) { #endif if (code < 0x10) { envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1); + if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \ + (code == ENVY24HT_MT_RATE_176400)) { + i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1); + i2sfmt |= ENVY24HT_MT_I2S_MLR128; + envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1); + } + else { + i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1); + i2sfmt &= ~ENVY24HT_MT_I2S_MLR128; + envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1); + } code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1); code &= ENVY24HT_MT_RATE_MASK; for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) { @@ -1684,6 +1733,7 @@ envy24htchan_trigger(kobj_t obj, void *data, int go) ch->emldma(ch); break; case PCMTRIG_ABORT: + if (ch->run) { #if(0) device_printf(sc->dev, "envy24htchan_trigger(): abort\n"); #endif @@ -1706,6 +1756,7 @@ envy24htchan_trigger(kobj_t obj, void *data, int go) if (ch->blk != sc->blk[slot]) envy24ht_updintr(sc, ch->dir); }*/ + } break; } snd_mtxunlock(sc->lock); @@ -1800,6 +1851,12 @@ envy24htmixer_init(struct snd_mixer *m) mix_setdevs(m, ENVY24HT_MIX_MASK); mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK); + + struct snddev_info *d = NULL; + d = device_get_softc(sc->dev); + if (d != NULL) + d->flags |= SD_F_SOFTPCMVOL; + snd_mtxunlock(sc->lock); return 0; @@ -2289,6 +2346,12 @@ envy24ht_init(struct sc_info *sc) envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); envy24ht_gpiowr(sc, sc->cfg->gpiostate); + + if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) { + envy24ht_wri2c(sc, 0x22, 0x00, 0x07); + envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80); + envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80); + } for (i = 0; i < sc->adcn; i++) { sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); diff --git a/sys/dev/sound/pci/envy24ht.h b/sys/dev/sound/pci/envy24ht.h index 2bb62e0..7eb0a65 100644 --- a/sys/dev/sound/pci/envy24ht.h +++ b/sys/dev/sound/pci/envy24ht.h @@ -108,13 +108,18 @@ #define ENVY24HT_MT_RATE_16000 0x05 #define ENVY24HT_MT_RATE_8000 0x06 #define ENVY24HT_MT_RATE_96000 0x07 +#define ENVY24HT_MT_RATE_192000 0x0e #define ENVY24HT_MT_RATE_64000 0x0f #define ENVY24HT_MT_RATE_44100 0x08 #define ENVY24HT_MT_RATE_22050 0x09 #define ENVY24HT_MT_RATE_11025 0x0a #define ENVY24HT_MT_RATE_88200 0x0b +#define ENVY24HT_MT_RATE_176400 0x0c #define ENVY24HT_MT_RATE_MASK 0x0f +#define ENVY24HT_MT_I2S 0x02 /* I2S Data Format Register */ +#define ENVY24HT_MT_I2S_MLR128 0x08 /* MCLK/LRCLK ratio 128x (or 256x) */ + #define ENVY24HT_MT_PADDR 0x10 /* Playback DMA Current/Base Address Register */ #define ENVY24HT_MT_PCNT 0x14 /* Playback DMA Current/Base Count Register */ #define ENVY24HT_MT_PTERM 0x1C /* Playback Current/Base Terminal Count Register */ diff --git a/sys/dev/sound/pci/spicds.c b/sys/dev/sound/pci/spicds.c index e43edb1..d559a6c 100644 --- a/sys/dev/sound/pci/spicds.c +++ b/sys/dev/sound/pci/spicds.c @@ -88,6 +88,12 @@ spicds_wrcd(struct spicds_info *codec, int reg, u_int16_t val) spicds_wrbit(codec, 0); spicds_wrbit(codec, 1); } + else if (codec->type == SPICDS_TYPE_AK4396) + { + /* AK4396 chip address */ + spicds_wrbit(codec, 0); + spicds_wrbit(codec, 0); + } else { /* chip address */ spicds_wrbit(codec, 1); @@ -229,6 +235,8 @@ spicds_init(struct spicds_info *codec) spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */ if (codec->type == SPICDS_TYPE_AK4381) spicds_wrcd(codec, 0x00, 0x0f); /* I2S, 24bit, power-up */ + if (codec->type == SPICDS_TYPE_AK4396) + spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */ snd_mtxunlock(codec->lock); } @@ -261,7 +269,8 @@ spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int r #endif snd_mtxlock(codec->lock); if (left >= 100) - if (codec->type == SPICDS_TYPE_AK4381) + if ((codec->type == SPICDS_TYPE_AK4381) || \ + (codec->type == SPICDS_TYPE_AK4396)) left = 255; else left = 127; @@ -270,14 +279,15 @@ spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int r case SPICDS_TYPE_WM8770: left = left + 27; break; - case SPICDS_TYPE_AK4381: + case SPICDS_TYPE_AK4381 || SPICDS_TYPE_AK4396: left = left * 255 / 100; break; default: left = left * 127 / 100; } if (right >= 100) - if (codec->type == SPICDS_TYPE_AK4381) + if ((codec->type == SPICDS_TYPE_AK4381) || \ + (codec->type == SPICDS_TYPE_AK4396)) right = 255; else right = 127; @@ -286,7 +296,7 @@ spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int r case SPICDS_TYPE_WM8770: right = right + 27; break; - case SPICDS_TYPE_AK4381: + case SPICDS_TYPE_AK4381 || SPICDS_TYPE_AK4396: right = right * 255 / 100; break; default: @@ -335,6 +345,14 @@ spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int r spicds_wrcd(codec, AK4381_ROATT, right); } + if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4396) { +#if(0) + device_printf(codec->dev, "spicds_set(): AK4396(PLAY) %d/%d\n", left, right); +#endif + spicds_wrcd(codec, AK4396_LOATT, left); + spicds_wrcd(codec, AK4396_ROATT, right); + } + snd_mtxunlock(codec->lock); } diff --git a/sys/dev/sound/pci/spicds.h b/sys/dev/sound/pci/spicds.h index c999b4c..c206be3 100644 --- a/sys/dev/sound/pci/spicds.h +++ b/sys/dev/sound/pci/spicds.h @@ -33,6 +33,7 @@ #define SPICDS_TYPE_WM8770 2 #define SPICDS_TYPE_AK4358 3 #define SPICDS_TYPE_AK4381 4 +#define SPICDS_TYPE_AK4396 5 /* AK4524/AK4528 control registers */ #define AK4524_POWER 0x00 @@ -101,6 +102,10 @@ #define AK4381_LOATT 0x03 #define AK4381_ROATT 0x04 +/* AK4396 control registers */ +#define AK4396_LOATT 0x03 +#define AK4396_ROATT 0x04 + struct spicds_info; typedef void (*spicds_ctrl)(void *, unsigned int, unsigned int, unsigned int); |