Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0be9898a authored by Mark Brown's avatar Mark Brown Committed by Jaroslav Kysela
Browse files

[ALSA] ASoC: Clarify API for bias configuration



Currently the ASoC core configures the bias levels in the system using
a callback on codecs and machines called 'dapm_event', passing it PCI
style power levels as SNDRV_CTL_POWER_ constants. This is more obscure
than it needs to be and has caused confusion to driver authors,
especially given that DAPM is also performing power management.

Address this by renaming the callback function to 'set_bias_level' and
using constants explicitly representing the off, standby, pre-on and on
states which DAPM transitions through.

Also unexport the API for setting bias level: there are currently no
in-tree users of this API other than the core itself and it is likely
that the core would need to be extended to cater for any users.

Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Jarkko Nikula <jarkko.nikula@nokia.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
parent 1ef6ab75
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -221,7 +221,8 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
/* dapm events */
/* dapm events */
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
	int event);
	int event);
int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event);
int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
	enum snd_soc_bias_level level);


/* dapm sys fs - used by the core */
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
int snd_soc_dapm_sys_add(struct device *dev);
+24 −4
Original line number Original line Diff line number Diff line
@@ -102,6 +102,24 @@
	.get = xhandler_get, .put = xhandler_put, \
	.get = xhandler_get, .put = xhandler_put, \
	.private_value = (unsigned long)&xenum }
	.private_value = (unsigned long)&xenum }


/*
 * Bias levels
 *
 * @ON:      Bias is fully on for audio playback and capture operations.
 * @PREPARE: Prepare for audio operations. Called before DAPM switching for
 *           stream start and stop operations.
 * @STANDBY: Low power standby state when no playback/capture operations are
 *           in progress. NOTE: The transition time between STANDBY and ON
 *           should be as fast as possible and no longer than 10ms.
 * @OFF:     Power Off. No restrictions on transition times.
 */
enum snd_soc_bias_level {
	SND_SOC_BIAS_ON,
	SND_SOC_BIAS_PREPARE,
	SND_SOC_BIAS_STANDBY,
	SND_SOC_BIAS_OFF,
};

/*
/*
 * Digital Audio Interface (DAI) types
 * Digital Audio Interface (DAI) types
 */
 */
@@ -356,7 +374,8 @@ struct snd_soc_codec {
	struct mutex mutex;
	struct mutex mutex;


	/* callbacks */
	/* callbacks */
	int (*dapm_event)(struct snd_soc_codec *codec, int event);
	int (*set_bias_level)(struct snd_soc_codec *,
			      enum snd_soc_bias_level level);


	/* runtime */
	/* runtime */
	struct snd_card *card;
	struct snd_card *card;
@@ -378,8 +397,8 @@ struct snd_soc_codec {
	/* dapm */
	/* dapm */
	struct list_head dapm_widgets;
	struct list_head dapm_widgets;
	struct list_head dapm_paths;
	struct list_head dapm_paths;
	unsigned int dapm_state;
	enum snd_soc_bias_level bias_level;
	unsigned int suspend_dapm_state;
	enum snd_soc_bias_level suspend_bias_level;
	struct delayed_work delayed_work;
	struct delayed_work delayed_work;


	/* codec DAI's */
	/* codec DAI's */
@@ -449,7 +468,8 @@ struct snd_soc_machine {
	int (*resume_post)(struct platform_device *pdev);
	int (*resume_post)(struct platform_device *pdev);


	/* callbacks */
	/* callbacks */
	int (*dapm_event)(struct snd_soc_machine *, int event);
	int (*set_bias_level)(struct snd_soc_machine *,
			      enum snd_soc_bias_level level);


	/* CPU <--> Codec DAI links  */
	/* CPU <--> Codec DAI links  */
	struct snd_soc_dai_link *dai_link;
	struct snd_soc_dai_link *dai_link;
+13 −13
Original line number Original line Diff line number Diff line
@@ -847,13 +847,14 @@ static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
	return 0;
	return 0;
}
}


static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
static int aic3x_set_bias_level(struct snd_soc_codec *codec,
				enum snd_soc_bias_level level)
{
{
	struct aic3x_priv *aic3x = codec->private_data;
	struct aic3x_priv *aic3x = codec->private_data;
	u8 reg;
	u8 reg;


	switch (event) {
	switch (level) {
	case SNDRV_CTL_POWER_D0:
	case SND_SOC_BIAS_ON:
		/* all power is driven by DAPM system */
		/* all power is driven by DAPM system */
		if (aic3x->master) {
		if (aic3x->master) {
			/* enable pll */
			/* enable pll */
@@ -862,10 +863,9 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
				    reg | PLL_ENABLE);
				    reg | PLL_ENABLE);
		}
		}
		break;
		break;
	case SNDRV_CTL_POWER_D1:
	case SND_SOC_BIAS_PREPARE:
	case SNDRV_CTL_POWER_D2:
		break;
		break;
	case SNDRV_CTL_POWER_D3hot:
	case SND_SOC_BIAS_STANDBY:
		/*
		/*
		 * all power is driven by DAPM system,
		 * all power is driven by DAPM system,
		 * so output power is safe if bypass was set
		 * so output power is safe if bypass was set
@@ -877,7 +877,7 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
				    reg & ~PLL_ENABLE);
				    reg & ~PLL_ENABLE);
		}
		}
		break;
		break;
	case SNDRV_CTL_POWER_D3cold:
	case SND_SOC_BIAS_OFF:
		/* force all power off */
		/* force all power off */
		reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL);
		reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL);
		aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON);
		aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON);
@@ -913,7 +913,7 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
		}
		}
		break;
		break;
	}
	}
	codec->dapm_state = event;
	codec->bias_level = level;


	return 0;
	return 0;
}
}
@@ -979,7 +979,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec = socdev->codec;
	struct snd_soc_codec *codec = socdev->codec;


	aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
	aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);


	return 0;
	return 0;
}
}
@@ -999,7 +999,7 @@ static int aic3x_resume(struct platform_device *pdev)
		codec->hw_write(codec->control_data, data, 2);
		codec->hw_write(codec->control_data, data, 2);
	}
	}


	aic3x_dapm_event(codec, codec->suspend_dapm_state);
	aic3x_set_bias_level(codec, codec->suspend_bias_level);


	return 0;
	return 0;
}
}
@@ -1018,7 +1018,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
	codec->owner = THIS_MODULE;
	codec->owner = THIS_MODULE;
	codec->read = aic3x_read_reg_cache;
	codec->read = aic3x_read_reg_cache;
	codec->write = aic3x_write;
	codec->write = aic3x_write;
	codec->dapm_event = aic3x_dapm_event;
	codec->set_bias_level = aic3x_set_bias_level;
	codec->dai = &aic3x_dai;
	codec->dai = &aic3x_dai;
	codec->num_dai = 1;
	codec->num_dai = 1;
	codec->reg_cache_size = sizeof(aic3x_reg);
	codec->reg_cache_size = sizeof(aic3x_reg);
@@ -1100,7 +1100,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
	aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
	aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);


	/* off, with power on */
	/* off, with power on */
	aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
	aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);


	/* setup GPIO functions */
	/* setup GPIO functions */
	aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4);
	aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4);
@@ -1271,7 +1271,7 @@ static int aic3x_remove(struct platform_device *pdev)


	/* power down chip */
	/* power down chip */
	if (codec->control_data)
	if (codec->control_data)
		aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3);
		aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);


	snd_soc_free_pcms(socdev);
	snd_soc_free_pcms(socdev);
	snd_soc_dapm_free(socdev);
	snd_soc_dapm_free(socdev);
+14 −14
Original line number Original line Diff line number Diff line
@@ -435,29 +435,29 @@ static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
	return 0;
	return 0;
}
}


static int wm8731_dapm_event(struct snd_soc_codec *codec, int event)
static int wm8731_set_bias_level(struct snd_soc_codec *codec,
				 enum snd_soc_bias_level level)
{
{
	u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
	u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;


	switch (event) {
	switch (level) {
	case SNDRV_CTL_POWER_D0: /* full On */
	case SND_SOC_BIAS_ON:
		/* vref/mid, osc on, dac unmute */
		/* vref/mid, osc on, dac unmute */
		wm8731_write(codec, WM8731_PWR, reg);
		wm8731_write(codec, WM8731_PWR, reg);
		break;
		break;
	case SNDRV_CTL_POWER_D1: /* partial On */
	case SND_SOC_BIAS_PREPARE:
	case SNDRV_CTL_POWER_D2: /* partial On */
		break;
		break;
	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
	case SND_SOC_BIAS_STANDBY:
		/* everything off except vref/vmid, */
		/* everything off except vref/vmid, */
		wm8731_write(codec, WM8731_PWR, reg | 0x0040);
		wm8731_write(codec, WM8731_PWR, reg | 0x0040);
		break;
		break;
	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
	case SND_SOC_BIAS_OFF:
		/* everything off, dac mute, inactive */
		/* everything off, dac mute, inactive */
		wm8731_write(codec, WM8731_ACTIVE, 0x0);
		wm8731_write(codec, WM8731_ACTIVE, 0x0);
		wm8731_write(codec, WM8731_PWR, 0xffff);
		wm8731_write(codec, WM8731_PWR, 0xffff);
		break;
		break;
	}
	}
	codec->dapm_state = event;
	codec->bias_level = level;
	return 0;
	return 0;
}
}


@@ -503,7 +503,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
	struct snd_soc_codec *codec = socdev->codec;
	struct snd_soc_codec *codec = socdev->codec;


	wm8731_write(codec, WM8731_ACTIVE, 0x0);
	wm8731_write(codec, WM8731_ACTIVE, 0x0);
	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
	wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
	return 0;
	return 0;
}
}


@@ -521,8 +521,8 @@ static int wm8731_resume(struct platform_device *pdev)
		data[1] = cache[i] & 0x00ff;
		data[1] = cache[i] & 0x00ff;
		codec->hw_write(codec->control_data, data, 2);
		codec->hw_write(codec->control_data, data, 2);
	}
	}
	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
	wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	wm8731_dapm_event(codec, codec->suspend_dapm_state);
	wm8731_set_bias_level(codec, codec->suspend_bias_level);
	return 0;
	return 0;
}
}


@@ -539,7 +539,7 @@ static int wm8731_init(struct snd_soc_device *socdev)
	codec->owner = THIS_MODULE;
	codec->owner = THIS_MODULE;
	codec->read = wm8731_read_reg_cache;
	codec->read = wm8731_read_reg_cache;
	codec->write = wm8731_write;
	codec->write = wm8731_write;
	codec->dapm_event = wm8731_dapm_event;
	codec->set_bias_level = wm8731_set_bias_level;
	codec->dai = &wm8731_dai;
	codec->dai = &wm8731_dai;
	codec->num_dai = 1;
	codec->num_dai = 1;
	codec->reg_cache_size = sizeof(wm8731_reg);
	codec->reg_cache_size = sizeof(wm8731_reg);
@@ -557,7 +557,7 @@ static int wm8731_init(struct snd_soc_device *socdev)
	}
	}


	/* power on device */
	/* power on device */
	wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
	wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);


	/* set the update bits */
	/* set the update bits */
	reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
	reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
@@ -730,7 +730,7 @@ static int wm8731_remove(struct platform_device *pdev)
	struct snd_soc_codec *codec = socdev->codec;
	struct snd_soc_codec *codec = socdev->codec;


	if (codec->control_data)
	if (codec->control_data)
		wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
		wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);


	snd_soc_free_pcms(socdev);
	snd_soc_free_pcms(socdev);
	snd_soc_dapm_free(socdev);
	snd_soc_dapm_free(socdev);
+18 −18
Original line number Original line Diff line number Diff line
@@ -686,29 +686,29 @@ static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute)
	return 0;
	return 0;
}
}


static int wm8750_dapm_event(struct snd_soc_codec *codec, int event)
static int wm8750_set_bias_level(struct snd_soc_codec *codec,
				 enum snd_soc_bias_level level)
{
{
	u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e;
	u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e;


	switch (event) {
	switch (level) {
	case SNDRV_CTL_POWER_D0: /* full On */
	case SND_SOC_BIAS_ON:
		/* set vmid to 50k and unmute dac */
		/* set vmid to 50k and unmute dac */
		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
		break;
		break;
	case SNDRV_CTL_POWER_D1: /* partial On */
	case SND_SOC_BIAS_PREPARE:
	case SNDRV_CTL_POWER_D2: /* partial On */
		/* set vmid to 5k for quick power up */
		/* set vmid to 5k for quick power up */
		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
		break;
		break;
	case SNDRV_CTL_POWER_D3hot: /* Off, with power */
	case SND_SOC_BIAS_STANDBY:
		/* mute dac and set vmid to 500k, enable VREF */
		/* mute dac and set vmid to 500k, enable VREF */
		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
		wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
		break;
		break;
	case SNDRV_CTL_POWER_D3cold: /* Off, without power */
	case SND_SOC_BIAS_OFF:
		wm8750_write(codec, WM8750_PWR1, 0x0001);
		wm8750_write(codec, WM8750_PWR1, 0x0001);
		break;
		break;
	}
	}
	codec->dapm_state = event;
	codec->bias_level = level;
	return 0;
	return 0;
}
}


@@ -748,7 +748,7 @@ static void wm8750_work(struct work_struct *work)
{
{
	struct snd_soc_codec *codec =
	struct snd_soc_codec *codec =
		container_of(work, struct snd_soc_codec, delayed_work.work);
		container_of(work, struct snd_soc_codec, delayed_work.work);
	wm8750_dapm_event(codec, codec->dapm_state);
	wm8750_set_bias_level(codec, codec->bias_level);
}
}


static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
@@ -756,7 +756,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec = socdev->codec;
	struct snd_soc_codec *codec = socdev->codec;


	wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
	wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
	return 0;
	return 0;
}
}


@@ -777,12 +777,12 @@ static int wm8750_resume(struct platform_device *pdev)
		codec->hw_write(codec->control_data, data, 2);
		codec->hw_write(codec->control_data, data, 2);
	}
	}


	wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
	wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);


	/* charge wm8750 caps */
	/* charge wm8750 caps */
	if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
	if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
		wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
		wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
		codec->dapm_state = SNDRV_CTL_POWER_D0;
		codec->bias_level = SND_SOC_BIAS_ON;
		schedule_delayed_work(&codec->delayed_work,
		schedule_delayed_work(&codec->delayed_work,
					msecs_to_jiffies(1000));
					msecs_to_jiffies(1000));
	}
	}
@@ -803,7 +803,7 @@ static int wm8750_init(struct snd_soc_device *socdev)
	codec->owner = THIS_MODULE;
	codec->owner = THIS_MODULE;
	codec->read = wm8750_read_reg_cache;
	codec->read = wm8750_read_reg_cache;
	codec->write = wm8750_write;
	codec->write = wm8750_write;
	codec->dapm_event = wm8750_dapm_event;
	codec->set_bias_level = wm8750_set_bias_level;
	codec->dai = &wm8750_dai;
	codec->dai = &wm8750_dai;
	codec->num_dai = 1;
	codec->num_dai = 1;
	codec->reg_cache_size = sizeof(wm8750_reg);
	codec->reg_cache_size = sizeof(wm8750_reg);
@@ -821,8 +821,8 @@ static int wm8750_init(struct snd_soc_device *socdev)
	}
	}


	/* charge output caps */
	/* charge output caps */
	wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
	wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
	codec->dapm_state = SNDRV_CTL_POWER_D3hot;
	codec->bias_level = SND_SOC_BIAS_STANDBY;
	schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
	schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));


	/* set the update bits */
	/* set the update bits */
@@ -1021,7 +1021,7 @@ static int wm8750_remove(struct platform_device *pdev)
	struct snd_soc_codec *codec = socdev->codec;
	struct snd_soc_codec *codec = socdev->codec;


	if (codec->control_data)
	if (codec->control_data)
		wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
		wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
	run_delayed_work(&codec->delayed_work);
	run_delayed_work(&codec->delayed_work);
	snd_soc_free_pcms(socdev);
	snd_soc_free_pcms(socdev);
	snd_soc_dapm_free(socdev);
	snd_soc_dapm_free(socdev);
Loading