Loading sound/pci/hda/Makefile +4 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o Loading @@ -12,6 +11,7 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o CFLAGS_hda_codec.o := -I$(src) CFLAGS_hda_intel.o := -I$(src) snd-hda-codec-generic-objs := hda_generic.o snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o snd-hda-codec-analog-objs := patch_analog.o Loading @@ -28,6 +28,9 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o # codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans) ifdef CONFIG_SND_HDA_GENERIC obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-generic.o endif ifdef CONFIG_SND_HDA_CODEC_REALTEK obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o endif Loading sound/pci/hda/hda_codec.c +140 −45 Original line number Diff line number Diff line Loading @@ -96,19 +96,28 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_PM #define codec_in_pm(codec) ((codec)->in_pm) static void hda_pm_work(struct work_struct *work); static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); #define hda_codec_is_power_on(codec) ((codec)->power_on) static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) { struct hda_bus *bus = codec->bus; if ((power_up && codec->pm_up_notified) || (!power_up && !codec->pm_up_notified)) return; if (bus->ops.pm_notify) bus->ops.pm_notify(bus, power_up); codec->pm_up_notified = power_up; } #else #define codec_in_pm(codec) 0 static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 #define hda_call_pm_notify(bus, state) {} #define hda_call_pm_notify(codec, state) {} #endif /** Loading Loading @@ -831,6 +840,12 @@ static int snd_hda_bus_free(struct hda_bus *bus) bus->ops.private_free(bus); if (bus->workq) destroy_workqueue(bus->workq); #ifdef CONFIG_PM if (bus->pm_wq) destroy_workqueue(bus->pm_wq); #endif kfree(bus); return 0; } Loading Loading @@ -875,6 +890,9 @@ int snd_hda_bus_new(struct snd_card *card, .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, }; #ifdef CONFIG_PM char wqname[16]; #endif if (snd_BUG_ON(!temp)) return -EINVAL; Loading Loading @@ -911,6 +929,16 @@ int snd_hda_bus_new(struct snd_card *card, return -ENOMEM; } #ifdef CONFIG_PM sprintf(wqname, "hda-pm-wq-%d", card->number); bus->pm_wq = create_workqueue(wqname); if (!bus->pm_wq) { snd_printk(KERN_ERR "cannot create PM workqueue\n"); snd_hda_bus_free(bus); return -ENOMEM; } #endif err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); if (err < 0) { snd_hda_bus_free(bus); Loading Loading @@ -945,9 +973,6 @@ find_codec_preset(struct hda_codec *codec) const struct hda_codec_preset *preset; unsigned int mod_requested = 0; if (is_generic_config(codec)) return NULL; /* use the generic parser */ again: mutex_lock(&preset_mutex); list_for_each_entry(tbl, &hda_preset_tables, list) { Loading Loading @@ -1329,6 +1354,28 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) return p; } /* * Dynamic symbol binding for the codec parsers */ #ifdef MODULE #define load_parser_sym(sym) ((int (*)(struct hda_codec *))symbol_request(sym)) #define unload_parser_addr(addr) symbol_put_addr(addr) #else #define load_parser_sym(sym) (sym) #define unload_parser_addr(addr) do {} while (0) #endif #define load_parser(codec, sym) \ ((codec)->parser = load_parser_sym(sym)) static void unload_parser(struct hda_codec *codec) { if (codec->parser) { unload_parser_addr(codec->parser); codec->parser = NULL; } } /* * codec destructor */ Loading @@ -1352,10 +1399,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); #ifdef CONFIG_PM if (!codec->pm_down_notified) /* cancel leftover refcounts */ hda_call_pm_notify(codec->bus, false); #endif hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ unload_parser(codec); module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); Loading @@ -1363,6 +1408,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) kfree(codec->chip_name); kfree(codec->modelname); kfree(codec->wcaps); codec->bus->num_codecs--; kfree(codec); } Loading Loading @@ -1428,12 +1474,12 @@ int snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); INIT_DELAYED_WORK(&codec->power_work, hda_power_work); INIT_WORK(&codec->pm_work, hda_pm_work); /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. * the caller has to power down appropriatley after initialization * phase. */ hda_keep_power_on(codec); hda_call_pm_notify(bus, true); #endif if (codec->bus->modelname) { Loading @@ -1445,6 +1491,11 @@ int snd_hda_codec_new(struct hda_bus *bus, } list_add_tail(&codec->list, &bus->codec_list); bus->num_codecs++; #ifdef CONFIG_PM workqueue_set_max_active(bus->pm_wq, bus->num_codecs); #endif bus->caddr_tbl[codec_addr] = codec; codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, Loading Loading @@ -1486,11 +1537,14 @@ int snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_CLKSTOP); if (!codec->d3_stop_clk) bus->power_keep_link_on = 1; #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); #ifdef CONFIG_PM if (!codec->d3_stop_clk || !codec->epss) bus->power_keep_link_on = 1; #endif /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); Loading Loading @@ -1537,6 +1591,31 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets); #ifdef CONFIG_SND_HDA_CODEC_HDMI /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ static bool is_likely_hdmi_codec(struct hda_codec *codec) { hda_nid_t nid = codec->start_nid; int i; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); switch (get_wcaps_type(wcaps)) { case AC_WID_AUD_IN: return false; /* HDMI parser supports only HDMI out */ case AC_WID_AUD_OUT: if (!(wcaps & AC_WCAP_DIGITAL)) return false; break; } } return true; } #else /* no HDMI codec parser support */ #define is_likely_hdmi_codec(codec) false #endif /* CONFIG_SND_HDA_CODEC_HDMI */ /** * snd_hda_codec_configure - (Re-)configure the HD-audio codec * @codec: the HDA codec Loading @@ -1548,6 +1627,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets); */ int snd_hda_codec_configure(struct hda_codec *codec) { int (*patch)(struct hda_codec *) = NULL; int err; codec->preset = find_codec_preset(codec); Loading @@ -1557,29 +1637,40 @@ int snd_hda_codec_configure(struct hda_codec *codec) return err; } if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); goto patched; if (!is_generic_config(codec) && codec->preset) patch = codec->preset->patch; if (!patch) { unload_parser(codec); /* to be sure */ if (is_likely_hdmi_codec(codec)) patch = load_parser(codec, snd_hda_parse_hdmi_codec); #ifdef CONFIG_SND_HDA_GENERIC if (!patch) patch = load_parser(codec, snd_hda_parse_generic_codec); #endif if (!patch) { printk(KERN_ERR "hda-codec: No codec parser is available\n"); return -ENODEV; } if (codec->preset && codec->preset->patch) { err = codec->preset->patch(codec); goto patched; } /* call the default parser */ err = snd_hda_parse_generic_codec(codec); if (err < 0) printk(KERN_ERR "hda-codec: No codec parser is available\n"); err = patch(codec); if (err < 0) { unload_parser(codec); return err; } patched: if (!err && codec->patch_ops.unsol_event) if (codec->patch_ops.unsol_event) { err = init_unsol_queue(codec->bus); if (err < 0) return err; } /* audio codec should override the mixer name */ if (!err && (codec->afg || !*codec->bus->card->mixername)) if (codec->afg || !*codec->bus->card->mixername) snprintf(codec->bus->card->mixername, sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); return err; return 0; } EXPORT_SYMBOL_HDA(snd_hda_codec_configure); Loading Loading @@ -2610,6 +2701,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) codec->preset = NULL; codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; unload_parser(codec); module_put(codec->owner); codec->owner = NULL; Loading Loading @@ -4000,10 +4092,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) * in the resume / power-save sequence */ hda_keep_power_on(codec); if (codec->pm_down_notified) { codec->pm_down_notified = 0; hda_call_pm_notify(codec->bus, true); } hda_set_power_state(codec, AC_PWRST_D0); restore_shutup_pins(codec); hda_exec_init_verbs(codec); Loading Loading @@ -4877,11 +4965,8 @@ static void hda_power_work(struct work_struct *work) spin_unlock(&codec->power_lock); state = hda_call_codec_suspend(codec, true); if (!codec->pm_down_notified && !bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) { codec->pm_down_notified = 1; hda_call_pm_notify(bus, false); } if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) hda_call_pm_notify(codec, false); } static void hda_keep_power_on(struct hda_codec *codec) Loading @@ -4891,6 +4976,7 @@ static void hda_keep_power_on(struct hda_codec *codec) codec->power_on = 1; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); hda_call_pm_notify(codec, true); } /* update the power on/off account with the current jiffies */ Loading @@ -4910,8 +4996,6 @@ void snd_hda_update_power_acct(struct hda_codec *codec) /* call this with codec->power_lock held! */ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) { struct hda_bus *bus = codec->bus; /* Return if power_on or transitioning to power_on, unless currently * powering down. */ if ((codec->power_on || codec->power_transition > 0) && Loading @@ -4938,11 +5022,6 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) codec->power_transition = 1; /* avoid reentrance */ spin_unlock(&codec->power_lock); if (codec->pm_down_notified) { codec->pm_down_notified = 0; hda_call_pm_notify(bus, true); } hda_call_codec_resume(codec); spin_lock(&codec->power_lock); Loading Loading @@ -5036,6 +5115,14 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, return 0; } EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); static void hda_pm_work(struct work_struct *work) { struct hda_codec *codec = container_of(work, struct hda_codec, pm_work); hda_call_codec_suspend(codec, false); } #endif /* Loading Loading @@ -5611,9 +5698,17 @@ int snd_hda_suspend(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { cancel_delayed_work_sync(&codec->jackpoll_work); if (hda_codec_is_power_on(codec)) if (hda_codec_is_power_on(codec)) { if (bus->num_codecs > 1) queue_work(bus->pm_wq, &codec->pm_work); else hda_call_codec_suspend(codec, false); } } if (bus->num_codecs > 1) flush_workqueue(bus->pm_wq); return 0; } EXPORT_SYMBOL_HDA(snd_hda_suspend); Loading sound/pci/hda/hda_codec.h +7 −1 Original line number Diff line number Diff line Loading @@ -673,6 +673,7 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; unsigned int num_codecs; /* link caddr -> codec */ struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; Loading @@ -683,6 +684,9 @@ struct hda_bus { struct hda_bus_unsolicited *unsol; char workq_name[16]; struct workqueue_struct *workq; /* common workqueue for codecs */ #ifdef CONFIG_PM struct workqueue_struct *pm_wq; /* workqueue to parallel codec PM */ #endif /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); Loading Loading @@ -834,6 +838,7 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; struct module *owner; int (*parser)(struct hda_codec *codec); const char *vendor_name; /* codec vendor name */ const char *chip_name; /* codec chip name */ const char *modelname; /* model name for preset */ Loading Loading @@ -907,7 +912,7 @@ struct hda_codec { #ifdef CONFIG_PM unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int pm_down_notified:1; /* PM notified to controller */ unsigned int pm_up_notified:1; /* PM notified to controller */ unsigned int in_pm:1; /* suspend/resume being performed */ int power_transition; /* power-state in transition */ int power_count; /* current (global) power refcount */ Loading @@ -916,6 +921,7 @@ struct hda_codec { unsigned long power_off_acct; unsigned long power_jiffies; spinlock_t power_lock; struct work_struct pm_work; /* task to parallel multi-codec PM */ #endif /* filter the requested power state per nid */ Loading sound/pci/hda/hda_generic.c +4 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include <linux/ctype.h> #include <linux/string.h> #include <linux/bitops.h> #include <linux/module.h> #include <sound/core.h> #include <sound/jack.h> #include "hda_codec.h" Loading Loading @@ -5291,3 +5292,6 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) return err; } EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic HD-audio codec parser"); sound/pci/hda/hda_intel.c +1 −1 Original line number Diff line number Diff line Loading @@ -3978,7 +3978,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, Loading Loading
sound/pci/hda/Makefile +4 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o Loading @@ -12,6 +11,7 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o CFLAGS_hda_codec.o := -I$(src) CFLAGS_hda_intel.o := -I$(src) snd-hda-codec-generic-objs := hda_generic.o snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o snd-hda-codec-analog-objs := patch_analog.o Loading @@ -28,6 +28,9 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o # codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans) ifdef CONFIG_SND_HDA_GENERIC obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-generic.o endif ifdef CONFIG_SND_HDA_CODEC_REALTEK obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o endif Loading
sound/pci/hda/hda_codec.c +140 −45 Original line number Diff line number Diff line Loading @@ -96,19 +96,28 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_PM #define codec_in_pm(codec) ((codec)->in_pm) static void hda_pm_work(struct work_struct *work); static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); #define hda_codec_is_power_on(codec) ((codec)->power_on) static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) { struct hda_bus *bus = codec->bus; if ((power_up && codec->pm_up_notified) || (!power_up && !codec->pm_up_notified)) return; if (bus->ops.pm_notify) bus->ops.pm_notify(bus, power_up); codec->pm_up_notified = power_up; } #else #define codec_in_pm(codec) 0 static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 #define hda_call_pm_notify(bus, state) {} #define hda_call_pm_notify(codec, state) {} #endif /** Loading Loading @@ -831,6 +840,12 @@ static int snd_hda_bus_free(struct hda_bus *bus) bus->ops.private_free(bus); if (bus->workq) destroy_workqueue(bus->workq); #ifdef CONFIG_PM if (bus->pm_wq) destroy_workqueue(bus->pm_wq); #endif kfree(bus); return 0; } Loading Loading @@ -875,6 +890,9 @@ int snd_hda_bus_new(struct snd_card *card, .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, }; #ifdef CONFIG_PM char wqname[16]; #endif if (snd_BUG_ON(!temp)) return -EINVAL; Loading Loading @@ -911,6 +929,16 @@ int snd_hda_bus_new(struct snd_card *card, return -ENOMEM; } #ifdef CONFIG_PM sprintf(wqname, "hda-pm-wq-%d", card->number); bus->pm_wq = create_workqueue(wqname); if (!bus->pm_wq) { snd_printk(KERN_ERR "cannot create PM workqueue\n"); snd_hda_bus_free(bus); return -ENOMEM; } #endif err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); if (err < 0) { snd_hda_bus_free(bus); Loading Loading @@ -945,9 +973,6 @@ find_codec_preset(struct hda_codec *codec) const struct hda_codec_preset *preset; unsigned int mod_requested = 0; if (is_generic_config(codec)) return NULL; /* use the generic parser */ again: mutex_lock(&preset_mutex); list_for_each_entry(tbl, &hda_preset_tables, list) { Loading Loading @@ -1329,6 +1354,28 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) return p; } /* * Dynamic symbol binding for the codec parsers */ #ifdef MODULE #define load_parser_sym(sym) ((int (*)(struct hda_codec *))symbol_request(sym)) #define unload_parser_addr(addr) symbol_put_addr(addr) #else #define load_parser_sym(sym) (sym) #define unload_parser_addr(addr) do {} while (0) #endif #define load_parser(codec, sym) \ ((codec)->parser = load_parser_sym(sym)) static void unload_parser(struct hda_codec *codec) { if (codec->parser) { unload_parser_addr(codec->parser); codec->parser = NULL; } } /* * codec destructor */ Loading @@ -1352,10 +1399,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); #ifdef CONFIG_PM if (!codec->pm_down_notified) /* cancel leftover refcounts */ hda_call_pm_notify(codec->bus, false); #endif hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ unload_parser(codec); module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); Loading @@ -1363,6 +1408,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) kfree(codec->chip_name); kfree(codec->modelname); kfree(codec->wcaps); codec->bus->num_codecs--; kfree(codec); } Loading Loading @@ -1428,12 +1474,12 @@ int snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); INIT_DELAYED_WORK(&codec->power_work, hda_power_work); INIT_WORK(&codec->pm_work, hda_pm_work); /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. * the caller has to power down appropriatley after initialization * phase. */ hda_keep_power_on(codec); hda_call_pm_notify(bus, true); #endif if (codec->bus->modelname) { Loading @@ -1445,6 +1491,11 @@ int snd_hda_codec_new(struct hda_bus *bus, } list_add_tail(&codec->list, &bus->codec_list); bus->num_codecs++; #ifdef CONFIG_PM workqueue_set_max_active(bus->pm_wq, bus->num_codecs); #endif bus->caddr_tbl[codec_addr] = codec; codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, Loading Loading @@ -1486,11 +1537,14 @@ int snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_CLKSTOP); if (!codec->d3_stop_clk) bus->power_keep_link_on = 1; #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); #ifdef CONFIG_PM if (!codec->d3_stop_clk || !codec->epss) bus->power_keep_link_on = 1; #endif /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); Loading Loading @@ -1537,6 +1591,31 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets); #ifdef CONFIG_SND_HDA_CODEC_HDMI /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ static bool is_likely_hdmi_codec(struct hda_codec *codec) { hda_nid_t nid = codec->start_nid; int i; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); switch (get_wcaps_type(wcaps)) { case AC_WID_AUD_IN: return false; /* HDMI parser supports only HDMI out */ case AC_WID_AUD_OUT: if (!(wcaps & AC_WCAP_DIGITAL)) return false; break; } } return true; } #else /* no HDMI codec parser support */ #define is_likely_hdmi_codec(codec) false #endif /* CONFIG_SND_HDA_CODEC_HDMI */ /** * snd_hda_codec_configure - (Re-)configure the HD-audio codec * @codec: the HDA codec Loading @@ -1548,6 +1627,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets); */ int snd_hda_codec_configure(struct hda_codec *codec) { int (*patch)(struct hda_codec *) = NULL; int err; codec->preset = find_codec_preset(codec); Loading @@ -1557,29 +1637,40 @@ int snd_hda_codec_configure(struct hda_codec *codec) return err; } if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); goto patched; if (!is_generic_config(codec) && codec->preset) patch = codec->preset->patch; if (!patch) { unload_parser(codec); /* to be sure */ if (is_likely_hdmi_codec(codec)) patch = load_parser(codec, snd_hda_parse_hdmi_codec); #ifdef CONFIG_SND_HDA_GENERIC if (!patch) patch = load_parser(codec, snd_hda_parse_generic_codec); #endif if (!patch) { printk(KERN_ERR "hda-codec: No codec parser is available\n"); return -ENODEV; } if (codec->preset && codec->preset->patch) { err = codec->preset->patch(codec); goto patched; } /* call the default parser */ err = snd_hda_parse_generic_codec(codec); if (err < 0) printk(KERN_ERR "hda-codec: No codec parser is available\n"); err = patch(codec); if (err < 0) { unload_parser(codec); return err; } patched: if (!err && codec->patch_ops.unsol_event) if (codec->patch_ops.unsol_event) { err = init_unsol_queue(codec->bus); if (err < 0) return err; } /* audio codec should override the mixer name */ if (!err && (codec->afg || !*codec->bus->card->mixername)) if (codec->afg || !*codec->bus->card->mixername) snprintf(codec->bus->card->mixername, sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); return err; return 0; } EXPORT_SYMBOL_HDA(snd_hda_codec_configure); Loading Loading @@ -2610,6 +2701,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) codec->preset = NULL; codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; unload_parser(codec); module_put(codec->owner); codec->owner = NULL; Loading Loading @@ -4000,10 +4092,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) * in the resume / power-save sequence */ hda_keep_power_on(codec); if (codec->pm_down_notified) { codec->pm_down_notified = 0; hda_call_pm_notify(codec->bus, true); } hda_set_power_state(codec, AC_PWRST_D0); restore_shutup_pins(codec); hda_exec_init_verbs(codec); Loading Loading @@ -4877,11 +4965,8 @@ static void hda_power_work(struct work_struct *work) spin_unlock(&codec->power_lock); state = hda_call_codec_suspend(codec, true); if (!codec->pm_down_notified && !bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) { codec->pm_down_notified = 1; hda_call_pm_notify(bus, false); } if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) hda_call_pm_notify(codec, false); } static void hda_keep_power_on(struct hda_codec *codec) Loading @@ -4891,6 +4976,7 @@ static void hda_keep_power_on(struct hda_codec *codec) codec->power_on = 1; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); hda_call_pm_notify(codec, true); } /* update the power on/off account with the current jiffies */ Loading @@ -4910,8 +4996,6 @@ void snd_hda_update_power_acct(struct hda_codec *codec) /* call this with codec->power_lock held! */ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) { struct hda_bus *bus = codec->bus; /* Return if power_on or transitioning to power_on, unless currently * powering down. */ if ((codec->power_on || codec->power_transition > 0) && Loading @@ -4938,11 +5022,6 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) codec->power_transition = 1; /* avoid reentrance */ spin_unlock(&codec->power_lock); if (codec->pm_down_notified) { codec->pm_down_notified = 0; hda_call_pm_notify(bus, true); } hda_call_codec_resume(codec); spin_lock(&codec->power_lock); Loading Loading @@ -5036,6 +5115,14 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, return 0; } EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); static void hda_pm_work(struct work_struct *work) { struct hda_codec *codec = container_of(work, struct hda_codec, pm_work); hda_call_codec_suspend(codec, false); } #endif /* Loading Loading @@ -5611,9 +5698,17 @@ int snd_hda_suspend(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { cancel_delayed_work_sync(&codec->jackpoll_work); if (hda_codec_is_power_on(codec)) if (hda_codec_is_power_on(codec)) { if (bus->num_codecs > 1) queue_work(bus->pm_wq, &codec->pm_work); else hda_call_codec_suspend(codec, false); } } if (bus->num_codecs > 1) flush_workqueue(bus->pm_wq); return 0; } EXPORT_SYMBOL_HDA(snd_hda_suspend); Loading
sound/pci/hda/hda_codec.h +7 −1 Original line number Diff line number Diff line Loading @@ -673,6 +673,7 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; unsigned int num_codecs; /* link caddr -> codec */ struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; Loading @@ -683,6 +684,9 @@ struct hda_bus { struct hda_bus_unsolicited *unsol; char workq_name[16]; struct workqueue_struct *workq; /* common workqueue for codecs */ #ifdef CONFIG_PM struct workqueue_struct *pm_wq; /* workqueue to parallel codec PM */ #endif /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); Loading Loading @@ -834,6 +838,7 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; struct module *owner; int (*parser)(struct hda_codec *codec); const char *vendor_name; /* codec vendor name */ const char *chip_name; /* codec chip name */ const char *modelname; /* model name for preset */ Loading Loading @@ -907,7 +912,7 @@ struct hda_codec { #ifdef CONFIG_PM unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int pm_down_notified:1; /* PM notified to controller */ unsigned int pm_up_notified:1; /* PM notified to controller */ unsigned int in_pm:1; /* suspend/resume being performed */ int power_transition; /* power-state in transition */ int power_count; /* current (global) power refcount */ Loading @@ -916,6 +921,7 @@ struct hda_codec { unsigned long power_off_acct; unsigned long power_jiffies; spinlock_t power_lock; struct work_struct pm_work; /* task to parallel multi-codec PM */ #endif /* filter the requested power state per nid */ Loading
sound/pci/hda/hda_generic.c +4 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include <linux/ctype.h> #include <linux/string.h> #include <linux/bitops.h> #include <linux/module.h> #include <sound/core.h> #include <sound/jack.h> #include "hda_codec.h" Loading Loading @@ -5291,3 +5292,6 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) return err; } EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic HD-audio codec parser");
sound/pci/hda/hda_intel.c +1 −1 Original line number Diff line number Diff line Loading @@ -3978,7 +3978,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, Loading