static bool hda_volatile_reg(struct device *dev, unsigned int reg)
{
+ struct hdac_device *codec = dev_to_hdac_dev(dev);
unsigned int verb = get_verb(reg);
switch (verb) {
case AC_VERB_GET_PROC_COEF:
+ return !codec->cache_coef;
case AC_VERB_GET_COEF_INDEX:
case AC_VERB_GET_PROC_STATE:
case AC_VERB_GET_POWER_STATE:
case AC_VERB_GET_STREAM_FORMAT:
case AC_VERB_GET_AMP_GAIN_MUTE:
return true;
+ case AC_VERB_GET_PROC_COEF:
+ return codec->cache_coef;
case 0xf00:
break;
default:
switch (verb) {
case AC_VERB_GET_CONNECT_SEL:
case AC_VERB_GET_SDI_SELECT:
- case AC_VERB_GET_CONV:
case AC_VERB_GET_PIN_WIDGET_CONTROL:
case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */
case AC_VERB_GET_BEEP_CONTROL:
case AC_VERB_GET_DIGI_CONVERT_1:
case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */
case AC_VERB_GET_VOLUME_KNOB_CONTROL:
- case AC_VERB_GET_CONFIG_DEFAULT:
case AC_VERB_GET_GPIO_MASK:
case AC_VERB_GET_GPIO_DIRECTION:
case AC_VERB_GET_GPIO_DATA: /* not for volatile read */
case AC_VERB_GET_GPIO_WAKE_MASK:
case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK:
case AC_VERB_GET_GPIO_STICKY_MASK:
- case AC_VERB_GET_CVT_CHAN_COUNT:
return true;
}
case AC_VERB_GET_CONNECT_LIST:
case AC_VERB_GET_SUBSYSTEM_ID:
return true;
+ /* below are basically writable, but disabled for reducing unnecessary
+ * writes at sync
+ */
+ case AC_VERB_GET_CONFIG_DEFAULT: /* usually just read */
+ case AC_VERB_GET_CONV: /* managed in PCM code */
+ case AC_VERB_GET_CVT_CHAN_COUNT: /* managed in HDMI CA code */
+ return true;
}
return hda_writeable_reg(dev, reg);
return 0;
}
+/* read a pseudo coef register (16bit) */
+static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg,
+ unsigned int *val)
+{
+ unsigned int verb;
+ int err;
+
+ if (!codec->cache_coef)
+ return -EINVAL;
+ /* LSB 8bit = coef index */
+ verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
+ err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+ if (err < 0)
+ return err;
+ verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8);
+ return snd_hdac_exec_verb(codec, verb, 0, val);
+}
+
+/* write a pseudo coef register (16bit) */
+static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg,
+ unsigned int val)
+{
+ unsigned int verb;
+ int err;
+
+ if (!codec->cache_coef)
+ return -EINVAL;
+ /* LSB 8bit = coef index */
+ verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
+ err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+ if (err < 0)
+ return err;
+ verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) |
+ (val & 0xffff);
+ return snd_hdac_exec_verb(codec, verb, 0, NULL);
+}
+
static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct hdac_device *codec = context;
+ int verb = get_verb(reg);
int err;
- if (!codec_is_running(codec))
+ if (!codec_is_running(codec) && verb != AC_VERB_GET_POWER_STATE)
return -EAGAIN;
reg |= (codec->addr << 28);
if (is_stereo_amp_verb(reg))
return hda_reg_read_stereo_amp(codec, reg, val);
+ if (verb == AC_VERB_GET_PROC_COEF)
+ return hda_reg_read_coef(codec, reg, val);
err = snd_hdac_exec_verb(codec, reg, 0, val);
if (err < 0)
return err;
/* special handling for asymmetric reads */
- if (get_verb(reg) == AC_VERB_GET_POWER_STATE) {
+ if (verb == AC_VERB_GET_POWER_STATE) {
if (*val & AC_PWRST_ERROR)
*val = -1;
else /* take only the actual state */
unsigned int verb;
int i, bytes, err;
- if (!codec_is_running(codec))
- return codec->lazy_cache ? 0 : -EAGAIN;
-
reg &= ~0x00080000U; /* drop GET bit */
reg |= (codec->addr << 28);
+ verb = get_verb(reg);
+
+ if (!codec_is_running(codec) && verb != AC_VERB_SET_POWER_STATE)
+ return codec->lazy_cache ? 0 : -EAGAIN;
if (is_stereo_amp_verb(reg))
return hda_reg_write_stereo_amp(codec, reg, val);
- verb = get_verb(reg);
+ if (verb == AC_VERB_SET_PROC_COEF)
+ return hda_reg_write_coef(codec, reg, val);
+
switch (verb & 0xf00) {
case AC_VERB_SET_AMP_GAIN_MUTE:
verb = AC_VERB_SET_AMP_GAIN_MUTE;
.cache_type = REGCACHE_RBTREE,
.reg_read = hda_reg_read,
.reg_write = hda_reg_write,
+ .use_single_rw = true,
};
int snd_hdac_regmap_init(struct hdac_device *codec)
if (!p)
return -ENOMEM;
- *p = verb;
+ *p = verb | 0x800; /* set GET bit */
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
err = reg_raw_write(codec, reg, val);
if (err == -EAGAIN) {
- snd_hdac_power_up(codec);
+ snd_hdac_power_up_pm(codec);
err = reg_raw_write(codec, reg, val);
- snd_hdac_power_down(codec);
+ snd_hdac_power_down_pm(codec);
}
return err;
}
err = reg_raw_read(codec, reg, val);
if (err == -EAGAIN) {
- snd_hdac_power_up(codec);
+ snd_hdac_power_up_pm(codec);
err = reg_raw_read(codec, reg, val);
- snd_hdac_power_down(codec);
+ snd_hdac_power_down_pm(codec);
}
return err;
}