From: Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
To: Florian Meier <florian.meier-oZ8rN/sblLk@public.gmane.org>
Cc: Liam Girdwood <lgirdwood-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>,
devicetree <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-rpi-kernel
<linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>,
dmaengine <dmaengine-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
martin-d5rIkyn9cnPYtjvyW6yDsg@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Subject: Re: [alsa-devel] [RFC] ASoC: Add support for BCM2835
Date: Mon, 11 Nov 2013 19:37:30 +0100 [thread overview]
Message-ID: <528123EA.6090609@metafoo.de> (raw)
In-Reply-To: <527D5013.7080508-oZ8rN/sblLk@public.gmane.org>
On 11/08/2013 09:56 PM, Florian Meier wrote:
Is the I2S clock part of a generic clocking module? If yes it might be
better to implement this as a clock chip driver.
[...]
> +static void bcm2835_i2s_stop(struct bcm2835_i2s_dev *dev,
> + struct snd_pcm_substream *substream)
> +{
> + unsigned int still_running;
> +
> + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
> + BCM2835_I2S_RXON, 0);
> + } else {
> + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
> + BCM2835_I2S_TXON, 0);
> + }
> +
> + regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &still_running);
> + still_running &= BCM2835_I2S_TXON | BCM2835_I2S_RXON;
> +
still_running can be replaced with dai->active, I think
> + /* Stop also the clock when not SND_SOC_DAIFMT_CONT */
> + if (!still_running && !(dev->fmt & SND_SOC_DAIFMT_CONT))
> + bcm2835_i2s_stop_clock(dev);
> +
> +}
> +
> +static int bcm2835_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
> + struct snd_soc_dai *dai)
> +{
> + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
> +
> + switch (cmd) {
> + case SNDRV_PCM_TRIGGER_START:
> + case SNDRV_PCM_TRIGGER_RESUME:
> + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> + bcm2835_i2s_start_clock(dev);
> +
> + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> + regmap_update_bits(dev->i2s_regmap,
> + BCM2835_I2S_CS_A_REG,
> + BCM2835_I2S_RXON, BCM2835_I2S_RXON);
> + } else {
> + regmap_update_bits(dev->i2s_regmap,
> + BCM2835_I2S_CS_A_REG,
> + BCM2835_I2S_TXON, BCM2835_I2S_TXON);
> + }
Doing something like
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
mask = BCM2835_I2S_RXON;
else
mask = BCM2835_I2S_TXON;
regmap_update_bits(dev->i2s_regmap,
BCM2835_I2S_CS_A_REG, mask, mask);
makes the code a bit shorter. Same for bcm2835_i2s_stop().
> + break;
> +
> + case SNDRV_PCM_TRIGGER_STOP:
> + case SNDRV_PCM_TRIGGER_SUSPEND:
> + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> + bcm2835_i2s_stop(dev, substream);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int bcm2835_i2s_startup(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
> +
> + if (!dev->first_stream) {
> + dev->first_stream = substream;
> +
Since you use first_stream and second_stream for anything else I think you
can just use dai->active here instead.
> + /* should this still be running stop it */
> + bcm2835_i2s_stop_clock(dev);
> +
> + /* enable PCM block */
> + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
> + BCM2835_I2S_EN, -1);
> +
> + /*
> + * Disable STBY
> + * Requires at least 4 PCM clock cycles to take effect
> + */
> + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
> + BCM2835_I2S_STBY, -1);
> +
> + } else {
> + dev->second_stream = substream;
> + }
> +
> + return 0;
> +}
> +
[...]
> +static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
> +{
> + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
> +
> + /* Set the appropriate DMA parameters */
> + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
> + (dma_addr_t)BCM2835_I2S_FIFO_PHYSICAL_ADDR;
> + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
> + (dma_addr_t)BCM2835_I2S_FIFO_PHYSICAL_ADDR;
The dma address for the FIFO should not be hardcoded but rather use an
offset to the resource that get's pass to the driver.
dma_data->addr = mem->start + BCM2835_I2S_FIFO_A_REG;
I think it should be fine to initialize dma_data already in the driver
probe() function.
> +
> + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].slave_id =
> + BCM2835_DMA_DREQ_PCM_TX;
> + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].slave_id =
> + BCM2835_DMA_DREQ_PCM_RX;
> +
> + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
> + DMA_SLAVE_BUSWIDTH_4_BYTES;
> + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width =
> + DMA_SLAVE_BUSWIDTH_4_BYTES;
> +
> + /* TODO other burst parameters possible? */
> + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2;
> + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2;
> +
> + dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
> + dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
> +
> + return 0;
> +}
> +
[...]
> +
> +static bool bcm2835_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
> +{
> + switch (reg) {
> + case BCM2835_I2S_CS_A_REG:
> + case BCM2835_I2S_FIFO_A_REG:
> + case BCM2835_I2S_MODE_A_REG:
> + case BCM2835_I2S_RXC_A_REG:
> + case BCM2835_I2S_TXC_A_REG:
> + case BCM2835_I2S_DREQ_A_REG:
> + case BCM2835_I2S_INTEN_A_REG:
> + case BCM2835_I2S_INTSTC_A_REG:
> + case BCM2835_I2S_GRAY_REG:
> + return true;
> + default:
> + return false;
> + };
> +}
I think you use the default implementation of the here, which is basically
(reg >= 0 && reg <= config->max_register). Just leave the writeable_reg and
readable_reg fields of your config NULL.
[...]
> +
> +static const struct regmap_config bcm2835_i2s_regmap_config = {
> +};
This one seems to be unused.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
prev parent reply other threads:[~2013-11-11 18:37 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-08 20:56 [RFC] ASoC: Add support for BCM2835 Florian Meier
2013-11-09 18:48 ` Mark Brown
[not found] ` <527D5013.7080508-oZ8rN/sblLk@public.gmane.org>
2013-11-11 18:37 ` Lars-Peter Clausen [this message]
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=528123EA.6090609@metafoo.de \
--to=lars-qo5elluwu/uelga04laivw@public.gmane.org \
--cc=alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org \
--cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=dmaengine-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=florian.meier-oZ8rN/sblLk@public.gmane.org \
--cc=lgirdwood-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=martin-d5rIkyn9cnPYtjvyW6yDsg@public.gmane.org \
--cc=swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org \
/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;
as well as URLs for NNTP newsgroup(s).