[alsa-devel] ASoC: at91sam9260-PCM1808/TAS5709-based board driver
Hello,
I have to develop a driver for a custom board based on the at91sam9260 with a PCM1808/TAS5709 chipset combo. I am addressing the PCM1808 first because it is a simpler device. Since I'm new to ASoC I'm looking for some help in this list on how to go about writing this driver.
So far I have identified two files that I need to work on (other than the needed kconfig modifications). First is the codec driver at sound/soc/codecs/PCM1808.[c|h] which is based on the existent pcm3008 driver; I believe I'm fine with this.
The second file is the machine driver at sound/soc/atmel/myBoard.c. I'm using sam9g20_wm8731.c as reference, on which I believe I found a typo which I reported in a separated e-mail.
So my first question is, is this two-files step the right approach? am I in the right track? I'm using the 2.6.30 kernel.
Other questions will come and I hope I will get some cycles from you to help me direct my work. Of course I'll be glad to submit my driver work for inclusion in the kernel if it proves useful.
Regards,
On Sat, Aug 8, 2009 at 1:39 PM, Pedro Sanchezpsanchez@fosstel.com wrote:
Hello,
I have to develop a driver for a custom board based on the at91sam9260 with a PCM1808/TAS5709 chipset combo. I am addressing the PCM1808 first because it is a simpler device. Since I'm new to ASoC I'm looking for some help in this list on how to go about writing this driver.
I attached a PCM1690 driver I'm currently working on.
So far I have identified two files that I need to work on (other than the needed kconfig modifications). First is the codec driver at sound/soc/codecs/PCM1808.[c|h] which is based on the existent pcm3008 driver; I believe I'm fine with this.
The second file is the machine driver at sound/soc/atmel/myBoard.c. I'm using sam9g20_wm8731.c as reference, on which I believe I found a typo which I reported in a separated e-mail.
So my first question is, is this two-files step the right approach? am I in the right track? I'm using the 2.6.30 kernel.
Other questions will come and I hope I will get some cycles from you to help me direct my work. Of course I'll be glad to submit my driver work for inclusion in the kernel if it proves useful.
Regards,
-- Pedro
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Sun, Aug 9, 2009 at 9:35 AM, Jon Smirljonsmirl@gmail.com wrote:
On Sat, Aug 8, 2009 at 1:39 PM, Pedro Sanchezpsanchez@fosstel.com wrote:
Hello,
I have to develop a driver for a custom board based on the at91sam9260 with a PCM1808/TAS5709 chipset combo. I am addressing the PCM1808 first because it is a simpler device. Since I'm new to ASoC I'm looking for some help in this list on how to go about writing this driver.
I attached a PCM1690 driver I'm currently working on.
The attached fabric driver show how to use it.
So far I have identified two files that I need to work on (other than the needed kconfig modifications). First is the codec driver at sound/soc/codecs/PCM1808.[c|h] which is based on the existent pcm3008 driver; I believe I'm fine with this.
The second file is the machine driver at sound/soc/atmel/myBoard.c. I'm using sam9g20_wm8731.c as reference, on which I believe I found a typo which I reported in a separated e-mail.
So my first question is, is this two-files step the right approach? am I in the right track? I'm using the 2.6.30 kernel.
Other questions will come and I hope I will get some cycles from you to help me direct my work. Of course I'll be glad to submit my driver work for inclusion in the kernel if it proves useful.
Regards,
-- Pedro
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
-- Jon Smirl jonsmirl@gmail.com
Thank you John for the sample code. It's going to be very useful specially when I get to the TAS5709 part and the I2C interface.
My next question is with regards to clocking on the SSC interface. The PCM1808 in my board has a pretty straight forward connection as follows:
SSC-I/F PCM1808 Comment RF ----> LRCK Frame clock RK ----> BCK Bit clock RD <---- DOUT Digital data
The PCM1808 is hardwired to be in slave mode. The two clock lines are expected to be provided by the SoC's SSC interface.
I have the following code in my machine driver to request the SSC interface and bind the PCM1808 to it:
/* * Request SSC device */ ssc = ssc_request(0); if (IS_ERR(ssc)) { printk(KERN_ERR "ASoC: Failed to request SSC 0\n"); ret = PTR_ERR(ssc); ssc = NULL; goto err_ssc; } ssc_p->ssc = ssc;
What I need to do now is to set the SSC's clock divider to feed the PCM1808 with the proper clocking. So these are my next questions:
1. How do I specify in the machine driver that my pcm1808 is hardwired to slave mode and that I need bit/frame clocks to be provided by the SSC interface?
2. How do I set the SSC's clock divider to provide the right clock signals?
Thanks again,
On Tue, Aug 11, 2009 at 2:41 PM, Pedro I. Sanchezpsanchez@fosstel.com wrote:
Thank you John for the sample code. It's going to be very useful specially when I get to the TAS5709 part and the I2C interface.
I attached a TAS5504 driver. It plays music. You need to use a custom app to manipulate the rest of the registers.
TAS chips have a complicated variable length register scheme that is hard to cache.
My next question is with regards to clocking on the SSC interface. The PCM1808 in my board has a pretty straight forward connection as follows:
SSC-I/F PCM1808 Comment RF ----> LRCK Frame clock RK ----> BCK Bit clock RD <---- DOUT Digital data
The PCM1808 is hardwired to be in slave mode. The two clock lines are expected to be provided by the SoC's SSC interface.
I have the following code in my machine driver to request the SSC interface and bind the PCM1808 to it:
/* * Request SSC device */ ssc = ssc_request(0); if (IS_ERR(ssc)) { printk(KERN_ERR "ASoC: Failed to request SSC 0\n"); ret = PTR_ERR(ssc); ssc = NULL; goto err_ssc; } ssc_p->ssc = ssc;
What I need to do now is to set the SSC's clock divider to feed the PCM1808 with the proper clocking. So these are my next questions:
- How do I specify in the machine driver that my pcm1808 is hardwired to
slave mode and that I need bit/frame clocks to be provided by the SSC interface?
- How do I set the SSC's clock divider to provide the right clock signals?
Thanks again,
-- Pedro
Jon Smirl wrote:
On Sun, Aug 9, 2009 at 9:35 AM, Jon Smirljonsmirl@gmail.com wrote:
On Sat, Aug 8, 2009 at 1:39 PM, Pedro Sanchezpsanchez@fosstel.com wrote:
Hello,
I have to develop a driver for a custom board based on the at91sam9260 with a PCM1808/TAS5709 chipset combo. I am addressing the PCM1808 first because it is a simpler device. Since I'm new to ASoC I'm looking for some help in this list on how to go about writing this driver.
I attached a PCM1690 driver I'm currently working on.
The attached fabric driver show how to use it.
So far I have identified two files that I need to work on (other than the needed kconfig modifications). First is the codec driver at sound/soc/codecs/PCM1808.[c|h] which is based on the existent pcm3008 driver; I believe I'm fine with this.
The second file is the machine driver at sound/soc/atmel/myBoard.c. I'm using sam9g20_wm8731.c as reference, on which I believe I found a typo which I reported in a separated e-mail.
So my first question is, is this two-files step the right approach? am I in the right track? I'm using the 2.6.30 kernel.
Other questions will come and I hope I will get some cycles from you to help me direct my work. Of course I'll be glad to submit my driver work for inclusion in the kernel if it proves useful.
Regards,
-- Pedro
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
-- Jon Smirl jonsmirl@gmail.com
On Tue, Aug 11, 2009 at 02:41:57PM -0400, Pedro I. Sanchez wrote:
- How do I specify in the machine driver that my pcm1808 is hardwired
to slave mode and that I need bit/frame clocks to be provided by the SSC interface?
Configure the SSC driver so that the CPU is in master mode (CBS_CFS).
- How do I set the SSC's clock divider to provide the right clock signals?
Older versions of the sam9g20 driver ran the SSC in master mode, that might be useful to refer to. There's normally a clocking diagram in the manual for the SoC showing the clocking structure with all the dividers you can configure.
Hello,
I've been working on my driver, this time concentrating on the TAS5760. I decided to use the WM8731 codec and the sam9g20_wm8731 machine drivers as templates.
Things are mostly OK now, my kernel modules install, and the driver can read/write the chip registers properly. User space applications can see my custom board as a sound card. Tha's progress!
The TAS5709 is a playback-slave-only device The SSC is therefore put in master mode and I can see the SSC clock signals (SCLK and LRCLK) on the scope when playing a sound file. I can also see the activity on the data line. But unfortunately, there is no sound, just a speaker Hisss when I play a file. I doubled checked all the volume levels to ensure they are not mutted.
However, I noticed that the duty cycle of the SSC clocks is not 50% as I would expect it to be. There seem to be much more bits on one channel than in the other (my sample file is stereo, 16 bits, 44.1 MHz). The sample clock illustrations in the TAS5709 all have the same number of bits per channel, but it doesn't say explicitly that this is mandatory. From my understanding of the I2S spec, this is not.
The TAS5709 is supposed to detect the clock and data rates automatically. Do you know if this non-50% duty cycle could be the reason for the lack of sound? Is there a way to force it to be 50%?
Thanks,
On Tue, Aug 25, 2009 at 01:31:57PM -0400, Pedro I. Sanchez wrote:
The TAS5709 is a playback-slave-only device The SSC is therefore put in master mode and I can see the SSC clock signals (SCLK and LRCLK) on the scope when playing a sound file. I can also see the activity on the data line. But unfortunately, there is no sound, just a speaker Hisss when I play a file. I doubled checked all the volume levels to ensure they are not mutted.
Is there any control in the CODEC? If so you should check that it is set up properly.
However, I noticed that the duty cycle of the SSC clocks is not 50% as I would expect it to be. There seem to be much more bits on one channel than in the other (my sample file is stereo, 16 bits, 44.1 MHz). The sample clock illustrations in the TAS5709 all have the same number of bits per channel, but it doesn't say explicitly that this is mandatory. From my understanding of the I2S spec, this is not.
The TAS5709 is supposed to detect the clock and data rates automatically. Do you know if this non-50% duty cycle could be the reason for the lack of sound? Is there a way to force it to be 50%?
If the CODEC is trying to work out what the sample and clock rates are automatically then it does seem reasonable that any oddities in the clocks that it's given might confuse it somehow - for example, causing it to expect more bit clocks than it's actually getting which would cause it to fail to clock in enough data to do a conversion.
I'd expect that appropriate configuration of the clock dividers for the SSC it's possible to make it generate more normal looking clocks, I don't think anyone ever optimised the divider configuration when the AT91SAM9G20-EK was running the SSC in master mode.
Mark Brown wrote:
On Tue, Aug 25, 2009 at 01:31:57PM -0400, Pedro I. Sanchez wrote:
The TAS5709 is a playback-slave-only device The SSC is therefore put in master mode and I can see the SSC clock signals (SCLK and LRCLK) on the scope when playing a sound file. I can also see the activity on the data line. But unfortunately, there is no sound, just a speaker Hisss when I play a file. I doubled checked all the volume levels to ensure they are not mutted.
Is there any control in the CODEC? If so you should check that it is set up properly.
There are registers to mute/unmute channels and master volume. For the time being I am using my pcm_prepare function to write directly to those registers to ensure that they are not muted when a sound file is played.
I haven't "mastered" the definitions of sound controls in ALSA yet, I'll do that later.
However, I noticed that the duty cycle of the SSC clocks is not 50% as I would expect it to be. There seem to be much more bits on one channel than in the other (my sample file is stereo, 16 bits, 44.1 MHz). The sample clock illustrations in the TAS5709 all have the same number of bits per channel, but it doesn't say explicitly that this is mandatory. From my understanding of the I2S spec, this is not.
The TAS5709 is supposed to detect the clock and data rates automatically. Do you know if this non-50% duty cycle could be the reason for the lack of sound? Is there a way to force it to be 50%?
If the CODEC is trying to work out what the sample and clock rates are automatically then it does seem reasonable that any oddities in the clocks that it's given might confuse it somehow - for example, causing it to expect more bit clocks than it's actually getting which would cause it to fail to clock in enough data to do a conversion.
I'd expect that appropriate configuration of the clock dividers for the SSC it's possible to make it generate more normal looking clocks, I don't think anyone ever optimised the divider configuration when the AT91SAM9G20-EK was running the SSC in master mode.
Indeed, as I change the dividers the duty cycle changes. But I am out of logic now on how to find the right values. It seems that a high degree of black magic is required to find them. This is the code that I am using in the machine driver to set them up:
/* set the MCK divider for BCLK */ ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div); if (ret < 0) return ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* set the BCLK divider for DACLRC */ ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_TCMR_PERIOD, period); } else { /* set the BCLK divider for ADCLRC */ ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_RCMR_PERIOD, period); } if (ret < 0) return ret;
The big quest for me now is to figure out what "cmr_div" and "period" have to be. They must be different for each sample rate. Any pointers would be appreciated.
Thanks,
-- Pedro
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Tue, Aug 25, 2009 at 03:46:14PM -0400, Pedro I. Sanchez wrote:
The big quest for me now is to figure out what "cmr_div" and "period" have to be. They must be different for each sample rate. Any pointers would be appreciated.
There should be a clocking diagram in the CPU manual which will show how things are interrelated. The period of a clock will be 1/rate - the length of time taken for a clock cycle.
On Tue, Aug 25, 2009 at 03:46:14PM -0400, Pedro I. Sanchez wrote:
The big quest for me now is to figure out what "cmr_div" and "period" have to be. They must be different for each sample rate. Any pointers would be appreciated.
There should be a clocking diagram in the CPU manual which will show how things are interrelated. The period of a clock will be 1/rate - the length of time taken for a clock cycle.
I'm still struggling with the clocks but in the mean time I have a related question. Why is it that if I play a 24-bit encoded play the hw_params() function in my driver is called with SNDRV_PCM_FORMAT_S16_LE format? Does ALSA makes an on-the-fly conversion?
$ aplay c2_24.wav Playing WAVE 'c2_24.wav' : Signed 24 bit Little Endian in 3bytes, Rate 44100 Hz, Mono
... and my ipspeaker machine driver module says:
Aug 27 15:03:15 ubuntu kernel: ipspeaker_hw_params: pcm rate is 44100 Aug 27 15:03:16 ubuntu kernel: ipspeaker_hw_params: PCM format SNDRV_PCM_FORMAT_S16_LE
I would expect my driver to be told that the format is SNDRV_PCM_FORMAT_S24_LE. Why is this?
Thanks,
[Please note that the standard thing on Linux mailing lists is to do a reply to all.]
On Thu, Aug 27, 2009 at 03:11:49PM -0400, Pedro I. Sanchez wrote:
question. Why is it that if I play a 24-bit encoded play the hw_params() function in my driver is called with SNDRV_PCM_FORMAT_S16_LE format? Does ALSA makes an on-the-fly conversion?
Yes, ALSA can do on the fly format translations if required to play things. This normally happens because the input format is not supported by the drivers. Telling the application to use the hardware device directly will bypass this conversion.
Well, it turns out that the TAS5709 documentation doesn't say the whole story. It seems that after all the chip can only guess the incoming bit rates in rare occasions and I can't really rely on this. What the chip really needs is a MCLK signal which is a multiple of the sound file's sample frequency. This is a third clock line to be provided to that chip in addition to the regular TF (frame) and TK (bit) clocks from the SSC interface.
Now I know that I have to output this additional clock line via one of the gpio pins of the SoC and therefore I have to somehow "attach" one of the CPU internal timers to one of the SoC gpio pins (PC6, linux gpio102 pin to be more exact). I have the following (borrowed) code now:
/* PCK0 provides MCLK */ at91_set_A_periph(AT91_PIN_PC6, 0);
How is this linking the internal pck0 timer to pin PC6? or is it?
And then I have
/* * Codec MCLK is supplied by PCK0 - set it up. */ mclk = clk_get(NULL, "pck0"); if (IS_ERR(mclk)) { pr_err("%s: Failed to get MCLK\n", __func__); ret = PTR_ERR(mclk); goto err; }
pllb = clk_get(NULL, "pllb"); if (IS_ERR(pllb)) { pr_err("%s: Failed to get PLLB\n", __func__); ret = PTR_ERR(pllb); goto err_pllb; }
ret = clk_set_parent(mclk, pllb); if (ret != 0) { pr_err("%s: Failed to set MCLK parent\n", __func__); goto err_parent; }
clk_set_rate(mclk, 11289600); clk_put(pllb); pr_info("%s: MCLK rate %luHz\n", __func__, clk_get_rate(mclk));
... but it prints "MCLK rate 6000000Hz". Where does the 600000 come from, I don't know. And certainly there is no clock on the PC6 pin :-(
Mark, or someone, any enlightenment on how to proceed would be very much appreciated.
Thank you,
On Fri, 28 Aug 2009 17:24:59 -0400, "Pedro I. Sanchez" psanchez@fosstel.com wrote:
Well, it turns out that the TAS5709 documentation doesn't say the whole story. It seems that after all the chip can only guess the incoming bit rates in rare occasions and I can't really rely on this. What the chip really needs is a MCLK signal which is a multiple of the sound file's sample frequency. This is a third clock line to be provided to that chip
in
addition to the regular TF (frame) and TK (bit) clocks from the SSC interface.
Now I know that I have to output this additional clock line via one of
the
gpio pins of the SoC and therefore I have to somehow "attach" one of the CPU internal timers to one of the SoC gpio pins (PC6, linux gpio102 pin
to
be more exact). I have the following (borrowed) code now:
/* PCK0 provides MCLK */ at91_set_A_periph(AT91_PIN_PC6, 0);
How is this linking the internal pck0 timer to pin PC6? or is it?
And then I have
/* * Codec MCLK is supplied by PCK0 - set it up. */ mclk = clk_get(NULL, "pck0"); if (IS_ERR(mclk)) { pr_err("%s: Failed to get MCLK\n", __func__); ret = PTR_ERR(mclk); goto err; } pllb = clk_get(NULL, "pllb"); if (IS_ERR(pllb)) { pr_err("%s: Failed to get PLLB\n", __func__); ret = PTR_ERR(pllb); goto err_pllb; } ret = clk_set_parent(mclk, pllb); if (ret != 0) { pr_err("%s: Failed to set MCLK parent\n", __func__); goto err_parent; } clk_set_rate(mclk, 11289600); clk_put(pllb); pr_info("%s: MCLK rate %luHz\n", __func__, clk_get_rate(mclk));
... but it prints "MCLK rate 6000000Hz". Where does the 600000 come from,
I
don't know. And certainly there is no clock on the PC6 pin :-(
Mark, or someone, any enlightenment on how to proceed would be very much appreciated.
Thank you,
BTW, I forgot to mention that this board is just a slight variation of the sam9260ek eval board and I would suspect that the internal wiring of the SoC is pretty much the same. So understanding how to use the programmable clocks on the latter should give me the solution for the former.
Thanks,
On Fri, Aug 28, 2009 at 05:24:59PM -0400, Pedro I. Sanchez wrote:
Well, it turns out that the TAS5709 documentation doesn't say the whole story. It seems that after all the chip can only guess the incoming bit rates in rare occasions and I can't really rely on this. What the chip really needs is a MCLK signal which is a multiple of the sound file's sample frequency. This is a third clock line to be provided to that chip in addition to the regular TF (frame) and TK (bit) clocks from the SSC interface.
That's fairly standard for CODECs - some have FLLs or similar which allow them to generate their master clock from the BCLK or LRCLK but most need a MCLK too.
Now I know that I have to output this additional clock line via one of the gpio pins of the SoC and therefore I have to somehow "attach" one of the CPU internal timers to one of the SoC gpio pins (PC6, linux gpio102 pin to be more exact). I have the following (borrowed) code now:
Be careful here. Generally CODECs require some synchronisation between the master clock and the other audio clocks - normally the controller block in the CPU will have a clock it can provide with the intention that it be used as a master clock.
/* PCK0 provides MCLK */ at91_set_A_periph(AT91_PIN_PC6, 0);
How is this linking the internal pck0 timer to pin PC6? or is it?
You'd be better off asking the Atmel people on linux-arm-kernel (or some other Atmel-specific list if there is one) about this - it's more of a general question about the CPU port than an audio-specific question.
ret = clk_set_parent(mclk, pllb); if (ret != 0) { pr_err("%s: Failed to set MCLK parent\n", __func__); goto err_parent; }
clk_set_rate(mclk, 11289600); clk_put(pllb); pr_info("%s: MCLK rate %luHz\n", __func__, clk_get_rate(mclk));
... but it prints "MCLK rate 6000000Hz". Where does the 600000 come from, I don't know. And certainly there is no clock on the PC6 pin :-(
It'll be derived from the parent clock plus any dividers in the way.
Mark Brown wrote:
On Fri, Aug 28, 2009 at 05:24:59PM -0400, Pedro I. Sanchez wrote:
Well, it turns out that the TAS5709 documentation doesn't say the whole story. It seems that after all the chip can only guess the incoming bit rates in rare occasions and I can't really rely on this. What the chip really needs is a MCLK signal which is a multiple of the sound file's sample frequency. This is a third clock line to be provided to that chip in addition to the regular TF (frame) and TK (bit) clocks from the SSC interface.
That's fairly standard for CODECs - some have FLLs or similar which allow them to generate their master clock from the BCLK or LRCLK but most need a MCLK too.
Now I know that I have to output this additional clock line via one of the gpio pins of the SoC and therefore I have to somehow "attach" one of the CPU internal timers to one of the SoC gpio pins (PC6, linux gpio102 pin to be more exact). I have the following (borrowed) code now:
Be careful here. Generally CODECs require some synchronisation between the master clock and the other audio clocks - normally the controller block in the CPU will have a clock it can provide with the intention that it be used as a master clock.
Yes, but the manual says, if I still believe in it, that the MCLK needs no phase alignment with the bit clock and that in fact it can be generated by external circuitry. I'll have to wait and see.
/* PCK0 provides MCLK */ at91_set_A_periph(AT91_PIN_PC6, 0);
How is this linking the internal pck0 timer to pin PC6? or is it?
You'd be better off asking the Atmel people on linux-arm-kernel (or some other Atmel-specific list if there is one) about this - it's more of a general question about the CPU port than an audio-specific question.
I was suspecting that, thank you anyway. I will keep my questions on this thread on the sound aspects only.
ret = clk_set_parent(mclk, pllb); if (ret != 0) { pr_err("%s: Failed to set MCLK parent\n", __func__); goto err_parent; }
clk_set_rate(mclk, 11289600); clk_put(pllb); pr_info("%s: MCLK rate %luHz\n", __func__, clk_get_rate(mclk));
... but it prints "MCLK rate 6000000Hz". Where does the 600000 come from, I don't know. And certainly there is no clock on the PC6 pin :-(
It'll be derived from the parent clock plus any dividers in the way.
Thanks again,
participants (5)
-
Jon Smirl
-
Mark Brown
-
Pedro I. Sanchez
-
Pedro I. Sanchez
-
Pedro Sanchez