[alsa-devel] SAIF configuration on imx28
Hello, I am using a custom board based on imx28 (running 2.6.35) with the SAIF interface connected to the PCM output of a modem. I have developed a dummy codec for the modem and customized mxs-devb.c to use that codec instead of sgtl5000. Clock master, fixed at 256kHz, Frame sync master, fixed 125us frame duration (8kHz): 32 bits of total data; first 16 bits are valid (while FS is high), following 16 are "don't care" (while FS low) 16-bit linear samples, sent MSB first "Long Frame" sync: transmit and receive occur simultaneously while the common FS line is active (high). TX data with 0-bit delay; start at the rising edge of the clock, while FS is high. RX data with 0-bit delay; sample at the falling edge of the clock, while FS is high. This configuration is fixed so the only setup needed for SAIF is
dai_format = SND_SOC_DAIFMT_RIGHT_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;
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? Thanks, George.
Hi George,
On Tue, Aug 21, 2012 at 8:24 AM, George Stefan stefan.george87@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
2012/8/21 Fabio Estevam festevam@gmail.com
Hi George,
On Tue, Aug 21, 2012 at 8:24 AM, George Stefan stefan.george87@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
2012/8/21 George Stefan stefan.george87@gmail.com
2012/8/21 Fabio Estevam festevam@gmail.com
Hi George,
On Tue, Aug 21, 2012 at 8:24 AM, George Stefan stefan.george87@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:
- registerd by a machine driver as one of line discipline operations,
- 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
Also, the output from aplay and arecord. aplay -l**** List of PLAYBACK Hardware Devices ****card 0: mxsevk [mxs-evk], device 0: cinterion pcm cinterion-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0
~ # arecord -l **** List of CAPTURE Hardware Devices **** card 0: mxsevk [mxs-evk], device 0: cinterion pcm cinterion-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0
What is the cause of receiving just FF ?
From my perspective its something related to the configuration of the SAIF.
Regards, George
On Wed, Aug 22, 2012 at 5:25 AM, George Stefan stefan.george87@gmail.com wrote:
aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: mxsevk [mxs-evk], device 0: cinterion pcm cinterion-0 []
Subdevices: 1/1
Subdevice #0: subdevice #0
~ # arecord -l **** List of CAPTURE Hardware Devices **** card 0: mxsevk [mxs-evk], device 0: cinterion pcm cinterion-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0
Shouldn't this register as pcm cinterion-1 instead?
On mx28evk we have:
root@freescale ~$ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: mxssgtl5000 [mxs_sgtl5000], device 0: HiFi Playback sgtl5000-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: mxssgtl5000 [mxs_sgtl5000], device 1: HiFi Capture sgtl5000-1 [] Subdevices: 1/1 Subdevice #0: subdevice #0
and we register it as:
static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { { .name = "HiFi Tx", .stream_name = "HiFi Playback", .codec_dai_name = "sgtl5000", .codec_name = "sgtl5000.0-000a", .cpu_dai_name = "mxs-saif.0", .platform_name = "mxs-saif.0", .ops = &mxs_sgtl5000_hifi_ops, }, { .name = "HiFi Rx", .stream_name = "HiFi Capture", .codec_dai_name = "sgtl5000", .codec_name = "sgtl5000.0-000a", .cpu_dai_name = "mxs-saif.1", .platform_name = "mxs-saif.1", .ops = &mxs_sgtl5000_hifi_ops, }, };
Regards,
Fabio Estevam
2012/8/23 Fabio Estevam festevam@gmail.com
On Wed, Aug 22, 2012 at 5:25 AM, George Stefan stefan.george87@gmail.com wrote:
aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: mxsevk [mxs-evk], device 0: cinterion pcm cinterion-0 []
Subdevices: 1/1
Subdevice #0: subdevice #0
~ # arecord -l **** List of CAPTURE Hardware Devices **** card 0: mxsevk [mxs-evk], device 0: cinterion pcm cinterion-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0
Shouldn't this register as pcm cinterion-1 instead?
On mx28evk we have:
root@freescale ~$ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: mxssgtl5000 [mxs_sgtl5000], device 0: HiFi Playback sgtl5000-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: mxssgtl5000 [mxs_sgtl5000], device 1: HiFi Capture sgtl5000-1 [] Subdevices: 1/1 Subdevice #0: subdevice #0
and we register it as:
static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { { .name = "HiFi Tx", .stream_name = "HiFi Playback", .codec_dai_name = "sgtl5000", .codec_name = "sgtl5000.0-000a", .cpu_dai_name = "mxs-saif.0", .platform_name = "mxs-saif.0", .ops = &mxs_sgtl5000_hifi_ops, }, { .name = "HiFi Rx", .stream_name = "HiFi Capture", .codec_dai_name = "sgtl5000", .codec_name = "sgtl5000.0-000a", .cpu_dai_name = "mxs-saif.1", .platform_name = "mxs-saif.1", .ops = &mxs_sgtl5000_hifi_ops, }, };
Regards,
Fabio Estevam
Hello! Yes, thats true. I think there is another problem with the receiving of the clock from the modem part!
/*set a default freq of 128Hz to cinterion*/ // clk_set_rate(clk, 1280000); /* its slave...it should take the clock from master */ clk_enable(clk); /*set the saif clk mux, saif0/saif1 both use saif0 clk*/ __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0), \ IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL);
Using this configuration i am not able to receive IRQs from DMA and i think the reason is that SAIF is not receiving the CLK. What do you think? Thanks, George.
On Thu, Aug 23, 2012 at 02:41:30PM +0800, George Stefan wrote: ...
/*set the saif clk mux, saif0/saif1 both use saif0 clk*/ __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0), \
Should this be 0x2 if both saif0 and saif1 are using saif0 clk?
IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL); Using this configuration i am not able to receive IRQs from DMA and i think the reason is that SAIF is not receiving the CLK. What do you think? Thanks, George.
Regards Dong Aisheng
2012/8/23 Dong Aisheng b29396@freescale.com
On Thu, Aug 23, 2012 at 02:41:30PM +0800, George Stefan wrote: ...
/*set the saif clk mux, saif0/saif1 both use saif0 clk*/ __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0), \
Should this be 0x2 if both saif0 and saif1 are using saif0 clk?
IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL); Using this configuration i am not able to receive IRQs from DMA and i think the reason is that SAIF is not receiving the CLK. What do you think? Thanks, George.
Regards Dong Aisheng
Yes, it should be 0x2 if they are using saif0 clk. but it they are using
the CLK from an external device which is master, i think that they should use an independent clock. "In slave clocking mode, the SAIF configures the BITCLK and LRCLK pins as inputs, and the off-chip codec is responsible for driving both clocks to the SAIF"(imx28 reference manual) 0x0 - DIRECT — SAIF0 clock pins selected for SAIF0 input clocks, and SAIF1 clock pins selected for SAIF1 input clocks. Am i interpreting this in the wrong way? Regards, George.
On Thu, Aug 23, 2012 at 03:13:11PM +0800, George Stefan wrote:
2012/8/23 Dong Aisheng b29396@freescale.com
On Thu, Aug 23, 2012 at 02:41:30PM +0800, George Stefan wrote: ... > /*set the saif clk mux, saif0/saif1 both use saif0 clk*/ > __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0), \ Should this be 0x2 if both saif0 and saif1 are using saif0 clk? > IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL); > Using this configuration i am not able to receive IRQs from DMA and i > think the reason > is that SAIF is not receiving the CLK. > What do you think? > Thanks, > George. Regards Dong Aisheng
Yes, it should be 0x2 if they are using saif0 clk. but it they are using the CLK from an external device which is master, i think that they should use an independent clock. "In slave clocking mode, the SAIF configures the BITCLK and LRCLK pins as inputs, and the off-chip codec is responsible for driving both clocks to the SAIF"(imx28 reference manual) 0x0 - DIRECT - SAIF0 clock pins selected for SAIF0 input clocks, and SAIF1 clock pins selected for SAIF1 input clocks. Am i interpreting this in the wrong way?
Your understand is right if all are working on slave mode. But be noted that the current driver in mainline only supports master mode, mainly due to playback can not work on slave mode(see spec) while capture can. If all are in slave mode, that means the playback may not work. You should make sure if your requirements really wants that. And if you want to run in slave mode, you need change the mainline driver to support it.
Regards Dong Aisheng
2012/8/23 Dong Aisheng b29396@freescale.com
On Thu, Aug 23, 2012 at 03:13:11PM +0800, George Stefan wrote:
2012/8/23 Dong Aisheng b29396@freescale.com
On Thu, Aug 23, 2012 at 02:41:30PM +0800, George Stefan wrote: ... > /*set the saif clk mux, saif0/saif1 both use saif0 clk*/ > __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0),
\
Should this be 0x2 if both saif0 and saif1 are using saif0 clk? > IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL); > Using this configuration i am not able to receive IRQs from
DMA and
i > think the reason > is that SAIF is not receiving the CLK. > What do you think? > Thanks, > George. Regards Dong Aisheng
Yes, it should be 0x2 if they are using saif0 clk. but it they are
using
the CLK from an external device which is master, i think that they should use an independent clock. "In slave clocking mode, the SAIF configures the BITCLK and LRCLK
pins as
inputs, and the off-chip codec is responsible for driving both clocks to the SAIF"(imx28 reference manual) 0x0 - DIRECT - SAIF0 clock pins selected for SAIF0 input clocks, and
SAIF1
clock pins selected for SAIF1 input clocks. Am i interpreting this in the wrong way?
Your understand is right if all are working on slave mode. But be noted that the current driver in mainline only supports master mode, mainly due to playback can not work on slave mode(see spec) while capture can. If all are in slave mode, that means the playback may not work. You should make sure if your requirements really wants that. And if you want to run in slave mode, you need change the mainline driver to support it.
Regards Dong Aisheng
The problem in using SAIF as master, is that in slave mode the modem uses
short frame sync(SND_SOC_DAIFMT_DSP_A), which is not supported in the current driver.
2012/8/23 George Stefan stefan.george87@gmail.com
2012/8/23 Dong Aisheng b29396@freescale.com
On Thu, Aug 23, 2012 at 03:13:11PM +0800, George Stefan wrote:
2012/8/23 Dong Aisheng b29396@freescale.com
On Thu, Aug 23, 2012 at 02:41:30PM +0800, George Stefan wrote: ... > /*set the saif clk mux, saif0/saif1 both use saif0 clk*/ > __raw_writel(BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(0x0),
\
Should this be 0x2 if both saif0 and saif1 are using saif0 clk? > IO_ADDRESS(DIGCTL_PHYS_ADDR) + HW_DIGCTL_CTRL); > Using this configuration i am not able to receive IRQs from
DMA and
i > think the reason > is that SAIF is not receiving the CLK. > What do you think? > Thanks, > George. Regards Dong Aisheng
Yes, it should be 0x2 if they are using saif0 clk. but it they are
using
the CLK from an external device which is master, i think that they should use an independent clock. "In slave clocking mode, the SAIF configures the BITCLK and LRCLK
pins as
inputs, and the off-chip codec is responsible for driving both clocks to the SAIF"(imx28 reference manual) 0x0 - DIRECT - SAIF0 clock pins selected for SAIF0 input clocks, and
SAIF1
clock pins selected for SAIF1 input clocks. Am i interpreting this in the wrong way?
Your understand is right if all are working on slave mode. But be noted that the current driver in mainline only supports master mode, mainly due to playback can not work on slave mode(see spec) while capture can. If all are in slave mode, that means the playback may not work. You should make sure if your requirements really wants that. And if you want to run in slave mode, you need change the mainline driver to support it.
Regards Dong Aisheng
The problem in using SAIF as master, is that in slave mode the modem uses
short frame sync(SND_SOC_DAIFMT_DSP_A), which is not supported in the current driver.
I have added support for SND_SOC_DAIFMT_DSP_A case SND_SOC_DAIFMT_DSP_A: scr &= ~BM_SAIF_CTRL_DELAY; scr |= BM_SAIF_CTRL_LRCLK_POLARITY; scr |= BM_SAIF_CTRL_JUSTIFY; scr |= BM_SAIF_CTRL_BITCLK_EDGE;
} The clock is set at 256 KHZ: /* set the SAIF system clock as output */ snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 2560000, SND_SOC_CLOCK_OUT);
I test record with: arecord -d 5 -f S16_LE -r 8000 -c 2 1.wav
Dump for 1.wav exdump -C 1.wav 00000000 52 49 46 46 24 71 02 00 57 41 56 45 66 6d 74 20 |RIFF$q..WAVEfmt | 00000010 10 00 00 00 01 00 02 00 40 1f 00 00 00 7d 00 00 |........@....}..| 00000020 04 00 10 00 64 61 74 61 00 71 02 00 00 00 00 00 |....data.q......| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00004b90 00 00 00 18 00 00 30 00 00 00 00 00 00 00 00 00 |......0.........| 00004ba0 00 07 00 00 1c 00 00 00 02 00 00 00 00 00 00 03 |................| 00004bb0 e0 41 7c 78 07 10 c1 84 f0 e0 1e 3c 83 0f f0 c1 |.A|x.......<....| 00004bc0 3c 78 0f 03 c1 83 f8 f0 1f 3c 83 07 f0 e1 3e 78 |<x.......<....>x| 00004bd0 07 1f e1 83 78 f0 1f 3e c3 07 f0 e0 3e 7c 07 0f |....x..>....>|..| 00004be0 e0 c3 7c f0 0f 3e c1 87 f8 e0 1e 7c 87 0f e0 c1 |..|..>.....|....| 00004bf0 7c f8 0f 1e c1 83 f8 f0 1f 3c 83 0f f0 c1 3c f8 ||........<....<.| 00004c00 07 1f e1 83 78 f0 1f 3e 83 07 f0 e1 3e 78 07 0f |....x..>....>x..| 00004c10 e0 c3 7c f0 0f 3e c3 07 f0 e0 3e 7c 87 0f e0 c1 |..|..>....>|....| 00004c20 fc f9 0f 1e c3 87 fc f0 1f fe f3 0f f0 c1 ff fb |................| 00004c30 ff df c1 83 ff f0 ff ff e7 07 ff e1 3e ff ff 1f |............>...| 00004c40 ff 83 fe ff ff 3f cf f7 ff ff bf ff ff ff ff ff |.....?..........| 00004c50 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| * 00027120
On Thu, Aug 23, 2012 at 9:54 AM, George Stefan stefan.george87@gmail.com wrote:
I test record with: arecord -d 5 -f S16_LE -r 8000 -c 2 1.wav
Dump for 1.wav exdump -C 1.wav
Does this wav file have good data?
2012/8/23 Fabio Estevam festevam@gmail.com
On Thu, Aug 23, 2012 at 9:54 AM, George Stefan stefan.george87@gmail.com wrote:
I test record with: arecord -d 5 -f S16_LE -r 8000 -c 2 1.wav
Dump for 1.wav exdump -C 1.wav
Does this wav file have good data?
That is my main problem. I have a modem...which is a "black box" and i am not sure if it is emitting valid data. I just configure an audio loop on the modem side. If i play this on my laptop, its just a spike...at the begining and then silence.
On Thu, Aug 23, 2012 at 10:09 AM, George Stefan stefan.george87@gmail.com wrote:
That is my main problem. I have a modem...which is a "black box" and i am not sure if it is emitting valid data. I just configure an audio loop on the modem side. If i play this on my laptop, its just a spike...at the begining and then silence.
From your first message in this thread, you say you are running
2.6.35. Please try it on a mainline kernel instead.
Regards,
Fabio Estevam
2012/8/23 Fabio Estevam festevam@gmail.com
On Thu, Aug 23, 2012 at 10:09 AM, George Stefan stefan.george87@gmail.com wrote:
That is my main problem. I have a modem...which is a "black box" and i am not sure if it is emitting valid data. I just configure an audio loop on the modem
side.
If i play this on my laptop, its just a spike...at the begining and then silence.
From your first message in this thread, you say you are running 2.6.35. Please try it on a mainline kernel instead.
Regards,
Fabio Estevam
I am afraid i don't have this option!
participants (3)
-
Dong Aisheng
-
Fabio Estevam
-
George Stefan