#include <linux/jiffies.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_supply] = 1,
+ [snd_soc_dapm_regulator_supply] = 1,
[snd_soc_dapm_micbias] = 2,
[snd_soc_dapm_aif_in] = 3,
[snd_soc_dapm_aif_out] = 3,
[snd_soc_dapm_value_mux] = 9,
[snd_soc_dapm_aif_in] = 10,
[snd_soc_dapm_aif_out] = 10,
+ [snd_soc_dapm_regulator_supply] = 11,
[snd_soc_dapm_supply] = 11,
[snd_soc_dapm_post] = 12,
};
static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
unsigned short reg, unsigned int mask, unsigned int value)
{
- int change;
+ bool change;
unsigned int old, new;
int ret;
- ret = soc_widget_read(w, reg);
- if (ret < 0)
- return ret;
-
- old = ret;
- new = (old & ~mask) | (value & mask);
- change = old != new;
- if (change) {
- ret = soc_widget_write(w, reg, new);
+ if (w->codec && w->codec->using_regmap) {
+ ret = regmap_update_bits_check(w->codec->control_data,
+ reg, mask, value, &change);
+ if (ret != 0)
+ return ret;
+ } else {
+ ret = soc_widget_read(w, reg);
if (ret < 0)
return ret;
+
+ old = ret;
+ new = (old & ~mask) | (value & mask);
+ change = old != new;
+ if (change) {
+ ret = soc_widget_write(w, reg, new);
+ if (ret < 0)
+ return ret;
+ }
}
return change;
case snd_soc_dapm_micbias:
case snd_soc_dapm_vmid:
case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out:
case snd_soc_dapm_hp:
DAPM_UPDATE_STAT(widget, path_checks);
- if (widget->id == snd_soc_dapm_supply)
+ switch (widget->id) {
+ case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
return 0;
+ default:
+ break;
+ }
switch (widget->id) {
case snd_soc_dapm_adc:
DAPM_UPDATE_STAT(widget, path_checks);
- if (widget->id == snd_soc_dapm_supply)
+ switch (widget->id) {
+ case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
return 0;
+ default:
+ break;
+ }
/* active stream ? */
switch (widget->id) {
}
EXPORT_SYMBOL_GPL(dapm_reg_event);
+/*
+ * Handler for regulator supply widget.
+ */
+int dapm_regulator_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ return regulator_enable(w->priv);
+ else
+ return regulator_disable_deferred(w->priv, w->shift);
+}
+EXPORT_SYMBOL_GPL(dapm_regulator_event);
+
static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
{
if (w->power_checked)
dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
if (d->dev)
- pm_runtime_put_sync(d->dev);
+ pm_runtime_put(d->dev);
}
/* If we just powered up then move to active bias */
}
switch (w->id) {
case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
/* Supplies can't affect their outputs, only their inputs */
break;
default:
/* Supplies and micbiases only bring the
* context up to STANDBY as unless something
* else is active and passing audio they
- * generally don't require full power.
+ * generally don't require full power. Signal
+ * generators are virtual pins and have no
+ * power impact themselves.
*/
switch (w->id) {
+ case snd_soc_dapm_siggen:
+ break;
case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_micbias:
if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
d->target_bias_level = SND_SOC_BIAS_STANDBY;
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
if (w->name)
count += sprintf(buf + count, "%s: %s\n",
w->name, w->power ? "On":"Off");
case snd_soc_dapm_pre:
case snd_soc_dapm_post:
case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out:
list_add(&path->list, &dapm->card->paths);
{
struct snd_soc_dapm_widget *w;
size_t name_len;
+ int ret;
if ((w = dapm_cnew_widget(widget)) == NULL)
return -ENOMEM;
+ switch (w->id) {
+ case snd_soc_dapm_regulator_supply:
+ w->priv = devm_regulator_get(dapm->dev, w->name);
+ if (IS_ERR(w->priv)) {
+ ret = PTR_ERR(w->priv);
+ dev_err(dapm->dev, "Failed to request %s: %d\n",
+ w->name, ret);
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
name_len = strlen(widget->name) + 1;
if (dapm->codec && dapm->codec->name_prefix)
name_len += 1 + strlen(dapm->codec->name_prefix);
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_supply:
+ case snd_soc_dapm_regulator_supply:
w->power_check = dapm_supply_check_power;
break;
default: