diff --git a/arch/arm/boot/dts/bcm2708_common.dtsi b/arch/arm/boot/dts/bcm2708_common.dtsi index 03ad313ad1a03f..a71ab1de5132c0 100644 --- a/arch/arm/boot/dts/bcm2708_common.dtsi +++ b/arch/arm/boot/dts/bcm2708_common.dtsi @@ -127,12 +127,11 @@ }; i2s: i2s@7e203000 { - compatible = "brcm,bcm2708-i2s"; + compatible = "brcm,bcm2835-i2s"; reg = <0x7e203000 0x24>, <0x7e101098 0x08>; - //dmas = <&dma 2>, - // <&dma 3>; + dmas = <&dma 2>, <&dma 3>; dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index c659ae015bd01b..aac8db35be0834 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -835,6 +835,7 @@ CONFIG_SND_USB_CAIAQ=m CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_6FIRE=m CONFIG_SND_SOC=m +CONFIG_SND_BCM2835_SOC_I2S=m CONFIG_SND_BCM2708_SOC_I2S=m CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index e09b2dfb9512d9..c80648e9afb1db 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -828,6 +828,7 @@ CONFIG_SND_USB_CAIAQ=m CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_6FIRE=m CONFIG_SND_SOC=m +CONFIG_SND_BCM2835_SOC_I2S=m CONFIG_SND_BCM2708_SOC_I2S=m CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS=m diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index f465dd2021e192..794ff7a61b2082 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -1,6 +1,6 @@ config SND_BCM2835_SOC_I2S tristate "SoC Audio support for the Broadcom BCM2835 I2S module" - depends on ARCH_BCM2835 || COMPILE_TEST + depends on ARCH_BCM2835 || MACH_BCM2708 || MACH_BCM2709 || COMPILE_TEST select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help @@ -70,7 +70,7 @@ config SND_BCM2708_SOC_IQAUDIO_DAC config SND_BCM2708_SOC_RASPIDAC3 tristate "Support for RaspiDAC Rev.3x" - depends on SND_BCM2708_SOC_I2S + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S select SND_SOC_PCM512x_I2C select SND_SOC_TPA6130A2 help diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index c8165263492191..cbc772d4d3f968 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -158,10 +159,6 @@ static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = { #define BCM2835_I2S_INT_RXR BIT(1) #define BCM2835_I2S_INT_TXW BIT(0) -/* I2S DMA interface */ -/* FIXME: Needs IOMMU support */ -#define BCM2835_VCMMU_SHIFT (0x7E000000 - 0x20000000) - /* General device struct */ struct bcm2835_i2s_dev { struct device *dev; @@ -343,11 +340,15 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: data_length = 16; - bclk_ratio = 40; + bclk_ratio = 50; + break; + case SNDRV_PCM_FORMAT_S24_LE: + data_length = 24; + bclk_ratio = 50; break; case SNDRV_PCM_FORMAT_S32_LE: data_length = 32; - bclk_ratio = 80; + bclk_ratio = 100; break; default: return -EINVAL; @@ -410,20 +411,30 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, divf = dividend & BCM2835_CLK_DIVF_MASK; } - /* Set clock divider */ - regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD - | BCM2835_CLK_DIVI(divi) - | BCM2835_CLK_DIVF(divf)); - - /* Setup clock, but don't start it yet */ - regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD - | BCM2835_CLK_MASH(mash) - | BCM2835_CLK_SRC(clk_src)); + /* Clock should only be set up here if CPU is clock master */ + switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBS_CFM: + /* Set clock divider */ + regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, + BCM2835_CLK_PASSWD + | BCM2835_CLK_DIVI(divi) + | BCM2835_CLK_DIVF(divf)); + + /* Setup clock, but don't start it yet */ + regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, + BCM2835_CLK_PASSWD + | BCM2835_CLK_MASH(mash) + | BCM2835_CLK_SRC(clk_src)); + break; + default: + break; + } /* Setup the frame format */ format = BCM2835_I2S_CHEN; - if (data_length > 24) + if (data_length >= 24) format |= BCM2835_I2S_CHWEX; format |= BCM2835_I2S_CHWID((data_length-8)&0xf); @@ -714,6 +725,7 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE }, .capture = { @@ -721,6 +733,7 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE }, .ops = &bcm2835_i2s_dai_ops, @@ -769,6 +782,7 @@ static const struct regmap_config bcm2835_regmap_config[] = { .precious_reg = bcm2835_i2s_precious_reg, .volatile_reg = bcm2835_i2s_volatile_reg, .cache_type = REGCACHE_RBTREE, + .name = "i2s", }, { .reg_bits = 32, @@ -777,6 +791,7 @@ static const struct regmap_config bcm2835_regmap_config[] = { .max_register = BCM2835_CLK_PCMDIV_REG, .volatile_reg = bcm2835_clk_volatile_reg, .cache_type = REGCACHE_RBTREE, + .name = "clk", }, }; @@ -784,6 +799,25 @@ static const struct snd_soc_component_driver bcm2835_i2s_component = { .name = "bcm2835-i2s-comp", }; +static struct snd_pcm_hardware bcm2835_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_JOINT_DUPLEX, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 32, + .period_bytes_max = 64 * PAGE_SIZE, + .periods_min = 2, + .periods_max = 255, + .buffer_bytes_max = 128 * PAGE_SIZE, +}; + +static const struct snd_dmaengine_pcm_config bcm2835_dmaengine_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .pcm_hardware = &bcm2835_pcm_hardware, + .prealloc_buffer_size = 256 * PAGE_SIZE, +}; + static int bcm2835_i2s_probe(struct platform_device *pdev) { struct bcm2835_i2s_dev *dev; @@ -791,6 +825,20 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) int ret; struct regmap *regmap[2]; struct resource *mem[2]; + const __be32 *addr; + dma_addr_t dma_reg_base; + + addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL); + if (!addr) { + dev_err(&pdev->dev, "could not get DMA-register address\n"); + return -ENODEV; + } + dma_reg_base = be32_to_cpup(addr); + + if (of_property_read_bool(pdev->dev.of_node, "brcm,enable-mmap")) + bcm2835_pcm_hardware.info |= + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID; /* Request both ioareas */ for (i = 0; i <= 1; i++) { @@ -817,12 +865,10 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) /* Set the DMA address */ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = - (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG - + BCM2835_VCMMU_SHIFT; + dma_reg_base + BCM2835_I2S_FIFO_A_REG; dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = - (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG - + BCM2835_VCMMU_SHIFT; + dma_reg_base + BCM2835_I2S_FIFO_A_REG; /* Set the bus width */ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = @@ -848,7 +894,9 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) return ret; } - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, + &bcm2835_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_COMPAT); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); return ret;