[alsa-devel] SAIF configuration on imx28

George Stefan stefan.george87 at gmail.com
Tue Aug 21 14:39:25 CEST 2012


2012/8/21 Fabio Estevam <festevam at gmail.com>

> Hi George,
>
> On Tue, Aug 21, 2012 at 8:24 AM, George Stefan
> <stefan.george87 at gmail.com> wrote:
>
> > My problem is, although i am receiving dma irqs when i record ( arecord
> -f
> > S16_LE -r 8000 -c 1 <file>.wav), when i play the resulting file its just
> > silence.
> >
> > [ 5295.890000] dump @ mxs_saif_trigger
> > [ 5295.890000] scr 101  , 107
> > [ 5295.890000] stat 80010041    , 80010071
> > [ 5295.890000] data 0   , ffffffff
> > [ 5295.890000] version 1010000  , 1010000
> > This  is a dump for arecord!
> >
> > Do you have any ideeas?
>
> Can you please to record as:
> arecord -D hw:0,1 -d 5 -f S16_LE -r 44100 -c 2 1.wav
>
> ,as suggested here: http://www.spinics.net/lists/arm-kernel/msg186015.html
>
> Regards,
>
> Fabio Estevam
>
I don't think thats the issue.
In order to be more clear i will attach the code:

/* This is the codec code */
static struct snd_soc_codec *cinterion_codec;
/*
 * Line discpline related code
 *
 * Any of the callback functions below can be used in two ways:
 * 1) registerd by a machine driver as one of line discipline operations,
 * 2) called from a machine's provided line discipline callback function
 *    in case when extra machine specific code must be run as well.
 */

static const char *init_audio_mode = "AT^SNFS=6/r";
/* Please see pg 422 of AHS3-W AT Command Set */
static const char *init_pcm_audio = "AT^SAIC=1,1,1,1,0,0,1/r";

/* Line discipline .open() */
static int cinterion_tty_open(struct tty_struct *tty)
{
        int len = strlen(init_audio_mode);
        int ret;
        struct snd_soc_codec *codec = cinterion_codec;

/* Doesn't make sense without write callback */
if (!tty->ops->write)
return -EINVAL;

/* Pass the codec structure address for use by other ldisc callbacks */
tty->disc_data = codec;

if (tty->ops->write(tty, init_audio_mode, len) != len) {
ret = -EIO;
return ret;
}

len = strlen(init_pcm_audio);
if (tty->ops->write(tty, init_pcm_audio, len) != len) {
ret = -EIO;
return ret;
}
/* Actual setup will be performed after the modem responds. */
return 0;

err:
tty->disc_data = NULL;
return ret;
}


/* Line discipline .receive_buf() */
static void cinterion_tty_receive(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct snd_soc_codec *codec = tty->disc_data;
if (!codec)
return;

if (!codec->control_data) {
/* First modem response, complete setup procedure */

/* Set up codec driver access to modem controls */
codec->control_data = tty;
codec->hw_write = (hw_write_t)tty->ops->write;
codec->pop_time = 1;
}
}

/* Line discipline .close() */
static void cinterion_tty_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;

tty->disc_data = NULL;

if (!codec)
return;

/* Prevent the codec driver from further accessing the modem */
codec->hw_write = NULL;
codec->control_data = NULL;
codec->pop_time = 0;
}

struct tty_ldisc_ops cinterion_tty_ops = {
.magic = TTY_LDISC_MAGIC,
.name  = "cinterion-ahs3w",
.owner = THIS_MODULE,
.open  = cinterion_tty_open,
.close = cinterion_tty_close,
.receive_buf = cinterion_tty_receive,
};
EXPORT_SYMBOL_GPL(cinterion_tty_ops);

struct snd_soc_dai cinterion_codec_dai = {
.name            = "cinterion",
.playback        = {
.channels_min = 1,
.channels_max = 2,
.rates =  SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates =  SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
};
EXPORT_SYMBOL_GPL(cinterion_codec_dai);

static int cinterion_soc_probe(struct platform_device *pdev)
{

struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
int ret = 0;

if (!cinterion_codec) {
dev_err(&pdev->dev, "cinterion codec not yet discovered\n");
return -ENODEV;
}
codec = cinterion_codec;
socdev->card->codec = codec;

ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
printk(KERN_ERR "cinterion: failed to create pcms\n");
goto pcm_err;
}
return ret;

pcm_err:
return ret;
}

static int cinterion_soc_remove(struct platform_device *pdev)
{

struct snd_soc_device *socdev = platform_get_drvdata(pdev);

snd_soc_free_pcms(socdev);

return 0;
}

struct snd_soc_codec_device soc_codec_dev_cinterion = {
.probe =        cinterion_soc_probe,
.remove =       cinterion_soc_remove,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_cinterion);

static __devinit int cinterion_codec_probe(struct platform_device *pdev)
{
struct snd_soc_codec *codec;
int ret;

if (cinterion_codec) {
printk(KERN_ERR "Cinterion is allready registered\n");
return -EBUSY;
}

codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if(codec == NULL)
return -ENOMEM;


codec->control_data = NULL;
codec->hw_write = NULL;
codec->pop_time = 0;

cinterion_codec = codec;

platform_set_drvdata(pdev, codec);
mutex_init(&codec->mutex);
codec->dev = &pdev->dev;
codec->name = "cinterion";
codec->owner = THIS_MODULE;
codec->dai = &cinterion_codec_dai;
codec->num_dai = 1;
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);

cinterion_codec_dai.dev = &pdev->dev;

ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret);
goto err;
}

ret = snd_soc_register_dai(&cinterion_codec_dai);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
goto err_codec;
}
return 0;


err_codec:
snd_soc_unregister_codec(codec);
err:
kfree(codec);
return ret;
}


static __devexit int cinterion_codec_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&cinterion_codec_dai);
snd_soc_unregister_codec(platform_get_drvdata(pdev));
return 0;
}

static struct platform_driver cinterion_codec_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},

.probe = cinterion_codec_probe,
.remove = __devexit_p(cinterion_codec_remove),
};

static int __init cinterion_codec_modinit(void)
{
return platform_driver_register(&cinterion_codec_driver);
}

static void __exit cinterion_codec_exit(void)
{
platform_driver_unregister(&cinterion_codec_driver);
}

module_init(cinterion_codec_modinit);
module_exit(cinterion_codec_exit);


mxs-devb.c code
#include "../codecs/cinterion-ahs3w.h"

struct mxs_evk_priv {
int sysclk;
int hw;
struct platform_device *pdev;
};

static struct mxs_evk_priv card_priv;

/* this should be implemented */
static int mxs_acu2_audio_hw_params(struct snd_pcm_substream *substream,
      struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct mxs_evk_priv *priv = &card_priv;

unsigned int rate = params_rate(params);
int ret = 0;

u32 dai_format;
/* only need to do this once as capture and playback are sync */
#if 0
if (priv->hw)
return 0;

priv->hw = 1;
priv->sysclk = 512 * rate;

        printk("sysclk %lu\n", priv->sysclk);
        snd_soc_dai_set_clkdiv(cpu_dai, IMX_SSP_SYS_MCLK, 256);
#endif
        /* set cpu_dai to master mode for playback, slave mode for record */
        //       dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
        //       SND_SOC_DAIFMT_CBM_CFM;

        dai_format = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_IB_NF |
             SND_SOC_DAIFMT_CBM_CFM;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
if (ret < 0)
             return ret;
#if 0
        /* set the SAIF system clock as output */
snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, priv->sysclk,  \
SND_SOC_CLOCK_OUT);
        snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 256000,
SND_SOC_CLOCK_OUT);
#endif

        snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
SND_SOC_CLOCK_IN);
        return 0;
}

/*
 * mxs_acu2 Cinterion audio DAI operations.
 */
static struct snd_soc_ops mxs_acu2_ops = {
.hw_params = mxs_acu2_audio_hw_params,
};

/* Line discipline .open() */
static int cinterion_ahs3w_open(struct tty_struct *tty)
{
  return cinterion_tty_ops.open(tty);
}

/* Line discipline .receive_buf() */
static void cinterion_ahs3w_receive(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct snd_soc_codec *codec = tty->disc_data;
const unsigned char *c;
int apply, ret;

/* First modem response...must complete setup */
if (!codec->control_data) {
cinterion_tty_ops.receive_buf(tty, cp, fp, count);
return ;
}
      cinterion_tty_ops.receive_buf(tty, cp, fp, count);
        printk("count %d\n", count);
}

/* Line discipline .close() */
static void cinterion_ahs3w_close(struct tty_struct *tty)
{
struct snd_soc_codec *codec = tty->disc_data;
cinterion_tty_ops.close(tty);
}

static struct tty_ldisc_ops cinterion_ahs3w_ops = {
.magic = TTY_LDISC_MAGIC,
.name = "cinterion_ahs3w",
.owner = THIS_MODULE,
.open = cinterion_ahs3w_open,
.close = cinterion_ahs3w_close,
.receive_buf = cinterion_ahs3w_receive,
};

/*
 * Card initialization
 */
static int mxs_cinterion_init(struct snd_soc_codec *codec)
{
struct snd_soc_dai *codec_dai = codec->dai;
int ret;

            /* Register optional line discipline for over the modem control
*/

ret = tty_register_ldisc(N_V253, &cinterion_ahs3w_ops);
if (ret)
printk(KERN_ERR,
                       "Failed to register line discipline, "
                       "will continue without any controls.\n");
        return ret;
}

/* mxs_evk digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link acu2_dai = {
.name = "cinterion",
.stream_name = "cinterion pcm",
.codec_dai = &cinterion_codec_dai,
        .init = mxs_cinterion_init,
.ops = &mxs_acu2_ops,
};

/* SoC machine structure */
static struct snd_soc_card acu2_snd_soc_card = {
.name = "mxs-evk",
.platform = &mxs_soc_platform,
.dai_link = &acu2_dai,
.num_links = 1,
};

static struct snd_soc_device acu2_snd_soc_device = {
        .card = &acu2_snd_soc_card,
        .codec_dev = &soc_codec_dev_cinterion,
};

static int __devinit mxs_evk_cinterion_probe(struct platform_device *pdev)
{
struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
struct mxs_saif *saif_select;
int ret = -EINVAL;

        /* saif 0 and 1 clocks and stuff */
if (plat->init && plat->init())
          goto err_plat_init;

        acu2_dai.cpu_dai = &mxs_saif_dai[0]; /* adds the cpu dai */
        acu2_dai.cpu_dai->name = "imx28-dai";
saif_select = (struct mxs_saif *)acu2_dai.cpu_dai->private_data;
saif_select->stream_mapping = PLAYBACK_SAIF0_CAPTURE_SAIF1;
saif_select->saif_mclk = plat->saif_mclock;
saif_select->saif_clk = SAIF0;
return 0;
err_plat_init:
if (plat->finit)
plat->finit();
return ret;
}


static int mxs_evk_cinterion_remove(struct platform_device *pdev)
{
struct mxs_audio_platform_data *plat = pdev->dev.platform_data;

if (plat->finit)
plat->finit();
return 0;
}

/* audio platform driver */
static struct platform_driver acu2_cinterion_audio_driver = {
.probe = mxs_evk_cinterion_probe,
.remove = mxs_evk_cinterion_remove,
.driver = {
   .name = "mxs-sgtl5000",
   },
};

static struct platform_device *acu2_snd_platform_device;
static struct platform_device *cinterion_codec_platform_device;

static int __init mxs_acu2_init(void)
{
int ret;

ret = platform_driver_register(&acu2_cinterion_audio_driver);
if (ret)
return -ENOMEM;

acu2_snd_platform_device = platform_device_alloc("soc-audio", 1);
if (!acu2_snd_platform_device) {
                 printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
        }

platform_set_drvdata(acu2_snd_platform_device, &acu2_snd_soc_device);
acu2_snd_soc_device.dev = &acu2_snd_platform_device->dev;
ret = platform_device_add(acu2_snd_platform_device);
if (ret)
             platform_device_put(acu2_snd_platform_device);

        cinterion_codec_platform_device =
platform_device_register_simple("cinterion",
                                                                -1, NULL,
0);

return ret;
}

static void __exit mxs_acu2_exit(void)
{
     platform_device_unregister(acu2_snd_platform_device);
}

module_init(mxs_acu2_init);
module_exit(mxs_acu2_exit);

Also the dump of arecord -d 5 -f S16_LE -r 8000 -c 2 1.wav
hexdump -C test.wav
00000000  52 49 46 46 04 ca 55 00  57 41 56 45 66 6d 74 20
 |RIFF..U.WAVEfmt |
00000010  10 00 00 00 01 00 02 00  44 ac 00 00 10 b1 02 00
 |........D.......|
00000020  04 00 10 00 64 61 74 61  e0 c9 55 00 00 00 00 00
 |....data..U.....|
00000030  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
 |................|
*
00562020


More information about the Alsa-devel mailing list