Index: arch/arm/mach-bcm2708/bcm2708.c =================================================================== RCS file: /home/cvsroot/VolumioLinux/arch/arm/mach-bcm2708/bcm2708.c,v retrieving revision 1.1.1.2 retrieving revision 1.5 diff -p -u -8 -r1.1.1.2 -r1.5 --- arch/arm/mach-bcm2708/bcm2708.c 29 Mar 2015 00:02:51 -0000 1.1.1.2 +++ arch/arm/mach-bcm2708/bcm2708.c 8 May 2015 12:26:11 -0000 1.5 @@ -626,20 +626,25 @@ static struct platform_device bcm2835_th #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) static struct resource bcm2708_i2s_resources[] = { { .start = I2S_BASE, .end = I2S_BASE + 0x20, .flags = IORESOURCE_MEM, }, - { + { .start = PCM_CLOCK_BASE, .end = PCM_CLOCK_BASE + 0x02, .flags = IORESOURCE_MEM, + }, + { + .start = GP0CLK_CLOCK_BASE, + .end = GP0CLK_CLOCK_BASE + 0x02, + .flags = IORESOURCE_MEM, } }; static struct platform_device bcm2708_i2s_device = { .name = "bcm2708-i2s", .id = 0, .num_resources = ARRAY_SIZE(bcm2708_i2s_resources), .resource = bcm2708_i2s_resources, @@ -648,21 +653,45 @@ static struct platform_device bcm2708_i2 #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE) static struct platform_device snd_hifiberry_dac_device = { .name = "snd-hifiberry-dac", .id = 0, .num_resources = 0, }; +static struct platform_device snd_hifiberry_rtdac_device = { + .name = "snd-hifiberry-rtdac", + .id = 0, + .num_resources = 0, +}; + +static struct platform_device snd_hifiberry_iddac_device = { + .name = "snd-hifiberry-iddac", + .id = 0, + .num_resources = 0, +}; + static struct platform_device snd_pcm5102a_codec_device = { .name = "pcm5102a-codec", .id = -1, .num_resources = 0, }; + +static struct platform_device snd_hifiberry_24dac_device = { + .name = "snd-hifiberry-24dac", + .id = 0, + .num_resources = 0, +}; + +static struct platform_device snd_r2r_24_codec_device = { + .name = "r2r-24-codec", + .id = -1, + .num_resources = 0, +}; #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE) static struct platform_device snd_rpi_hifiberry_dacplus_device = { .name = "snd-rpi-hifiberry-dacplus", .id = 0, .num_resources = 0, }; @@ -899,17 +928,21 @@ void __init bcm2708_init(void) } #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) bcm_register_device_dt(&bcm2708_i2s_device); #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE) bcm_register_device_dt(&snd_hifiberry_dac_device); + bcm_register_device_dt(&snd_hifiberry_rtdac_device); + bcm_register_device_dt(&snd_hifiberry_iddac_device); bcm_register_device_dt(&snd_pcm5102a_codec_device); + bcm_register_device_dt(&snd_hifiberry_24dac_device); + bcm_register_device_dt(&snd_r2r_24_codec_device); #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE) bcm_register_device_dt(&snd_rpi_hifiberry_dacplus_device); i2c_register_board_info_dt(1, snd_pcm512x_hbdacplus_i2c_devices, ARRAY_SIZE(snd_pcm512x_hbdacplus_i2c_devices)); #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE) Index: arch/arm/mach-bcm2708/include/mach/platform.h =================================================================== RCS file: /home/cvsroot/VolumioLinux/arch/arm/mach-bcm2708/include/mach/platform.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -p -u -8 -r1.1.1.1 -r1.2 --- arch/arm/mach-bcm2708/include/mach/platform.h 14 Mar 2015 11:48:33 -0000 1.1.1.1 +++ arch/arm/mach-bcm2708/include/mach/platform.h 14 Mar 2015 22:42:33 -0000 1.2 @@ -58,16 +58,17 @@ #define BCM2708_PERI_BASE 0x20000000 #define IC0_BASE (BCM2708_PERI_BASE + 0x2000) #define ST_BASE (BCM2708_PERI_BASE + 0x3000) /* System Timer */ #define MPHI_BASE (BCM2708_PERI_BASE + 0x6000) /* Message -based Parallel Host Interface */ #define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */ #define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */ #define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */ #define PCM_CLOCK_BASE (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */ +#define GP0CLK_CLOCK_BASE (BCM2708_PERI_BASE + 0x101070) /* CM_GP0CLK Clock for I2S MCLK */ #define RNG_BASE (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */ #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */ #define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */ #define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */ #define I2S_BASE (BCM2708_PERI_BASE + 0x203000) /* I2S */ #define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 */ #define BSC0_BASE (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */ #define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */ Index: arch/arm/mach-bcm2709/bcm2709.c =================================================================== RCS file: /home/cvsroot/VolumioLinux/arch/arm/mach-bcm2709/bcm2709.c,v retrieving revision 1.1.1.1 retrieving revision 1.3 diff -p -u -8 -r1.1.1.1 -r1.3 --- arch/arm/mach-bcm2709/bcm2709.c 29 Mar 2015 00:02:46 -0000 1.1.1.1 +++ arch/arm/mach-bcm2709/bcm2709.c 8 May 2015 12:26:11 -0000 1.3 @@ -648,20 +648,25 @@ static struct platform_device bcm2835_th #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) static struct resource bcm2708_i2s_resources[] = { { .start = I2S_BASE, .end = I2S_BASE + 0x20, .flags = IORESOURCE_MEM, }, - { + { .start = PCM_CLOCK_BASE, .end = PCM_CLOCK_BASE + 0x02, .flags = IORESOURCE_MEM, + }, + { + .start = GP0CLK_CLOCK_BASE, + .end = GP0CLK_CLOCK_BASE + 0x02, + .flags = IORESOURCE_MEM, } }; static struct platform_device bcm2708_i2s_device = { .name = "bcm2708-i2s", .id = 0, .num_resources = ARRAY_SIZE(bcm2708_i2s_resources), .resource = bcm2708_i2s_resources, @@ -670,21 +675,45 @@ static struct platform_device bcm2708_i2 #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE) static struct platform_device snd_hifiberry_dac_device = { .name = "snd-hifiberry-dac", .id = 0, .num_resources = 0, }; +static struct platform_device snd_hifiberry_rtdac_device = { + .name = "snd-hifiberry-rtdac", + .id = 0, + .num_resources = 0, +}; + +static struct platform_device snd_hifiberry_iddac_device = { + .name = "snd-hifiberry-iddac", + .id = 0, + .num_resources = 0, +}; + static struct platform_device snd_pcm5102a_codec_device = { .name = "pcm5102a-codec", .id = -1, .num_resources = 0, }; + +static struct platform_device snd_hifiberry_24dac_device = { + .name = "snd-hifiberry-24dac", + .id = 0, + .num_resources = 0, +}; + +static struct platform_device snd_r2r_24_codec_device = { + .name = "r2r-24-codec", + .id = -1, + .num_resources = 0, +}; #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE) static struct platform_device snd_rpi_hifiberry_dacplus_device = { .name = "snd-rpi-hifiberry-dacplus", .id = 0, .num_resources = 0, }; @@ -921,17 +950,21 @@ void __init bcm2709_init(void) } #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) bcm_register_device_dt(&bcm2708_i2s_device); #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE) bcm_register_device_dt(&snd_hifiberry_dac_device); + bcm_register_device_dt(&snd_hifiberry_rtdac_device); + bcm_register_device_dt(&snd_hifiberry_iddac_device); bcm_register_device_dt(&snd_pcm5102a_codec_device); + bcm_register_device_dt(&snd_hifiberry_24dac_device); + bcm_register_device_dt(&snd_r2r_24_codec_device); #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE) bcm_register_device_dt(&snd_rpi_hifiberry_dacplus_device); i2c_register_board_info_dt(1, snd_pcm512x_hbdacplus_i2c_devices, ARRAY_SIZE(snd_pcm512x_hbdacplus_i2c_devices)); #endif #if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE) Index: arch/arm/mach-bcm2709/include/mach/platform.h =================================================================== RCS file: /home/cvsroot/VolumioLinux/arch/arm/mach-bcm2709/include/mach/platform.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -p -u -8 -r1.1.1.1 -r1.2 --- arch/arm/mach-bcm2709/include/mach/platform.h 29 Mar 2015 00:02:46 -0000 1.1.1.1 +++ arch/arm/mach-bcm2709/include/mach/platform.h 5 Apr 2015 04:04:20 -0000 1.2 @@ -58,16 +58,17 @@ #define BCM2708_PERI_BASE 0x3F000000 #define IC0_BASE (BCM2708_PERI_BASE + 0x2000) #define ST_BASE (BCM2708_PERI_BASE + 0x3000) /* System Timer */ #define MPHI_BASE (BCM2708_PERI_BASE + 0x6000) /* Message -based Parallel Host Interface */ #define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */ #define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */ #define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */ #define PCM_CLOCK_BASE (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */ +#define GP0CLK_CLOCK_BASE (BCM2708_PERI_BASE + 0x101070) /* CM_GP0CLK Clock for I2S MCLK */ #define RNG_BASE (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */ #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */ #define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */ #define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */ #define I2S_BASE (BCM2708_PERI_BASE + 0x203000) /* I2S */ #define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 */ #define BSC0_BASE (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */ #define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */ Index: include/sound/soc-dai.h =================================================================== RCS file: /home/cvsroot/VolumioLinux/include/sound/soc-dai.h,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -p -u -8 -r1.1.1.2 -r1.2 --- include/sound/soc-dai.h 29 Mar 2015 00:06:13 -0000 1.1.1.2 +++ include/sound/soc-dai.h 8 May 2015 12:26:11 -0000 1.2 @@ -65,21 +65,28 @@ struct snd_compr_stream; * i.e. if the codec is clk and FRM master then the interface is * clk and frame slave. */ #define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */ #define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */ #define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */ #define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */ -#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f -#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 -#define SND_SOC_DAIFMT_INV_MASK 0x0f00 -#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 +/* + * Clock division control + */ +#define SND_SOC_DAIFMT_CLKDIV_ASYNC (1 << 16) /* Integer division MLCK / async BCLK */ +#define SND_SOC_DAIFMT_CLKDIV_INDEP (2 << 16) /* Integer division MCLK / non async BLCK */ +#define SND_SOC_DAIFMT_CLKDIV_RTIME (3 << 16) /* Realtime MCKL / BCLK */ +#define SND_SOC_DAIFMT_FORMAT_MASK 0x0000000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x000000f0 +#define SND_SOC_DAIFMT_INV_MASK 0x00000f00 +#define SND_SOC_DAIFMT_MASTER_MASK 0x0000f000 +#define SND_SOC_DAIFMT_CLKDIV_MASK 0x000f0000 /* * Master Clock Directions */ #define SND_SOC_CLOCK_IN 0 #define SND_SOC_CLOCK_OUT 1 #define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\ SNDRV_PCM_FMTBIT_S16_LE |\ Index: sound/soc/bcm/Kconfig =================================================================== RCS file: /home/cvsroot/VolumioLinux/sound/soc/bcm/Kconfig,v retrieving revision 1.1.1.2 retrieving revision 1.4 diff -p -u -8 -r1.1.1.2 -r1.4 --- sound/soc/bcm/Kconfig 29 Mar 2015 00:07:36 -0000 1.1.1.2 +++ sound/soc/bcm/Kconfig 8 May 2015 12:26:11 -0000 1.4 @@ -21,16 +21,37 @@ config SND_BCM2708_SOC_I2S config SND_BCM2708_SOC_HIFIBERRY_DAC tristate "Support for HifiBerry DAC" depends on SND_BCM2708_SOC_I2S select SND_SOC_PCM5102A help Say Y or M if you want to add support for HifiBerry DAC. +config SND_BCM2708_SOC_HIFIBERRY_RTDAC + tristate "Support for HifiBerry RTDAC" + depends on SND_BCM2708_SOC_I2S + select SND_SOC_PCM5102A + help + Say Y or M if you want to add support for HifiBerry RTDAC. + +config SND_BCM2708_SOC_HIFIBERRY_IDDAC + tristate "Support for HifiBerry IDDAC" + depends on SND_BCM2708_SOC_I2S + select SND_SOC_PCM5102A + help + Say Y or M if you want to add support for HifiBerry IDDAC. + +config SND_BCM2708_SOC_HIFIBERRY_24DAC + tristate "Support for HifiBerry 24DAC" + depends on SND_BCM2708_SOC_I2S + select SND_SOC_R2R_24 + help + Say Y or M if you want to add support for HifiBerry 24DAC. + config SND_BCM2708_SOC_HIFIBERRY_DACPLUS tristate "Support for HifiBerry DAC+" depends on SND_BCM2708_SOC_I2S select SND_SOC_PCM512x help Say Y or M if you want to add support for HifiBerry DAC+. config SND_BCM2708_SOC_HIFIBERRY_DIGI Index: sound/soc/bcm/Makefile =================================================================== RCS file: /home/cvsroot/VolumioLinux/sound/soc/bcm/Makefile,v retrieving revision 1.1.1.2 retrieving revision 1.4 diff -p -u -8 -r1.1.1.2 -r1.4 --- sound/soc/bcm/Makefile 29 Mar 2015 00:07:36 -0000 1.1.1.2 +++ sound/soc/bcm/Makefile 8 May 2015 12:26:11 -0000 1.4 @@ -5,22 +5,28 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd # BCM2708 Platform Support snd-soc-bcm2708-i2s-objs := bcm2708-i2s.o obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o # BCM2708 Machine Support snd-soc-hifiberry-dac-objs := hifiberry_dac.o +snd-soc-hifiberry-rtdac-objs := hifiberry_rtdac.o +snd-soc-hifiberry-iddac-objs := hifiberry_iddac.o +snd-soc-hifiberry-24dac-objs := hifiberry_24dac.o snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o snd-soc-hifiberry-digi-objs := hifiberry_digi.o snd-soc-hifiberry-amp-objs := hifiberry_amp.o snd-soc-rpi-dac-objs := rpi-dac.o snd-soc-rpi-proto-objs := rpi-proto.o snd-soc-iqaudio-dac-objs := iqaudio-dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_RTDAC) += snd-soc-hifiberry-rtdac.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_IDDAC) += snd-soc-hifiberry-iddac.o +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_24DAC) += snd-soc-hifiberry-24dac.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o Index: sound/soc/bcm/bcm2708-i2s.c =================================================================== RCS file: /home/cvsroot/VolumioLinux/sound/soc/bcm/bcm2708-i2s.c,v retrieving revision 1.1.1.2 retrieving revision 1.6 diff -p -u -8 -r1.1.1.2 -r1.6 --- sound/soc/bcm/bcm2708-i2s.c 29 Mar 2015 00:07:36 -0000 1.1.1.2 +++ sound/soc/bcm/bcm2708-i2s.c 8 May 2015 12:26:11 -0000 1.6 @@ -175,16 +175,17 @@ static int bcm2708_i2s_gpio=BCM2708_I2S_ struct bcm2708_i2s_dev { struct device *dev; struct snd_dmaengine_dai_dma_data dma_data[2]; unsigned int fmt; unsigned int bclk_ratio; struct regmap *i2s_regmap; struct regmap *clk_regmap; + struct regmap *gpclk_regmap; }; void bcm2708_i2s_set_gpio(int gpio) { bcm2708_i2s_gpio=gpio; } EXPORT_SYMBOL(bcm2708_i2s_set_gpio); @@ -194,16 +195,19 @@ static void bcm2708_i2s_start_clock(stru unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; switch (master) { case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFM: regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); + regmap_update_bits(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, + BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, + BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); break; default: break; } } static void bcm2708_i2s_stop_clock(struct bcm2708_i2s_dev *dev) { @@ -224,27 +228,50 @@ static void bcm2708_i2s_stop_clock(struc if (!timeout) { /* KILL the clock */ dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n"); regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_KILL | BCM2708_CLK_PASSWD_MASK, BCM2708_CLK_KILL | BCM2708_CLK_PASSWD); } + + /* Stop clock for MCLK */ + regmap_update_bits(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, + BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, + BCM2708_CLK_PASSWD); + + /* Wait for the BUSY flag going down for GP0CLK */ + timeout = 1000; + while (--timeout) { + regmap_read(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); + if (!(clkreg & BCM2708_CLK_BUSY)) + break; + } + + if (!timeout) { + /* KILL the clock */ + dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n"); + regmap_update_bits(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, + BCM2708_CLK_KILL | BCM2708_CLK_PASSWD_MASK, + BCM2708_CLK_KILL | BCM2708_CLK_PASSWD); + } } static void bcm2708_i2s_clear_fifos(struct bcm2708_i2s_dev *dev, bool tx, bool rx) { int timeout = 1000; uint32_t syncval; uint32_t csreg; uint32_t i2s_active_state; uint32_t clkreg; uint32_t clk_active_state; + uint32_t gpclkreg; + uint32_t gpclk_active_state; uint32_t off; uint32_t clr; off = tx ? BCM2708_I2S_TXON : 0; off |= rx ? BCM2708_I2S_RXON : 0; clr = tx ? BCM2708_I2S_TXCLR : 0; clr |= rx ? BCM2708_I2S_RXCLR : 0; @@ -257,17 +284,27 @@ static void bcm2708_i2s_clear_fifos(stru clk_active_state = clkreg & BCM2708_CLK_ENAB; /* Start clock if not running */ if (!clk_active_state) { regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); } + + regmap_read(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, &gpclkreg); + gpclk_active_state = clkreg & BCM2708_CLK_ENAB; + /* Start clock if not running */ + if (!gpclk_active_state) { + regmap_update_bits(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, + BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, + BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); + } + /* Stop I2S module */ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, off, 0); /* * Clear the FIFOs * Requires at least 2 PCM clock cycles to take effect */ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, clr, clr); @@ -373,29 +410,31 @@ static void bcm2708_i2s_setup_gpio(void) printk(KERN_INFO "Can't configure I2S GPIOs, unknown pin mode for I2S: %i\n",pinconfig); return; } /* configure I2S pins to correct ALT mode */ for (pin = startpin; pin <= startpin+3; pin++) { bcm2708_i2s_set_function(pin, alt); } + bcm2708_i2s_set_function(4,0); } static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); unsigned int sampling_rate = params_rate(params); unsigned int data_length, data_delay, bclk_ratio; unsigned int ch1pos, ch2pos, mode, format; unsigned int mash = BCM2708_CLK_MASH_1; unsigned int divi, divf, target_frequency; + unsigned int mdivi, mdivf, mtarget_frequency; int clk_src = -1; unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS || master == SND_SOC_DAIFMT_CBS_CFM); bool frame_master = (master == SND_SOC_DAIFMT_CBS_CFS || master == SND_SOC_DAIFMT_CBM_CFS); uint32_t csreg; @@ -456,74 +495,152 @@ static int bcm2708_i2s_hw_params(struct * * MASH mode: * For all other sampling rates, it is not possible to * have an integer divider. Approximate the clock * with the MASH module that induces a slight frequency * variance. To minimize that it is best to have the fastest * clock here. That is PLLD with 500 MHz. */ +#if 0 target_frequency = sampling_rate * bclk_ratio; + mtarget_frequency = sampling_rate * 256; clk_src = BCM2708_CLK_SRC_OSC; mash = BCM2708_CLK_MASH_0; +#endif - if (bcm2708_clk_freq[clk_src] % target_frequency == 0 - && bit_master && frame_master) { - divi = bcm2708_clk_freq[clk_src] / target_frequency; - divf = 0; - } else { - uint64_t dividend; - - if (!dev->bclk_ratio) { - /* - * Overwrite bclk_ratio, because the - * above trick is not needed or can - * not be used. - */ - bclk_ratio = 2 * data_length; - } - + switch (dev->fmt & SND_SOC_DAIFMT_CLKDIV_MASK) + { + case SND_SOC_DAIFMT_CLKDIV_ASYNC: + case SND_SOC_DAIFMT_CLKDIV_INDEP: + bclk_ratio = 2 * data_length; target_frequency = sampling_rate * bclk_ratio; - clk_src = BCM2708_CLK_SRC_PLLD; - mash = BCM2708_CLK_MASH_1; + mash = BCM2708_CLK_MASH_0; + + switch (params_format(params)) + { + case SNDRV_PCM_FORMAT_S16_LE: + mtarget_frequency = sampling_rate * 256; + mdivi = bcm2708_clk_freq[clk_src] / mtarget_frequency; + divi = mdivi * 8; + break; + case SNDRV_PCM_FORMAT_S24_LE: + mtarget_frequency = sampling_rate * 192; + mdivi = bcm2708_clk_freq[clk_src] / mtarget_frequency; + divi = mdivi * 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + mtarget_frequency = sampling_rate * 256; + mdivi = bcm2708_clk_freq[clk_src] / mtarget_frequency; + divi = mdivi * 4; + break; + } + if((dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_CLKDIV_INDEP) + divi = bcm2708_clk_freq[clk_src] / target_frequency; + + divf = 0; + mdivf = 0; + + break; + + case SND_SOC_DAIFMT_CLKDIV_RTIME: + target_frequency = sampling_rate * bclk_ratio; + clk_src = BCM2708_CLK_SRC_OSC; + mash = BCM2708_CLK_MASH_0; + switch (params_format(params)) + { + case SNDRV_PCM_FORMAT_S16_LE: + mtarget_frequency = sampling_rate * 256; + break; + case SNDRV_PCM_FORMAT_S24_LE: + mtarget_frequency = sampling_rate * 192; + break; + case SNDRV_PCM_FORMAT_S32_LE: + mtarget_frequency = sampling_rate * 256; + break; + } + if (bcm2708_clk_freq[clk_src] % target_frequency == 0 + && bit_master && frame_master) { + divi = bcm2708_clk_freq[clk_src] / target_frequency; + divf = 0; + mdivi = bcm2708_clk_freq[clk_src] / mtarget_frequency; + mdivf = 0; + } else { + uint64_t dividend; + uint64_t mdividend; - dividend = bcm2708_clk_freq[clk_src]; - dividend <<= BCM2708_CLK_SHIFT; - do_div(dividend, target_frequency); - divi = dividend >> BCM2708_CLK_SHIFT; - divf = dividend & BCM2708_CLK_DIVF_MASK; + if (!dev->bclk_ratio) { + /* + * Overwrite bclk_ratio, because the + * above trick is not needed or can + * not be used. + */ + bclk_ratio = 2 * data_length; + } + + target_frequency = sampling_rate * bclk_ratio; + + clk_src = BCM2708_CLK_SRC_PLLD; + mash = BCM2708_CLK_MASH_1; + + dividend = bcm2708_clk_freq[clk_src]; + dividend <<= BCM2708_CLK_SHIFT; + + do_div(dividend, target_frequency); + divi = dividend >> BCM2708_CLK_SHIFT; + divf = dividend & BCM2708_CLK_DIVF_MASK; + + + mdividend = bcm2708_clk_freq[clk_src]; + mdividend <<= BCM2708_CLK_SHIFT; + + do_div(mdividend, mtarget_frequency); + mdivi = mdividend >> BCM2708_CLK_SHIFT; + mdivf = mdividend & BCM2708_CLK_DIVF_MASK; + } } - + /* Clock should only be set up here if CPU is clock master */ if (((dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) || ((dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFM)) { /* Set clock divider */ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMDIV_REG, BCM2708_CLK_PASSWD | BCM2708_CLK_DIVI(divi) | BCM2708_CLK_DIVF(divf)); /* Setup clock, but don't start it yet */ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD | BCM2708_CLK_MASH(mash) | BCM2708_CLK_SRC(clk_src)); + + + regmap_write(dev->gpclk_regmap, BCM2708_CLK_PCMDIV_REG, BCM2708_CLK_PASSWD + | BCM2708_CLK_DIVI(mdivi) + | BCM2708_CLK_DIVF(mdivf)); + regmap_write(dev->gpclk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD + | BCM2708_CLK_MASH(mash) + | BCM2708_CLK_SRC(clk_src)); } /* Setup the frame format */ format = BCM2708_I2S_CHEN; if (data_length >= 24) format |= BCM2708_I2S_CHWEX; format |= BCM2708_I2S_CHWID((data_length-8)&0xf); switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: data_delay = 1; break; + case SND_SOC_DAIFMT_LEFT_J: + data_delay = 0; + break; default: /* * TODO * Others are possible but are not implemented at the moment. */ dev_err(dev->dev, "%s:bad format\n", __func__); return -EINVAL; } @@ -863,16 +980,25 @@ static const struct regmap_config bcm270 .reg_bits = 32, .reg_stride = 4, .val_bits = 32, .max_register = BCM2708_CLK_PCMDIV_REG, .volatile_reg = bcm2708_clk_volatile_reg, .cache_type = REGCACHE_RBTREE, .name = "clk", }, + { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM2708_CLK_PCMDIV_REG, + .volatile_reg = bcm2708_clk_volatile_reg, + .cache_type = REGCACHE_RBTREE, + .name = "gp0clk", + }, }; static const struct snd_soc_component_driver bcm2708_i2s_component = { .name = "bcm2708-i2s-comp", }; static const struct snd_pcm_hardware bcm2708_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | @@ -894,21 +1020,21 @@ static const struct snd_dmaengine_pcm_co }; static int bcm2708_i2s_probe(struct platform_device *pdev) { struct bcm2708_i2s_dev *dev; int i; int ret; - struct regmap *regmap[2]; - struct resource *mem[2]; + struct regmap *regmap[3]; + struct resource *mem[3]; /* Request both ioareas */ - for (i = 0; i <= 1; i++) { + for (i = 0; i <= 2; i++) { void __iomem *base; mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i); base = devm_ioremap_resource(&pdev->dev, mem[i]); if (IS_ERR(base)) return PTR_ERR(base); regmap[i] = devm_regmap_init_mmio(&pdev->dev, base, @@ -921,16 +1047,17 @@ static int bcm2708_i2s_probe(struct plat dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (IS_ERR(dev)) return PTR_ERR(dev); dev->i2s_regmap = regmap[0]; dev->clk_regmap = regmap[1]; + dev->gpclk_regmap = regmap[2]; /* Set the DMA address */ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; Index: sound/soc/bcm/hifiberry_dac.c =================================================================== RCS file: /home/cvsroot/VolumioLinux/sound/soc/bcm/hifiberry_dac.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -p -u -8 -r1.1.1.2 -r1.2 --- sound/soc/bcm/hifiberry_dac.c 29 Mar 2015 00:07:36 -0000 1.1.1.2 +++ sound/soc/bcm/hifiberry_dac.c 8 May 2015 12:26:11 -0000 1.2 @@ -49,17 +49,17 @@ static struct snd_soc_dai_link snd_rpi_h { .name = "HifiBerry DAC", .stream_name = "HifiBerry DAC HiFi", .cpu_dai_name = "bcm2708-i2s.0", .codec_dai_name = "pcm5102a-hifi", .platform_name = "bcm2708-i2s.0", .codec_name = "pcm5102a-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_CLKDIV_ASYNC, .ops = &snd_rpi_hifiberry_dac_ops, .init = snd_rpi_hifiberry_dac_init, }, }; /* audio machine driver */ static struct snd_soc_card snd_rpi_hifiberry_dac = { .name = "snd_rpi_hifiberry_dac", Index: sound/soc/codecs/Kconfig =================================================================== RCS file: /home/cvsroot/VolumioLinux/sound/soc/codecs/Kconfig,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -p -u -8 -r1.1.1.2 -r1.3 --- sound/soc/codecs/Kconfig 29 Mar 2015 00:07:32 -0000 1.1.1.2 +++ sound/soc/codecs/Kconfig 3 Apr 2015 13:31:58 -0000 1.3 @@ -76,16 +76,17 @@ config SND_SOC_ALL_CODECS select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C select SND_SOC_PCM5102A if I2C + select SND_SOC_R2R_24 if I2C select SND_SOC_PCM1794A if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C select SND_SOC_SGTL5000 if I2C @@ -488,17 +489,23 @@ config SND_SOC_RL6231 config SND_SOC_RT286 tristate depends on I2C config SND_SOC_PCM1794A tristate config SND_SOC_PCM5102A + tristate + +config SND_SOC_R2R_24 tristate + +config SND_SOC_PCM512x + tristate config SND_SOC_RT5631 tristate config SND_SOC_RT5640 tristate config SND_SOC_RT5645 Index: sound/soc/codecs/Makefile =================================================================== RCS file: /home/cvsroot/VolumioLinux/sound/soc/codecs/Makefile,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -p -u -8 -r1.1.1.2 -r1.3 --- sound/soc/codecs/Makefile 29 Mar 2015 00:07:32 -0000 1.1.1.2 +++ sound/soc/codecs/Makefile 3 Apr 2015 13:31:58 -0000 1.3 @@ -71,16 +71,17 @@ snd-soc-pcm1792a-codec-objs := pcm1792a. snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rl6231-objs := rl6231.o snd-soc-rt286-objs := rt286.o snd-soc-pcm1794a-objs := pcm1794a.o snd-soc-pcm5102a-objs := pcm5102a.o +snd-soc-r2r-24-objs := r2r-24.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o @@ -250,16 +251,17 @@ obj-$(CONFIG_SND_SOC_PCM1792A) += snd-so obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o +obj-$(CONFIG_SND_SOC_R2R_24) += snd-soc-r2r-24.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o