summaryrefslogtreecommitdiff
path: root/sound/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/i2c')
-rw-r--r--sound/i2c/cs8427.c116
-rw-r--r--sound/i2c/other/ak4xxx-adda.c585
2 files changed, 486 insertions, 215 deletions
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index cb89f7eb9236..64388cb8d6e5 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -76,23 +76,28 @@ int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
buf[0] = reg & 0x7f;
buf[1] = val;
if ((err = snd_i2c_sendbytes(device, buf, 2)) != 2) {
- snd_printk(KERN_ERR "unable to send bytes 0x%02x:0x%02x to CS8427 (%i)\n", buf[0], buf[1], err);
+ snd_printk(KERN_ERR "unable to send bytes 0x%02x:0x%02x "
+ "to CS8427 (%i)\n", buf[0], buf[1], err);
return err < 0 ? err : -EIO;
}
return 0;
}
+EXPORT_SYMBOL(snd_cs8427_reg_write);
+
static int snd_cs8427_reg_read(struct snd_i2c_device *device, unsigned char reg)
{
int err;
unsigned char buf;
if ((err = snd_i2c_sendbytes(device, &reg, 1)) != 1) {
- snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg);
+ snd_printk(KERN_ERR "unable to send register 0x%x byte "
+ "to CS8427\n", reg);
return err < 0 ? err : -EIO;
}
if ((err = snd_i2c_readbytes(device, &buf, 1)) != 1) {
- snd_printk(KERN_ERR "unable to read register 0x%x byte from CS8427\n", reg);
+ snd_printk(KERN_ERR "unable to read register 0x%x byte "
+ "from CS8427\n", reg);
return err < 0 ? err : -EIO;
}
return buf;
@@ -121,7 +126,8 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
int count)
{
struct cs8427 *chip = device->private_data;
- char *hw_data = udata ? chip->playback.hw_udata : chip->playback.hw_status;
+ char *hw_data = udata ?
+ chip->playback.hw_udata : chip->playback.hw_status;
char data[32];
int err, idx;
@@ -134,11 +140,11 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
memset(data, 0, sizeof(data));
if (memcmp(hw_data, data, count) == 0) {
chip->regmap[CS8427_REG_UDATABUF] &= ~CS8427_UBMMASK;
- chip->regmap[CS8427_REG_UDATABUF] |= CS8427_UBMZEROS | CS8427_EFTUI;
- if ((err = snd_cs8427_reg_write(device, CS8427_REG_UDATABUF,
- chip->regmap[CS8427_REG_UDATABUF])) < 0)
- return err;
- return 0;
+ chip->regmap[CS8427_REG_UDATABUF] |= CS8427_UBMZEROS |
+ CS8427_EFTUI;
+ err = snd_cs8427_reg_write(device, CS8427_REG_UDATABUF,
+ chip->regmap[CS8427_REG_UDATABUF]);
+ return err < 0 ? err : 0;
}
}
data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF;
@@ -161,24 +167,32 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
{
static unsigned char initvals1[] = {
CS8427_REG_CONTROL1 | CS8427_REG_AUTOINC,
- /* CS8427_REG_CONTROL1: RMCK to OMCK, valid PCM audio, disable mutes, TCBL=output */
+ /* CS8427_REG_CONTROL1: RMCK to OMCK, valid PCM audio, disable mutes,
+ TCBL=output */
CS8427_SWCLK | CS8427_TCBLDIR,
- /* CS8427_REG_CONTROL2: hold last valid audio sample, RMCK=256*Fs, normal stereo operation */
+ /* CS8427_REG_CONTROL2: hold last valid audio sample, RMCK=256*Fs,
+ normal stereo operation */
0x00,
- /* CS8427_REG_DATAFLOW: output drivers normal operation, Tx<=serial, Rx=>serial */
+ /* CS8427_REG_DATAFLOW: output drivers normal operation, Tx<=serial,
+ Rx=>serial */
CS8427_TXDSERIAL | CS8427_SPDAES3RECEIVER,
- /* CS8427_REG_CLOCKSOURCE: Run off, CMCK=256*Fs, output time base = OMCK, input time base =
- recovered input clock, recovered input clock source is ILRCK changed to AES3INPUT (workaround, see snd_cs8427_reset) */
+ /* CS8427_REG_CLOCKSOURCE: Run off, CMCK=256*Fs,
+ output time base = OMCK, input time base = recovered input clock,
+ recovered input clock source is ILRCK changed to AES3INPUT
+ (workaround, see snd_cs8427_reset) */
CS8427_RXDILRCK,
- /* CS8427_REG_SERIALINPUT: Serial audio input port data format = I2S, 24-bit, 64*Fsi */
+ /* CS8427_REG_SERIALINPUT: Serial audio input port data format = I2S,
+ 24-bit, 64*Fsi */
CS8427_SIDEL | CS8427_SILRPOL,
- /* CS8427_REG_SERIALOUTPUT: Serial audio output port data format = I2S, 24-bit, 64*Fsi */
+ /* CS8427_REG_SERIALOUTPUT: Serial audio output port data format
+ = I2S, 24-bit, 64*Fsi */
CS8427_SODEL | CS8427_SOLRPOL,
};
static unsigned char initvals2[] = {
CS8427_REG_RECVERRMASK | CS8427_REG_AUTOINC,
- /* CS8427_REG_RECVERRMASK: unmask the input PLL clock, V, confidence, biphase, parity status bits */
- /* CS8427_UNLOCK | CS8427_V | CS8427_CONF | CS8427_BIP | CS8427_PAR, */
+ /* CS8427_REG_RECVERRMASK: unmask the input PLL clock, V, confidence,
+ biphase, parity status bits */
+ /* CS8427_UNLOCK | CS8427_V | CS8427_CONF | CS8427_BIP | CS8427_PAR,*/
0xff, /* set everything */
/* CS8427_REG_CSDATABUF:
Registers 32-55 window to CS buffer
@@ -201,7 +215,8 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
struct snd_i2c_device *device;
unsigned char buf[24];
- if ((err = snd_i2c_device_create(bus, "CS8427", CS8427_ADDR | (addr & 7),
+ if ((err = snd_i2c_device_create(bus, "CS8427",
+ CS8427_ADDR | (addr & 7),
&device)) < 0)
return err;
chip = device->private_data = kzalloc(sizeof(*chip), GFP_KERNEL);
@@ -212,8 +227,8 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
device->private_free = snd_cs8427_free;
snd_i2c_lock(bus);
- if ((err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER)) !=
- CS8427_VER8427A) {
+ err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER);
+ if (err != CS8427_VER8427A) {
snd_i2c_unlock(bus);
snd_printk(KERN_ERR "unable to find CS8427 signature "
"(expected 0x%x, read 0x%x),\n",
@@ -222,7 +237,8 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
return -EFAULT;
}
/* turn off run bit while making changes to configuration */
- if ((err = snd_cs8427_reg_write(device, CS8427_REG_CLOCKSOURCE, 0x00)) < 0)
+ err = snd_cs8427_reg_write(device, CS8427_REG_CLOCKSOURCE, 0x00);
+ if (err < 0)
goto __fail;
/* send initial values */
memcpy(chip->regmap + (initvals1[0] & 0x7f), initvals1 + 1, 6);
@@ -282,6 +298,8 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
return err < 0 ? err : -EIO;
}
+EXPORT_SYMBOL(snd_cs8427_create);
+
/*
* Reset the chip using run bit, also lock PLL using ILRCK and
* put back AES3INPUT. This workaround is described in latest
@@ -296,7 +314,8 @@ static void snd_cs8427_reset(struct snd_i2c_device *cs8427)
snd_assert(cs8427, return);
chip = cs8427->private_data;
snd_i2c_lock(cs8427->bus);
- if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) == CS8427_RXDAES3INPUT) /* AES3 bit is set */
+ if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) ==
+ CS8427_RXDAES3INPUT) /* AES3 bit is set */
aes3input = 1;
chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~(CS8427_RUN | CS8427_RXDMASK);
snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
@@ -367,12 +386,15 @@ static int snd_cs8427_qsubcode_get(struct snd_kcontrol *kcontrol,
snd_i2c_lock(device->bus);
if ((err = snd_i2c_sendbytes(device, &reg, 1)) != 1) {
- snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg);
+ snd_printk(KERN_ERR "unable to send register 0x%x byte "
+ "to CS8427\n", reg);
snd_i2c_unlock(device->bus);
return err < 0 ? err : -EIO;
}
- if ((err = snd_i2c_readbytes(device, ucontrol->value.bytes.data, 10)) != 10) {
- snd_printk(KERN_ERR "unable to read Q-subcode bytes from CS8427\n");
+ err = snd_i2c_readbytes(device, ucontrol->value.bytes.data, 10);
+ if (err != 10) {
+ snd_printk(KERN_ERR "unable to read Q-subcode bytes "
+ "from CS8427\n");
snd_i2c_unlock(device->bus);
return err < 0 ? err : -EIO;
}
@@ -380,7 +402,8 @@ static int snd_cs8427_qsubcode_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_cs8427_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int snd_cs8427_spdif_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
@@ -413,7 +436,8 @@ static int snd_cs8427_spdif_put(struct snd_kcontrol *kcontrol,
snd_i2c_lock(device->bus);
change = memcmp(ucontrol->value.iec958.status, status, 24) != 0;
memcpy(status, ucontrol->value.iec958.status, 24);
- if (change && (kcontrol->private_value ? runtime != NULL : runtime == NULL)) {
+ if (change && (kcontrol->private_value ?
+ runtime != NULL : runtime == NULL)) {
err = snd_cs8427_send_corudata(device, 0, status, 24);
if (err < 0)
change = err;
@@ -442,7 +466,8 @@ static struct snd_kcontrol_new snd_cs8427_iec958_controls[] = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.info = snd_cs8427_in_status_info,
.name = "IEC958 CS8427 Input Status",
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
.get = snd_cs8427_in_status_get,
.private_value = 15,
},
@@ -450,7 +475,8 @@ static struct snd_kcontrol_new snd_cs8427_iec958_controls[] = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.info = snd_cs8427_in_status_info,
.name = "IEC958 CS8427 Error Status",
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
.get = snd_cs8427_in_status_get,
.private_value = 16,
},
@@ -470,7 +496,8 @@ static struct snd_kcontrol_new snd_cs8427_iec958_controls[] = {
.private_value = 0
},
{
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE),
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
.info = snd_cs8427_spdif_info,
@@ -482,7 +509,8 @@ static struct snd_kcontrol_new snd_cs8427_iec958_controls[] = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.info = snd_cs8427_qsubcode_info,
.name = "IEC958 Q-subcode Capture Default",
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
.get = snd_cs8427_qsubcode_get
}};
@@ -505,7 +533,8 @@ int snd_cs8427_iec958_build(struct snd_i2c_device *cs8427,
err = snd_ctl_add(cs8427->bus->card, kctl);
if (err < 0)
return err;
- if (!strcmp(kctl->id.name, SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM)))
+ if (! strcmp(kctl->id.name,
+ SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM)))
chip->playback.pcm_ctl = kctl;
}
@@ -515,6 +544,8 @@ int snd_cs8427_iec958_build(struct snd_i2c_device *cs8427,
return 0;
}
+EXPORT_SYMBOL(snd_cs8427_iec958_build);
+
int snd_cs8427_iec958_active(struct snd_i2c_device *cs8427, int active)
{
struct cs8427 *chip;
@@ -522,13 +553,17 @@ int snd_cs8427_iec958_active(struct snd_i2c_device *cs8427, int active)
snd_assert(cs8427, return -ENXIO);
chip = cs8427->private_data;
if (active)
- memcpy(chip->playback.pcm_status, chip->playback.def_status, 24);
+ memcpy(chip->playback.pcm_status,
+ chip->playback.def_status, 24);
chip->playback.pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- snd_ctl_notify(cs8427->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
- SNDRV_CTL_EVENT_MASK_INFO, &chip->playback.pcm_ctl->id);
+ snd_ctl_notify(cs8427->bus->card,
+ SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
+ &chip->playback.pcm_ctl->id);
return 0;
}
+EXPORT_SYMBOL(snd_cs8427_iec958_active);
+
int snd_cs8427_iec958_pcm(struct snd_i2c_device *cs8427, unsigned int rate)
{
struct cs8427 *chip;
@@ -568,6 +603,8 @@ int snd_cs8427_iec958_pcm(struct snd_i2c_device *cs8427, unsigned int rate)
return err < 0 ? err : 0;
}
+EXPORT_SYMBOL(snd_cs8427_iec958_pcm);
+
static int __init alsa_cs8427_module_init(void)
{
return 0;
@@ -579,10 +616,3 @@ static void __exit alsa_cs8427_module_exit(void)
module_init(alsa_cs8427_module_init)
module_exit(alsa_cs8427_module_exit)
-
-EXPORT_SYMBOL(snd_cs8427_create);
-EXPORT_SYMBOL(snd_cs8427_reset);
-EXPORT_SYMBOL(snd_cs8427_reg_write);
-EXPORT_SYMBOL(snd_cs8427_iec958_build);
-EXPORT_SYMBOL(snd_cs8427_iec958_active);
-EXPORT_SYMBOL(snd_cs8427_iec958_pcm);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 045e32a311e0..5da49e2eb350 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -28,30 +28,80 @@
#include <linux/init.h>
#include <sound/core.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/ak4xxx-adda.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
MODULE_LICENSE("GPL");
-void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsigned char val)
+/* write the given register and save the data to the cache */
+void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+ unsigned char val)
{
ak->ops.lock(ak, chip);
ak->ops.write(ak, chip, reg, val);
/* save the data */
- if (ak->type == SND_AK4524 || ak->type == SND_AK4528) {
- if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0)
- snd_akm4xxx_set(ak, chip, reg, val);
- else
- snd_akm4xxx_set_ipga(ak, chip, reg, val);
- } else {
- /* AK4529, or else */
- snd_akm4xxx_set(ak, chip, reg, val);
- }
+ snd_akm4xxx_set(ak, chip, reg, val);
ak->ops.unlock(ak, chip);
}
+EXPORT_SYMBOL(snd_akm4xxx_write);
+
+/* reset procedure for AK4524 and AK4528 */
+static void ak4524_reset(struct snd_akm4xxx *ak, int state)
+{
+ unsigned int chip;
+ unsigned char reg, maxreg;
+
+ if (ak->type == SND_AK4528)
+ maxreg = 0x06;
+ else
+ maxreg = 0x08;
+ for (chip = 0; chip < ak->num_dacs/2; chip++) {
+ snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
+ if (state)
+ continue;
+ /* DAC volumes */
+ for (reg = 0x04; reg < maxreg; reg++)
+ snd_akm4xxx_write(ak, chip, reg,
+ snd_akm4xxx_get(ak, chip, reg));
+ }
+}
+
+/* reset procedure for AK4355 and AK4358 */
+static void ak4355_reset(struct snd_akm4xxx *ak, int state)
+{
+ unsigned char reg;
+
+ if (state) {
+ snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
+ return;
+ }
+ for (reg = 0x00; reg < 0x0b; reg++)
+ if (reg != 0x01)
+ snd_akm4xxx_write(ak, 0, reg,
+ snd_akm4xxx_get(ak, 0, reg));
+ snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
+}
+
+/* reset procedure for AK4381 */
+static void ak4381_reset(struct snd_akm4xxx *ak, int state)
+{
+ unsigned int chip;
+ unsigned char reg;
+
+ for (chip = 0; chip < ak->num_dacs/2; chip++) {
+ snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
+ if (state)
+ continue;
+ for (reg = 0x01; reg < 0x05; reg++)
+ snd_akm4xxx_write(ak, chip, reg,
+ snd_akm4xxx_get(ak, chip, reg));
+ }
+}
+
/*
* reset the AKM codecs
* @state: 1 = reset codec, 0 = restore the registers
@@ -60,52 +110,63 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, unsi
*/
void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
{
- unsigned int chip;
- unsigned char reg;
-
switch (ak->type) {
case SND_AK4524:
case SND_AK4528:
- for (chip = 0; chip < ak->num_dacs/2; chip++) {
- snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
- if (state)
- continue;
- /* DAC volumes */
- for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++)
- snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
- if (ak->type == SND_AK4528)
- continue;
- /* IPGA */
- for (reg = 0x04; reg < 0x06; reg++)
- snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get_ipga(ak, chip, reg));
- }
+ ak4524_reset(ak, state);
break;
case SND_AK4529:
/* FIXME: needed for ak4529? */
break;
case SND_AK4355:
case SND_AK4358:
- if (state) {
- snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
- return;
- }
- for (reg = 0x00; reg < 0x0b; reg++)
- if (reg != 0x01)
- snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg));
- snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
+ ak4355_reset(ak, state);
break;
case SND_AK4381:
- for (chip = 0; chip < ak->num_dacs/2; chip++) {
- snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
- if (state)
- continue;
- for (reg = 0x01; reg < 0x05; reg++)
- snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg));
- }
+ ak4381_reset(ak, state);
+ break;
+ default:
break;
}
}
+EXPORT_SYMBOL(snd_akm4xxx_reset);
+
+
+/*
+ * Volume conversion table for non-linear volumes
+ * from -63.5dB (mute) to 0dB step 0.5dB
+ *
+ * Used for AK4524 input/ouput attenuation, AK4528, and
+ * AK5365 input attenuation
+ */
+static unsigned char vol_cvt_datt[128] = {
+ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
+ 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
+ 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
+ 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
+ 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
+ 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
+ 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
+ 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
+ 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
+ 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
+ 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
+ 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
+};
+
+/*
+ * dB tables
+ */
+static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
+static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
+static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
+static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
+
/*
* initialize all the ak4xxx chips
*/
@@ -119,8 +180,6 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x01, 0x03, /* 1: ADC/DAC enable */
0x04, 0x00, /* 4: ADC left muted */
0x05, 0x00, /* 5: ADC right muted */
- 0x04, 0x80, /* 4: ADC IPGA gain 0dB */
- 0x05, 0x80, /* 5: ADC IPGA gain 0dB */
0x06, 0x00, /* 6: DAC left muted */
0x07, 0x00, /* 7: DAC right muted */
0xff, 0xff
@@ -153,7 +212,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
};
static unsigned char inits_ak4355[] = {
0x01, 0x02, /* 1: reset and soft-mute */
- 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
+ 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
+ * disable DZF, sharp roll-off, RSTN#=0 */
0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
// 0x02, 0x2e, /* quad speed */
0x03, 0x01, /* 3: de-emphasis off */
@@ -169,7 +229,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
};
static unsigned char inits_ak4358[] = {
0x01, 0x02, /* 1: reset and soft-mute */
- 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
+ 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
+ * disable DZF, sharp roll-off, RSTN#=0 */
0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
// 0x02, 0x2e, /* quad speed */
0x03, 0x01, /* 3: de-emphasis off */
@@ -187,7 +248,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
};
static unsigned char inits_ak4381[] = {
0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
- 0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */
+ 0x01, 0x02, /* 1: de-emphasis off, normal speed,
+ * sharp roll-off, DZF off */
// 0x01, 0x12, /* quad speed */
0x02, 0x00, /* 2: DZF disabled */
0x03, 0x00, /* 3: LATT 0 */
@@ -199,6 +261,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
int chip, num_chips;
unsigned char *ptr, reg, data, *inits;
+ memset(ak->images, 0, sizeof(ak->images));
+ memset(ak->volumes, 0, sizeof(ak->volumes));
+
switch (ak->type) {
case SND_AK4524:
inits = inits_ak4524;
@@ -224,6 +289,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
inits = inits_ak4381;
num_chips = ak->num_dacs / 2;
break;
+ case SND_AK5365:
+ /* FIXME: any init sequence? */
+ return;
default:
snd_BUG();
return;
@@ -239,13 +307,25 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
}
}
+EXPORT_SYMBOL(snd_akm4xxx_init);
+
+/*
+ * Mixer callbacks
+ */
+#define AK_IPGA (1<<20) /* including IPGA */
+#define AK_VOL_CVT (1<<21) /* need dB conversion */
+#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
+#define AK_INVERT (1<<23) /* data is inverted */
#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
#define AK_GET_ADDR(val) ((val) & 0xff)
-#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f)
+#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
+#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
+#define AK_GET_IPGA(val) (((val) >> 20) & 1)
+#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
#define AK_GET_INVERT(val) (((val) >> 23) & 1)
#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
-#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
-#define AK_INVERT (1<<23)
+#define AK_COMPOSE(chip,addr,shift,mask) \
+ (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -265,63 +345,74 @@ static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
- int invert = AK_GET_INVERT(kcontrol->private_value);
- unsigned int mask = AK_GET_MASK(kcontrol->private_value);
- unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
- ucontrol->value.integer.value[0] = invert ? mask - val : val;
+
+ ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
return 0;
}
-static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
+ unsigned char nval)
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
- int chip = AK_GET_CHIP(kcontrol->private_value);
- int addr = AK_GET_ADDR(kcontrol->private_value);
- int invert = AK_GET_INVERT(kcontrol->private_value);
unsigned int mask = AK_GET_MASK(kcontrol->private_value);
- unsigned char nval = ucontrol->value.integer.value[0] % (mask+1);
- int change;
+ int chip = AK_GET_CHIP(kcontrol->private_value);
- if (invert)
+ if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
+ return 0;
+
+ snd_akm4xxx_set_vol(ak, chip, addr, nval);
+ if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
+ nval = vol_cvt_datt[nval];
+ if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
+ nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
+ if (AK_GET_INVERT(kcontrol->private_value))
nval = mask - nval;
- change = snd_akm4xxx_get(ak, chip, addr) != nval;
- if (change)
- snd_akm4xxx_write(ak, chip, addr, nval);
- return change;
+ if (AK_GET_NEEDSMSB(kcontrol->private_value))
+ nval |= 0x80;
+ snd_akm4xxx_write(ak, chip, addr, nval);
+ return 1;
+}
+
+static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
+ ucontrol->value.integer.value[0]);
}
-static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
+ unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
+ uinfo->count = 2;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 36;
+ uinfo->value.integer.max = mask;
return 0;
}
-static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
- ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f;
+
+ ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
+ ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
return 0;
}
-static int snd_akm4xxx_ipga_gain_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
- int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
- unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
- int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval;
- if (change)
- snd_akm4xxx_write(ak, chip, addr, nval);
+ int change;
+
+ change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
+ change |= put_ak_reg(kcontrol, addr + 1,
+ ucontrol->value.integer.value[1]);
return change;
}
@@ -336,7 +427,8 @@ static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = 4;
if (uinfo->value.enumerated.item >= 4)
uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
return 0;
}
@@ -347,7 +439,8 @@ static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int shift = AK_GET_SHIFT(kcontrol->private_value);
- ucontrol->value.enumerated.item[0] = (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
+ ucontrol->value.enumerated.item[0] =
+ (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
return 0;
}
@@ -361,136 +454,289 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
int change;
- nval = (nval << shift) | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
+ nval = (nval << shift) |
+ (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
change = snd_akm4xxx_get(ak, chip, addr) != nval;
if (change)
snd_akm4xxx_write(ak, chip, addr, nval);
return change;
}
+static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+ int shift = AK_GET_SHIFT(kcontrol->private_value);
+ int invert = AK_GET_INVERT(kcontrol->private_value);
+ unsigned char val = snd_akm4xxx_get(ak, chip, addr);
+
+ if (invert)
+ val = ! val;
+ ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
+ return 0;
+}
+
+static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int chip = AK_GET_CHIP(kcontrol->private_value);
+ int addr = AK_GET_ADDR(kcontrol->private_value);
+ int shift = AK_GET_SHIFT(kcontrol->private_value);
+ int invert = AK_GET_INVERT(kcontrol->private_value);
+ long flag = ucontrol->value.integer.value[0];
+ unsigned char val, oval;
+ int change;
+
+ if (invert)
+ flag = ! flag;
+ oval = snd_akm4xxx_get(ak, chip, addr);
+ if (flag)
+ val = oval | (1<<shift);
+ else
+ val = oval & ~(1<<shift);
+ change = (oval != val);
+ if (change)
+ snd_akm4xxx_write(ak, chip, addr, val);
+ return change;
+}
+
/*
* build AK4xxx controls
*/
-int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
+static int build_dac_controls(struct snd_akm4xxx *ak)
{
- unsigned int idx, num_emphs;
- struct snd_kcontrol *ctl;
- int err;
-
- ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
- if (! ctl)
- return -ENOMEM;
-
- for (idx = 0; idx < ak->num_dacs; ++idx) {
- memset(ctl, 0, sizeof(*ctl));
- strcpy(ctl->id.name, "DAC Volume");
- ctl->id.index = idx + ak->idx_offset * 2;
- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- ctl->count = 1;
- ctl->info = snd_akm4xxx_volume_info;
- ctl->get = snd_akm4xxx_volume_get;
- ctl->put = snd_akm4xxx_volume_put;
+ int idx, err, mixer_ch, num_stereo;
+ struct snd_kcontrol_new knew;
+
+ mixer_ch = 0;
+ for (idx = 0; idx < ak->num_dacs; ) {
+ memset(&knew, 0, sizeof(knew));
+ if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
+ knew.name = "DAC Volume";
+ knew.index = mixer_ch + ak->idx_offset * 2;
+ num_stereo = 1;
+ } else {
+ knew.name = ak->dac_info[mixer_ch].name;
+ num_stereo = ak->dac_info[mixer_ch].num_channels;
+ }
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.count = 1;
+ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ if (num_stereo == 2) {
+ knew.info = snd_akm4xxx_stereo_volume_info;
+ knew.get = snd_akm4xxx_stereo_volume_get;
+ knew.put = snd_akm4xxx_stereo_volume_put;
+ } else {
+ knew.info = snd_akm4xxx_volume_info;
+ knew.get = snd_akm4xxx_volume_get;
+ knew.put = snd_akm4xxx_volume_put;
+ }
switch (ak->type) {
case SND_AK4524:
- ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */
+ /* register 6 & 7 */
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
+ AK_VOL_CVT;
+ knew.tlv.p = db_scale_vol_datt;
break;
case SND_AK4528:
- ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
+ /* register 4 & 5 */
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
+ AK_VOL_CVT;
+ knew.tlv.p = db_scale_vol_datt;
break;
case SND_AK4529: {
- int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
- ctl->private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
+ /* registers 2-7 and b,c */
+ int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
+ knew.private_value =
+ AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
+ knew.tlv.p = db_scale_8bit;
break;
}
case SND_AK4355:
- ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+ /* register 4-9, chip #0 only */
+ knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
+ knew.tlv.p = db_scale_8bit;
break;
- case SND_AK4358:
- if (idx >= 6)
- ctl->private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */
- else
- ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
+ case SND_AK4358: {
+ /* register 4-9 and 11-12, chip #0 only */
+ int addr = idx < 6 ? idx + 4 : idx + 5;
+ knew.private_value =
+ AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
+ knew.tlv.p = db_scale_7bit;
break;
+ }
case SND_AK4381:
- ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
+ /* register 3 & 4 */
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
+ knew.tlv.p = db_scale_linear;
break;
default:
- err = -EINVAL;
- goto __error;
+ return -EINVAL;
}
- ctl->private_data = ak;
- if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
- goto __error;
+
+ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+ return err;
+
+ idx += num_stereo;
+ mixer_ch++;
}
- for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
- memset(ctl, 0, sizeof(*ctl));
- strcpy(ctl->id.name, "ADC Volume");
- ctl->id.index = idx + ak->idx_offset * 2;
- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- ctl->count = 1;
- ctl->info = snd_akm4xxx_volume_info;
- ctl->get = snd_akm4xxx_volume_get;
- ctl->put = snd_akm4xxx_volume_put;
- ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */
- ctl->private_data = ak;
- if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
- goto __error;
-
- memset(ctl, 0, sizeof(*ctl));
- strcpy(ctl->id.name, "IPGA Analog Capture Volume");
- ctl->id.index = idx + ak->idx_offset * 2;
- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- ctl->count = 1;
- ctl->info = snd_akm4xxx_ipga_gain_info;
- ctl->get = snd_akm4xxx_ipga_gain_get;
- ctl->put = snd_akm4xxx_ipga_gain_put;
- ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */
- ctl->private_data = ak;
- if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
- goto __error;
+ return 0;
+}
+
+static int build_adc_controls(struct snd_akm4xxx *ak)
+{
+ int idx, err, mixer_ch, num_stereo;
+ struct snd_kcontrol_new knew;
+
+ mixer_ch = 0;
+ for (idx = 0; idx < ak->num_adcs;) {
+ memset(&knew, 0, sizeof(knew));
+ if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
+ knew.name = "ADC Volume";
+ knew.index = mixer_ch + ak->idx_offset * 2;
+ num_stereo = 1;
+ } else {
+ knew.name = ak->adc_info[mixer_ch].name;
+ num_stereo = ak->adc_info[mixer_ch].num_channels;
+ }
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.count = 1;
+ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ if (num_stereo == 2) {
+ knew.info = snd_akm4xxx_stereo_volume_info;
+ knew.get = snd_akm4xxx_stereo_volume_get;
+ knew.put = snd_akm4xxx_stereo_volume_put;
+ } else {
+ knew.info = snd_akm4xxx_volume_info;
+ knew.get = snd_akm4xxx_volume_get;
+ knew.put = snd_akm4xxx_volume_put;
+ }
+ /* register 4 & 5 */
+ if (ak->type == SND_AK5365)
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
+ AK_VOL_CVT | AK_IPGA;
+ else
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
+ AK_VOL_CVT | AK_IPGA;
+ knew.tlv.p = db_scale_vol_datt;
+ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+ return err;
+
+ if (ak->type == SND_AK5365 && (idx % 2) == 0) {
+ if (! ak->adc_info ||
+ ! ak->adc_info[mixer_ch].switch_name)
+ knew.name = "Capture Switch";
+ else
+ knew.name = ak->adc_info[mixer_ch].switch_name;
+ knew.info = ak4xxx_switch_info;
+ knew.get = ak4xxx_switch_get;
+ knew.put = ak4xxx_switch_put;
+ knew.access = 0;
+ /* register 2, bit 0 (SMUTE): 0 = normal operation,
+ 1 = mute */
+ knew.private_value =
+ AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
+ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+ return err;
+ }
+
+ idx += num_stereo;
+ mixer_ch++;
}
- if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
- num_emphs = 1;
- else
- num_emphs = ak->num_dacs / 2;
+ return 0;
+}
+
+static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
+{
+ int idx, err;
+ struct snd_kcontrol_new knew;
+
for (idx = 0; idx < num_emphs; idx++) {
- memset(ctl, 0, sizeof(*ctl));
- strcpy(ctl->id.name, "Deemphasis");
- ctl->id.index = idx + ak->idx_offset;
- ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- ctl->count = 1;
- ctl->info = snd_akm4xxx_deemphasis_info;
- ctl->get = snd_akm4xxx_deemphasis_get;
- ctl->put = snd_akm4xxx_deemphasis_put;
+ memset(&knew, 0, sizeof(knew));
+ knew.name = "Deemphasis";
+ knew.index = idx + ak->idx_offset;
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.count = 1;
+ knew.info = snd_akm4xxx_deemphasis_info;
+ knew.get = snd_akm4xxx_deemphasis_get;
+ knew.put = snd_akm4xxx_deemphasis_put;
switch (ak->type) {
case SND_AK4524:
case SND_AK4528:
- ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */
+ /* register 3 */
+ knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
break;
case SND_AK4529: {
int shift = idx == 3 ? 6 : (2 - idx) * 2;
- ctl->private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */
+ /* register 8 with shift */
+ knew.private_value = AK_COMPOSE(0, 8, shift, 0);
break;
}
case SND_AK4355:
case SND_AK4358:
- ctl->private_value = AK_COMPOSE(idx, 3, 0, 0);
+ knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
break;
case SND_AK4381:
- ctl->private_value = AK_COMPOSE(idx, 1, 1, 0);
+ knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
break;
+ default:
+ return -EINVAL;
}
- ctl->private_data = ak;
- if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
- goto __error;
+ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+ return err;
}
- err = 0;
+ return 0;
+}
+
+int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
+{
+ int err, num_emphs;
+
+ err = build_dac_controls(ak);
+ if (err < 0)
+ return err;
+
+ err = build_adc_controls(ak);
+ if (err < 0)
+ return err;
+
+ if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
+ num_emphs = 1;
+ else
+ num_emphs = ak->num_dacs / 2;
+ err = build_deemphasis(ak, num_emphs);
+ if (err < 0)
+ return err;
- __error:
- kfree(ctl);
- return err;
+ return 0;
}
+
+EXPORT_SYMBOL(snd_akm4xxx_build_controls);
static int __init alsa_akm4xxx_module_init(void)
{
@@ -503,8 +749,3 @@ static void __exit alsa_akm4xxx_module_exit(void)
module_init(alsa_akm4xxx_module_init)
module_exit(alsa_akm4xxx_module_exit)
-
-EXPORT_SYMBOL(snd_akm4xxx_write);
-EXPORT_SYMBOL(snd_akm4xxx_reset);
-EXPORT_SYMBOL(snd_akm4xxx_init);
-EXPORT_SYMBOL(snd_akm4xxx_build_controls);