ALSA: hda/cs8409: Add Speaker Playback Switch for Cyborg
Add support for a Speaker Playback Switch, which disables the Amp connected to cs8409. The Switch is not added automatically because cs8409 does not have an output amp for the speaker NID. Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> Link: https://lore.kernel.org/r/20220511100207.1268321-3-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
22bb82264c
commit
f129f26f76
@ -419,6 +419,39 @@ static void cs8409_fix_caps(struct hda_codec *codec, unsigned int nid)
|
||||
snd_hda_override_wcaps(codec, nid, (get_wcaps(codec, nid) | AC_WCAP_UNSOL_CAP));
|
||||
}
|
||||
|
||||
static int cs8409_spk_sw_gpio_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs8409_spec *spec = codec->spec;
|
||||
|
||||
ucontrol->value.integer.value[0] = !!(spec->gpio_data & spec->speaker_pdn_gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs8409_spk_sw_gpio_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct cs8409_spec *spec = codec->spec;
|
||||
unsigned int gpio_data;
|
||||
|
||||
gpio_data = (spec->gpio_data & ~spec->speaker_pdn_gpio) |
|
||||
(ucontrol->value.integer.value[0] ? spec->speaker_pdn_gpio : 0);
|
||||
if (gpio_data == spec->gpio_data)
|
||||
return 0;
|
||||
spec->gpio_data = gpio_data;
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new cs8409_spk_sw_ctrl = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = cs8409_spk_sw_gpio_get,
|
||||
.put = cs8409_spk_sw_gpio_put,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* CS42L42 Specific Functions
|
||||
******************************************************************************/
|
||||
@ -836,7 +869,7 @@ static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42)
|
||||
static void cs42l42_resume(struct sub_codec *cs42l42)
|
||||
{
|
||||
struct hda_codec *codec = cs42l42->codec;
|
||||
unsigned int gpio_data;
|
||||
struct cs8409_spec *spec = codec->spec;
|
||||
struct cs8409_i2c_param irq_regs[] = {
|
||||
{ CS42L42_CODEC_STATUS, 0x00 },
|
||||
{ CS42L42_DET_INT_STATUS1, 0x00 },
|
||||
@ -846,9 +879,9 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
|
||||
int fsv_old, fsv_new;
|
||||
|
||||
/* Bring CS42L42 out of Reset */
|
||||
gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
|
||||
gpio_data |= cs42l42->reset_gpio;
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
|
||||
spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
|
||||
spec->gpio_data |= cs42l42->reset_gpio;
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
cs42l42->suspended = 0;
|
||||
@ -880,7 +913,7 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
|
||||
static void cs42l42_suspend(struct sub_codec *cs42l42)
|
||||
{
|
||||
struct hda_codec *codec = cs42l42->codec;
|
||||
unsigned int gpio_data;
|
||||
struct cs8409_spec *spec = codec->spec;
|
||||
int reg_cdc_status = 0;
|
||||
const struct cs8409_i2c_param cs42l42_pwr_down_seq[] = {
|
||||
{ CS42L42_DAC_CTL2, 0x02 },
|
||||
@ -911,9 +944,9 @@ static void cs42l42_suspend(struct sub_codec *cs42l42)
|
||||
cs42l42->mic_jack_in = 0;
|
||||
|
||||
/* Put CS42L42 into Reset */
|
||||
gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
|
||||
gpio_data &= ~cs42l42->reset_gpio;
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, gpio_data);
|
||||
spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
|
||||
spec->gpio_data &= ~cs42l42->reset_gpio;
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1107,6 +1140,8 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
|
||||
spec->gen.no_primary_hp = 1;
|
||||
spec->gen.suppress_vmaster = 1;
|
||||
|
||||
spec->speaker_pdn_gpio = 0;
|
||||
|
||||
/* GPIO 5 out, 3,4 in */
|
||||
spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio;
|
||||
spec->gpio_data = 0;
|
||||
@ -1118,21 +1153,33 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
|
||||
cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID);
|
||||
cs8409_fix_caps(codec, CS8409_CS42L42_AMIC_PIN_NID);
|
||||
|
||||
/* Set HSBIAS_SENSE_EN and Full Scale volume for some variants. */
|
||||
spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
|
||||
|
||||
switch (codec->fixup_id) {
|
||||
case CS8409_CYBORG:
|
||||
spec->scodecs[CS8409_CODEC0]->full_scale_vol =
|
||||
CS42L42_FULL_SCALE_VOL_MINUS6DB;
|
||||
spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN;
|
||||
break;
|
||||
case CS8409_ODIN:
|
||||
spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB;
|
||||
spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN;
|
||||
break;
|
||||
case CS8409_WARLOCK_MLK:
|
||||
case CS8409_WARLOCK_MLK_DUAL_MIC:
|
||||
spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
|
||||
spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB;
|
||||
break;
|
||||
default:
|
||||
spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
|
||||
spec->scodecs[CS8409_CODEC0]->full_scale_vol =
|
||||
CS42L42_FULL_SCALE_VOL_MINUS6DB;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spec->speaker_pdn_gpio > 0) {
|
||||
spec->gpio_dir |= spec->speaker_pdn_gpio;
|
||||
spec->gpio_data |= spec->speaker_pdn_gpio;
|
||||
}
|
||||
|
||||
break;
|
||||
case HDA_FIXUP_ACT_PROBE:
|
||||
/* Fix Sample Rate to 48kHz */
|
||||
@ -1149,6 +1196,9 @@ void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix,
|
||||
&cs42l42_dac_volume_mixer);
|
||||
snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume",
|
||||
&cs42l42_adc_volume_mixer);
|
||||
if (spec->speaker_pdn_gpio > 0)
|
||||
snd_hda_gen_add_kctl(&spec->gen, "Speaker Playback Switch",
|
||||
&cs8409_spk_sw_ctrl);
|
||||
/* Disable Unsolicited Response during boot */
|
||||
cs8409_enable_ur(codec, 0);
|
||||
snd_hda_codec_set_name(codec, "CS8409/CS42L42");
|
||||
|
@ -238,6 +238,7 @@ enum cs8409_coefficient_index_registers {
|
||||
#define CS42L42_I2C_ADDR (0x48 << 1)
|
||||
#define CS8409_CS42L42_RESET GENMASK(5, 5) /* CS8409_GPIO5 */
|
||||
#define CS8409_CS42L42_INT GENMASK(4, 4) /* CS8409_GPIO4 */
|
||||
#define CS8409_CYBORG_SPEAKER_PDN GENMASK(2, 2) /* CS8409_GPIO2 */
|
||||
#define CS8409_CS42L42_HP_PIN_NID CS8409_PIN_ASP1_TRANSMITTER_A
|
||||
#define CS8409_CS42L42_SPK_PIN_NID CS8409_PIN_ASP2_TRANSMITTER_A
|
||||
#define CS8409_CS42L42_AMIC_PIN_NID CS8409_PIN_ASP1_RECEIVER_A
|
||||
@ -326,6 +327,8 @@ struct cs8409_spec {
|
||||
unsigned int gpio_dir;
|
||||
unsigned int gpio_data;
|
||||
|
||||
int speaker_pdn_gpio;
|
||||
|
||||
struct mutex i2c_mux;
|
||||
unsigned int i2c_clck_enabled;
|
||||
unsigned int dev_addr;
|
||||
|
Loading…
Reference in New Issue
Block a user