[alsa-devel] [PATCHv2 6/6] ASoC: OMAP4: Add McPDM platform driver

Candelaria Villareal, Jorge jorge.candelaria at ti.com
Mon Jan 25 22:06:44 CET 2010


From: Liam Girdwood wrote:
> On Fri, 2010-01-22 at 17:15 -0600, Candelaria Villareal, Jorge wrote:
> > From: Misael Lopez Cruz <x0052729 at ti.com>
> > 
> > McPDM platform driver is configured to use sDMA in order to transfer
> > to/from memory. Support for interfacing with ABE will be 
> added later.
> > 
> > McPDM dai currently supports up to 4 downlink channels and 2 uplink
> > channels simultaneously, as well as 88.2 and 96 KHz, and a sample
> > size of 32 bits.
> > 
> > Signed-off-by: Misael Lopez Cruz <x0052729 at ti.com>
> > Signed-off-by: Margarita Olaya <x0080101 at ti.com>
> > Signed-off-by: Jorge Eduardo Candelaria <x0107209 at ti.com>
> > ---
> >  sound/soc/omap/Makefile     |    2 +-
> >  sound/soc/omap/omap-mcpdm.c |  250 
> +++++++++++++++++++++++++++++++++++++++++++
> >  sound/soc/omap/omap-mcpdm.h |   29 +++++
> >  3 files changed, 280 insertions(+), 1 deletions(-)
> >  create mode 100644 sound/soc/omap/omap-mcpdm.c
> >  create mode 100644 sound/soc/omap/omap-mcpdm.h
> > 
> > diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
> > index bf8b388..d6382fa 100644
> > --- a/sound/soc/omap/Makefile
> > +++ b/sound/soc/omap/Makefile
> > @@ -1,7 +1,7 @@
> >  # OMAP Platform Support
> >  snd-soc-omap-objs := omap-pcm.o
> >  snd-soc-omap-mcbsp-objs := omap-mcbsp.o
> > -snd-soc-omap-mcpdm-objs := mcpdm.o
> > +snd-soc-omap-mcpdm-objs := mcpdm.o omap-mcpdm.o
> >  
> >  obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
> >  obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
> > diff --git a/sound/soc/omap/omap-mcpdm.c 
> b/sound/soc/omap/omap-mcpdm.c
> > new file mode 100644
> > index 0000000..180cca6
> > --- /dev/null
> > +++ b/sound/soc/omap/omap-mcpdm.c
> > @@ -0,0 +1,250 @@
> > +/*
> > + * omap-mcpdm.c  --  OMAP ALSA SoC DAI driver using McPDM port
> > + *
> > + * Copyright (C) 2009 Texas Instruments
> > + *
> > + * Author: Misael Lopez Cruz <x0052729 at ti.com>
> > + * Contact: Jorge Eduardo Candelaria <x0107209 at ti.com>
> > + *          Margarita Olaya <magi.olaya at ti.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be 
> useful, but
> > + * WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
> See the GNU
> > + * General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General 
> Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> > + * 02110-1301 USA
> > + *
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/device.h>
> > +#include <sound/core.h>
> > +#include <sound/pcm.h>
> > +#include <sound/pcm_params.h>
> > +#include <sound/initval.h>
> > +#include <sound/soc.h>
> > +
> > +#include <mach/control.h>
> > +#include <mach/dma.h>
> > +#include <mach/mcbsp.h>
> > +#include "mcpdm.h"
> > +#include "omap-mcpdm.h"
> > +#include "omap-pcm.h"
> > +
> > +struct omap_mcpdm_data {
> > +	struct omap_mcpdm_link *links;
> > +	int active;
> > +};
> > +
> > +static struct omap_mcpdm_link omap_mcpdm_links[] = {
> > +	/* downlink */
> > +	{
> > +		.irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
> > +		.threshold = 1,
> > +		.format = PDMOUTFORMAT_LJUST,
> > +	},
> > +	/* uplink */
> > +	{
> > +		.irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
> > +		.threshold = 1,
> > +		.format = PDMOUTFORMAT_LJUST,
> > +	},
> > +};
> > +
> > +static struct omap_mcpdm_data mcpdm_data = {
> > +	.links = omap_mcpdm_links,
> > +	.active = 0,
> > +};
> > +
> > +/*
> > + * Stream DMA parameters
> > + */
> > +static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
> > +	{
> > +		.name = "Audio downlink",
> > +		.dma_req = OMAP44XX_DMA_MCPDM_DL,
> > +		.data_type = OMAP_DMA_DATA_TYPE_S32,
> > +		.sync_mode = OMAP_DMA_SYNC_PACKET,
> > +		.packet_size = 16,
> > +		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
> > +	},
> > +	{
> > +		.name = "Audio uplink",
> > +		.dma_req = OMAP44XX_DMA_MCPDM_UP,
> > +		.data_type = OMAP_DMA_DATA_TYPE_S32,
> > +		.sync_mode = OMAP_DMA_SYNC_PACKET,
> > +		.packet_size = 16,
> > +		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
> > +	},
> > +};
> > +
> > +static int omap_mcpdm_dai_startup(struct snd_pcm_substream 
> *substream,
> > +				  struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
> > +	int err = 0;
> > +
> > +	if (!cpu_dai->active)
> > +		err = omap_mcpdm_request();
> 
> Will anything else use this hw interface other than ALSA audio ?
> If not, the request is probably better in the machine driver probe().

omap_mcpdm_request will enable the functional clock. Isn't it better
for the clock to be enabled only when is about to get used?

> 
> > +
> > +	return err;
> > +}
> > +
> > +static void omap_mcpdm_dai_shutdown(struct 
> snd_pcm_substream *substream,
> > +				    struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
> > +
> > +	if (!cpu_dai->active)
> > +		omap_mcpdm_free();
> 
> ditto.

Also, omap_mcpdm_free should disable the clock once it is not needed.

> 
> > +}
> > +
> > +static int omap_mcpdm_dai_trigger(struct snd_pcm_substream 
> *substream, int cmd,
> > +				  struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
> > +	struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
> > +	int stream = substream->stream;
> > +	int err = 0;
> > +
> > +	switch (cmd) {
> > +	case SNDRV_PCM_TRIGGER_START:
> > +	case SNDRV_PCM_TRIGGER_RESUME:
> > +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> > +		if (!mcpdm_priv->active++)
> > +			omap_mcpdm_start(stream);
> > +		break;
> > +
> > +	case SNDRV_PCM_TRIGGER_STOP:
> > +	case SNDRV_PCM_TRIGGER_SUSPEND:
> > +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> > +		if (!--mcpdm_priv->active)
> > +			omap_mcpdm_stop(stream);
> > +		break;
> > +	default:
> > +		err = -EINVAL;
> > +	}
> > +
> > +	return err;
> > +}
> > +
> > +static int omap_mcpdm_dai_hw_params(struct 
> snd_pcm_substream *substream,
> > +				    struct snd_pcm_hw_params *params,
> > +				    struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
> > +	struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
> > +	struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
> > +	int stream = substream->stream;
> > +	int channels, err, link_mask = 0;
> > +
> > +	cpu_dai->dma_data = &omap_mcpdm_dai_dma_params[stream];
> > +
> > +	channels = params_channels(params);
> > +	switch (channels) {
> > +	case 4:
> > +		if (stream)
> 
> stream is either PLAYBACK or CAPTURE here.

Downlink and uplink were chosen instead to avoid confusion
because that is how it is referred in McPDM technical
documentation. But I do understand that we are talking
about ALSA stream, not McPDM...

> 
> > +			/* up to 2 channels for uplink */

So I should refer to CAPTURE instead of UPLINK in here.

> > +			return -EINVAL;
> > +		link_mask |= 1 << 3;
> > +	case 3:
> > +		if (stream)
> > +			/* up to 2 channels for uplink */
> > +			return -EINVAL;
> > +		link_mask |= 1 << 2;
> > +	case 2:
> > +		link_mask |= 1 << 1;
> > +	case 1:
> > +		link_mask |= 1 << 0;
> > +		break;
> > +	default:
> > +		/* unsupported number of channels */
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (stream) {
> 
> ditto

Here, however, the methods set_uplink & set_downlink are
Named after McPDM data paths. In this case is it preferred
to name everything using ALSA convention? Or would it be ok
to use downlink/uplink on certain cases?

> 
> > +		mcpdm_links[stream].channels = link_mask << 0;
> > +		err = omap_mcpdm_set_uplink(&mcpdm_links[stream]);
> > +	} else {
> > +		mcpdm_links[stream].channels = link_mask << 3;
> > +		err = omap_mcpdm_set_downlink(&mcpdm_links[stream]);
> > +	}
> > +
> > +	return err;
> > +}
> > +
> > +static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream 
> *substream,
> > +				  struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > +	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
> > +	struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
> > +	struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
> > +	int err;
> > +
> > +	if (substream->stream)
> 
> 
> ditto

This is the same case, uplink and downlink refer to McPDM data
path names.
 
> > +		err = 
> omap_mcpdm_clr_uplink(&mcpdm_links[substream->stream]);
> > +	else
> > +		err = 
> omap_mcpdm_clr_downlink(&mcpdm_links[substream->stream]);
> > +
> > +	return err;
> > +}
> > +
> > +static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
> > +	.startup	= omap_mcpdm_dai_startup,
> > +	.shutdown	= omap_mcpdm_dai_shutdown,
> > +	.trigger	= omap_mcpdm_dai_trigger,
> > +	.hw_params	= omap_mcpdm_dai_hw_params,
> > +	.hw_free	= omap_mcpdm_dai_hw_free,
> > +};
> > +
> > +#define OMAP_MCPDM_RATES	(SNDRV_PCM_RATE_88200 | 
> SNDRV_PCM_RATE_96000)
> 
> Is this the link rate or sample rate ? What about slower rates ?

This is the sample rate. Slower rates are not supported by McPDM
nor by the audio codec. When ABE is present, it supports other
input rates, like 48000, but then ABE needs to upsample to 96000
before sending to McPDM module.

> 
> > +#define OMAP_MCPDM_FORMATS	(SNDRV_PCM_FMTBIT_S32_LE)
> > +
> 
> Is this the link format or sample format ? What about 16bit ?

Again, only ABE supports 16 bit, but needs to convert to 32 bit
before sending to McPDM. With current McPDM patches, we are
bypassing ABE.

> 
> > +struct snd_soc_dai omap_mcpdm_dai = {
> > +	.name = "omap-mcpdm",
> > +	.id = -1,
> > +	.playback = {
> > +		.channels_min = 1,
> > +		.channels_max = 4,
> > +		.rates = OMAP_MCPDM_RATES,
> > +		.formats = OMAP_MCPDM_FORMATS,
> > +	},
> > +	.capture = {
> > +		.channels_min = 1,
> > +		.channels_max = 2,
> > +		.rates = OMAP_MCPDM_RATES,
> > +		.formats = OMAP_MCPDM_FORMATS,
> > +	},
> > +	.ops = &omap_mcpdm_dai_ops,
> > +	.private_data = &mcpdm_data,
> > +};
> > +EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
> > +
> > +static int __init snd_omap_mcpdm_init(void)
> > +{
> > +	return snd_soc_register_dai(&omap_mcpdm_dai);
> > +}
> > +module_init(snd_omap_mcpdm_init);
> > +
> > +static void __exit snd_omap_mcpdm_exit(void)
> > +{
> > +	snd_soc_unregister_dai(&omap_mcpdm_dai);
> > +}
> > +module_exit(snd_omap_mcpdm_exit);
> > +
> > +MODULE_AUTHOR("Misael Lopez Cruz <x0052729 at ti.com>");
> > +MODULE_DESCRIPTION("OMAP PDM SoC Interface");
> > +MODULE_LICENSE("GPL");
> > diff --git a/sound/soc/omap/omap-mcpdm.h 
> b/sound/soc/omap/omap-mcpdm.h
> > new file mode 100644
> > index 0000000..73b80d5
> > --- /dev/null
> > +++ b/sound/soc/omap/omap-mcpdm.h
> > @@ -0,0 +1,29 @@
> > +/*
> > + * omap-mcpdm.h
> > + *
> > + * Copyright (C) 2009 Texas Instruments
> > + *
> > + * Contact: Misael Lopez Cruz <x0052729 at ti.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be 
> useful, but
> > + * WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
> See the GNU
> > + * General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General 
> Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> > + * 02110-1301 USA
> > + *
> > + */
> > +
> > +#ifndef __OMAP_MCPDM_H__
> > +#define __OMAP_MCPDM_H__
> > +
> > +extern struct snd_soc_dai omap_mcpdm_dai;
> > +
> > +#endif	/* End of __OMAP_MCPDM_H__ */
> 
> 
> 


More information about the Alsa-devel mailing list