}
EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps);
-/* read or sync the hash value with the current value;
- * call within hash_mutex
- */
-static struct hda_amp_info *
-update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
- int direction, int index, bool init_only)
-{
- struct hda_amp_info *info;
- unsigned int parm, val = 0;
- bool val_read = false;
-
- retry:
- info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
- if (!info)
- return NULL;
- if (!(info->head.val & INFO_AMP_VOL(ch))) {
- if (!val_read) {
- mutex_unlock(&codec->hash_mutex);
- parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
- parm |= direction == HDA_OUTPUT ?
- AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
- parm |= index;
- val = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_AMP_GAIN_MUTE, parm);
- val &= 0xff;
- val_read = true;
- mutex_lock(&codec->hash_mutex);
- goto retry;
- }
- info->vol[ch] = val;
- info->head.val |= INFO_AMP_VOL(ch);
- } else if (init_only)
- return NULL;
- return info;
-}
-
-/*
- * write the current volume in info to the h/w
- */
-static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps,
- hda_nid_t nid, int ch, int direction, int index,
- int val)
-{
- u32 parm;
-
- parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
- parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
- parm |= index << AC_AMP_SET_INDEX_SHIFT;
- if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) &&
- (amp_caps & AC_AMPCAP_MIN_MUTE))
- ; /* set the zero value as a fake mute */
- else
- parm |= val;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
-}
-
-/**
- * snd_hda_codec_amp_read - Read AMP value
- * @codec: HD-audio codec
- * @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @index: the index value (only for input direction)
- *
- * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
- */
-int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
- int direction, int index)
-{
- struct hda_amp_info *info;
- unsigned int val = 0;
-
- mutex_lock(&codec->hash_mutex);
- info = update_amp_hash(codec, nid, ch, direction, index, false);
- if (info)
- val = info->vol[ch];
- mutex_unlock(&codec->hash_mutex);
- return val;
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read);
-
-static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
- int direction, int idx, int mask, int val,
- bool init_only, bool cache_only)
-{
- struct hda_amp_info *info;
- unsigned int caps;
-
- if (snd_BUG_ON(mask & ~0xff))
- mask &= 0xff;
- val &= mask;
-
- mutex_lock(&codec->hash_mutex);
- info = update_amp_hash(codec, nid, ch, direction, idx, init_only);
- if (!info) {
- mutex_unlock(&codec->hash_mutex);
- return 0;
- }
- val |= info->vol[ch] & ~mask;
- if (info->vol[ch] == val) {
- mutex_unlock(&codec->hash_mutex);
- return 0;
- }
- info->vol[ch] = val;
- info->head.dirty |= cache_only;
- caps = info->amp_caps;
- mutex_unlock(&codec->hash_mutex);
- if (!cache_only)
- put_vol_mute(codec, caps, nid, ch, direction, idx, val);
- return 1;
-}
-
-/**
- * snd_hda_codec_amp_update - update the AMP value
- * @codec: HD-audio codec
- * @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @idx: the index value (only for input direction)
- * @mask: bit mask to set
- * @val: the bits value to set
- *
- * Update the AMP value with a bit mask.
- * Returns 0 if the value is unchanged, 1 if changed.
- */
-int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
- int direction, int idx, int mask, int val)
-{
- return codec_amp_update(codec, nid, ch, direction, idx, mask, val,
- false, codec->cached_write);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
-
/**
* snd_hda_codec_amp_stereo - update the AMP stereo values
* @codec: HD-audio codec
int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
int dir, int idx, int mask, int val)
{
- return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true,
- codec->cached_write);
+ int orig;
+
+ if (!codec->core.regmap)
+ return -EINVAL;
+ regcache_cache_only(codec->core.regmap, true);
+ orig = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
+ regcache_cache_only(codec->core.regmap, false);
+ if (orig >= 0)
+ return 0;
+ return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val);
}
EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
}
EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo);
-/**
- * snd_hda_codec_resume_amp - Resume all AMP commands from the cache
- * @codec: HD-audio codec
- *
- * Resume the all amp commands from the cache.
- */
-void snd_hda_codec_resume_amp(struct hda_codec *codec)
-{
- int i;
-
- mutex_lock(&codec->hash_mutex);
- codec->cached_write = 0;
- for (i = 0; i < codec->amp_cache.buf.used; i++) {
- struct hda_amp_info *buffer;
- u32 key;
- hda_nid_t nid;
- unsigned int idx, dir, ch;
- struct hda_amp_info info;
-
- buffer = snd_array_elem(&codec->amp_cache.buf, i);
- if (!buffer->head.dirty)
- continue;
- buffer->head.dirty = 0;
- info = *buffer;
- key = info.head.key;
- if (!key)
- continue;
- nid = key & 0xff;
- idx = (key >> 16) & 0xff;
- dir = (key >> 24) & 0xff;
- for (ch = 0; ch < 2; ch++) {
- if (!(info.head.val & INFO_AMP_VOL(ch)))
- continue;
- mutex_unlock(&codec->hash_mutex);
- put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx,
- info.vol[ch]);
- mutex_lock(&codec->hash_mutex);
- }
- }
- mutex_unlock(&codec->hash_mutex);
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp);
-
static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int ofs)
{
maxval = get_amp_max_value(codec, nid, dir, 0);
if (val > maxval)
val = maxval;
- return codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val,
- false, !hda_codec_is_power_on(codec));
+ return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
+ HDA_AMP_VOLMASK, val);
}
/**
int change = 0;
if (chs & 1) {
- change = codec_amp_update(codec, nid, 0, dir, idx,
- HDA_AMP_MUTE,
- *valp ? 0 : HDA_AMP_MUTE, false,
- !hda_codec_is_power_on(codec));
+ change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+ HDA_AMP_MUTE,
+ *valp ? 0 : HDA_AMP_MUTE);
valp++;
}
if (chs & 2)
- change |= codec_amp_update(codec, nid, 1, dir, idx,
- HDA_AMP_MUTE,
- *valp ? 0 : HDA_AMP_MUTE, false,
- !hda_codec_is_power_on(codec));
+ change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
+ HDA_AMP_MUTE,
+ *valp ? 0 : HDA_AMP_MUTE);
hda_call_check_power_status(codec, nid);
return change;
}
*/
void snd_hda_codec_flush_cache(struct hda_codec *codec)
{
- snd_hda_codec_resume_amp(codec);
+ if (codec->core.regmap)
+ regcache_sync(codec->core.regmap);
snd_hda_codec_resume_cache(codec);
}
EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache);
{
atomic_inc(&codec->core.in_pm);
+ if (codec->core.regmap)
+ regcache_mark_dirty(codec->core.regmap);
+
hda_mark_cmd_cache_dirty(codec);
codec->power_jiffies = jiffies;
else {
if (codec->patch_ops.init)
codec->patch_ops.init(codec);
- snd_hda_codec_resume_amp(codec);
+ if (codec->core.regmap)
+ regcache_sync(codec->core.regmap);
snd_hda_codec_resume_cache(codec);
}
struct snd_ctl_elem_value *ucontrol);
#endif
/* lowlevel accessor with caching; use carefully */
-int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
- int direction, int index);
-int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
- int direction, int idx, int mask, int val);
+#define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \
+ snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx)
+#define snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val) \
+ snd_hdac_regmap_update_amp(&(codec)->core, nid, ch, dir, idx, mask, val)
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
-void snd_hda_codec_resume_amp(struct hda_codec *codec);
-
void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int *tlv);
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,