From ad35879aa192e783db2d41c196f48f3fc059ce22 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 30 Mar 2010 18:00:59 +0200 Subject: ALSA: hda - Add mute LED support for HP laptop with ALC269 Some HP laptops have a mute LED that is controlled over the unused MIC2 VREF pin. Implement the LED updater like patch_sigmatel.c for this model. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1694f60..9a361c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3467,6 +3467,10 @@ static int alc_init(struct hda_codec *codec) if (spec->init_hook) spec->init_hook(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, 0x01); +#endif return 0; } @@ -3827,6 +3831,10 @@ static int alc_resume(struct hda_codec *codec) codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, 0x01); +#endif return 0; } #endif @@ -13983,6 +13991,34 @@ static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { /* NID is set in alc_build_pcms */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc269_mic2_for_mute_led(struct hda_codec *codec) +{ + switch (codec->subsystem_id) { + case 0x103c1586: + return 1; + } + return 0; +} + +static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) +{ + /* update mute-LED according to the speaker mute state */ + if (nid == 0x01 || nid == 0x14) { + int pinval; + if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) & + HDA_AMP_MUTE) + pinval = 0x24; + else + pinval = 0x20; + /* mic2 vref pin is used for mute LED control */ + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinval); + } + return alc_check_power_status(codec, nid); +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + /* * BIOS auto configuration */ @@ -14330,6 +14366,8 @@ static int patch_alc269(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc269_loopbacks; + if (alc269_mic2_for_mute_led(codec)) + codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps; #endif return 0; -- cgit v1.1 From a68d5a5419d2a15161488b20f740115068e7b666 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 30 Mar 2010 18:03:44 +0200 Subject: ALSA: hda - introduce snd_hda_codec_update_cache() Add a new helper, snd_hda_codec_update_cache(), for reducing the unneeded verbs. This function checks the cached value and skips if it's identical with the given one. Otherwise it works like snd_hda_codec_write_cache(). The alc269 code uses this function as an example. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 68 +++++++++++++++++++++++++++++++++++-------- sound/pci/hda/hda_codec.h | 3 ++ sound/pci/hda/patch_realtek.c | 5 ++-- 3 files changed, 62 insertions(+), 14 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d1424e7..a3d638c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1209,8 +1209,7 @@ static void free_hda_cache(struct hda_cache_rec *cache) } /* query the hash. allocate an entry if not found. */ -static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, - u32 key) +static struct hda_cache_head *get_hash(struct hda_cache_rec *cache, u32 key) { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; @@ -1222,17 +1221,27 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, return info; cur = info->next; } + return NULL; +} - /* add a new hash entry */ - info = snd_array_new(&cache->buf); - if (!info) - return NULL; - cur = snd_array_index(&cache->buf, info); - info->key = key; - info->val = 0; - info->next = cache->hash[idx]; - cache->hash[idx] = cur; - +/* query the hash. allocate an entry if not found. */ +static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, + u32 key) +{ + struct hda_cache_head *info = get_hash(cache, key); + if (!info) { + u16 idx, cur; + /* add a new hash entry */ + info = snd_array_new(&cache->buf); + if (!info) + return NULL; + cur = snd_array_index(&cache->buf, info); + info->key = key; + info->val = 0; + idx = key % (u16)ARRAY_SIZE(cache->hash); + info->next = cache->hash[idx]; + cache->hash[idx] = cur; + } return info; } @@ -2722,6 +2731,41 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); /** + * snd_hda_codec_update_cache - check cache and write the cmd only when needed + * @codec: the HDA codec + * @nid: NID to send the command + * @direct: direct flag + * @verb: the verb to send + * @parm: the parameter for the verb + * + * This function works like snd_hda_codec_write_cache(), but it doesn't send + * command if the parameter is already identical with the cached value. + * If not, it sends the command and refreshes the cache. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) +{ + struct hda_cache_head *c; + u32 key; + + /* parm may contain the verb stuff for get/set amp */ + verb = verb | (parm >> 8); + parm &= 0xff; + key = build_cmd_cache_key(nid, verb); + mutex_lock(&codec->bus->cmd_mutex); + c = get_hash(&codec->cmd_cache, key); + if (c && c->val == parm) { + mutex_unlock(&codec->bus->cmd_mutex); + return 0; + } + mutex_unlock(&codec->bus->cmd_mutex); + return snd_hda_codec_write_cache(codec, nid, direct, verb, parm); +} +EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); + +/** * snd_hda_codec_resume_cache - Resume the all commands from the cache * @codec: HD-audio codec * diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b75da47..49e939e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -885,9 +885,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, const struct hda_verb *seq); +int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); void snd_hda_codec_resume_cache(struct hda_codec *codec); #else #define snd_hda_codec_write_cache snd_hda_codec_write +#define snd_hda_codec_update_cache snd_hda_codec_write #define snd_hda_sequence_write_cache snd_hda_sequence_write #endif diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a361c2..8ae4806 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14012,8 +14012,9 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) else pinval = 0x20; /* mic2 vref pin is used for mute LED control */ - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinval); + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); } return alc_check_power_status(codec, nid); } -- cgit v1.1