Lines Matching +full:dai +full:- +full:tdm +full:- +full:slot +full:- +full:rx +full:- +full:mask
1 // SPDX-License-Identifier: GPL-2.0-only
16 * OMAP ALSA SoC DAI driver using McBSP port
21 * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
23 * Copyright 2007-2010 Freescale Semiconductor, Inc.
130 unsigned int provider = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; in bcm2835_i2s_start_clock()
132 if (dev->clk_prepared) in bcm2835_i2s_start_clock()
138 clk_prepare_enable(dev->clk); in bcm2835_i2s_start_clock()
139 dev->clk_prepared = true; in bcm2835_i2s_start_clock()
148 if (dev->clk_prepared) in bcm2835_i2s_stop_clock()
149 clk_disable_unprepare(dev->clk); in bcm2835_i2s_stop_clock()
150 dev->clk_prepared = false; in bcm2835_i2s_stop_clock()
154 bool tx, bool rx) in bcm2835_i2s_clear_fifos() argument
165 off |= rx ? BCM2835_I2S_RXON : 0; in bcm2835_i2s_clear_fifos()
168 clr |= rx ? BCM2835_I2S_RXCLR : 0; in bcm2835_i2s_clear_fifos()
171 regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); in bcm2835_i2s_clear_fifos()
175 clk_was_prepared = dev->clk_prepared; in bcm2835_i2s_clear_fifos()
180 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0); in bcm2835_i2s_clear_fifos()
186 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, clr, clr); in bcm2835_i2s_clear_fifos()
194 regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &syncval); in bcm2835_i2s_clear_fifos()
197 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, in bcm2835_i2s_clear_fifos()
201 while (--timeout) { in bcm2835_i2s_clear_fifos()
202 regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); in bcm2835_i2s_clear_fifos()
208 dev_err(dev->dev, "I2S SYNC error!\n"); in bcm2835_i2s_clear_fifos()
215 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, in bcm2835_i2s_clear_fifos()
219 static int bcm2835_i2s_set_dai_fmt(struct snd_soc_dai *dai, in bcm2835_i2s_set_dai_fmt() argument
222 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_set_dai_fmt()
223 dev->fmt = fmt; in bcm2835_i2s_set_dai_fmt()
227 static int bcm2835_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, in bcm2835_i2s_set_dai_bclk_ratio() argument
230 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_set_dai_bclk_ratio()
233 dev->tdm_slots = 0; in bcm2835_i2s_set_dai_bclk_ratio()
238 return -EINVAL; in bcm2835_i2s_set_dai_bclk_ratio()
240 dev->tdm_slots = 2; in bcm2835_i2s_set_dai_bclk_ratio()
241 dev->rx_mask = 0x03; in bcm2835_i2s_set_dai_bclk_ratio()
242 dev->tx_mask = 0x03; in bcm2835_i2s_set_dai_bclk_ratio()
243 dev->slot_width = ratio / 2; in bcm2835_i2s_set_dai_bclk_ratio()
244 dev->frame_length = ratio; in bcm2835_i2s_set_dai_bclk_ratio()
249 static int bcm2835_i2s_set_dai_tdm_slot(struct snd_soc_dai *dai, in bcm2835_i2s_set_dai_tdm_slot() argument
253 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_set_dai_tdm_slot()
257 return -EINVAL; in bcm2835_i2s_set_dai_tdm_slot()
260 rx_mask &= GENMASK(slots - 1, 0); in bcm2835_i2s_set_dai_tdm_slot()
261 tx_mask &= GENMASK(slots - 1, 0); in bcm2835_i2s_set_dai_tdm_slot()
264 * The driver is limited to 2-channel setups. in bcm2835_i2s_set_dai_tdm_slot()
269 return -EINVAL; in bcm2835_i2s_set_dai_tdm_slot()
272 return -EINVAL; in bcm2835_i2s_set_dai_tdm_slot()
275 dev->tdm_slots = slots; in bcm2835_i2s_set_dai_tdm_slot()
277 dev->rx_mask = rx_mask; in bcm2835_i2s_set_dai_tdm_slot()
278 dev->tx_mask = tx_mask; in bcm2835_i2s_set_dai_tdm_slot()
279 dev->slot_width = width; in bcm2835_i2s_set_dai_tdm_slot()
280 dev->frame_length = slots * width; in bcm2835_i2s_set_dai_tdm_slot()
286 * Convert logical slot number into physical slot number.
289 * This is used for DSP modes with slot numbering 0 1 2 3 ...
293 * translate from logical slot numbers 0 1 2 3 ... into physical slot
296 static int bcm2835_i2s_convert_slot(unsigned int slot, unsigned int odd_offset) in bcm2835_i2s_convert_slot() argument
299 return slot; in bcm2835_i2s_convert_slot()
301 if (slot & 1) in bcm2835_i2s_convert_slot()
302 return (slot >> 1) + odd_offset; in bcm2835_i2s_convert_slot()
304 return slot >> 1; in bcm2835_i2s_convert_slot()
308 * Calculate channel position from mask and slot width.
310 * Mask must contain exactly 2 set bits.
314 * If odd_offset is > 0 slot positions are translated to
315 * I2S-style TDM slot numbering ( 0 2 ... 3 4 ...) with odd
316 * logical slot numbers starting at physical slot odd_offset.
320 unsigned int mask, unsigned int width, in bcm2835_i2s_calc_channel_pos() argument
323 *ch1_pos = bcm2835_i2s_convert_slot((ffs(mask) - 1), odd_offset) in bcm2835_i2s_calc_channel_pos()
325 *ch2_pos = bcm2835_i2s_convert_slot((fls(mask) - 1), odd_offset) in bcm2835_i2s_calc_channel_pos()
331 struct snd_soc_dai *dai) in bcm2835_i2s_hw_params() argument
333 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_hw_params()
350 regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); in bcm2835_i2s_hw_params()
360 if (dev->tdm_slots) { in bcm2835_i2s_hw_params()
361 slots = dev->tdm_slots; in bcm2835_i2s_hw_params()
362 slot_width = dev->slot_width; in bcm2835_i2s_hw_params()
363 frame_length = dev->frame_length; in bcm2835_i2s_hw_params()
364 rx_mask = dev->rx_mask; in bcm2835_i2s_hw_params()
365 tx_mask = dev->tx_mask; in bcm2835_i2s_hw_params()
366 bclk_rate = dev->frame_length * params_rate(params); in bcm2835_i2s_hw_params()
384 return -EINVAL; in bcm2835_i2s_hw_params()
387 switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { in bcm2835_i2s_hw_params()
397 return -EINVAL; in bcm2835_i2s_hw_params()
401 switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { in bcm2835_i2s_hw_params()
411 return -EINVAL; in bcm2835_i2s_hw_params()
416 (!dev->clk_prepared || dev->clk_rate != bclk_rate)) { in bcm2835_i2s_hw_params()
417 if (dev->clk_prepared) in bcm2835_i2s_hw_params()
420 if (dev->clk_rate != bclk_rate) { in bcm2835_i2s_hw_params()
421 ret = clk_set_rate(dev->clk, bclk_rate); in bcm2835_i2s_hw_params()
424 dev->clk_rate = bclk_rate; in bcm2835_i2s_hw_params()
436 format |= BCM2835_I2S_CHWID((data_length-8)&0xf); in bcm2835_i2s_hw_params()
441 switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { in bcm2835_i2s_hw_params()
445 return -EINVAL; in bcm2835_i2s_hw_params()
448 * Use I2S-style logical slot numbering: even slots in bcm2835_i2s_hw_params()
462 return -EINVAL; in bcm2835_i2s_hw_params()
471 return -EINVAL; in bcm2835_i2s_hw_params()
475 return -EINVAL; in bcm2835_i2s_hw_params()
478 data_delay = slot_width - data_length; in bcm2835_i2s_hw_params()
493 return -EINVAL; in bcm2835_i2s_hw_params()
503 * in left-justified or DSP mode A, only works stable in bcm2835_i2s_hw_params()
507 dev_warn(dev->dev, in bcm2835_i2s_hw_params()
516 regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, in bcm2835_i2s_hw_params()
520 regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, in bcm2835_i2s_hw_params()
537 mode |= BCM2835_I2S_FLEN(frame_length - 1); in bcm2835_i2s_hw_params()
549 switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) { in bcm2835_i2s_hw_params()
558 return -EINVAL; in bcm2835_i2s_hw_params()
562 switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) { in bcm2835_i2s_hw_params()
574 return -EINVAL; in bcm2835_i2s_hw_params()
577 regmap_write(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, mode); in bcm2835_i2s_hw_params()
580 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, in bcm2835_i2s_hw_params()
585 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG, in bcm2835_i2s_hw_params()
594 dev_dbg(dev->dev, in bcm2835_i2s_hw_params()
595 "slots: %d width: %d rx mask: 0x%02x tx_mask: 0x%02x\n", in bcm2835_i2s_hw_params()
598 dev_dbg(dev->dev, "frame len: %d sync len: %d data len: %d\n", in bcm2835_i2s_hw_params()
601 dev_dbg(dev->dev, "rx pos: %d,%d tx pos: %d,%d\n", in bcm2835_i2s_hw_params()
604 dev_dbg(dev->dev, "sampling rate: %d bclk rate: %d\n", in bcm2835_i2s_hw_params()
607 dev_dbg(dev->dev, "CLKM: %d CLKI: %d FSM: %d FSI: %d frame start: %s edge\n", in bcm2835_i2s_hw_params()
618 struct snd_soc_dai *dai) in bcm2835_i2s_prepare() argument
620 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_prepare()
629 regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &cs_reg); in bcm2835_i2s_prepare()
631 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK in bcm2835_i2s_prepare()
634 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE in bcm2835_i2s_prepare()
643 struct snd_soc_dai *dai) in bcm2835_i2s_stop() argument
645 uint32_t mask; in bcm2835_i2s_stop() local
647 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) in bcm2835_i2s_stop()
648 mask = BCM2835_I2S_RXON; in bcm2835_i2s_stop()
650 mask = BCM2835_I2S_TXON; in bcm2835_i2s_stop()
652 regmap_update_bits(dev->i2s_regmap, in bcm2835_i2s_stop()
653 BCM2835_I2S_CS_A_REG, mask, 0); in bcm2835_i2s_stop()
656 if (!snd_soc_dai_active(dai) && !(dev->fmt & SND_SOC_DAIFMT_CONT)) in bcm2835_i2s_stop()
661 struct snd_soc_dai *dai) in bcm2835_i2s_trigger() argument
663 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_trigger()
664 uint32_t mask; in bcm2835_i2s_trigger() local
672 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) in bcm2835_i2s_trigger()
673 mask = BCM2835_I2S_RXON; in bcm2835_i2s_trigger()
675 mask = BCM2835_I2S_TXON; in bcm2835_i2s_trigger()
677 regmap_update_bits(dev->i2s_regmap, in bcm2835_i2s_trigger()
678 BCM2835_I2S_CS_A_REG, mask, mask); in bcm2835_i2s_trigger()
684 bcm2835_i2s_stop(dev, substream, dai); in bcm2835_i2s_trigger()
687 return -EINVAL; in bcm2835_i2s_trigger()
694 struct snd_soc_dai *dai) in bcm2835_i2s_startup() argument
696 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_startup()
698 if (snd_soc_dai_active(dai)) in bcm2835_i2s_startup()
705 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, in bcm2835_i2s_startup()
712 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, in bcm2835_i2s_startup()
719 struct snd_soc_dai *dai) in bcm2835_i2s_shutdown() argument
721 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_shutdown()
723 bcm2835_i2s_stop(dev, substream, dai); in bcm2835_i2s_shutdown()
726 if (snd_soc_dai_active(dai)) in bcm2835_i2s_shutdown()
730 regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, in bcm2835_i2s_shutdown()
740 static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) in bcm2835_i2s_dai_probe() argument
742 struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); in bcm2835_i2s_dai_probe()
744 snd_soc_dai_init_dma_data(dai, in bcm2835_i2s_dai_probe()
745 &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], in bcm2835_i2s_dai_probe()
746 &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); in bcm2835_i2s_dai_probe()
764 .name = "bcm2835-i2s",
824 .name = "bcm2835-i2s-comp",
836 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), in bcm2835_i2s_probe()
839 return -ENOMEM; in bcm2835_i2s_probe()
842 dev->clk_prepared = false; in bcm2835_i2s_probe()
843 dev->clk = devm_clk_get(&pdev->dev, NULL); in bcm2835_i2s_probe()
844 if (IS_ERR(dev->clk)) in bcm2835_i2s_probe()
845 return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk), in bcm2835_i2s_probe()
853 dev->i2s_regmap = devm_regmap_init_mmio(&pdev->dev, base, in bcm2835_i2s_probe()
855 if (IS_ERR(dev->i2s_regmap)) in bcm2835_i2s_probe()
856 return PTR_ERR(dev->i2s_regmap); in bcm2835_i2s_probe()
858 /* Set the DMA address - we have to parse DT ourselves */ in bcm2835_i2s_probe()
859 addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL); in bcm2835_i2s_probe()
861 dev_err(&pdev->dev, "could not get DMA-register address\n"); in bcm2835_i2s_probe()
862 return -EINVAL; in bcm2835_i2s_probe()
866 dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = in bcm2835_i2s_probe()
869 dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = in bcm2835_i2s_probe()
873 dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = in bcm2835_i2s_probe()
875 dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width = in bcm2835_i2s_probe()
879 dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; in bcm2835_i2s_probe()
880 dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; in bcm2835_i2s_probe()
884 * packed into 32-bit transfers). in bcm2835_i2s_probe()
886 dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].flags = in bcm2835_i2s_probe()
888 dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].flags = in bcm2835_i2s_probe()
892 dev->dev = &pdev->dev; in bcm2835_i2s_probe()
893 dev_set_drvdata(&pdev->dev, dev); in bcm2835_i2s_probe()
895 ret = devm_snd_soc_register_component(&pdev->dev, in bcm2835_i2s_probe()
898 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); in bcm2835_i2s_probe()
902 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); in bcm2835_i2s_probe()
904 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); in bcm2835_i2s_probe()
912 { .compatible = "brcm,bcm2835-i2s", },
921 .name = "bcm2835-i2s",
928 MODULE_ALIAS("platform:bcm2835-i2s");