]> www.infradead.org Git - users/hch/configfs.git/commitdiff
ALSA: hda/generic: Add a helper to mute speakers at suspend/shutdown
authorTakashi Iwai <tiwai@suse.de>
Fri, 26 Jul 2024 14:26:19 +0000 (16:26 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 26 Jul 2024 14:36:01 +0000 (16:36 +0200)
Some devices indicate click noises at suspend or shutdown when the
speakers are unmuted.  This patch adds a helper,
snd_hda_gen_shutup_speakers(), to work around it.  The new function is
supposed to be called at suspend or shutdown by the codec driver, and
it mutes the speakers.

The mute status isn't cached, hence the original mute state will be
restored at resume again.

Link: https://patch.msgid.link/20240726142625.2460-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h

index f64d9dc197a31af31a2cc80a5148830654fd9fb9..9cff87dfbecbb1fffa35a3d8819ac82c51571bb5 100644 (file)
@@ -4955,6 +4955,69 @@ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
 }
 EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
 
+/* forcibly mute the speaker output without caching; return true if updated */
+static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (!nid)
+               return false;
+       if (!nid_has_mute(codec, nid, HDA_OUTPUT))
+               return false; /* no mute, skip */
+       if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+           snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) &
+           HDA_AMP_MUTE)
+               return false; /* both channels already muted, skip */
+
+       /* direct amp update without caching */
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT |
+                           AC_AMP_SET_RIGHT | HDA_AMP_MUTE);
+       return true;
+}
+
+/**
+ * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs
+ * @codec: the HDA codec
+ *
+ * Forcibly mute the speaker outputs, to be called at suspend or shutdown.
+ *
+ * The mute state done by this function isn't cached, hence the original state
+ * will be restored at resume.
+ *
+ * Return true if the mute state has been changed.
+ */
+bool snd_hda_gen_shutup_speakers(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const int *paths;
+       const struct nid_path *path;
+       int i, p, num_paths;
+       bool updated = false;
+
+       /* if already powered off, do nothing */
+       if (!snd_hdac_is_power_on(&codec->core))
+               return false;
+
+       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
+               paths = spec->out_paths;
+               num_paths = spec->autocfg.line_outs;
+       } else {
+               paths = spec->speaker_paths;
+               num_paths = spec->autocfg.speaker_outs;
+       }
+
+       for (i = 0; i < num_paths; i++) {
+               path = snd_hda_get_path_from_idx(codec, paths[i]);
+               if (!path)
+                       continue;
+               for (p = 0; p < path->depth; p++)
+                       if (force_mute_output_path(codec, path->path[p]))
+                               updated = true;
+       }
+
+       return updated;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers);
+
 /**
  * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
  * set up the hda_gen_spec
index 8f5ecf740c4917051ee9c2f0a5d0666109f70dc7..08544601b4ce29865035734fa59901159dfbeff1 100644 (file)
@@ -353,5 +353,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
 int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
                                     int (*callback)(struct led_classdev *,
                                                     enum led_brightness));
+bool snd_hda_gen_shutup_speakers(struct hda_codec *codec);
 
 #endif /* __SOUND_HDA_GENERIC_H */