提交 b2a88774 编写于 作者: L Lucas Tanure 提交者: Takashi Iwai

ALSA: hda/cs8409: Generalize volume controls

Use amp offsets as indexes for saved volumes.
Remove dependencies on NID inside volume control functions.
Signed-off-by: NLucas Tanure <tanureal@opensource.cirrus.com>
Signed-off-by: NVitaly Rodionov <vitalyr@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210811185654.6837-13-vitalyr@opensource.cirrus.comSigned-off-by: NTakashi Iwai <tiwai@suse.de>
上级 a1a6c7df
...@@ -10,6 +10,43 @@ ...@@ -10,6 +10,43 @@
#include "patch_cs8409.h" #include "patch_cs8409.h"
/******************************************************************************
* CS42L42 Specific Data
*
******************************************************************************/
static const DECLARE_TLV_DB_SCALE(cs42l42_dac_db_scale,
CS8409_CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
static const DECLARE_TLV_DB_SCALE(cs42l42_adc_db_scale,
CS8409_CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
const struct snd_kcontrol_new cs42l42_dac_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
.info = cs8409_cs42l42_volume_info,
.get = cs8409_cs42l42_volume_get,
.put = cs8409_cs42l42_volume_put,
.tlv = { .p = cs42l42_dac_db_scale },
.private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_TRANSMITTER_A, 3, 0,
HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE
};
const struct snd_kcontrol_new cs42l42_adc_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
.info = cs8409_cs42l42_volume_info,
.get = cs8409_cs42l42_volume_get,
.put = cs8409_cs42l42_volume_put,
.tlv = { .p = cs42l42_adc_db_scale },
.private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_RECEIVER_A, 1, 0,
HDA_INPUT, CS42L42_VOL_ADC) | HDA_AMP_VAL_MIN_MUTE
};
/* Dell Inspiron platforms /* Dell Inspiron platforms
* with cs8409 bridge and cs42l42 codec * with cs8409 bridge and cs42l42 codec
*/ */
......
...@@ -208,162 +208,97 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u ...@@ -208,162 +208,97 @@ static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, u
return 0; return 0;
} }
static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo) int cs8409_cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo)
{ {
u16 nid = get_amp_nid(kctrl); unsigned int ofs = get_amp_offset(kctrl);
u8 chs = get_amp_channels(kctrl); u8 chs = get_amp_channels(kctrl);
switch (nid) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
case CS8409_CS42L42_HP_PIN_NID: uinfo->value.integer.step = 1;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = chs == 3 ? 2 : 1;
uinfo->count = chs == 3 ? 2 : 1;
switch (ofs) {
case CS42L42_VOL_DAC:
uinfo->value.integer.min = CS8409_CS42L42_HP_VOL_REAL_MIN; uinfo->value.integer.min = CS8409_CS42L42_HP_VOL_REAL_MIN;
uinfo->value.integer.max = CS8409_CS42L42_HP_VOL_REAL_MAX; uinfo->value.integer.max = CS8409_CS42L42_HP_VOL_REAL_MAX;
break; break;
case CS8409_CS42L42_AMIC_PIN_NID: case CS42L42_VOL_ADC:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = chs == 3 ? 2 : 1;
uinfo->value.integer.min = CS8409_CS42L42_AMIC_VOL_REAL_MIN; uinfo->value.integer.min = CS8409_CS42L42_AMIC_VOL_REAL_MIN;
uinfo->value.integer.max = CS8409_CS42L42_AMIC_VOL_REAL_MAX; uinfo->value.integer.max = CS8409_CS42L42_AMIC_VOL_REAL_MAX;
break; break;
default: default:
break; break;
} }
return 0;
}
static void cs8409_cs42l42_update_volume(struct hda_codec *codec) return 0;
{
struct cs8409_spec *spec = codec->spec;
int data;
mutex_lock(&spec->cs8409_i2c_mux);
data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHA, 1);
if (data >= 0)
spec->cs42l42_hp_volume[0] = -data;
else
spec->cs42l42_hp_volume[0] = CS8409_CS42L42_HP_VOL_REAL_MIN;
data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHB, 1);
if (data >= 0)
spec->cs42l42_hp_volume[1] = -data;
else
spec->cs42l42_hp_volume[1] = CS8409_CS42L42_HP_VOL_REAL_MIN;
data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOLUME, 1);
if (data >= 0)
spec->cs42l42_hs_mic_volume[0] = -data;
else
spec->cs42l42_hs_mic_volume[0] = CS8409_CS42L42_AMIC_VOL_REAL_MIN;
mutex_unlock(&spec->cs8409_i2c_mux);
spec->cs42l42_volume_init = 1;
} }
static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl) int cs8409_cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl)
{ {
struct hda_codec *codec = snd_kcontrol_chip(kctrl); struct hda_codec *codec = snd_kcontrol_chip(kctrl);
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kctrl);
int chs = get_amp_channels(kctrl); int chs = get_amp_channels(kctrl);
unsigned int ofs = get_amp_offset(kctrl);
long *valp = uctrl->value.integer.value; long *valp = uctrl->value.integer.value;
if (!spec->cs42l42_volume_init) { switch (ofs) {
snd_hda_power_up(codec); case CS42L42_VOL_DAC:
cs8409_cs42l42_update_volume(codec);
snd_hda_power_down(codec);
}
switch (nid) {
case CS8409_CS42L42_HP_PIN_NID:
if (chs & BIT(0)) if (chs & BIT(0))
*valp++ = spec->cs42l42_hp_volume[0]; *valp++ = spec->vol[ofs];
if (chs & BIT(1)) if (chs & BIT(1))
*valp++ = spec->cs42l42_hp_volume[1]; *valp = spec->vol[ofs+1];
break; break;
case CS8409_CS42L42_AMIC_PIN_NID: case CS42L42_VOL_ADC:
if (chs & BIT(0)) if (chs & BIT(0))
*valp++ = spec->cs42l42_hs_mic_volume[0]; *valp = spec->vol[ofs];
break; break;
default: default:
break; break;
} }
return 0; return 0;
} }
static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl) int cs8409_cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl)
{ {
struct hda_codec *codec = snd_kcontrol_chip(kctrl); struct hda_codec *codec = snd_kcontrol_chip(kctrl);
struct cs8409_spec *spec = codec->spec; struct cs8409_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kctrl);
int chs = get_amp_channels(kctrl); int chs = get_amp_channels(kctrl);
unsigned int ofs = get_amp_offset(kctrl);
long *valp = uctrl->value.integer.value; long *valp = uctrl->value.integer.value;
int change = 0;
char vol;
snd_hda_power_up(codec); switch (ofs) {
switch (nid) { case CS42L42_VOL_DAC:
case CS8409_CS42L42_HP_PIN_NID:
mutex_lock(&spec->cs8409_i2c_mux); mutex_lock(&spec->cs8409_i2c_mux);
if (chs & BIT(0)) { if (chs & BIT(0)) {
vol = -(*valp); spec->vol[ofs] = *valp;
change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR, cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHA,
CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1); -(spec->vol[ofs]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
valp++;
} }
if (chs & BIT(1)) { if (chs & BIT(1)) {
vol = -(*valp); ofs++;
change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR, valp++;
CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1); spec->vol[ofs] = *valp;
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHB,
-(spec->vol[ofs]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
} }
mutex_unlock(&spec->cs8409_i2c_mux); mutex_unlock(&spec->cs8409_i2c_mux);
break; break;
case CS8409_CS42L42_AMIC_PIN_NID: case CS42L42_VOL_ADC:
mutex_lock(&spec->cs8409_i2c_mux); mutex_lock(&spec->cs8409_i2c_mux);
if (chs & BIT(0)) { if (chs & BIT(0)) {
change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR, spec->vol[ofs] = *valp;
CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOL,
valp++; spec->vol[ofs] & CS8409_CS42L42_REG_AMIC_VOL_MASK, 1);
} }
mutex_unlock(&spec->cs8409_i2c_mux); mutex_unlock(&spec->cs8409_i2c_mux);
break; break;
default: default:
break; break;
} }
cs8409_cs42l42_update_volume(codec);
snd_hda_power_down(codec);
return change;
}
static const DECLARE_TLV_DB_SCALE(cs8409_cs42l42_hp_db_scale,
CS8409_CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
static const DECLARE_TLV_DB_SCALE(cs8409_cs42l42_amic_db_scale,
CS8409_CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.index = 0,
.name = "Headphone Playback Volume",
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
.info = cs8409_cs42l42_volume_info,
.get = cs8409_cs42l42_volume_get,
.put = cs8409_cs42l42_volume_put,
.tlv = { .p = cs8409_cs42l42_hp_db_scale },
.private_value = HDA_COMPOSE_AMP_VAL(CS8409_CS42L42_HP_PIN_NID, 3, 0, HDA_OUTPUT) |
HDA_AMP_VAL_MIN_MUTE
};
static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = { return 0;
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, }
.index = 0,
.name = "Mic Capture Volume",
.subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
.info = cs8409_cs42l42_volume_info,
.get = cs8409_cs42l42_volume_get,
.put = cs8409_cs42l42_volume_put,
.tlv = { .p = cs8409_cs42l42_amic_db_scale },
.private_value = HDA_COMPOSE_AMP_VAL(CS8409_CS42L42_AMIC_PIN_NID, 1, 0, HDA_INPUT) |
HDA_AMP_VAL_MIN_MUTE
};
/* Assert/release RTS# line to CS42L42 */ /* Assert/release RTS# line to CS42L42 */
static void cs8409_cs42l42_reset(struct hda_codec *codec) static void cs8409_cs42l42_reset(struct hda_codec *codec)
...@@ -657,18 +592,14 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec) ...@@ -657,18 +592,14 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
} }
/* Restore Volumes after Resume */ /* Restore Volumes after Resume */
if (spec->cs42l42_volume_init) { mutex_lock(&spec->cs8409_i2c_mux);
mutex_lock(&spec->cs8409_i2c_mux); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHA,
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHA, -(spec->vol[1]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
-spec->cs42l42_hp_volume[0], 1); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOL_CHB,
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHB, -(spec->vol[2]) & CS8409_CS42L42_REG_HS_VOL_MASK, 1);
-spec->cs42l42_hp_volume[1], 1); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOL,
cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOLUME, spec->vol[0] & CS8409_CS42L42_REG_AMIC_VOL_MASK, 1);
spec->cs42l42_hs_mic_volume[0], 1); mutex_unlock(&spec->cs8409_i2c_mux);
mutex_unlock(&spec->cs8409_i2c_mux);
}
cs8409_cs42l42_update_volume(codec);
cs8409_cs42l42_enable_jack_detect(codec); cs8409_cs42l42_enable_jack_detect(codec);
...@@ -811,8 +742,10 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, ...@@ -811,8 +742,10 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
/* Set initial DMIC volume to -26 dB */ /* Set initial DMIC volume to -26 dB */
snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID, snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID,
HDA_INPUT, 0, 0xff, 0x19); HDA_INPUT, 0, 0xff, 0x19);
snd_hda_gen_add_kctl(&spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer); snd_hda_gen_add_kctl(&spec->gen, "Headphone Playback Volume",
snd_hda_gen_add_kctl(&spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer); &cs42l42_dac_volume_mixer);
snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume",
&cs42l42_adc_volume_mixer);
/* Disable Unsolicited Response during boot */ /* Disable Unsolicited Response during boot */
cs8409_enable_ur(codec, 0); cs8409_enable_ur(codec, 0);
cs8409_cs42l42_hw_init(codec); cs8409_cs42l42_hw_init(codec);
......
...@@ -215,16 +215,17 @@ enum cs8409_coefficient_index_registers { ...@@ -215,16 +215,17 @@ enum cs8409_coefficient_index_registers {
/* CS42L42 Specific Definitions */ /* CS42L42 Specific Definitions */
#define CS42L42_HP_CH (2U) #define CS42L42_VOLUMES (4U)
#define CS42L42_HS_MIC_CH (1U)
#define CS8409_CS42L42_HP_VOL_REAL_MIN (-63) #define CS8409_CS42L42_HP_VOL_REAL_MIN (-63)
#define CS8409_CS42L42_HP_VOL_REAL_MAX (0) #define CS8409_CS42L42_HP_VOL_REAL_MAX (0)
#define CS8409_CS42L42_AMIC_VOL_REAL_MIN (-97) #define CS8409_CS42L42_AMIC_VOL_REAL_MIN (-97)
#define CS8409_CS42L42_AMIC_VOL_REAL_MAX (12) #define CS8409_CS42L42_AMIC_VOL_REAL_MAX (12)
#define CS8409_CS42L42_REG_HS_VOLUME_CHA (0x2301) #define CS8409_CS42L42_REG_HS_VOL_CHA (0x2301)
#define CS8409_CS42L42_REG_HS_VOLUME_CHB (0x2303) #define CS8409_CS42L42_REG_HS_VOL_CHB (0x2303)
#define CS8409_CS42L42_REG_AMIC_VOLUME (0x1D03) #define CS8409_CS42L42_REG_HS_VOL_MASK (0x003F)
#define CS8409_CS42L42_REG_AMIC_VOL (0x1D03)
#define CS8409_CS42L42_REG_AMIC_VOL_MASK (0x00FF)
#define CS42L42_HSDET_AUTO_DONE (0x02) #define CS42L42_HSDET_AUTO_DONE (0x02)
#define CS42L42_HSTYPE_MASK (0x03) #define CS42L42_HSTYPE_MASK (0x03)
#define CS42L42_JACK_INSERTED (0x0C) #define CS42L42_JACK_INSERTED (0x0C)
...@@ -248,6 +249,11 @@ enum { ...@@ -248,6 +249,11 @@ enum {
CS8409_FIXUPS, CS8409_FIXUPS,
}; };
enum {
CS42L42_VOL_ADC,
CS42L42_VOL_DAC,
};
struct cs8409_i2c_param { struct cs8409_i2c_param {
unsigned int addr; unsigned int addr;
unsigned int reg; unsigned int reg;
...@@ -268,10 +274,8 @@ struct cs8409_spec { ...@@ -268,10 +274,8 @@ struct cs8409_spec {
unsigned int cs42l42_hp_jack_in:1; unsigned int cs42l42_hp_jack_in:1;
unsigned int cs42l42_mic_jack_in:1; unsigned int cs42l42_mic_jack_in:1;
unsigned int cs42l42_volume_init:1;
unsigned int cs42l42_suspended:1; unsigned int cs42l42_suspended:1;
char cs42l42_hp_volume[CS42L42_HP_CH]; s8 vol[CS42L42_VOLUMES];
char cs42l42_hs_mic_volume[CS42L42_HS_MIC_CH];
struct mutex cs8409_i2c_mux; struct mutex cs8409_i2c_mux;
...@@ -280,6 +284,13 @@ struct cs8409_spec { ...@@ -280,6 +284,13 @@ struct cs8409_spec {
unsigned int *res); unsigned int *res);
}; };
extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
extern const struct snd_kcontrol_new cs42l42_adc_volume_mixer;
int cs8409_cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo);
int cs8409_cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
int cs8409_cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
extern const struct snd_pci_quirk cs8409_fixup_tbl[]; extern const struct snd_pci_quirk cs8409_fixup_tbl[];
extern const struct hda_model_fixup cs8409_models[]; extern const struct hda_model_fixup cs8409_models[];
extern const struct hda_fixup cs8409_fixups[]; extern const struct hda_fixup cs8409_fixups[];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册