From: 宋宝华 <21cnbao@gmail.com>
To: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: lrg@slimlogic.co.uk, alsa-devel@alsa-project.org,
linux-kernel@vger.kernel.org,
Mike Frysinger <vapier.adi@gmail.com>
Subject: Re: [PATCH] New ASoC Drivers for ADI AD1938 codec
Date: Mon, 13 Jul 2009 16:12:14 +0800 [thread overview]
Message-ID: <3c17e3570907130112i128dd0f2o4673200de3125d5d@mail.gmail.com> (raw)
In-Reply-To: <20090619104738.GF5270@sirena.org.uk>
2009/6/19 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jun 19, 2009 at 05:28:15PM +0800, Barry Song wrote:
>> 1. add AD1938 codec driver (codec)
>> 2. add blackfin SPORT-TDM DAI and PCM driver (platform)
>> 3. add bf5xx board with AD1938 driver (machine)
>
> As Liam said you really need to submit this as a patch series rather
> than as a single big patch - as your commit log here indicates you've
> got several different things going on here.
>
>> +++ b/include/sound/soc-dai.h
>> @@ -30,6 +30,7 @@ struct snd_pcm_substream;
>> #define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM LRC */
>> #define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM LRC */
>> #define SND_SOC_DAIFMT_AC97 5 /* AC97 */
>> +#define SND_SOC_DAIFMT_SPORT_TDM 6 /* SPORT TDM for ADI parts */
>
> If you're going to add a new DAI format that really needs more
> explanation than this explaining what the DAI format is. It'd be very
> surprising to see hardware needing a new format.
>
> Looking at the datasheet for the ad1938 it appears that the actual
> format here is just normal I2S with TDM. This does not need a new DAI
> format or new CPU DAI, you just need to add suport for TDM to the
> Blackfin I2S driver. The format is fairly standard and implemented by a
> number of other devices.
>
> See set_tdm_slot() for setting up the higher channel counts - there's
> some ongoing revisions to that API so you'll want to also ensure that
> the code is set up so that it can cope with specification of the sample
> width for each slot in set_tdm_slot().
>
> Given this I've only looked at the CODEC driver below.
>
>> diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c
>> new file mode 100644
>> index 0000000..9aa78e1
>> --- /dev/null
>> +++ b/sound/soc/codecs/ad1938.c
>
>> + *
>> + * Revision history
>> + * 4 June 2009 Initial version.
>
> Don't include this, git provides code history for us.
>
>> +struct snd_soc_device *ad1938_socdev;
>> +
>> +/* dac de-emphasis enum control */
>> +static const char *ad1938_deemp[] = {"flat", "48kHz", "44.1kHz", "32kHz"};
>
> For consistency with other drivers "flat" should be "None".
>
>> +/* AD1938 volume/mute/de-emphasis etc. controls */
>> +static const struct snd_kcontrol_new ad1938_snd_controls[] = {
>> + /* DAC volume control */
>> + SOC_SINGLE("DAC L1 Volume", AD1938_DAC_L1_VOL, 0, 0xFF, 1),
>> + SOC_SINGLE("DAC R1 Volume", AD1938_DAC_R1_VOL, 0, 0xFF, 1),
>
> These (and the other stereo pairs below) should be SOC_DOUBLE_R(). This
> allows ALSA to represent them as stereo controls to applications rather
> than as two separate controls. You should also provide TLV information
> so actually SOC_DOUBLE_R_TLV() if possible.
>
>> + /* DAC mute control */
>> + SOC_SINGLE("DAC L1 Switch", AD1938_DAC_CHNL_MUTE, 0, 1, 1),
>> + SOC_SINGLE("DAC R1 Switch", AD1938_DAC_CHNL_MUTE, 1, 1, 1),
>
> These should be stereo controls too - SOC_DOUBLE() since they're in the
> same register.
>
>> + /* ADC mute control */
>> + SOC_SINGLE("ADC L1 Switch", AD1938_ADC_CTRL0, ADC0_MUTE, 1, 1),
>> + SOC_SINGLE("ADC R1 Switch", AD1938_ADC_CTRL0, ADC1_MUTE, 1, 1),
>
> These too.
>
>> + /* DAC de-emphasis */
>> + SOC_ENUM("Playback Deemphasis", ad1938_enum[0]),
>
> Don't put your enums in an array, use named variables for them. This
> makes drivers easier to maintian when you get a lot of enums.
>
>> +static int ad1938_add_controls(struct snd_soc_codec *codec)
>> +{
>> + int err, i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(ad1938_snd_controls); i++) {
>> + err = snd_ctl_add(codec->card,
>> + snd_soc_cnew(&ad1938_snd_controls[i], codec, NULL));
>
> Use snd_soc_add_controls() here - you can replace the entire function
> with a call to that.
>
>> +/* dac/adc/pll poweron/off functions */
>> +static int ad1938_dac_powerctrl(struct snd_soc_codec *codec, int cmd)
>> +{
>> + int reg;
>> +
>> + reg = codec->read(codec, AD1938_DAC_CTRL0);
>> + if (cmd)
>> + reg &= ~DAC_POWERDOWN;
>> + else
>> + reg |= DAC_POWERDOWN;
>> + codec->write(codec, AD1938_DAC_CTRL0, reg);
>
> This should be handled by DAPM - either have a single DAC widget
> representing all the channels (since you don't appear to have
> independant control anyway) or have a bunch of dummy DAC widgets and a
> supply widget representing the actual power control. The same thing
> applies to the ADCs.
I want to use ADC/DAC widgets.
static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AD1938_DAC_CTRL0, 0, 1),
SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AD1938_ADC_CTRL0, 0, 1),
};
But for this AD1938 codec, DAC's work depends on ADC is powered on in
hardware. I think there is no any mechanism to handle this kind of
strange depending now. So is there a generic way to handle this?
>
>> +static int ad1938_set_pll(struct snd_soc_dai *codec_dai,
>> + int pll_id, unsigned int freq_in, unsigned int freq_out)
>> +{
>> + struct snd_soc_codec *codec = codec_dai->codec;
>> +
>> + if (freq_out)
>> + ad1938_pll_powerctrl(codec, 1);
>> + else {
>> + /* playing while recording, framework will poweroff-poweron pll redundantly */
>> + if ((!codec_dai->capture.active) && (!codec_dai->playback.active))
>> + ad1938_pll_powerctrl(codec, 0);
>> + }
>
> Hrm. This appears to completely ignore the frequencies supplied for the
> PLL and just provide power control. I suspect that you can just handle
> the PLL as a SND_SOC_DAPM_SUPPLY(), there seems to be no need to expose
> the set_pll() operation and make machine drivers call it given that
> there isn't any frequency configuration going on.
>
>> +static int ad1938_mute(struct snd_soc_dai *dai, int mute)
>> +{
>> + struct snd_soc_codec *codec = dai->codec;
>> +
>> + if (!mute)
>> + codec->write(codec, AD1938_DAC_CHNL_MUTE, 0);
>> + else
>> + codec->write(codec, AD1938_DAC_CHNL_MUTE, 0xff);
>> +
>> + return 0;
>> +}
>
> This isn't going to play well with the explicit mute controls you've got
> above - it's writing to the same register bits without any coordination.
> One or the other set of controls ought to be removed.
>
>> +static int ad1938_tdm_set(struct snd_soc_codec *codec)
>> +{
>> + codec->write(codec, AD1938_DAC_CTRL0, (codec->read(codec, AD1938_DAC_CTRL0) &
>> + (~DAC_SERFMT_MASK)) | DAC_SERFMT_TDM);
>> + codec->write(codec, AD1938_DAC_CTRL1, 0x84); /* invert bclk, 256bclk/frame, latch in mid */
>> + codec->write(codec, AD1938_ADC_CTRL1, 0x43); /* sata delay=1, adc aux mode */
>> + codec->write(codec, AD1938_ADC_CTRL2, 0x6F); /* left high, driver on rising edge */
>> +
>> + return 0;
>> +}
>
> If you use set_tdm_slot() then the BCLK/frame ratio will be set by that.
>
> Inversion of BCLK (and any other clocks) should be handled by the
> set_dai_fmt() operation based on the machine driver request rather than
> done unconditionally.
>
>> + /* bit size */
>> + switch (params_format(params)) {
>> + case SNDRV_PCM_FORMAT_S16_LE:
>> + word_len = 3;
>> + break;
>
> Once you implement set_tdm_slot() you should allow the word length to be
> configured there if it's called or otherwise keep this code here - see
> Daniel Ribeiro's patche "change set_tdm_slot api to allow slot_width
> override" posted to the ALSA list this week.
>
>> +static int __devinit ad1938_spi_probe(struct spi_device *spi)
>> +{
>> + spi->dev.power.power_state = PMSG_ON;
>> + ad1938_socdev->card->codec->control_data = spi;
>> +
>> + return 0;
>> +}
>> +
>> +static int __devexit ad1938_spi_remove(struct spi_device *spi)
>> +{
>> + return 0;
>> +}
>
> Your device probing should all be restructured so that the SPI device
> for the CODEC is registered as any other SPI device rather than being
> set up as part of probing the ASoC device. See the wm8731 driver for
> an example of doing this for a SPI device.
>
> This will require that the arch code for any systems with the ad1938
> do the setup of the device.
>
>> + .name = "AD1938",
>> + .playback = {
>> + .stream_name = "Playback",
>> + .channels_min = 2,
>> + .channels_max = 8,
>> + .rates = SNDRV_PCM_RATE_48000,
>> + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, },
>
> Please keep your lines to under 80 columns.
>
>> +#define AD1938_PLL_CLK_CTRL0 0
>> +#define PLL_POWERDOWN 0x01
>> +#define AD1938_PLL_CLK_CTRL1 1
>> +#define AD1938_DAC_CTRL0 2
>> +#define DAC_POWERDOWN 0x01
>> +#define DAC_SERFMT_MASK 0xC0
>> +#define DAC_SERFMT_STEREO (0 << 6)
>> +#define DAC_SERFMT_TDM (1 << 6)
>
> These defines need namespacing if they're going to appear in the headers
> - everything should have the AD1938_ prefix.
>
--
宋宝华 21cnbao@21cn.com
http://21cnbao.blog.51cto.com
next prev parent reply other threads:[~2009-07-13 8:12 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-19 9:28 Barry Song
2009-06-19 9:35 ` Liam Girdwood
2009-06-19 9:41 ` Liam Girdwood
2009-06-19 10:47 ` Mark Brown
2009-06-19 11:05 ` Mike Frysinger
2009-06-19 11:13 ` Mark Brown
2009-06-19 11:21 ` Mike Frysinger
2009-06-19 11:56 ` Mark Brown
2009-06-20 23:15 ` [alsa-devel] " Robin Getz
2009-06-21 0:13 ` Mark Brown
[not found] ` <3c17e3570906212008n6071e987sbcd4b9377364ae78@mail.gmail.com>
2009-06-22 10:57 ` Mark Brown
[not found] ` <3c17e3570906220600l3471b6f0rc29c674b4a5ec2df@mail.gmail.com>
2009-06-22 13:11 ` Mark Brown
2009-07-13 8:12 ` 宋宝华 [this message]
2009-07-13 9:15 ` Mark Brown
-- strict thread matches above, loose matches on Subject: below --
2009-06-19 5:58 Barry Song
2009-06-19 6:44 ` Mike Frysinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3c17e3570907130112i128dd0f2o4673200de3125d5d@mail.gmail.com \
--to=21cnbao@gmail.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@opensource.wolfsonmicro.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lrg@slimlogic.co.uk \
--cc=vapier.adi@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®