int type = get_wcaps_type(get_wcaps(codec, nid));
int i, n;
- if (nid == codec->afg)
+ if (nid == codec->core.afg)
return true;
for (n = 0; n < spec->paths.used; n++) {
for (i = 0; i < path->depth; i++) {
nid = path->path[i];
- if (nid == codec->afg)
+ if (!(get_wcaps(codec, nid) & AC_WCAP_POWER))
+ continue;
+ if (nid == codec->core.afg)
continue;
if (!allow_powerdown || is_active_nid_for_any(codec, nid))
state = AC_PWRST_D0;
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_POWER_STATE, state);
changed = nid;
- /* here we assume that widget attributes (e.g. amp,
- * pinctl connection) don't change with local power
- * state change. If not, need to sync the cache.
- */
+ if (state == AC_PWRST_D0)
+ snd_hdac_regmap_sync_node(&codec->core, nid);
}
}
return changed;
static void fill_all_dac_nids(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
- int i;
- hda_nid_t nid = codec->start_nid;
+ hda_nid_t nid;
spec->num_all_dacs = 0;
memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
- for (i = 0; i < codec->num_nodes; i++, nid++) {
+ for_each_hda_codec_node(nid, codec) {
if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
continue;
if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
hda_nid_t nid;
hda_nid_t *adc_nids = spec->adc_nids;
int max_nums = ARRAY_SIZE(spec->adc_nids);
- int i, nums = 0;
+ int nums = 0;
- nid = codec->start_nid;
- for (i = 0; i < codec->num_nodes; i++, nid++) {
+ for_each_hda_codec_node(nid, codec) {
unsigned int caps = get_wcaps(codec, nid);
int type = get_wcaps_type(caps);
imux = &spec->input_mux;
adc_idx = kcontrol->id.index;
mutex_lock(&codec->control_mutex);
- /* we use the cache-only update at first since multiple input paths
- * may shared the same amp; by updating only caches, the redundant
- * writes to hardware can be reduced.
- */
- codec->cached_write = 1;
for (i = 0; i < imux->num_items; i++) {
path = get_input_path(codec, adc_idx, i);
if (!path || !path->ctls[type])
kcontrol->private_value = path->ctls[type];
err = func(kcontrol, ucontrol);
if (err < 0)
- goto error;
+ break;
}
- error:
- codec->cached_write = 0;
mutex_unlock(&codec->control_mutex);
- snd_hda_codec_flush_cache(codec); /* flush the updates */
if (err >= 0 && spec->cap_sync_hook)
spec->cap_sync_hook(codec, kcontrol, ucontrol);
return err;
if (spec->autocfg.dig_in_pin) {
pin = spec->autocfg.dig_in_pin;
- dig_nid = codec->start_nid;
- for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
+ for_each_hda_codec_node(dig_nid, codec) {
unsigned int wcaps = get_wcaps(codec, dig_nid);
if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
continue;
return changed;
}
+/* check the jack status for power control */
+static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin)
+{
+ if (!is_jack_detectable(codec, pin))
+ return true;
+ return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
+}
+
/* power up/down the paths of the given pin according to the jack state;
* power = 0/1 : only power up/down if it matches with the jack state,
* < 0 : force power up/down to follow the jack sate
if (!codec->power_save_node)
return 0;
- on = snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
+ on = detect_pin_state(codec, pin);
+
if (power >= 0 && on != power)
return 0;
return set_path_power(codec, pin, on, -1);
if (codec->power_save_node) {
bool on = !mute;
if (on)
- on = snd_hda_jack_detect_state(codec, nid)
- != HDA_JACK_NOT_PRESENT;
+ on = detect_pin_state(codec, nid);
set_path_power(codec, nid, on, -1);
}
}
hda_nid_t nid,
unsigned int power_state)
{
- if (power_state != AC_PWRST_D0 || nid == codec->afg)
+ struct hda_gen_spec *spec = codec->spec;
+
+ if (!spec->power_down_unused && !codec->power_save_node)
+ return power_state;
+ if (power_state != AC_PWRST_D0 || nid == codec->core.afg)
return power_state;
if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
return power_state;
parse_digital(codec);
if (spec->power_down_unused || codec->power_save_node)
- codec->power_filter = snd_hda_gen_path_power_filter;
+ if (!codec->power_filter)
+ codec->power_filter = snd_hda_gen_path_power_filter;
if (!spec->no_analog && spec->beep_nid) {
err = snd_hda_attach_beep_device(codec, spec->beep_nid);
fill_pcm_stream_name(spec->stream_name_analog,
sizeof(spec->stream_name_analog),
- " Analog", codec->chip_name);
+ " Analog", codec->core.chip_name);
info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
if (!info)
return -ENOMEM;
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
fill_pcm_stream_name(spec->stream_name_digital,
sizeof(spec->stream_name_digital),
- " Digital", codec->chip_name);
+ " Digital", codec->core.chip_name);
info = snd_hda_codec_pcm_new(codec, "%s",
spec->stream_name_digital);
if (!info)
if (spec->alt_dac_nid || have_multi_adcs) {
fill_pcm_stream_name(spec->stream_name_alt_analog,
sizeof(spec->stream_name_alt_analog),
- " Alt Analog", codec->chip_name);
+ " Alt Analog", codec->core.chip_name);
info = snd_hda_codec_pcm_new(codec, "%s",
spec->stream_name_alt_analog);
if (!info)
snd_hda_apply_verbs(codec);
- codec->cached_write = 1;
-
init_multi_out(codec);
init_extra_out(codec);
init_multi_io(codec);
/* call init functions of standard auto-mute helpers */
update_automute_all(codec);
- snd_hda_codec_flush_cache(codec);
+ regcache_sync(codec->core.regmap);
if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
snd_hda_sync_vmaster_hook(&spec->vmaster_mute);