From patchwork Wed Mar 18 08:50:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 6037051 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 562C0BF90F for ; Wed, 18 Mar 2015 08:51:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 63E7B204E7 for ; Wed, 18 Mar 2015 08:51:45 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 02C49204D9 for ; Wed, 18 Mar 2015 08:51:43 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 22AFD26071C; Wed, 18 Mar 2015 09:51:43 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,NO_DNS_FOR_FROM, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 37D5C2604DE; Wed, 18 Mar 2015 09:51:12 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9C0032604F3; Wed, 18 Mar 2015 09:51:11 +0100 (CET) Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by alsa0.perex.cz (Postfix) with ESMTP id 5D70C2604F4 for ; Wed, 18 Mar 2015 09:51:01 +0100 (CET) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 621FBAC46; Wed, 18 Mar 2015 08:51:00 +0000 (UTC) From: Takashi Iwai To: alsa-devel@alsa-project.org Date: Wed, 18 Mar 2015 09:50:58 +0100 Message-Id: <1426668658-15911-5-git-send-email-tiwai@suse.de> X-Mailer: git-send-email 2.3.3 In-Reply-To: <1426668658-15911-1-git-send-email-tiwai@suse.de> References: <1426668658-15911-1-git-send-email-tiwai@suse.de> Cc: David Henningsson Subject: [alsa-devel] [PATCH 4/4] ALSA: hda - Adjust power of beep widget and outputs X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP As the widget PM may turn off the pins, this might lead to the silent output for beep when no explicit paths are given. This patch adds fake output paths for the beep widget so that the output pins are dynamically powered upon beep on/off. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 29 ++++++++++--------- sound/pci/hda/hda_beep.h | 1 + sound/pci/hda/hda_generic.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 581b7fdef0e3..4cdac3a71cae 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -33,30 +33,36 @@ enum { DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ }; -static void snd_hda_generate_beep(struct work_struct *work) +/* generate or stop tone */ +static void generate_tone(struct hda_beep *beep, int tone) { - struct hda_beep *beep = - container_of(work, struct hda_beep, beep_work); struct hda_codec *codec = beep->codec; - int tone; - if (!beep->enabled) - return; - - tone = beep->tone; if (tone && !beep->playing) { snd_hda_power_up(codec); + if (beep->power_hook) + beep->power_hook(beep, true); beep->playing = 1; } - /* generate tone */ snd_hda_codec_write(codec, beep->nid, 0, AC_VERB_SET_BEEP_CONTROL, tone); if (!tone && beep->playing) { beep->playing = 0; + if (beep->power_hook) + beep->power_hook(beep, false); snd_hda_power_down(codec); } } +static void snd_hda_generate_beep(struct work_struct *work) +{ + struct hda_beep *beep = + container_of(work, struct hda_beep, beep_work); + + if (beep->enabled) + generate_tone(beep, beep->tone); +} + /* (non-standard) Linear beep tone calculation for IDT/STAC codecs * * The tone frequency of beep generator on IDT/STAC codecs is @@ -130,10 +136,7 @@ static void turn_off_beep(struct hda_beep *beep) cancel_work_sync(&beep->beep_work); if (beep->playing) { /* turn off beep */ - snd_hda_codec_write(beep->codec, beep->nid, 0, - AC_VERB_SET_BEEP_CONTROL, 0); - beep->playing = 0; - snd_hda_power_down(beep->codec); + generate_tone(beep, 0); } } diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index a63b5e077332..46524ff7e79e 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -40,6 +40,7 @@ struct hda_beep { unsigned int playing:1; struct work_struct beep_work; /* scheduled task for beep event */ struct mutex mutex; + void (*power_hook)(struct hda_beep *beep, bool on); }; #ifdef CONFIG_SND_HDA_INPUT_BEEP diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 8a5055d296f5..d7ca388651da 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -654,6 +654,9 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, int type = get_wcaps_type(get_wcaps(codec, nid)); int i, n; + if (nid == codec->afg) + return true; + for (n = 0; n < spec->paths.used; n++) { struct nid_path *path = snd_array_elem(&spec->paths, n); if (!path->active) @@ -829,6 +832,8 @@ static hda_nid_t path_power_update(struct hda_codec *codec, for (i = 0; i < path->depth; i++) { nid = path->path[i]; + if (nid == codec->afg) + continue; if (!allow_powerdown || is_active_nid_for_any(codec, nid)) state = AC_PWRST_D0; else @@ -4073,6 +4078,64 @@ static void sync_all_pin_power_ctls(struct hda_codec *codec) sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin); } +/* add fake paths if not present yet */ +static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid, + int num_pins, const hda_nid_t *pins) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i; + + for (i = 0; i < num_pins; i++) { + if (!pins[i]) + break; + if (get_nid_path(codec, nid, pins[i], 0)) + continue; + path = snd_array_new(&spec->paths); + if (!path) + return -ENOMEM; + memset(path, 0, sizeof(*path)); + path->depth = 2; + path->path[0] = nid; + path->path[1] = pins[i]; + path->active = true; + } + return 0; +} + +/* create fake paths to all outputs from beep */ +static int add_fake_beep_paths(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid = spec->beep_nid; + int err; + + if (!codec->power_mgmt || !nid) + return 0; + err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = add_fake_paths(codec, nid, cfg->speaker_outs, + cfg->speaker_pins); + if (err < 0) + return err; + } + return 0; +} + +/* power up/down beep widget and its output paths */ +static void beep_power_hook(struct hda_beep *beep, bool on) +{ + set_path_power(beep->codec, beep->nid, -1, on); +} + /* * Jack detections for HP auto-mute and mic-switch */ @@ -4837,6 +4900,12 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, err = snd_hda_attach_beep_device(codec, spec->beep_nid); if (err < 0) return err; + if (codec->beep && codec->power_mgmt) { + err = add_fake_beep_paths(codec); + if (err < 0) + return err; + codec->beep->power_hook = beep_power_hook; + } } return 1;