|
@@ -994,267 +994,6 @@ const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
|
|
|
|
|
|
EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
|
|
EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
|
|
|
|
|
|
-/*
|
|
|
|
- * MIXER part
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
|
|
|
-{
|
|
|
|
- static char *texts[4] = {
|
|
|
|
- "Line", "Aux", "Mic", "Mix"
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
|
|
|
- uinfo->count = 2;
|
|
|
|
- uinfo->value.enumerated.items = 4;
|
|
|
|
- if (uinfo->value.enumerated.item > 3)
|
|
|
|
- uinfo->value.enumerated.item = 3;
|
|
|
|
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
-{
|
|
|
|
- struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
|
|
|
- unsigned long flags;
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&chip->reg_lock, flags);
|
|
|
|
- ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6;
|
|
|
|
- ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6;
|
|
|
|
- spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
-{
|
|
|
|
- struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
|
|
|
- unsigned long flags;
|
|
|
|
- unsigned short left, right;
|
|
|
|
- int change;
|
|
|
|
-
|
|
|
|
- if (ucontrol->value.enumerated.item[0] > 3 ||
|
|
|
|
- ucontrol->value.enumerated.item[1] > 3)
|
|
|
|
- return -EINVAL;
|
|
|
|
- left = ucontrol->value.enumerated.item[0] << 6;
|
|
|
|
- right = ucontrol->value.enumerated.item[1] << 6;
|
|
|
|
- spin_lock_irqsave(&chip->reg_lock, flags);
|
|
|
|
- left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left;
|
|
|
|
- right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right;
|
|
|
|
- change = left != chip->image[AD1848_LEFT_INPUT] ||
|
|
|
|
- right != chip->image[AD1848_RIGHT_INPUT];
|
|
|
|
- snd_ad1848_out(chip, AD1848_LEFT_INPUT, left);
|
|
|
|
- snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right);
|
|
|
|
- spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
|
|
- return change;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
|
|
|
-{
|
|
|
|
- int mask = (kcontrol->private_value >> 16) & 0xff;
|
|
|
|
-
|
|
|
|
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
|
|
- uinfo->count = 1;
|
|
|
|
- uinfo->value.integer.min = 0;
|
|
|
|
- uinfo->value.integer.max = mask;
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
-{
|
|
|
|
- struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
|
|
|
- unsigned long flags;
|
|
|
|
- int reg = kcontrol->private_value & 0xff;
|
|
|
|
- int shift = (kcontrol->private_value >> 8) & 0xff;
|
|
|
|
- int mask = (kcontrol->private_value >> 16) & 0xff;
|
|
|
|
- int invert = (kcontrol->private_value >> 24) & 0xff;
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&chip->reg_lock, flags);
|
|
|
|
- ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
|
|
|
|
- spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
|
|
- if (invert)
|
|
|
|
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
-{
|
|
|
|
- struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
|
|
|
- unsigned long flags;
|
|
|
|
- int reg = kcontrol->private_value & 0xff;
|
|
|
|
- int shift = (kcontrol->private_value >> 8) & 0xff;
|
|
|
|
- int mask = (kcontrol->private_value >> 16) & 0xff;
|
|
|
|
- int invert = (kcontrol->private_value >> 24) & 0xff;
|
|
|
|
- int change;
|
|
|
|
- unsigned short val;
|
|
|
|
-
|
|
|
|
- val = (ucontrol->value.integer.value[0] & mask);
|
|
|
|
- if (invert)
|
|
|
|
- val = mask - val;
|
|
|
|
- val <<= shift;
|
|
|
|
- spin_lock_irqsave(&chip->reg_lock, flags);
|
|
|
|
- val = (chip->image[reg] & ~(mask << shift)) | val;
|
|
|
|
- change = val != chip->image[reg];
|
|
|
|
- snd_ad1848_out(chip, reg, val);
|
|
|
|
- spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
|
|
- return change;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
|
|
|
-{
|
|
|
|
- int mask = (kcontrol->private_value >> 24) & 0xff;
|
|
|
|
-
|
|
|
|
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
|
|
- uinfo->count = 2;
|
|
|
|
- uinfo->value.integer.min = 0;
|
|
|
|
- uinfo->value.integer.max = mask;
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
-{
|
|
|
|
- struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
|
|
|
- unsigned long flags;
|
|
|
|
- int left_reg = kcontrol->private_value & 0xff;
|
|
|
|
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
|
|
|
|
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
|
|
|
|
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
|
|
|
|
- int mask = (kcontrol->private_value >> 24) & 0xff;
|
|
|
|
- int invert = (kcontrol->private_value >> 22) & 1;
|
|
|
|
-
|
|
|
|
- spin_lock_irqsave(&chip->reg_lock, flags);
|
|
|
|
- ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
|
|
|
|
- ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
|
|
|
|
- spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
|
|
- if (invert) {
|
|
|
|
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
|
|
|
|
- ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
|
|
|
|
- }
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
|
|
|
|
-{
|
|
|
|
- struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
|
|
|
|
- unsigned long flags;
|
|
|
|
- int left_reg = kcontrol->private_value & 0xff;
|
|
|
|
- int right_reg = (kcontrol->private_value >> 8) & 0xff;
|
|
|
|
- int shift_left = (kcontrol->private_value >> 16) & 0x07;
|
|
|
|
- int shift_right = (kcontrol->private_value >> 19) & 0x07;
|
|
|
|
- int mask = (kcontrol->private_value >> 24) & 0xff;
|
|
|
|
- int invert = (kcontrol->private_value >> 22) & 1;
|
|
|
|
- int change;
|
|
|
|
- unsigned short val1, val2;
|
|
|
|
-
|
|
|
|
- val1 = ucontrol->value.integer.value[0] & mask;
|
|
|
|
- val2 = ucontrol->value.integer.value[1] & mask;
|
|
|
|
- if (invert) {
|
|
|
|
- val1 = mask - val1;
|
|
|
|
- val2 = mask - val2;
|
|
|
|
- }
|
|
|
|
- val1 <<= shift_left;
|
|
|
|
- val2 <<= shift_right;
|
|
|
|
- spin_lock_irqsave(&chip->reg_lock, flags);
|
|
|
|
- if (left_reg != right_reg) {
|
|
|
|
- val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
|
|
|
|
- val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
|
|
|
|
- change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
|
|
|
|
- snd_ad1848_out(chip, left_reg, val1);
|
|
|
|
- snd_ad1848_out(chip, right_reg, val2);
|
|
|
|
- } else {
|
|
|
|
- val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
|
|
|
|
- change = val1 != chip->image[left_reg];
|
|
|
|
- snd_ad1848_out(chip, left_reg, val1);
|
|
|
|
- }
|
|
|
|
- spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
|
|
- return change;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
|
|
|
|
-static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
|
|
|
|
-static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
|
|
|
|
-
|
|
|
|
-#define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
|
|
|
|
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
|
|
|
- .name = xname, \
|
|
|
|
- .index = xindex, \
|
|
|
|
- .info = snd_ad1848_info_single, \
|
|
|
|
- .get = snd_ad1848_get_single, \
|
|
|
|
- .put = snd_ad1848_put_single, \
|
|
|
|
- .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
|
|
|
|
- .tlv = { .p = (xtlv) } }
|
|
|
|
-
|
|
|
|
-#define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
|
|
|
|
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
|
|
|
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
|
|
|
|
- .name = xname, \
|
|
|
|
- .index = xindex, \
|
|
|
|
- .info = snd_ad1848_info_double, \
|
|
|
|
- .get = snd_ad1848_get_double, \
|
|
|
|
- .put = snd_ad1848_put_double, \
|
|
|
|
- .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
|
|
|
|
- (shift_right << 19) | (mask << 24) | (invert << 22), \
|
|
|
|
- .tlv = { .p = (xtlv) } }
|
|
|
|
-
|
|
|
|
-static struct snd_kcontrol_new snd_ad1848_controls[] = {
|
|
|
|
-WSS_DOUBLE("PCM Playback Switch", 0,
|
|
|
|
- AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
|
|
|
|
-AD1848_DOUBLE_TLV("PCM Playback Volume", 0,
|
|
|
|
- AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1,
|
|
|
|
- db_scale_6bit),
|
|
|
|
-WSS_DOUBLE("Aux Playback Switch", 0,
|
|
|
|
- AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
|
|
|
|
-AD1848_DOUBLE_TLV("Aux Playback Volume", 0,
|
|
|
|
- AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
|
|
|
|
- db_scale_5bit_12db_max),
|
|
|
|
-WSS_DOUBLE("Aux Playback Switch", 1,
|
|
|
|
- AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
|
|
|
|
-AD1848_DOUBLE_TLV("Aux Playback Volume", 1,
|
|
|
|
- AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
|
|
|
|
- db_scale_5bit_12db_max),
|
|
|
|
-AD1848_DOUBLE_TLV("Capture Volume", 0,
|
|
|
|
- AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0,
|
|
|
|
- db_scale_rec_gain),
|
|
|
|
-{
|
|
|
|
- .name = "Capture Source",
|
|
|
|
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
- .info = snd_ad1848_info_mux,
|
|
|
|
- .get = snd_ad1848_get_mux,
|
|
|
|
- .put = snd_ad1848_put_mux,
|
|
|
|
-},
|
|
|
|
-WSS_SINGLE("Loopback Capture Switch", 0,
|
|
|
|
- AD1848_LOOPBACK, 0, 1, 0),
|
|
|
|
-AD1848_SINGLE_TLV("Loopback Capture Volume", 0,
|
|
|
|
- AD1848_LOOPBACK, 1, 63, 0,
|
|
|
|
- db_scale_6bit),
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-int snd_ad1848_mixer(struct snd_wss *chip)
|
|
|
|
-{
|
|
|
|
- struct snd_card *card;
|
|
|
|
- struct snd_pcm *pcm;
|
|
|
|
- unsigned int idx;
|
|
|
|
- int err;
|
|
|
|
-
|
|
|
|
- snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
|
|
|
|
-
|
|
|
|
- pcm = chip->pcm;
|
|
|
|
- card = chip->card;
|
|
|
|
-
|
|
|
|
- strcpy(card->mixername, pcm->name);
|
|
|
|
-
|
|
|
|
- for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
|
|
|
|
- err = snd_ctl_add(card,
|
|
|
|
- snd_ctl_new1(&snd_ad1848_controls[idx], chip));
|
|
|
|
- if (err < 0)
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-EXPORT_SYMBOL(snd_ad1848_mixer);
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* INIT part
|
|
* INIT part
|
|
*/
|
|
*/
|