[alsa-devel] [RFC 1/4] ASoC SST: Add msic codec driver

Mark Brown broonie at opensource.wolfsonmicro.com
Tue Dec 28 15:48:05 CET 2010


On Tue, Dec 28, 2010 at 05:39:36PM +0530, Koul, Vinod wrote:
> From: Vinod Koul <vinod.koul at intel.com>
> 
> This patch adds the msic asoc codec driver. This driver currently supports only playback.
> Capture and jack detection to be added later


>  sound/soc/codecs/msic.c |  721 +++++++++++++++++++++++++++++++++++++++++++++++
>  sound/soc/codecs/msic.h |  102 +++++++
>  2 files changed, 823 insertions(+), 0 deletions(-)

Makefile and Kconfig too please.

> +static inline int msic_modify(struct snd_soc_codec *codec,
> +		unsigned int reg, unsigned int value, unsigned int mask)
> +{
> +	int ret;
> +
> +	pr_debug("Modify for %x with %x of mask %x\n", reg, value, mask);
> +	ret = intel_scu_ipc_update_register(reg, value, mask);
> +	if (ret)
> +		pr_err("modify of %x failed, err %d\n", reg, ret);
> +	return ret;
> +}

snd_soc_update_bits().

> +/*sound controls*/
> +static const char *headset_switch_text[] = {"Earpiece", "HeadSet"};

Headset.

> +static int headset_set_switch(struct snd_kcontrol *kcontrol,
> +	struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
> +	struct intel_msic_pvt *msic = snd_soc_codec_get_drvdata(codec);
> +
> +	if (ucontrol->value.integer.value[0] == msic->hs_switch)
> +		return 0;
> +
> +	if (ucontrol->value.integer.value[0]) {
> +		pr_debug("hs_set HS path\n");
> +		snd_soc_dapm_enable_pin(&codec->dapm, "HPOUTL");
> +		snd_soc_dapm_enable_pin(&codec->dapm, "HPOUTR");
> +		snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
> +	} else {
> +		pr_debug("hs_set EP path\n");
> +		snd_soc_dapm_disable_pin(&codec->dapm, "HPOUTL");
> +		snd_soc_dapm_disable_pin(&codec->dapm, "HPOUTR");
> +		snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");

This should be implemented in the machine driver if it's useful.
Putting this in the CODEC driver restricts the system design as it
prevents both outputs being simultaneously active and means that the
system can't do things like drive selection between the headset and
earpiece outputs automatically from jack detection.

> +static void msic_lo_enable_out_pins(struct snd_soc_codec *codec)
> +{
> +	struct intel_msic_pvt *msic = snd_soc_codec_get_drvdata(codec);
> +
> +	snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL");
> +	snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR");
> +	snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL");
> +	snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR");
> +	snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT");
> +	snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT");
> +	if (msic->hs_switch) {
> +		snd_soc_dapm_enable_pin(&codec->dapm, "HPOUTL");
> +		snd_soc_dapm_enable_pin(&codec->dapm, "HPOUTR");
> +		snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
> +	} else {
> +		snd_soc_dapm_disable_pin(&codec->dapm, "HPOUTL");
> +		snd_soc_dapm_disable_pin(&codec->dapm, "HPOUTR");
> +		snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
> +	}

This also looks like it's in the machine driver domain.

> +	switch (level) {
> +	case SND_SOC_BIAS_PREPARE:
> +	case SND_SOC_BIAS_STANDBY:
> +		break;
> +
> +	case SND_SOC_BIAS_ON:
> +		pr_debug("vaud_bias doing rail statup now\n");
> +		/*power up the rail*/
> +		msic_write(codec, MSIC_VAUD, BIT(2)|BIT(1)|BIT(0));
> +		msleep(1);
> +		/*power up the pll*/
> +		msic_write(codec, MSIC_AUDPLLCTRL, BIT(5));

In general _ON should be doing the absolute minimum possible - it's done
after everything else has been brought up.  Depending on what these are
controlling they should be either in _PREPARE (audio is about to start)
or _STANDBY (the system is idle).

> +		/*adding pcm 2 here for a while*/
> +		msic_modify(codec, MSIC_PCM2C2, BIT(0), BIT(0));
> +		break;

Hrm?

> +static int msic_vhs_event(struct snd_soc_dapm_widget *w,
> +		    struct snd_kcontrol *kcontrol, int event)
> +{
> +	pr_debug("msic_vhs_event %d\n", event);
> +	if (event == SND_SOC_DAPM_PRE_PMU) {

SND_SOC_DAPM_EVENT_ON().

> +	/*playback paths speaker, dac, filter, rx selector*/
> +	SND_SOC_DAPM_SWITCH("Headset Left Playback",
> +		MSIC_DRIVEREN, 0, 0, &msic_driver_controls[0]),

Don't use big arrays of enumerated controls that you reference by
number; use individually named variables.  The numeric references are
error prone and hard to read.

Most of these look like they're just plain mute controls which would
more normally be represented as regular sound controls not related to
power, leaving these controls as PGAs (which is what they mostly appear
to be).  That would make the sequencing better, I expect, and would give
stereo controls to the application layer which is more normal.

> +
> +	/*SND_SOC_DAPM_MICBIAS("Mic Bias", MICBIAS, 0, 0),*/

Remove the commented code; you can add it later when you add capture
support.

> +static int msic_pcm_hs_startup(struct snd_pcm_substream *substream,
> +		struct snd_soc_dai *dai)
> +{
> +	pr_debug("pcm hs startup for %d\n", substream->pcm->device);
> +
> +	/*configure digital reciever here, add to DAPM later on*/
> +	msic_write(dai->codec, MSIC_HSMIXER, BIT(0)|BIT(4));
> +	msic_write(dai->codec, MSIC_HSEPRXCTRL, BIT(5)|BIT(4));

This does seem straightforward enough to handle using DAPM...

> +	pr_debug("pcm hs shutdown\n");
> +	msic_write(dai->codec, MSIC_HSEPRXCTRL, 0);
> +	return ;

No need for empty return statements.

> +static int msic_pcm_hs_mute(struct snd_soc_dai *dai, int mute)
> +{
> +	msic_modify(dai->codec, MSIC_HSLVOLCTRL, (!mute << 7), BIT(7));
> +	msic_modify(dai->codec, MSIC_HSRVOLCTRL, (!mute << 7), BIT(7));
> +	return 0;

It feels more idiomatic to just not implement a mute for these
interfaces and make these regular user visible controls - these mutes
are on the output rather than the digital mutes on the DAC that would
normally be controllled by a mute() function.  Unless there's pop/click
issues, in which case it's an OK workaround.  The user control is
useful. 

> +	.capture = {
> +		.stream_name = "Capture",
> +		.channels_min = 1,
> +		.channels_max = 5,
> +		.rates = MSIC_RATES,
> +		.formats = MSIC_FORMATS,
> +	},

Remove this until you implement capture.

> +},
> +};
> +EXPORT_SYMBOL_GPL(intel_msic_dais);

No need to export this with current ASoC APIs.

> +	/*fix the initial volume at 0dB*/
> +	msic_write(codec, MSIC_HSLVOLCTRL, 0x08);
> +	msic_write(codec, MSIC_HSRVOLCTRL, 0x08);
> +	msic_write(codec, MSIC_IHFLVOLCTRL, 0x08);
> +	msic_write(codec, MSIC_IHFRVOLCTRL, 0x08);

Leave these at the hardware defaults; 0dB may not be appropriate for
other systems (it seems rather loud for a headphone output...).

> +	/*dac mode and lo w/a*/
> +	msic_write(codec, MSIC_SSR2, 0x10);
> +	msic_write(codec, MSIC_SSR3, 0x40);

"lo w/a"?

> +	/*default is lineout NC, userspace sets it explcitly*/
> +	snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL");
> +	snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR");

Let the machine driver do this.

> +	.set_bias_level	= msic_set_vaud_bias,
> +/*	.suspend =	msic_codec_suspend,
> +	.resume =	msic_codec_resume,
> +*/

Remove these until you implement them.

> +MODULE_DESCRIPTION("ASoC Intel(R) MSIC codec driver");
> +MODULE_AUTHOR("Vinod Koul <vinod.koul at intel.com>");
> +MODULE_AUTHOR("Harsha Priya <priya.harsha at intel.com>");
> +MODULE_LICENSE("GPL v2");

MODULE_ALIAS() too.

> +extern struct snd_soc_dai_driver intel_msic_dais[4];
> +extern struct snd_soc_codec_driver intel_msic_codec;

Remove these.


More information about the Alsa-devel mailing list