From c62db3d5abf89ca5502c7fe1f869c2862e48336d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 12 Jan 2016 15:53:46 +0800 Subject: ASoC: rt5659: Staticise rt5659_i2c_shutdown Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5659.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 820d8fa62b5e..47c717f4964a 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -4184,7 +4184,7 @@ static int rt5659_i2c_remove(struct i2c_client *i2c) return 0; } -void rt5659_i2c_shutdown(struct i2c_client *client) +static void rt5659_i2c_shutdown(struct i2c_client *client) { struct rt5659_priv *rt5659 = i2c_get_clientdata(client); -- cgit v1.2.3 From fcde5a7eca1a28d3f7158399809cb01f83bd0114 Mon Sep 17 00:00:00 2001 From: PC Liao Date: Tue, 12 Jan 2016 14:33:42 +0800 Subject: ASoC: mediatek: Enable 33bit memory address to support 4GB DRAM If platform is embedded with memory more than 3GB, the address will go out of the scope that 32-bit can handle with. This patch sets the dma_mask and MSB properly to describe its address to 33-bit. Signed-off-by: Hidalgo Huang Signed-off-by: PC Liao Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-common.h | 1 + sound/soc/mediatek/mtk-afe-pcm.c | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h index 9b1af1a70874..f341f623e887 100644 --- a/sound/soc/mediatek/mtk-afe-common.h +++ b/sound/soc/mediatek/mtk-afe-common.h @@ -87,6 +87,7 @@ struct mtk_afe_memif_data { int irq_en_shift; int irq_fs_shift; int irq_clr_shift; + int msb_shift; }; struct mtk_afe_memif { diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 08af9f5dc4ab..689c51f23d9f 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "mtk-afe-common.h" @@ -35,6 +36,7 @@ #define AFE_I2S_CON1 0x0034 #define AFE_I2S_CON2 0x0038 #define AFE_CONN_24BIT 0x006c +#define AFE_MEMIF_MSB 0x00cc #define AFE_CONN1 0x0024 #define AFE_CONN2 0x0028 @@ -592,6 +594,7 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + int msb_at_bit33 = 0; int ret; dev_dbg(afe->dev, @@ -603,7 +606,8 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - memif->phys_buf_addr = substream->runtime->dma_addr; + msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0; + memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); memif->buffer_size = substream->runtime->dma_bytes; /* start */ @@ -614,6 +618,11 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, memif->phys_buf_addr + memif->buffer_size - 1); + /* set MSB to 33-bit */ + regmap_update_bits(afe->regmap, AFE_MEMIF_MSB, + 1 << memif->data->msb_shift, + msb_at_bit33 << memif->data->msb_shift); + /* set channel */ if (memif->data->mono_shift >= 0) { unsigned int mono = (params_channels(params) == 1) ? 1 : 0; @@ -978,6 +987,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 0, .irq_fs_shift = 4, .irq_clr_shift = 0, + .msb_shift = 0, }, { .name = "DL2", .id = MTK_AFE_MEMIF_DL2, @@ -991,6 +1001,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 2, .irq_fs_shift = 16, .irq_clr_shift = 2, + .msb_shift = 1, }, { .name = "VUL", .id = MTK_AFE_MEMIF_VUL, @@ -1004,6 +1015,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 1, .irq_fs_shift = 8, .irq_clr_shift = 1, + .msb_shift = 6, }, { .name = "DAI", .id = MTK_AFE_MEMIF_DAI, @@ -1017,6 +1029,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 3, .irq_fs_shift = 20, .irq_clr_shift = 3, + .msb_shift = 5, }, { .name = "AWB", .id = MTK_AFE_MEMIF_AWB, @@ -1030,6 +1043,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 14, .irq_fs_shift = 24, .irq_clr_shift = 6, + .msb_shift = 3, }, { .name = "MOD_DAI", .id = MTK_AFE_MEMIF_MOD_DAI, @@ -1043,6 +1057,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 3, .irq_fs_shift = 20, .irq_clr_shift = 3, + .msb_shift = 4, }, { .name = "HDMI", .id = MTK_AFE_MEMIF_HDMI, @@ -1056,6 +1071,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .irq_en_shift = 12, .irq_fs_shift = -1, .irq_clr_shift = 4, + .msb_shift = 8, }, }; @@ -1189,6 +1205,10 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) struct mtk_afe *afe; struct resource *res; + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); + if (ret) + return ret; + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; -- cgit v1.2.3 From 517e7a1537ae4663268be5d0c0ec62c563b9fc99 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 12 Jan 2016 12:35:46 +0000 Subject: ASoC: bcm2835: move to use the clock framework Since the move to the new clock framework with commit 94cb7f76caa0 ("ARM: bcm2835: Switch to using the new clock driver support.") this driver was no longer functional as it was manipulating the clock registers locally without going true the framework. This patch moves to use the new clock framework and also moves away from the hardcoded address offsets for DMA getting the dma-address directly from the device tree. Note that the optimal bclk_ratio selection to avoid jitter due to the use of fractional dividers, which is in the current version has been removed, because not all devices support these non power of 2 sized transfers, which resulted in lots of (downstream) modules that use: snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); Signed-off-by: Martin Sperl Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 284 ++++++++++---------------------------------- 1 file changed, 64 insertions(+), 220 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 3303d5f58082..1c1f2210387b 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -46,55 +47,6 @@ #include #include -/* Clock registers */ -#define BCM2835_CLK_PCMCTL_REG 0x00 -#define BCM2835_CLK_PCMDIV_REG 0x04 - -/* Clock register settings */ -#define BCM2835_CLK_PASSWD (0x5a000000) -#define BCM2835_CLK_PASSWD_MASK (0xff000000) -#define BCM2835_CLK_MASH(v) ((v) << 9) -#define BCM2835_CLK_FLIP BIT(8) -#define BCM2835_CLK_BUSY BIT(7) -#define BCM2835_CLK_KILL BIT(5) -#define BCM2835_CLK_ENAB BIT(4) -#define BCM2835_CLK_SRC(v) (v) - -#define BCM2835_CLK_SHIFT (12) -#define BCM2835_CLK_DIVI(v) ((v) << BCM2835_CLK_SHIFT) -#define BCM2835_CLK_DIVF(v) (v) -#define BCM2835_CLK_DIVF_MASK (0xFFF) - -enum { - BCM2835_CLK_MASH_0 = 0, - BCM2835_CLK_MASH_1, - BCM2835_CLK_MASH_2, - BCM2835_CLK_MASH_3, -}; - -enum { - BCM2835_CLK_SRC_GND = 0, - BCM2835_CLK_SRC_OSC, - BCM2835_CLK_SRC_DBG0, - BCM2835_CLK_SRC_DBG1, - BCM2835_CLK_SRC_PLLA, - BCM2835_CLK_SRC_PLLC, - BCM2835_CLK_SRC_PLLD, - BCM2835_CLK_SRC_HDMI, -}; - -/* Most clocks are not useable (freq = 0) */ -static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = { - [BCM2835_CLK_SRC_GND] = 0, - [BCM2835_CLK_SRC_OSC] = 19200000, - [BCM2835_CLK_SRC_DBG0] = 0, - [BCM2835_CLK_SRC_DBG1] = 0, - [BCM2835_CLK_SRC_PLLA] = 0, - [BCM2835_CLK_SRC_PLLC] = 0, - [BCM2835_CLK_SRC_PLLD] = 500000000, - [BCM2835_CLK_SRC_HDMI] = 0, -}; - /* I2S registers */ #define BCM2835_I2S_CS_A_REG 0x00 #define BCM2835_I2S_FIFO_A_REG 0x04 @@ -158,10 +110,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; @@ -169,21 +117,23 @@ struct bcm2835_i2s_dev { unsigned int fmt; unsigned int bclk_ratio; - struct regmap *i2s_regmap; - struct regmap *clk_regmap; + struct regmap *i2s_regmap; + struct clk *clk; + bool clk_prepared; }; static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) { - /* Start the clock if in master mode */ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; + if (dev->clk_prepared) + return; + switch (master) { case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFM: - regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, - BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, - BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB); + clk_prepare_enable(dev->clk); + dev->clk_prepared = true; break; default: break; @@ -192,28 +142,9 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev) { - uint32_t clkreg; - int timeout = 1000; - - /* Stop clock */ - regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, - BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, - BCM2835_CLK_PASSWD); - - /* Wait for the BUSY flag going down */ - while (--timeout) { - regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg); - if (!(clkreg & BCM2835_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->clk_regmap, BCM2835_CLK_PCMCTL_REG, - BCM2835_CLK_KILL | BCM2835_CLK_PASSWD_MASK, - BCM2835_CLK_KILL | BCM2835_CLK_PASSWD); - } + if (dev->clk_prepared) + clk_disable_unprepare(dev->clk); + dev->clk_prepared = false; } static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, @@ -223,8 +154,7 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, uint32_t syncval; uint32_t csreg; uint32_t i2s_active_state; - uint32_t clkreg; - uint32_t clk_active_state; + bool clk_was_prepared; uint32_t off; uint32_t clr; @@ -238,15 +168,10 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON); - regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg); - clk_active_state = clkreg & BCM2835_CLK_ENAB; - /* Start clock if not running */ - if (!clk_active_state) { - regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, - BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, - BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB); - } + clk_was_prepared = dev->clk_prepared; + if (!clk_was_prepared) + bcm2835_i2s_start_clock(dev); /* Stop I2S module */ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0); @@ -280,7 +205,7 @@ static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, dev_err(dev->dev, "I2S SYNC error!\n"); /* Stop clock if it was not running before */ - if (!clk_active_state) + if (!clk_was_prepared) bcm2835_i2s_stop_clock(dev); /* Restore I2S state */ @@ -309,19 +234,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct bcm2835_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 = BCM2835_CLK_MASH_1; - unsigned int divi, divf, target_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; /* @@ -343,11 +258,9 @@ 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; break; case SNDRV_PCM_FORMAT_S32_LE: data_length = 32; - bclk_ratio = 80; break; default: return -EINVAL; @@ -356,69 +269,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, /* If bclk_ratio already set, use that one. */ if (dev->bclk_ratio) bclk_ratio = dev->bclk_ratio; + else + /* otherwise calculate a fitting block ratio */ + bclk_ratio = 2 * data_length; - /* - * Clock Settings - * - * The target frequency of the bit clock is - * sampling rate * frame length - * - * Integer mode: - * Sampling rates that are multiples of 8000 kHz - * can be driven by the oscillator of 19.2 MHz - * with an integer divider as long as the frame length - * is an integer divider of 19200000/8000=2400 as set up above. - * This is no longer possible if the sampling rate - * is too high (e.g. 192 kHz), because the oscillator is too slow. - * - * 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. - */ - target_frequency = sampling_rate * bclk_ratio; - clk_src = BCM2835_CLK_SRC_OSC; - mash = BCM2835_CLK_MASH_0; - - if (bcm2835_clk_freq[clk_src] % target_frequency == 0 - && bit_master && frame_master) { - divi = bcm2835_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; - } - - target_frequency = sampling_rate * bclk_ratio; - - clk_src = BCM2835_CLK_SRC_PLLD; - mash = BCM2835_CLK_MASH_1; - - dividend = bcm2835_clk_freq[clk_src]; - dividend <<= BCM2835_CLK_SHIFT; - do_div(dividend, target_frequency); - divi = dividend >> BCM2835_CLK_SHIFT; - 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)); + /* set target clock rate*/ + clk_set_rate(dev->clk, sampling_rate * bclk_ratio); /* Setup the frame format */ format = BCM2835_I2S_CHEN; @@ -692,7 +548,7 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .trigger = bcm2835_i2s_trigger, .hw_params = bcm2835_i2s_hw_params, .set_fmt = bcm2835_i2s_set_dai_fmt, - .set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio + .set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio, }; static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) @@ -750,34 +606,14 @@ static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg) }; } -static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case BCM2835_CLK_PCMCTL_REG: - return true; - default: - return false; - }; -} - -static const struct regmap_config bcm2835_regmap_config[] = { - { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = BCM2835_I2S_GRAY_REG, - .precious_reg = bcm2835_i2s_precious_reg, - .volatile_reg = bcm2835_i2s_volatile_reg, - .cache_type = REGCACHE_RBTREE, - }, - { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = BCM2835_CLK_PCMDIV_REG, - .volatile_reg = bcm2835_clk_volatile_reg, - .cache_type = REGCACHE_RBTREE, - }, +static const struct regmap_config bcm2835_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM2835_I2S_GRAY_REG, + .precious_reg = bcm2835_i2s_precious_reg, + .volatile_reg = bcm2835_i2s_volatile_reg, + .cache_type = REGCACHE_RBTREE, }; static const struct snd_soc_component_driver bcm2835_i2s_component = { @@ -787,42 +623,50 @@ static const struct snd_soc_component_driver bcm2835_i2s_component = { static int bcm2835_i2s_probe(struct platform_device *pdev) { struct bcm2835_i2s_dev *dev; - int i; int ret; - struct regmap *regmap[2]; - struct resource *mem[2]; - - /* Request both ioareas */ - for (i = 0; i <= 1; 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, - &bcm2835_regmap_config[i]); - if (IS_ERR(regmap[i])) - return PTR_ERR(regmap[i]); - } + struct resource *mem; + void __iomem *base; + const __be32 *addr; + dma_addr_t dma_base; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->i2s_regmap = regmap[0]; - dev->clk_regmap = regmap[1]; + /* get the clock */ + dev->clk_prepared = false; + dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) { + dev_err(&pdev->dev, "could not get clk: %ld\n", + PTR_ERR(dev->clk)); + return PTR_ERR(dev->clk); + } + + /* Request ioarea */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(base)) + return PTR_ERR(base); + + dev->i2s_regmap = devm_regmap_init_mmio(&pdev->dev, base, + &bcm2835_regmap_config); + if (IS_ERR(dev->i2s_regmap)) + return PTR_ERR(dev->i2s_regmap); + + /* Set the DMA address - we have to parse DT ourselves */ + 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 -EINVAL; + } + dma_base = be32_to_cpup(addr); - /* 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_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_base + BCM2835_I2S_FIFO_A_REG; /* Set the bus width */ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = -- cgit v1.2.3 From 22363e758770fa24edcc67ba33326f007bcd66a8 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 19 Jan 2016 11:13:12 +0800 Subject: ASoC: ab8500: remove the useless 'break' after 'return' 'break' here is not useful after 'return' or 'goto'. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index affb192238a4..b6820a1f16c7 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2134,7 +2134,6 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) "%s: ERROR: Unsupporter master mask 0x%x\n", __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); return -EINVAL; - break; } snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val); -- cgit v1.2.3 From 512feb4e19a262ea0dfd7209506a998897feaadc Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 15 Jan 2016 19:35:24 +0800 Subject: ASoC: fsl_sai: Use usleep_range() instead of msleep() Since msleep() will sleep longer than intended time for values less than 20ms, this patch allows the use of usleep_range for just 1ms. usleep_range is a finer precision implementation of msleep and is designed to be a drop-in replacement for udelay where a precise sleep/busy-wait is unnecessary. More details see Documentation/timers/timers-howto.txt. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 43ba5dc26775..4919de9684eb 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -884,7 +885,7 @@ static int fsl_sai_resume(struct device *dev) regcache_cache_only(sai->regmap, false); regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); - msleep(1); + usleep_range(1000, 2000); regmap_write(sai->regmap, FSL_SAI_TCSR, 0); regmap_write(sai->regmap, FSL_SAI_RCSR, 0); return regcache_sync(sai->regmap); -- cgit v1.2.3 From 0d55ad456337487e8cdb72acdd520050e575a0bd Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 15 Jan 2016 19:35:25 +0800 Subject: ASoC: fsl-mpc5200: Use usleep_range() instead of msleep() Since msleep() will sleep longer than intended time for values less than 20ms, this patch allows the use of usleep_range for just 1ms. usleep_range is a finer precision implementation of msleep and is designed to be a drop-in replacement for udelay where a precise sleep/busy-wait is unnecessary. More details see Documentation/timers/timers-howto.txt. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_ac97.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 0bab76051fd8..243700cc29e6 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -127,7 +128,7 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97) mutex_unlock(&psc_dma->mutex); - msleep(1); + usleep_range(1000, 2000); psc_ac97_warm_reset(ac97); } -- cgit v1.2.3 From 678ea0037263bb8afb139c4035be5ad4bc610a2f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:55:16 +0000 Subject: ASoC: rsnd: remove unsed *parent Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7ee89da4dd5f..df3ab74adf3e 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -64,7 +64,6 @@ #define SSI_NAME "ssi" struct rsnd_ssi { - struct rsnd_ssi *parent; struct rsnd_mod mod; struct rsnd_mod *dma; -- cgit v1.2.3 From 7c89746eede3acbbb67f848a741f8bca412986af Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:55:39 +0000 Subject: ASoC: rsnd: use rsnd_mod_init() for ADG Current ADG doesn't use rsnd_mod_init(), but this limitation is no longer necessary. Let's use common rsnd_mod_init() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 6d3ef366d536..19f5509f908d 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -518,13 +518,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv) return -ENOMEM; } - /* - * ADG is special module. - * Use ADG mod without rsnd_mod_init() to make debug easy - * for rsnd_write/rsnd_read - */ - adg->mod.ops = &adg_ops; - adg->mod.priv = priv; + rsnd_mod_init(priv, &adg->mod, &adg_ops, + NULL, 0, 0); rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkout(priv, adg); -- cgit v1.2.3 From 4e880b2674a6d36d6c7b9741d88973e00a76922b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:55:57 +0000 Subject: ASoC: rsnd: add debug message for rsnd_mod_call() rsnd_mod_call() tries to call each IP's relevant function. But it is difficult to understand which function returned error. This patch adds debug message for this purpose Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ca05a0a95a4d..691e22381280 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -337,6 +337,9 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) *status, call ? #func : ""); \ if (call) \ ret = (mod)->ops->func(mod, io, param); \ + if (ret) \ + dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ ret; \ }) -- cgit v1.2.3 From 6c001f3ab4ce20f01a1b3064b2bd1a9352c5d6b1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:56:18 +0000 Subject: ASoC: rsnd: don't update status if rsnd_mod_call() doesn't match If system uses CTU/MUX, and if probe error happened, it will try to call rsnd_dai_call(remove, ...). Then, MUX/DVC/SSIU/SSI might be called without calling rsnd_dai_call(probe, ...). Then, each mod status might be un-matched. It doesn't call un-matched remove function by this patch. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 691e22381280..3eb7e9a7b5dc 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -330,8 +330,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ int ret = 0; \ int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ - *status = (*status & ~mask) + \ - (add << __rsnd_mod_shift_##func); \ + if (add == 0xF) \ + call = 0; \ + else \ + *status = (*status & ~mask) + \ + (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ *status, call ? #func : ""); \ -- cgit v1.2.3 From bfa3119c38afb8177f8e403b9e9b2ecd0306bb26 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:56:36 +0000 Subject: ASoC: rsnd: try to connect connected mod is not error If system uses CTU/MUX, CTU/MUX/DVC will try to connect same CMD to system, but it is not error in this case. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3eb7e9a7b5dc..ad97ce3ae844 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -369,6 +369,9 @@ int rsnd_dai_connect(struct rsnd_mod *mod, if (!mod) return -EIO; + if (io->mod[type] == mod) + return 0; + if (io->mod[type]) return -EINVAL; -- cgit v1.2.3 From ea96380baa2794cb6e0d5bfbcca0c78b237a5f8a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:56:59 +0000 Subject: ASoC: rsnd: always call probe/remove for MUX CTU/MUX/DVC/SSIU/SSI/Audio-DMAC-periperi might be used under multipath. So, probe()/remove() need to be called multiple times. This patch allows it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 1 + sound/soc/sh/rcar/rsnd.h | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ad97ce3ae844..ed0918967def 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -163,6 +163,7 @@ void rsnd_mod_quit(struct rsnd_mod *mod) { if (mod->clk) clk_unprepare(mod->clk); + mod->clk = NULL; } void rsnd_mod_interrupt(struct rsnd_mod *mod, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 317dd793149a..c7b2ba0daf2a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -237,29 +237,29 @@ struct rsnd_mod { /* * status * - * 0xH0000CBA + * 0xH0000CB0 * - * A 0: probe 1: remove * B 0: init 1: quit * C 0: start 1: stop * * H is always called (see __rsnd_mod_call) + * H 0: probe 1: remove * H 0: pcm_new * H 0: fallback * H 0: hw_params */ -#define __rsnd_mod_shift_probe 0 -#define __rsnd_mod_shift_remove 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_probe 28 /* always called */ +#define __rsnd_mod_shift_remove 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ -#define __rsnd_mod_add_probe 1 -#define __rsnd_mod_add_remove -1 +#define __rsnd_mod_add_probe 0 +#define __rsnd_mod_add_remove 0 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -269,7 +269,7 @@ struct rsnd_mod { #define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_call_probe 0 -#define __rsnd_mod_call_remove 1 +#define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 -- cgit v1.2.3 From 654a12b86305b1fd78279616f876b8d21d146a5e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:57:17 +0000 Subject: ASoC: rsnd: don't overwrite io on rsnd_cmd_init() Current rsnd_cmd_init() overwrites "io" which will be used end of this function. This patch solved this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index cd1f064e63c4..e77e4935b4ea 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -38,6 +38,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, if (mix) { struct rsnd_dai *rdai; + struct rsnd_dai_stream *tio; int i; u32 path[] = { [0] = 0, @@ -55,12 +56,12 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, */ data = 0; for_each_rsnd_dai(rdai, priv, i) { - io = &rdai->playback; - if (mix == rsnd_io_to_mod_mix(io)) + tio = &rdai->playback; + if (mix == rsnd_io_to_mod_mix(tio)) data |= path[rsnd_mod_id(src)]; - io = &rdai->capture; - if (mix == rsnd_io_to_mod_mix(io)) + tio = &rdai->capture; + if (mix == rsnd_io_to_mod_mix(tio)) data |= path[rsnd_mod_id(src)]; } -- cgit v1.2.3 From 72154e50728e8a08940332db20884b63dfa6590d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:57:37 +0000 Subject: ASoC: rsnd: select each SRC correctly for CMD data path To select CMD data patch, it should use correct SRC from each stream in MUX case. But current code is selecting SRC from fixed stream. This patch solves this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index e77e4935b4ea..4b2d50d9a686 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -29,7 +29,6 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, { struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct device *dev = rsnd_priv_to_dev(priv); u32 data; @@ -38,6 +37,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, if (mix) { struct rsnd_dai *rdai; + struct rsnd_mod *src; struct rsnd_dai_stream *tio; int i; u32 path[] = { @@ -57,15 +57,19 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, data = 0; for_each_rsnd_dai(rdai, priv, i) { tio = &rdai->playback; + src = rsnd_io_to_mod_src(tio); if (mix == rsnd_io_to_mod_mix(tio)) data |= path[rsnd_mod_id(src)]; tio = &rdai->capture; + src = rsnd_io_to_mod_src(tio); if (mix == rsnd_io_to_mod_mix(tio)) data |= path[rsnd_mod_id(src)]; } } else { + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + u32 path[] = { [0] = 0x30000, [1] = 0x30001, -- cgit v1.2.3 From 5ba17b42e1755c3c5cfe96370cfd47f34d01f62c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:58:07 +0000 Subject: ASoC: rsnd: each mod has status again for CTU/MUX support SSI will be used as normal SSI or as clock parent SSI. Therefor, rsnd driver wants to control SSI and parent SSI separately. Otherwise it can't use Playback/Capture in the same time. And it has been done by c2dc47d5cf("ASoC: rsnd: rsnd_dai_stream has each mod's status insted of rsnd_mod") before. OTOH, rsnd driver doesn't want to control CTU/MUX/DVC/SSIU/SSI in separately. Otherwise, these will be re-initialized during playing if MUX merges 2 sounds. Because of these picky reasons, this patch re-defines status on each mod, and add new parent_ssi_status on rsnd_dai_stream. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 2 +- sound/soc/sh/rcar/cmd.c | 3 ++- sound/soc/sh/rcar/core.c | 21 ++++++++++++++++----- sound/soc/sh/rcar/ctu.c | 2 +- sound/soc/sh/rcar/dma.c | 2 +- sound/soc/sh/rcar/dvc.c | 2 +- sound/soc/sh/rcar/mix.c | 2 +- sound/soc/sh/rcar/rsnd.h | 21 ++++++++++++++++----- sound/soc/sh/rcar/src.c | 3 ++- sound/soc/sh/rcar/ssi.c | 37 ++++++++++++++++++++++++++++++++++++- sound/soc/sh/rcar/ssiu.c | 3 ++- 11 files changed, 79 insertions(+), 19 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 19f5509f908d..d74e1ccc0f8f 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -519,7 +519,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) } rsnd_mod_init(priv, &adg->mod, &adg_ops, - NULL, 0, 0); + NULL, NULL, 0, 0); rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkout(priv, adg); diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 4b2d50d9a686..abb5eaac854a 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -157,7 +157,8 @@ int rsnd_cmd_probe(struct rsnd_priv *priv) for_each_rsnd_cmd(cmd, priv, i) { ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), - &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i); + &rsnd_cmd_ops, NULL, + rsnd_mod_get_status, RSND_MOD_CMD, i); if (ret) return ret; } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ed0918967def..b460d714d088 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -138,12 +138,22 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, return mod->ops->dma_req(io, mod); } +u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type) +{ + return &mod->status; +} + int rsnd_mod_init(struct rsnd_priv *priv, struct rsnd_mod *mod, - struct rsnd_mod_ops *ops, - struct clk *clk, - enum rsnd_mod_type type, - int id) + struct rsnd_mod_ops *ops, + struct clk *clk, + u32* (*get_status)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type), + enum rsnd_mod_type type, + int id) { int ret = clk_prepare(clk); @@ -155,6 +165,7 @@ int rsnd_mod_init(struct rsnd_priv *priv, mod->type = type; mod->clk = clk; mod->priv = priv; + mod->get_status = get_status; return ret; } @@ -325,7 +336,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ struct rsnd_mod *mod = (io)->mod[idx]; \ struct device *dev = rsnd_priv_to_dev(priv); \ - u32 *status = (io)->mod_status + idx; \ + u32 *status = mod->get_status(io, mod, idx); \ u32 mask = 0xF << __rsnd_mod_shift_##func; \ u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index d53a225d19e9..109930a20401 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -129,7 +129,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, - clk, RSND_MOD_CTU, i); + clk, rsnd_mod_get_status, RSND_MOD_CTU, i); if (ret) goto rsnd_ctu_probe_done; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 418e6fdd06a3..d1cb3c177572 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -681,7 +681,7 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, dma_mod = rsnd_mod_get(dma); ret = rsnd_mod_init(priv, dma_mod, - ops, NULL, type, dma_id); + ops, NULL, rsnd_mod_get_status, type, dma_id); if (ret < 0) return ERR_PTR(ret); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d45ffe496397..302c193f674d 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -373,7 +373,7 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, - clk, RSND_MOD_DVC, i); + clk, rsnd_mod_get_status, RSND_MOD_DVC, i); if (ret) goto rsnd_dvc_probe_done; diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 65542b6a89e9..e0e337ad4206 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -172,7 +172,7 @@ int rsnd_mix_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, - clk, RSND_MOD_MIX, i); + clk, rsnd_mod_get_status, RSND_MOD_MIX, i); if (ret) goto rsnd_mix_probe_done; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c7b2ba0daf2a..28602607cf5e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -233,6 +233,10 @@ struct rsnd_mod { struct rsnd_mod_ops *ops; struct rsnd_priv *priv; struct clk *clk; + u32 *(*get_status)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type); + u32 status; }; /* * status @@ -286,10 +290,13 @@ struct rsnd_mod { int rsnd_mod_init(struct rsnd_priv *priv, struct rsnd_mod *mod, - struct rsnd_mod_ops *ops, - struct clk *clk, - enum rsnd_mod_type type, - int id); + struct rsnd_mod_ops *ops, + struct clk *clk, + u32* (*get_status)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type), + enum rsnd_mod_type type, + int id); void rsnd_mod_quit(struct rsnd_mod *mod); char *rsnd_mod_name(struct rsnd_mod *mod); struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, @@ -297,6 +304,10 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); +u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type); + void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), struct device_node *node, @@ -319,7 +330,7 @@ struct rsnd_dai_stream { struct rsnd_mod *mod[RSND_MOD_MAX]; struct rsnd_dai_path_info *info; /* rcar_snd.h */ struct rsnd_dai *rdai; - u32 mod_status[RSND_MOD_MAX]; + u32 parent_ssi_status; int byte_pos; int period_pos; int byte_per_period; diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index b438538a0a69..516b0c05451c 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -615,7 +615,8 @@ int rsnd_src_probe(struct rsnd_priv *priv) } ret = rsnd_mod_init(priv, rsnd_mod_get(src), - &rsnd_src_ops, clk, RSND_MOD_SRC, i); + &rsnd_src_ops, clk, rsnd_mod_get_status, + RSND_MOD_SRC, i); if (ret) goto rsnd_src_probe_done; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index df3ab74adf3e..e68f3a1c9cb4 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -857,6 +857,41 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } +static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + enum rsnd_mod_type type) +{ + /* + * SSIP (= SSI parent) needs to be special, otherwise, + * 2nd SSI might doesn't start. see also rsnd_mod_call() + * + * We can't include parent SSI status on SSI, because we don't know + * how many SSI requests parent SSI. Thus, it is localed on "io" now. + * ex) trouble case + * Playback: SSI0 + * Capture : SSI1 (needs SSI0) + * + * 1) start Capture -> SSI0/SSI1 are started. + * 2) start Playback -> SSI0 doesn't work, because it is already + * marked as "started" on 1) + * + * OTOH, using each mod's status is good for MUX case. + * It doesn't need to start in 2nd start + * ex) + * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 + * | + * IO-1: SRC1 -> CTU2 -+ + * + * 1) start IO-0 -> start SSI0 + * 2) start IO-1 -> SSI0 doesn't need to start, because it is + * already started on 1) + */ + if (type == RSND_MOD_SSIP) + return &io->parent_ssi_status; + + return rsnd_mod_get_status(io, mod, type); +} + int rsnd_ssi_probe(struct rsnd_priv *priv) { struct device_node *node; @@ -919,7 +954,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) ops = &rsnd_ssi_dma_ops; ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, - RSND_MOD_SSI, i); + rsnd_ssi_get_status, RSND_MOD_SSI, i); if (ret) goto rsnd_ssi_probe_done; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 06d72828e5bc..11e55889b401 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -206,7 +206,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) for_each_rsnd_ssiu(ssiu, priv, i) { ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), - ops, NULL, RSND_MOD_SSIU, i); + ops, NULL, rsnd_mod_get_status, + RSND_MOD_SSIU, i); if (ret) return ret; } -- cgit v1.2.3 From 355cb84fbe1f098f80c17dad9027ad2c6aec3fa0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:58:33 +0000 Subject: ASoC: rsnd: attach Audio-DMAC-periperi correctly SSI/SRC will try to attach DMAC as Audio-DMAC or Audio-DMAC-periperi. It is fixed IP, but will be attached to each streams as different module in case of MUX (= multi sound path will be merged). This patch solves this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 56 +++++++++++++++++++++++++----------------------- sound/soc/sh/rcar/rsnd.h | 4 ++-- sound/soc/sh/rcar/src.c | 4 +--- sound/soc/sh/rcar/ssi.c | 5 ++--- 4 files changed, 34 insertions(+), 35 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index d1cb3c177572..7658e8fd7bdc 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -622,15 +622,13 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } } -struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, int id) +int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, + struct rsnd_mod **dma_mod, int id) { - struct rsnd_mod *dma_mod; struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct rsnd_dma *dma; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; @@ -646,17 +644,10 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, * rsnd_rdai_continuance_probe() */ if (!dmac) - return ERR_PTR(-EAGAIN); - - dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); - if (!dma) - return ERR_PTR(-ENOMEM); + return -EAGAIN; rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); - dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); - dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); - /* for Gen2 */ if (mod_from && mod_to) { ops = &rsnd_dmapp_ops; @@ -678,27 +669,38 @@ struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, type = RSND_MOD_AUDMA; } - dma_mod = rsnd_mod_get(dma); + if (!(*dma_mod)) { + struct rsnd_dma *dma; - ret = rsnd_mod_init(priv, dma_mod, - ops, NULL, rsnd_mod_get_status, type, dma_id); - if (ret < 0) - return ERR_PTR(ret); + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; - dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", - rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod), - rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), - rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + *dma_mod = rsnd_mod_get(dma); - ret = attach(io, dma, id, mod_from, mod_to); - if (ret < 0) - return ERR_PTR(ret); + dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); + dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); + + ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, + rsnd_mod_get_status, type, dma_id); + if (ret < 0) + return ret; - ret = rsnd_dai_connect(dma_mod, io, type); + dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", + rsnd_mod_name(*dma_mod), rsnd_mod_id(*dma_mod), + rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), + rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + + ret = attach(io, dma, id, mod_from, mod_to); + if (ret < 0) + return ret; + } + + ret = rsnd_dai_connect(*dma_mod, io, type); if (ret < 0) - return ERR_PTR(ret); + return ret; - return rsnd_mod_get(dma); + return 0; } int rsnd_dma_probe(struct rsnd_priv *priv) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 28602607cf5e..90c732e265a2 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -166,8 +166,8 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); /* * R-Car DMA */ -struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, int id); +int rsnd_dma_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 516b0c05451c..8dc9b483b5fa 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -495,9 +495,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, return ret; } - src->dma = rsnd_dma_attach(io, mod, 0); - if (IS_ERR(src->dma)) - return PTR_ERR(src->dma); + ret = rsnd_dma_attach(io, mod, &src->dma, 0); return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index e68f3a1c9cb4..90674137aa90 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -704,9 +704,8 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, if (ret) return ret; - ssi->dma = rsnd_dma_attach(io, mod, dma_id); - if (IS_ERR(ssi->dma)) - return PTR_ERR(ssi->dma); + /* SSI probe might be called many times in MUX multi path */ + ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); return ret; } -- cgit v1.2.3 From bd9a603fe78fa838a9c884b1e67749120a45508c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:58:53 +0000 Subject: ASoC: rsnd: ctu: add rsnd_mix_activation() Based on datasheet Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 9 +++++++++ sound/soc/sh/rcar/gen.c | 1 + sound/soc/sh/rcar/rsnd.h | 1 + 3 files changed, 11 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 109930a20401..0dc451803eb6 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -24,6 +24,13 @@ struct rsnd_ctu { i++) #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) + +static void rsnd_ctu_activation(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, CTU_SWRSR, 0); + rsnd_mod_write(mod, CTU_SWRSR, 1); +} + #define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) #define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) @@ -44,6 +51,8 @@ static int rsnd_ctu_init(struct rsnd_mod *mod, { rsnd_mod_power_on(mod); + rsnd_ctu_activation(mod); + rsnd_ctu_initialize_lock(mod); rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io)); diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index c7aee9e59e86..2f01e5eb462c 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -260,6 +260,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), + RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100), RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 90c732e265a2..12227f6b6221 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -86,6 +86,7 @@ enum rsnd_reg { RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ + RSND_REG_CTU_SWRSR, RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, RSND_REG_MIX_SWRSR, -- cgit v1.2.3 From d0658b31c712327e04ddc2621742144de5562962 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:59:12 +0000 Subject: ASoC: rsnd: ctu: add rsnd_ctu_halt() Based on datasheet process Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 0dc451803eb6..7b482f36cb63 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -31,6 +31,12 @@ static void rsnd_ctu_activation(struct rsnd_mod *mod) rsnd_mod_write(mod, CTU_SWRSR, 1); } +static void rsnd_ctu_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, CTU_CTUIR, 1); + rsnd_mod_write(mod, CTU_SWRSR, 0); +} + #define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) #define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) @@ -66,6 +72,8 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + rsnd_ctu_halt(mod); + rsnd_mod_power_off(mod); return 0; -- cgit v1.2.3 From dc037afdbc4f285dc2f8107a0b8eaf89892e28ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:59:33 +0000 Subject: ASoC: rsnd: ctu: settings matches to datasheet Current CTU settings was rough. This patch makes it match to datasheet. But do nothing at this point. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 61 ++++++++++++++++++++++++++++++++++++++---------- sound/soc/sh/rcar/gen.c | 34 +++++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 34 +++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 12 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 7b482f36cb63..a10d0f7b73fa 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -37,13 +37,6 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod) rsnd_mod_write(mod, CTU_SWRSR, 0); } -#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) -#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) -static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) -{ - rsnd_mod_write(mod, CTU_CTUIR, enable); -} - static int rsnd_ctu_probe_(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -51,6 +44,54 @@ static int rsnd_ctu_probe_(struct rsnd_mod *mod, return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4); } +static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, CTU_CTUIR, 1); + + rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io)); + + rsnd_mod_write(mod, CTU_CPMDR, 0); + rsnd_mod_write(mod, CTU_SCMDR, 0); + rsnd_mod_write(mod, CTU_SV00R, 0); + rsnd_mod_write(mod, CTU_SV01R, 0); + rsnd_mod_write(mod, CTU_SV02R, 0); + rsnd_mod_write(mod, CTU_SV03R, 0); + rsnd_mod_write(mod, CTU_SV04R, 0); + rsnd_mod_write(mod, CTU_SV05R, 0); + rsnd_mod_write(mod, CTU_SV06R, 0); + rsnd_mod_write(mod, CTU_SV07R, 0); + + rsnd_mod_write(mod, CTU_SV10R, 0); + rsnd_mod_write(mod, CTU_SV11R, 0); + rsnd_mod_write(mod, CTU_SV12R, 0); + rsnd_mod_write(mod, CTU_SV13R, 0); + rsnd_mod_write(mod, CTU_SV14R, 0); + rsnd_mod_write(mod, CTU_SV15R, 0); + rsnd_mod_write(mod, CTU_SV16R, 0); + rsnd_mod_write(mod, CTU_SV17R, 0); + + rsnd_mod_write(mod, CTU_SV20R, 0); + rsnd_mod_write(mod, CTU_SV21R, 0); + rsnd_mod_write(mod, CTU_SV22R, 0); + rsnd_mod_write(mod, CTU_SV23R, 0); + rsnd_mod_write(mod, CTU_SV24R, 0); + rsnd_mod_write(mod, CTU_SV25R, 0); + rsnd_mod_write(mod, CTU_SV26R, 0); + rsnd_mod_write(mod, CTU_SV27R, 0); + + rsnd_mod_write(mod, CTU_SV30R, 0); + rsnd_mod_write(mod, CTU_SV31R, 0); + rsnd_mod_write(mod, CTU_SV32R, 0); + rsnd_mod_write(mod, CTU_SV33R, 0); + rsnd_mod_write(mod, CTU_SV34R, 0); + rsnd_mod_write(mod, CTU_SV35R, 0); + rsnd_mod_write(mod, CTU_SV36R, 0); + rsnd_mod_write(mod, CTU_SV37R, 0); + + rsnd_mod_write(mod, CTU_CTUIR, 0); +} + static int rsnd_ctu_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -59,11 +100,7 @@ static int rsnd_ctu_init(struct rsnd_mod *mod, rsnd_ctu_activation(mod); - rsnd_ctu_initialize_lock(mod); - - rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io)); - - rsnd_ctu_initialize_unlock(mod); + rsnd_ctu_value_init(io, mod); return 0; } diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 2f01e5eb462c..b6e487e06019 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -263,6 +263,40 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100), RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), + RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100), + RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100), + RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100), + RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100), + RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100), + RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100), + RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100), + RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100), + RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100), + RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100), + RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100), + RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100), + RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100), + RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100), + RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100), + RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100), + RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100), + RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100), + RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100), + RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100), + RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100), + RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100), + RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100), + RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100), + RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100), + RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100), + RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100), + RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100), + RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100), + RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100), + RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100), + RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100), + RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100), + RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100), RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 12227f6b6221..4974db6679c3 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -89,6 +89,40 @@ enum rsnd_reg { RSND_REG_CTU_SWRSR, RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, + RSND_REG_CTU_CPMDR, + RSND_REG_CTU_SCMDR, + RSND_REG_CTU_SV00R, + RSND_REG_CTU_SV01R, + RSND_REG_CTU_SV02R, + RSND_REG_CTU_SV03R, + RSND_REG_CTU_SV04R, + RSND_REG_CTU_SV05R, + RSND_REG_CTU_SV06R, + RSND_REG_CTU_SV07R, + RSND_REG_CTU_SV10R, + RSND_REG_CTU_SV11R, + RSND_REG_CTU_SV12R, + RSND_REG_CTU_SV13R, + RSND_REG_CTU_SV14R, + RSND_REG_CTU_SV15R, + RSND_REG_CTU_SV16R, + RSND_REG_CTU_SV17R, + RSND_REG_CTU_SV20R, + RSND_REG_CTU_SV21R, + RSND_REG_CTU_SV22R, + RSND_REG_CTU_SV23R, + RSND_REG_CTU_SV24R, + RSND_REG_CTU_SV25R, + RSND_REG_CTU_SV26R, + RSND_REG_CTU_SV27R, + RSND_REG_CTU_SV30R, + RSND_REG_CTU_SV31R, + RSND_REG_CTU_SV32R, + RSND_REG_CTU_SV33R, + RSND_REG_CTU_SV34R, + RSND_REG_CTU_SV35R, + RSND_REG_CTU_SV36R, + RSND_REG_CTU_SV37R, RSND_REG_MIX_SWRSR, RSND_REG_MIX_MIXIR, RSND_REG_MIX_ADINR, -- cgit v1.2.3 From 38587f4cb7937344e12a9eef1ccdc5b8a0e992ba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:59:55 +0000 Subject: ASoC: rsnd: tidyup Playback/Capture sequence Based on datasheet sequence Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index b460d714d088..1fcefab03ad6 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -358,15 +358,51 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ret; \ }) +static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { + { + /* CAPTURE */ + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_DVC, + RSND_MOD_MIX, + RSND_MOD_CTU, + RSND_MOD_CMD, + RSND_MOD_SRC, + RSND_MOD_SSIU, + RSND_MOD_SSIM3, + RSND_MOD_SSIM2, + RSND_MOD_SSIM1, + RSND_MOD_SSIP, + RSND_MOD_SSI, + }, { + /* PLAYBACK */ + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_SSIM3, + RSND_MOD_SSIM2, + RSND_MOD_SSIM1, + RSND_MOD_SSIP, + RSND_MOD_SSI, + RSND_MOD_SSIU, + RSND_MOD_DVC, + RSND_MOD_MIX, + RSND_MOD_CTU, + RSND_MOD_CMD, + RSND_MOD_SRC, + }, +}; + #define rsnd_dai_call(fn, io, param...) \ ({ \ struct rsnd_mod *mod; \ + int type, is_play = rsnd_io_is_play(io); \ int ret = 0, i; \ for (i = 0; i < RSND_MOD_MAX; i++) { \ - mod = (io)->mod[i]; \ + type = rsnd_mod_sequence[is_play][i]; \ + mod = (io)->mod[type]; \ if (!mod) \ continue; \ - ret |= rsnd_mod_call(i, io, fn, param); \ + ret |= rsnd_mod_call(type, io, fn, param); \ } \ ret; \ }) -- cgit v1.2.3 From 31739a689f828345a7ef52fd8dbbb200df1b6555 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 02:00:13 +0000 Subject: ASoC: rsnd: disable SRC.out/in in same time commit b761bf272bce ("ASoC: rsnd: disable SRC.out only when stop timing") disabled SRC.out/in in different timing, but was based on picky HW information. Now, we have confirmed that we can disable both in the same time. This patch do it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 8dc9b483b5fa..7749615bd404 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -367,11 +367,7 @@ static int rsnd_src_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - /* - * stop SRC output only - * see rsnd_src_quit - */ - rsnd_mod_write(mod, SRC_CTRL, 0x01); + rsnd_mod_write(mod, SRC_CTRL, 0); return 0; } @@ -409,9 +405,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod, rsnd_src_irq_disable(mod); - /* stop both out/in */ - rsnd_mod_write(mod, SRC_CTRL, 0); - rsnd_src_halt(mod); rsnd_mod_power_off(mod); -- cgit v1.2.3 From 6f08cbdaac5a3050ea1898aef8ce326030fd1117 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 14 Jan 2016 21:57:20 +0100 Subject: ASoC: Intel: Use acpi_dev_present() Use shiny new acpi_dev_present() and remove all the boilerplate to search for a particular ACPI device. No functional change. Cf. 2d12b6b381ba ("ACPI / utils: Add acpi_dev_present()"). Signed-off-by: Lukas Wunner Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 17 ++--------------- sound/soc/intel/boards/cht_bsw_rt5645.c | 13 +------------ sound/soc/intel/common/sst-match-acpi.c | 16 +--------------- 3 files changed, 4 insertions(+), 42 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 90588d6e64fc..e609f089593a 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -287,33 +287,20 @@ static struct snd_soc_card snd_soc_card_cht = { .num_controls = ARRAY_SIZE(cht_mc_controls), }; -static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; - bool found = false; struct cht_mc_private *drv; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); if (!drv) return -ENOMEM; - if (ACPI_SUCCESS(acpi_get_devices( - "104C227E", - snd_acpi_codec_match, - &found, NULL)) && found) { - drv->ts3a227e_present = true; - } else { + drv->ts3a227e_present = acpi_dev_present("104C227E"); + if (!drv->ts3a227e_present) { /* no need probe TI jack detection chip */ snd_soc_card_cht.aux_dev = NULL; snd_soc_card_cht.num_aux_devs = 0; - drv->ts3a227e_present = false; } /* register the soc card */ diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 2d3afddb0a2e..e6cf800ab231 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -333,20 +333,12 @@ static struct cht_acpi_card snd_soc_cards[] = { {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, }; -static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; int i; struct cht_mc_private *drv; struct snd_soc_card *card = snd_soc_cards[0].soc_card; - bool found = false; char codec_name[16]; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); @@ -354,10 +346,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { - if (ACPI_SUCCESS(acpi_get_devices( - snd_soc_cards[i].codec_id, - snd_acpi_codec_match, - &found, NULL)) && found) { + if (acpi_dev_present(snd_soc_cards[i].codec_id)) { dev_dbg(&pdev->dev, "found codec %s\n", snd_soc_cards[i].codec_id); card = snd_soc_cards[i].soc_card; diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index dd077e116d25..c429e2226d40 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -13,29 +13,15 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ -#include -#include -#include -#include #include "sst-acpi.h" -static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) { struct sst_acpi_mach *mach; - bool found = false; for (mach = machines; mach->id[0]; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->id, - sst_acpi_mach_match, - &found, NULL)) && found) + if (acpi_dev_present(mach->id)) return mach; return NULL; -- cgit v1.2.3 From 51b2bb3f2568e6d9d81a001d38b8d70c2ba4af99 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Mon, 25 Jan 2016 12:36:43 +0000 Subject: ASoC: wm8974: configure pll and mclk divider automatically This adds a set_sysclk() DAI op so the card driver can set the input clock frequency. If this is done, the pll and mclk divider are configured to produce the required 256x fs clock when the sample rate is set by hw_params(). These additions make the codec work with the simple-card driver. Card drivers calling set_pll() and set_clkdiv() directly are unaffected. Signed-off-by: Mans Rullgard Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8974.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index c284c7b6db8b..dc8c3b1ebb6f 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -28,6 +28,11 @@ #include "wm8974.h" +struct wm8974_priv { + unsigned int mclk; + unsigned int fs; +}; + static const struct reg_default wm8974_reg_defaults[] = { { 0, 0x0000 }, { 1, 0x0000 }, { 2, 0x0000 }, { 3, 0x0000 }, { 4, 0x0050 }, { 5, 0x0000 }, { 6, 0x0140 }, { 7, 0x0000 }, @@ -379,6 +384,79 @@ static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, return 0; } +static unsigned int wm8974_get_mclkdiv(unsigned int f_in, unsigned int f_out, + int *mclkdiv) +{ + unsigned int ratio = 2 * f_in / f_out; + + if (ratio <= 2) { + *mclkdiv = WM8974_MCLKDIV_1; + ratio = 2; + } else if (ratio == 3) { + *mclkdiv = WM8974_MCLKDIV_1_5; + } else if (ratio == 4) { + *mclkdiv = WM8974_MCLKDIV_2; + } else if (ratio <= 6) { + *mclkdiv = WM8974_MCLKDIV_3; + ratio = 6; + } else if (ratio <= 8) { + *mclkdiv = WM8974_MCLKDIV_4; + ratio = 8; + } else if (ratio <= 12) { + *mclkdiv = WM8974_MCLKDIV_6; + ratio = 12; + } else if (ratio <= 16) { + *mclkdiv = WM8974_MCLKDIV_8; + ratio = 16; + } else { + *mclkdiv = WM8974_MCLKDIV_12; + ratio = 24; + } + + return f_out * ratio / 2; +} + +static int wm8974_update_clocks(struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8974_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int fs256; + unsigned int fpll = 0; + unsigned int f; + int mclkdiv; + + if (!priv->mclk || !priv->fs) + return 0; + + fs256 = 256 * priv->fs; + + f = wm8974_get_mclkdiv(priv->mclk, fs256, &mclkdiv); + + if (f != priv->mclk) { + /* The PLL performs best around 90MHz */ + fpll = wm8974_get_mclkdiv(22500000, fs256, &mclkdiv); + } + + wm8974_set_dai_pll(dai, 0, 0, priv->mclk, fpll); + wm8974_set_dai_clkdiv(dai, WM8974_MCLKDIV, mclkdiv); + + return 0; +} + +static int wm8974_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8974_priv *priv = snd_soc_codec_get_drvdata(codec); + + if (dir != SND_SOC_CLOCK_IN) + return -EINVAL; + + priv->mclk = freq; + + return wm8974_update_clocks(dai); +} + static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { @@ -441,8 +519,15 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct wm8974_priv *priv = snd_soc_codec_get_drvdata(codec); u16 iface = snd_soc_read(codec, WM8974_IFACE) & 0x19f; u16 adn = snd_soc_read(codec, WM8974_ADD) & 0x1f1; + int err; + + priv->fs = params_rate(params); + err = wm8974_update_clocks(dai); + if (err) + return err; /* bit size */ switch (params_width(params)) { @@ -547,6 +632,7 @@ static const struct snd_soc_dai_ops wm8974_ops = { .set_fmt = wm8974_set_dai_fmt, .set_clkdiv = wm8974_set_dai_clkdiv, .set_pll = wm8974_set_dai_pll, + .set_sysclk = wm8974_set_dai_sysclk, }; static struct snd_soc_dai_driver wm8974_dai = { @@ -606,9 +692,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { static int wm8974_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct wm8974_priv *priv; struct regmap *regmap; int ret; + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_clientdata(i2c, priv); + regmap = devm_regmap_init_i2c(i2c, &wm8974_regmap); if (IS_ERR(regmap)) return PTR_ERR(regmap); -- cgit v1.2.3 From 6a25c8da00284f5612b404368bd07b69efd84aa2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Jan 2016 04:56:14 +0000 Subject: ASoC: rsnd: don't auto-recover when under/over run error Renesas R-Car sound needs recovery (= restart) when under/over run error occurred, and current driver tries it on under/over run error handler automatically. But this recovery should be handled by userland, not kernel. This patch stops XRUN when under/over run error occur, and will leave the recovery of HW in userland. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 39 ++++---------------- sound/soc/sh/rcar/ssi.c | 97 +++++++++++-------------------------------------- 2 files changed, 29 insertions(+), 107 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 7749615bd404..cccca154e4c3 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -25,7 +25,6 @@ struct rsnd_src { struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ struct rsnd_kctrl_cfg_s sync; /* sync convert */ u32 convert_rate; /* sampling rate convert */ - int err; int irq; }; @@ -316,7 +315,7 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod) rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); } -static bool rsnd_src_record_error(struct rsnd_mod *mod) +static bool rsnd_src_error_occurred(struct rsnd_mod *mod) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val0, val1; @@ -333,12 +332,8 @@ static bool rsnd_src_record_error(struct rsnd_mod *mod) val0 = val0 & 0xffff; if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) || - (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) { - struct rsnd_src *src = rsnd_mod_to_src(mod); - - src->err++; + (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) ret = true; - } return ret; } @@ -388,8 +383,6 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_src_irq_enable(mod); - src->err = 0; - /* reset sync convert_rate */ src->sync.val = 0; @@ -401,7 +394,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); rsnd_src_irq_disable(mod); @@ -409,10 +401,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod, rsnd_mod_power_off(mod); - if (src->err) - dev_warn(dev, "%s[%d] under/over flow err = %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); - src->convert_rate = 0; /* reset sync convert_rate */ @@ -425,8 +413,7 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); + bool stop = false; spin_lock(&priv->lock); @@ -434,26 +421,16 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod, if (!rsnd_io_is_working(io)) goto rsnd_src_interrupt_out; - if (rsnd_src_record_error(mod)) { - - dev_dbg(dev, "%s[%d] restart\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - - rsnd_src_stop(mod, io, priv); - rsnd_src_start(mod, io, priv); - } - - if (src->err > 1024) { - rsnd_src_irq_disable(mod); - - dev_warn(dev, "no more %s[%d] restart\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - } + if (rsnd_src_error_occurred(mod)) + stop = true; rsnd_src_status_clear(mod); rsnd_src_interrupt_out: spin_unlock(&priv->lock); + + if (stop) + snd_pcm_stop_xrun(io->substream); } static irqreturn_t rsnd_src_interrupt(int irq, void *data) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 90674137aa90..5870434bbc58 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -74,7 +74,6 @@ struct rsnd_ssi { u32 wsr; int chan; int rate; - int err; int irq; unsigned int usrcnt; }; @@ -385,8 +384,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (ret < 0) return ret; - ssi->err = -1; /* ignore 1st error */ - /* clear error status */ rsnd_ssi_status_clear(mod); @@ -409,13 +406,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, } if (!rsnd_ssi_is_parent(mod, io)) { - if (ssi->err > 0) - dev_warn(dev, "%s[%d] under/over flow err = %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), - ssi->err); - ssi->cr_own = 0; - ssi->err = 0; rsnd_ssi_irq_disable(mod); } @@ -455,21 +446,9 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return 0; } -static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - u32 status = rsnd_ssi_status_get(mod); - - /* under/over flow error */ - if (status & (UIRQ | OIRQ)) - ssi->err++; - - return status; -} - -static int __rsnd_ssi_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_ssi_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); u32 cr; @@ -491,25 +470,21 @@ static int __rsnd_ssi_start(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_ssi_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + /* - * no limit to start + * don't stop if not last user * see also - * rsnd_ssi_stop + * rsnd_ssi_start * rsnd_ssi_interrupt */ - return __rsnd_ssi_start(mod, io, priv); -} - -static int __rsnd_ssi_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 cr; + if (ssi->usrcnt > 1) + return 0; /* * disable all IRQ, @@ -531,33 +506,14 @@ static int __rsnd_ssi_stop(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - /* - * don't stop if not last user - * see also - * rsnd_ssi_start - * rsnd_ssi_interrupt - */ - if (ssi->usrcnt > 1) - return 0; - - return __rsnd_ssi_stop(mod, io, priv); -} - static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); int is_dma = rsnd_ssi_is_dma_mode(mod); u32 status; bool elapsed = false; + bool stop = false; spin_lock(&priv->lock); @@ -565,7 +521,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, if (!rsnd_io_is_working(io)) goto rsnd_ssi_interrupt_out; - status = rsnd_ssi_record_error(ssi); + status = rsnd_ssi_status_get(mod); /* PIO only */ if (!is_dma && (status & DIRQ)) { @@ -587,23 +543,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, } /* DMA only */ - if (is_dma && (status & (UIRQ | OIRQ))) { - /* - * restart SSI - */ - dev_dbg(dev, "%s[%d] restart\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - - __rsnd_ssi_stop(mod, io, priv); - __rsnd_ssi_start(mod, io, priv); - } - - if (ssi->err > 1024) { - rsnd_ssi_irq_disable(mod); - - dev_warn(dev, "no more %s[%d] restart\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); - } + if (is_dma && (status & (UIRQ | OIRQ))) + stop = true; rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: @@ -611,6 +552,10 @@ rsnd_ssi_interrupt_out: if (elapsed) rsnd_dai_period_elapsed(io); + + if (stop) + snd_pcm_stop_xrun(io->substream); + } static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) -- cgit v1.2.3 From b5b442abd9d5cfe4f04a1e83be9900c87444bd66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 26 Jan 2016 04:56:57 +0000 Subject: ASoC: rsnd: add .irq callback Current rsnd driver has .init/.start/.stop/.quit callbacks, and it needs many IPs (SRC/CTU/MUX/DVC/CMD/SSIU/SSI). Because of these relationship, it might get unnecessary error IRQ when start/stop. This patch adds new .irq callback and control IRQ enable/disable timing to avoid it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 9 ++++++++- sound/soc/sh/rcar/rsnd.h | 6 ++++++ sound/soc/sh/rcar/src.c | 16 ++++++++-------- sound/soc/sh/rcar/ssi.c | 36 +++++++++++++----------------------- 4 files changed, 35 insertions(+), 32 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1fcefab03ad6..704ba7ae9eaf 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -568,9 +568,16 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret = rsnd_dai_call(start, io, priv); if (ret < 0) goto dai_trigger_end; + + ret = rsnd_dai_call(irq, io, priv, 1); + if (ret < 0) + goto dai_trigger_end; + break; case SNDRV_PCM_TRIGGER_STOP: - ret = rsnd_dai_call(stop, io, priv); + ret = rsnd_dai_call(irq, io, priv, 0); + + ret |= rsnd_dai_call(stop, io, priv); ret |= rsnd_dai_call(quit, io, priv); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4974db6679c3..bbaf89b6de8a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -249,6 +249,9 @@ struct rsnd_mod_ops { int (*stop)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*irq)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, int enable); int (*pcm_new)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd); @@ -293,6 +296,7 @@ struct rsnd_mod { #define __rsnd_mod_shift_stop 8 #define __rsnd_mod_shift_probe 28 /* always called */ #define __rsnd_mod_shift_remove 28 /* always called */ +#define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ @@ -303,6 +307,7 @@ struct rsnd_mod { #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 #define __rsnd_mod_add_stop -1 +#define __rsnd_mod_add_irq 0 #define __rsnd_mod_add_pcm_new 0 #define __rsnd_mod_add_fallback 0 #define __rsnd_mod_add_hw_params 0 @@ -313,6 +318,7 @@ struct rsnd_mod { #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 #define __rsnd_mod_call_stop 1 +#define __rsnd_mod_call_irq 0 #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index cccca154e4c3..ab5f13155055 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -271,9 +271,10 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_adg_set_convert_timing_gen2(mod, io); } -#define rsnd_src_irq_enable(mod) rsnd_src_irq_ctrol(mod, 1) -#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0) -static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) +static int rsnd_src_irq(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, + int enable) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 sys_int_val, int_val, sys_int_mask; @@ -305,6 +306,8 @@ static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); + + return 0; } static void rsnd_src_status_clear(struct rsnd_mod *mod) @@ -381,8 +384,6 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_src_status_clear(mod); - rsnd_src_irq_enable(mod); - /* reset sync convert_rate */ src->sync.val = 0; @@ -395,8 +396,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); - rsnd_src_irq_disable(mod); - rsnd_src_halt(mod); rsnd_mod_power_off(mod); @@ -455,7 +454,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, /* * IRQ is not supported on non-DT * see - * rsnd_src_irq_enable() + * rsnd_src_irq() */ ret = devm_request_irq(dev, irq, rsnd_src_interrupt, @@ -518,6 +517,7 @@ static struct rsnd_mod_ops rsnd_src_ops = { .quit = rsnd_src_quit, .start = rsnd_src_start, .stop = rsnd_src_stop, + .irq = rsnd_src_irq, .hw_params = rsnd_src_hw_params, .pcm_new = rsnd_src_pcm_new, }; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 5870434bbc58..803e9ae65915 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -142,30 +142,24 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, dev_warn(dev, "status check failed\n"); } -static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod) +static int rsnd_ssi_irq(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, + int enable) { - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 val = 0; if (rsnd_is_gen1(priv)) return 0; - /* enable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, - rsnd_ssi_is_dma_mode(ssi_mod) ? - 0x0e000000 : 0x0f000000); - - return 0; -} - -static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - - if (rsnd_is_gen1(priv)) + if (ssi->usrcnt != 1) return 0; - /* disable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); + if (enable) + val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; + + rsnd_mod_write(mod, SSI_INT_ENABLE, val); return 0; } @@ -387,8 +381,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, /* clear error status */ rsnd_ssi_status_clear(mod); - rsnd_ssi_irq_enable(mod); - return 0; } @@ -405,12 +397,9 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, return -EIO; } - if (!rsnd_ssi_is_parent(mod, io)) { + if (!rsnd_ssi_is_parent(mod, io)) ssi->cr_own = 0; - rsnd_ssi_irq_disable(mod); - } - rsnd_ssi_master_clk_stop(ssi, io); rsnd_mod_power_off(mod); @@ -627,6 +616,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, + .irq = rsnd_ssi_irq, .hw_params = rsnd_ssi_hw_params, }; -- cgit v1.2.3 From c670254f63fe09681b1c4c82d3d059c6cc04ce09 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 27 Jan 2016 15:02:49 +0200 Subject: ASoC: davinci-mcasp: Discourage use of fck_parent for clock reparenting The in-driver clock reparenting had been added when we did not had other means to cleanly set the parent for the fck. Now we can use assigned-clocks/assigned-clock-parents in DT binding. Print warning when the fck_parent is present for McASP and recommend the switch to the proper way to handle the clock selection. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 2ccb8bccc9d4..3cf46afb353f 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1517,6 +1517,8 @@ static int mcasp_reparent_fck(struct platform_device *pdev) if (!parent_name) return 0; + dev_warn(&pdev->dev, "Update the bindings to use assigned-clocks!\n"); + gfclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(gfclk)) { dev_err(&pdev->dev, "failed to get fck\n"); -- cgit v1.2.3 From 712a8038cc24dba668afe82f0413714ca87184e0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Jan 2016 14:26:18 +0100 Subject: ASoC: ssm4567: Reset device before regcache_sync() When the ssm4567 is powered up the driver calles regcache_sync() to restore the register map content. regcache_sync() assumes that the device is in its power-on reset state. Make sure that this is the case by explicitly resetting the ssm4567 register map before calling regcache_sync() otherwise we might end up with a incorrect register map which leads to undefined behaviour. One such undefined behaviour was observed when returning from system suspend while a playback stream is active, in that case the ssm4567 was kept muted after resume. Fixes: 1ee44ce03011 ("ASoC: ssm4567: Add driver for Analog Devices SSM4567 amplifier") Reported-by: Harsha Priya Tested-by: Fang, Yang A Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index e619d5651b09..080c78e88e10 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -352,6 +352,11 @@ static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) regcache_cache_only(ssm4567->regmap, !enable); if (enable) { + ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, + 0x00); + if (ret) + return ret; + ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_POWER_CTRL, SSM4567_POWER_SPWDN, 0x00); -- cgit v1.2.3 From 7315917f7ccdf5eb5758f663a781daa7599d63d7 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 25 Jan 2016 18:23:30 +0100 Subject: ASoC: rk3036: fix missing dependency on REGMAP_MMIO When SND_SOC_INNO_RK3036 is enabled but REGMAP_MMIO is not, the MODPOST step fails with this error: ... Kernel: arch/x86/boot/bzImage is ready (#3) Building modules, stage 2. MODPOST 3203 modules ERROR: "__devm_regmap_init_mmio_clk" [sound/soc/codecs/snd-soc-inno-rk3036.ko] undefined! Signed-off-by: Antonio Ospite Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50693c867e71..1f7eaa919088 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -497,6 +497,7 @@ config SND_SOC_ICS43432 config SND_SOC_INNO_RK3036 tristate "Inno codec driver for RK3036 SoC" + select REGMAP_MMIO config SND_SOC_ISABELLE tristate -- cgit v1.2.3 From ba4bc32eaa39ba7687f0958ae90eec94da613b46 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 25 Jan 2016 18:07:33 +0100 Subject: ASoC: s3c24xx: use const snd_soc_component_driver pointer An older patch to convert the API in the s3c i2s driver ended up passing a const pointer into a function that takes a non-const pointer, so we now get a warning: sound/soc/samsung/s3c2412-i2s.c: In function 's3c2412_iis_dev_probe': sound/soc/samsung/s3c2412-i2s.c:172:9: error: passing argument 3 of 's3c_i2sv2_register_component' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] However, the s3c_i2sv2_register_component() function again passes the pointer into another function taking a const, so we just need to change its prototype. Fixes: eca3b01d0885 ("ASoC: switch over to use snd_soc_register_component() on s3c i2s") Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/s3c-i2s-v2.c | 2 +- sound/soc/samsung/s3c-i2s-v2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index df65c5b494b1..b6ab3fc5789e 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -709,7 +709,7 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) #endif int s3c_i2sv2_register_component(struct device *dev, int id, - struct snd_soc_component_driver *cmp_drv, + const struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv) { struct snd_soc_dai_ops *ops = (struct snd_soc_dai_ops *)dai_drv->ops; diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h index 90abab364b49..d0684145ed1f 100644 --- a/sound/soc/samsung/s3c-i2s-v2.h +++ b/sound/soc/samsung/s3c-i2s-v2.h @@ -101,7 +101,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai, * soc core. */ extern int s3c_i2sv2_register_component(struct device *dev, int id, - struct snd_soc_component_driver *cmp_drv, + const struct snd_soc_component_driver *cmp_drv, struct snd_soc_dai_driver *dai_drv); #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */ -- cgit v1.2.3 From a2e2876aa0bab5939daf1cb20ef07ebf38744c1f Mon Sep 17 00:00:00 2001 From: anish kumar Date: Thu, 14 Jan 2016 14:03:33 -0800 Subject: ASoC: Add max98926 codec driver Signed-off-by: anish kumar Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98926.txt | 32 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/max98926.c | 604 +++++++++++++++ sound/soc/codecs/max98926.h | 848 +++++++++++++++++++++ 5 files changed, 1490 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max98926.txt create mode 100644 sound/soc/codecs/max98926.c create mode 100644 sound/soc/codecs/max98926.h (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/max98926.txt b/Documentation/devicetree/bindings/sound/max98926.txt new file mode 100644 index 000000000000..0b7f4e4d5f9a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98926.txt @@ -0,0 +1,32 @@ +max98926 audio CODEC + +This device supports I2C. + +Required properties: + + - compatible : "maxim,max98926" + + - vmon-slot-no : slot number used to send voltage information + or in inteleave mode this will be used as + interleave slot. + + - imon-slot-no : slot number used to send current information + + - interleave-mode : When using two MAX98926 in a system it is + possible to create ADC data that that will + overflow the frame size. Digital Audio Interleave + mode provides a means to output VMON and IMON data + from two devices on a single DOUT line when running + smaller frames sizes such as 32 BCLKS per LRCLK or + 48 BCLKS per LRCLK. + + - reg : the I2C address of the device for I2C + +Example: + +codec: max98926@1a { + compatible = "maxim,max98926"; + vmon-slot-no = <0>; + imon-slot-no = <2>; + reg = <0x1a>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50693c867e71..ebaaa51823ef 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -80,6 +80,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98095 if I2C select SND_SOC_MAX98357A if GPIOLIB select SND_SOC_MAX98925 if I2C + select SND_SOC_MAX98926 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -519,6 +520,9 @@ config SND_SOC_MAX98357A config SND_SOC_MAX98925 tristate +config SND_SOC_MAX98926 + tristate + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d44f7d347183..16c014a46ae8 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -75,6 +75,7 @@ snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o snd-soc-max98357a-objs := max98357a.o snd-soc-max98925-objs := max98925.o +snd-soc-max98926-objs := max98926.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o @@ -279,6 +280,7 @@ obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o +obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c new file mode 100644 index 000000000000..66884ebdf2bb --- /dev/null +++ b/sound/soc/codecs/max98926.c @@ -0,0 +1,604 @@ +/* + * max98926.c -- ALSA SoC MAX98926 driver + * Copyright 2013-15 Maxim Integrated Products + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "max98926.h" + +static const char * const max98926_boost_voltage_txt[] = { + "8.5V", "8.25V", "8.0V", "7.75V", "7.5V", "7.25V", "7.0V", "6.75V", + "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V" +}; + +static const char * const max98926_boost_current_txt[] = { + "0.6", "0.8", "1.0", "1.2", "1.4", "1.6", "1.8", "2.0", + "2.2", "2.4", "2.6", "2.8", "3.2", "3.6", "4.0", "4.4" +}; + +static const char *const max98926_dai_txt[] = { + "Left", "Right", "LeftRight", "LeftRightDiv2", +}; + +static const char *const max98926_pdm_ch_text[] = { + "Current", "Voltage", +}; + +static const char *const max98926_hpf_cutoff_txt[] = { + "Disable", "DC Block", "100Hz", + "200Hz", "400Hz", "800Hz", +}; + +static struct reg_default max98926_reg[] = { + { 0x0B, 0x00 }, /* IRQ Enable0 */ + { 0x0C, 0x00 }, /* IRQ Enable1 */ + { 0x0D, 0x00 }, /* IRQ Enable2 */ + { 0x0E, 0x00 }, /* IRQ Clear0 */ + { 0x0F, 0x00 }, /* IRQ Clear1 */ + { 0x10, 0x00 }, /* IRQ Clear2 */ + { 0x11, 0xC0 }, /* Map0 */ + { 0x12, 0x00 }, /* Map1 */ + { 0x13, 0x00 }, /* Map2 */ + { 0x14, 0xF0 }, /* Map3 */ + { 0x15, 0x00 }, /* Map4 */ + { 0x16, 0xAB }, /* Map5 */ + { 0x17, 0x89 }, /* Map6 */ + { 0x18, 0x00 }, /* Map7 */ + { 0x19, 0x00 }, /* Map8 */ + { 0x1A, 0x04 }, /* DAI Clock Mode 1 */ + { 0x1B, 0x00 }, /* DAI Clock Mode 2 */ + { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */ + { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */ + { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */ + { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */ + { 0x20, 0x50 }, /* Format */ + { 0x21, 0x00 }, /* TDM Slot Select */ + { 0x22, 0x00 }, /* DOUT Configuration VMON */ + { 0x23, 0x00 }, /* DOUT Configuration IMON */ + { 0x24, 0x00 }, /* DOUT Configuration VBAT */ + { 0x25, 0x00 }, /* DOUT Configuration VBST */ + { 0x26, 0x00 }, /* DOUT Configuration FLAG */ + { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */ + { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */ + { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */ + { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */ + { 0x2B, 0x02 }, /* DOUT Drive Strength */ + { 0x2C, 0x90 }, /* Filters */ + { 0x2D, 0x00 }, /* Gain */ + { 0x2E, 0x02 }, /* Gain Ramping */ + { 0x2F, 0x00 }, /* Speaker Amplifier */ + { 0x30, 0x0A }, /* Threshold */ + { 0x31, 0x00 }, /* ALC Attack */ + { 0x32, 0x80 }, /* ALC Atten and Release */ + { 0x33, 0x00 }, /* ALC Infinite Hold Release */ + { 0x34, 0x92 }, /* ALC Configuration */ + { 0x35, 0x01 }, /* Boost Converter */ + { 0x36, 0x00 }, /* Block Enable */ + { 0x37, 0x00 }, /* Configuration */ + { 0x38, 0x00 }, /* Global Enable */ + { 0x3A, 0x00 }, /* Boost Limiter */ +}; + +static const struct soc_enum max98926_voltage_enum[] = { + SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, 0, + ARRAY_SIZE(max98926_pdm_ch_text), + max98926_pdm_ch_text), +}; + +static const struct snd_kcontrol_new max98926_voltage_control = + SOC_DAPM_ENUM("Route", max98926_voltage_enum); + +static const struct soc_enum max98926_current_enum[] = { + SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, + MAX98926_PDM_SOURCE_1_SHIFT, + ARRAY_SIZE(max98926_pdm_ch_text), + max98926_pdm_ch_text), +}; + +static const struct snd_kcontrol_new max98926_current_control = + SOC_DAPM_ENUM("Route", max98926_current_enum); + +static const struct snd_kcontrol_new max98926_mixer_controls[] = { + SOC_DAPM_SINGLE("PCM Single Switch", MAX98926_SPK_AMP, + MAX98926_INSELECT_MODE_SHIFT, 0, 0), + SOC_DAPM_SINGLE("PDM Single Switch", MAX98926_SPK_AMP, + MAX98926_INSELECT_MODE_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new max98926_dai_controls[] = { + SOC_DAPM_SINGLE("Left", MAX98926_GAIN, + MAX98926_DAC_IN_SEL_SHIFT, 0, 0), + SOC_DAPM_SINGLE("Right", MAX98926_GAIN, + MAX98926_DAC_IN_SEL_SHIFT, 1, 0), + SOC_DAPM_SINGLE("LeftRight", MAX98926_GAIN, + MAX98926_DAC_IN_SEL_SHIFT, 2, 0), + SOC_DAPM_SINGLE("(Left+Right)/2 Switch", MAX98926_GAIN, + MAX98926_DAC_IN_SEL_SHIFT, 3, 0), +}; + +static const struct snd_soc_dapm_widget max98926_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("Amp Enable", NULL, MAX98926_BLOCK_ENABLE, + MAX98926_SPK_EN_SHIFT, 0), + SND_SOC_DAPM_SUPPLY("Global Enable", MAX98926_GLOBAL_ENABLE, + MAX98926_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("VI Enable", MAX98926_BLOCK_ENABLE, + MAX98926_ADC_IMON_EN_WIDTH | + MAX98926_ADC_VMON_EN_SHIFT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("BST Enable", MAX98926_BLOCK_ENABLE, + MAX98926_BST_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("BE_OUT"), + SND_SOC_DAPM_MIXER("PCM Sel", MAX98926_SPK_AMP, + MAX98926_INSELECT_MODE_SHIFT, 0, + &max98926_mixer_controls[0], + ARRAY_SIZE(max98926_mixer_controls)), + SND_SOC_DAPM_MIXER("DAI Sel", + MAX98926_GAIN, MAX98926_DAC_IN_SEL_SHIFT, 0, + &max98926_dai_controls[0], + ARRAY_SIZE(max98926_dai_controls)), + SND_SOC_DAPM_MUX("PDM CH1 Source", + MAX98926_DAI_CLK_DIV_N_LSBS, + MAX98926_PDM_CURRENT_SHIFT, + 0, &max98926_current_control), + SND_SOC_DAPM_MUX("PDM CH0 Source", + MAX98926_DAI_CLK_DIV_N_LSBS, + MAX98926_PDM_VOLTAGE_SHIFT, + 0, &max98926_voltage_control), +}; + +static const struct snd_soc_dapm_route max98926_audio_map[] = { + {"VI Enable", NULL, "DAI_OUT"}, + {"DAI Sel", "Left", "VI Enable"}, + {"DAI Sel", "Right", "VI Enable"}, + {"DAI Sel", "LeftRight", "VI Enable"}, + {"DAI Sel", "LeftRightDiv2", "VI Enable"}, + {"PCM Sel", "PCM", "DAI Sel"}, + + {"PDM CH1 Source", "Current", "DAI_OUT"}, + {"PDM CH1 Source", "Voltage", "DAI_OUT"}, + {"PDM CH0 Source", "Current", "DAI_OUT"}, + {"PDM CH0 Source", "Voltage", "DAI_OUT"}, + {"PCM Sel", "Analog", "PDM CH1 Source"}, + {"PCM Sel", "Analog", "PDM CH0 Source"}, + {"Amp Enable", NULL, "PCM Sel"}, + + {"BST Enable", NULL, "Amp Enable"}, + {"BE_OUT", NULL, "BST Enable"}, +}; + +static bool max98926_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98926_VBAT_DATA: + case MAX98926_VBST_DATA: + case MAX98926_LIVE_STATUS0: + case MAX98926_LIVE_STATUS1: + case MAX98926_LIVE_STATUS2: + case MAX98926_STATE0: + case MAX98926_STATE1: + case MAX98926_STATE2: + case MAX98926_FLAG0: + case MAX98926_FLAG1: + case MAX98926_FLAG2: + case MAX98926_VERSION: + return true; + default: + return false; + } +} + +static bool max98926_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98926_IRQ_CLEAR0: + case MAX98926_IRQ_CLEAR1: + case MAX98926_IRQ_CLEAR2: + case MAX98926_ALC_HOLD_RLS: + return false; + default: + return true; + } +}; + +DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0); +DECLARE_TLV_DB_RANGE(max98926_current_tlv, + 0, 11, TLV_DB_SCALE_ITEM(20, 20, 0), + 12, 15, TLV_DB_SCALE_ITEM(320, 40, 0), +); + +static SOC_ENUM_SINGLE_DECL(max98926_dac_hpf_cutoff, + MAX98926_FILTERS, MAX98926_DAC_HPF_SHIFT, + max98926_hpf_cutoff_txt); + +static SOC_ENUM_SINGLE_DECL(max98926_boost_voltage, + MAX98926_CONFIGURATION, MAX98926_BST_VOUT_SHIFT, + max98926_boost_voltage_txt); + +static const struct snd_kcontrol_new max98926_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", MAX98926_GAIN, + MAX98926_SPK_GAIN_SHIFT, + (1<regmap, + MAX98926_DOUT_CFG_VMON, + MAX98926_DAI_VMON_EN_MASK, + MAX98926_DAI_VMON_EN_MASK); + regmap_update_bits(max98926->regmap, + MAX98926_DOUT_CFG_IMON, + MAX98926_DAI_IMON_EN_MASK, + MAX98926_DAI_IMON_EN_MASK); + + if (!max98926->interleave_mode) { + /* set VMON slots */ + regmap_update_bits(max98926->regmap, + MAX98926_DOUT_CFG_VMON, + MAX98926_DAI_VMON_SLOT_MASK, + max98926->v_slot); + /* set IMON slots */ + regmap_update_bits(max98926->regmap, + MAX98926_DOUT_CFG_IMON, + MAX98926_DAI_IMON_SLOT_MASK, + max98926->i_slot); + } else { + /* enable interleave mode */ + regmap_update_bits(max98926->regmap, + MAX98926_FORMAT, + MAX98926_DAI_INTERLEAVE_MASK, + MAX98926_DAI_INTERLEAVE_MASK); + /* set interleave slots */ + regmap_update_bits(max98926->regmap, + MAX98926_DOUT_CFG_VBAT, + MAX98926_DAI_INTERLEAVE_SLOT_MASK, + max98926->v_slot); + } +} + +static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec); + unsigned int invert = 0; + + dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + max98926_set_sense_data(max98926); + break; + default: + dev_err(codec->dev, "DAI clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + invert = MAX98926_DAI_WCI_MASK; + break; + case SND_SOC_DAIFMT_IB_NF: + invert = MAX98926_DAI_BCI_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK; + break; + default: + dev_err(codec->dev, "DAI invert mode unsupported"); + return -EINVAL; + } + + regmap_write(max98926->regmap, + MAX98926_FORMAT, MAX98926_DAI_DLY_MASK); + regmap_update_bits(max98926->regmap, MAX98926_FORMAT, + MAX98926_DAI_BCI_MASK, invert); + return 0; +} + +static int max98926_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int dai_sr = -EINVAL; + int rate = params_rate(params), i; + struct snd_soc_codec *codec = dai->codec; + struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec); + /* BCLK/LRCLK ratio calculation */ + int blr_clk_ratio = params_channels(params) * max98926->ch_size; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + regmap_update_bits(max98926->regmap, + MAX98926_FORMAT, + MAX98926_DAI_CHANSZ_MASK, + MAX98926_DAI_CHANSZ_16); + max98926->ch_size = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + regmap_update_bits(max98926->regmap, + MAX98926_FORMAT, + MAX98926_DAI_CHANSZ_MASK, + MAX98926_DAI_CHANSZ_24); + max98926->ch_size = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + regmap_update_bits(max98926->regmap, + MAX98926_FORMAT, + MAX98926_DAI_CHANSZ_MASK, + MAX98926_DAI_CHANSZ_32); + max98926->ch_size = 32; + break; + default: + dev_dbg(codec->dev, "format unsupported %d", + params_format(params)); + return -EINVAL; + } + + switch (blr_clk_ratio) { + case 32: + regmap_update_bits(max98926->regmap, + MAX98926_DAI_CLK_MODE2, + MAX98926_DAI_BSEL_MASK, + MAX98926_DAI_BSEL_32); + break; + case 48: + regmap_update_bits(max98926->regmap, + MAX98926_DAI_CLK_MODE2, + MAX98926_DAI_BSEL_MASK, + MAX98926_DAI_BSEL_48); + break; + case 64: + regmap_update_bits(max98926->regmap, + MAX98926_DAI_CLK_MODE2, + MAX98926_DAI_BSEL_MASK, + MAX98926_DAI_BSEL_64); + break; + default: + return -EINVAL; + } + + /* find the closest rate */ + for (i = 0; i < ARRAY_SIZE(rate_table); i++) { + if (rate_table[i].rate >= rate) { + dai_sr = rate_table[i].sr; + break; + } + } + if (dai_sr < 0) + return -EINVAL; + + /* set DAI_SR to correct LRCLK frequency */ + regmap_update_bits(max98926->regmap, + MAX98926_DAI_CLK_MODE2, + MAX98926_DAI_SR_MASK, dai_sr << MAX98926_DAI_SR_SHIFT); + return 0; +} + +#define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops max98926_dai_ops = { + .set_fmt = max98926_dai_set_fmt, + .hw_params = max98926_dai_hw_params, +}; + +static struct snd_soc_dai_driver max98926_dai[] = { +{ + .name = "max98926-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = MAX98926_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = MAX98926_FORMATS, + }, + .ops = &max98926_dai_ops, +} +}; + +static int max98926_probe(struct snd_soc_codec *codec) +{ + struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec); + + max98926->codec = codec; + codec->control_data = max98926->regmap; + /* Hi-Z all the slots */ + regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0); + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_max98926 = { + .probe = max98926_probe, + .controls = max98926_snd_controls, + .num_controls = ARRAY_SIZE(max98926_snd_controls), + .dapm_routes = max98926_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98926_audio_map), + .dapm_widgets = max98926_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), +}; + +static struct regmap_config max98926_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX98926_VERSION, + .reg_defaults = max98926_reg, + .num_reg_defaults = ARRAY_SIZE(max98926_reg), + .volatile_reg = max98926_volatile_register, + .readable_reg = max98926_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int max98926_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret, reg; + u32 value; + struct max98926_priv *max98926; + + max98926 = devm_kzalloc(&i2c->dev, + sizeof(*max98926), GFP_KERNEL); + if (!max98926) + return -ENOMEM; + + i2c_set_clientdata(i2c, max98926); + max98926->regmap = devm_regmap_init_i2c(i2c, &max98926_regmap); + if (IS_ERR(max98926->regmap)) { + ret = PTR_ERR(max98926->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + goto err_out; + } + if (of_property_read_bool(i2c->dev.of_node, "interleave-mode")) + max98926->interleave_mode = true; + + if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { + if (value > MAX98926_DAI_VMON_SLOT_1E_1F) { + dev_err(&i2c->dev, "vmon slot number is wrong:\n"); + return -EINVAL; + } + max98926->v_slot = value; + } + if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) { + if (value > MAX98926_DAI_IMON_SLOT_1E_1F) { + dev_err(&i2c->dev, "imon slot number is wrong:\n"); + return -EINVAL; + } + max98926->i_slot = value; + } + ret = regmap_read(max98926->regmap, + MAX98926_VERSION, ®); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read: %x\n", reg); + return ret; + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98926, + max98926_dai, ARRAY_SIZE(max98926_dai)); + if (ret < 0) + dev_err(&i2c->dev, + "Failed to register codec: %d\n", ret); + dev_info(&i2c->dev, "device version: %x\n", reg); +err_out: + return ret; +} + +static int max98926_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98926_i2c_id[] = { + { "max98926", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max98926_i2c_id); + +static const struct of_device_id max98926_of_match[] = { + { .compatible = "maxim,max98926", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98926_of_match); + +static struct i2c_driver max98926_i2c_driver = { + .driver = { + .name = "max98926", + .of_match_table = of_match_ptr(max98926_of_match), + .pm = NULL, + }, + .probe = max98926_i2c_probe, + .remove = max98926_i2c_remove, + .id_table = max98926_i2c_id, +}; + +module_i2c_driver(max98926_i2c_driver) +MODULE_DESCRIPTION("ALSA SoC MAX98926 driver"); +MODULE_AUTHOR("Anish kumar "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98926.h b/sound/soc/codecs/max98926.h new file mode 100644 index 000000000000..9d7ab6df79ca --- /dev/null +++ b/sound/soc/codecs/max98926.h @@ -0,0 +1,848 @@ +/* + * max98926.h -- MAX98926 ALSA SoC Audio driver + * Copyright 2013-2015 Maxim Integrated Products + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MAX98926_H +#define _MAX98926_H + +#define MAX98926_CHIP_VERSION 0x40 +#define MAX98926_CHIP_VERSION1 0x50 + +#define MAX98926_VBAT_DATA 0x00 +#define MAX98926_VBST_DATA 0x01 +#define MAX98926_LIVE_STATUS0 0x02 +#define MAX98926_LIVE_STATUS1 0x03 +#define MAX98926_LIVE_STATUS2 0x04 +#define MAX98926_STATE0 0x05 +#define MAX98926_STATE1 0x06 +#define MAX98926_STATE2 0x07 +#define MAX98926_FLAG0 0x08 +#define MAX98926_FLAG1 0x09 +#define MAX98926_FLAG2 0x0A +#define MAX98926_IRQ_ENABLE0 0x0B +#define MAX98926_IRQ_ENABLE1 0x0C +#define MAX98926_IRQ_ENABLE2 0x0D +#define MAX98926_IRQ_CLEAR0 0x0E +#define MAX98926_IRQ_CLEAR1 0x0F +#define MAX98926_IRQ_CLEAR2 0x10 +#define MAX98926_MAP0 0x11 +#define MAX98926_MAP1 0x12 +#define MAX98926_MAP2 0x13 +#define MAX98926_MAP3 0x14 +#define MAX98926_MAP4 0x15 +#define MAX98926_MAP5 0x16 +#define MAX98926_MAP6 0x17 +#define MAX98926_MAP7 0x18 +#define MAX98926_MAP8 0x19 +#define MAX98926_DAI_CLK_MODE1 0x1A +#define MAX98926_DAI_CLK_MODE2 0x1B +#define MAX98926_DAI_CLK_DIV_M_MSBS 0x1C +#define MAX98926_DAI_CLK_DIV_M_LSBS 0x1D +#define MAX98926_DAI_CLK_DIV_N_MSBS 0x1E +#define MAX98926_DAI_CLK_DIV_N_LSBS 0x1F +#define MAX98926_FORMAT 0x20 +#define MAX98926_TDM_SLOT_SELECT 0x21 +#define MAX98926_DOUT_CFG_VMON 0x22 +#define MAX98926_DOUT_CFG_IMON 0x23 +#define MAX98926_DOUT_CFG_VBAT 0x24 +#define MAX98926_DOUT_CFG_VBST 0x25 +#define MAX98926_DOUT_CFG_FLAG 0x26 +#define MAX98926_DOUT_HIZ_CFG1 0x27 +#define MAX98926_DOUT_HIZ_CFG2 0x28 +#define MAX98926_DOUT_HIZ_CFG3 0x29 +#define MAX98926_DOUT_HIZ_CFG4 0x2A +#define MAX98926_DOUT_DRV_STRENGTH 0x2B +#define MAX98926_FILTERS 0x2C +#define MAX98926_GAIN 0x2D +#define MAX98926_GAIN_RAMPING 0x2E +#define MAX98926_SPK_AMP 0x2F +#define MAX98926_THRESHOLD 0x30 +#define MAX98926_ALC_ATTACK 0x31 +#define MAX98926_ALC_ATTEN_RLS 0x32 +#define MAX98926_ALC_HOLD_RLS 0x33 +#define MAX98926_ALC_CONFIGURATION 0x34 +#define MAX98926_BOOST_CONVERTER 0x35 +#define MAX98926_BLOCK_ENABLE 0x36 +#define MAX98926_CONFIGURATION 0x37 +#define MAX98926_GLOBAL_ENABLE 0x38 +#define MAX98926_BOOST_LIMITER 0x3A +#define MAX98926_VERSION 0xFF + +#define MAX98926_REG_CNT (MAX98926_R03A_BOOST_LIMITER+1) + +#define MAX98926_PDM_CURRENT_MASK (1<<7) +#define MAX98926_PDM_CURRENT_SHIFT 7 +#define MAX98926_PDM_VOLTAGE_MASK (1<<3) +#define MAX98926_PDM_VOLTAGE_SHIFT 3 +#define MAX98926_PDM_CHANNEL_0_MASK (1<<2) +#define MAX98926_PDM_CHANNEL_0_SHIFT 2 +#define MAX98926_PDM_CHANNEL_1_MASK (1<<6) +#define MAX98926_PDM_CHANNEL_1_SHIFT 6 +#define MAX98926_PDM_CHANNEL_1_HIZ 5 +#define MAX98926_PDM_CHANNEL_0_HIZ 1 +#define MAX98926_PDM_SOURCE_0_SHIFT 0 +#define MAX98926_PDM_SOURCE_0_MASK (1<<0) +#define MAX98926_PDM_SOURCE_1_MASK (1<<4) +#define MAX98926_PDM_SOURCE_1_SHIFT 4 + +/* MAX98926 Register Bit Fields */ + +/* MAX98926_R002_LIVE_STATUS0 */ +#define MAX98926_THERMWARN_STATUS_MASK (1<<3) +#define MAX98926_THERMWARN_STATUS_SHIFT 3 +#define MAX98926_THERMWARN_STATUS_WIDTH 1 +#define MAX98926_THERMSHDN_STATUS_MASK (1<<1) +#define MAX98926_THERMSHDN_STATUS_SHIFT 1 +#define MAX98926_THERMSHDN_STATUS_WIDTH 1 + +/* MAX98926_R003_LIVE_STATUS1 */ +#define MAX98926_SPKCURNT_STATUS_MASK (1<<5) +#define MAX98926_SPKCURNT_STATUS_SHIFT 5 +#define MAX98926_SPKCURNT_STATUS_WIDTH 1 +#define MAX98926_WATCHFAIL_STATUS_MASK (1<<4) +#define MAX98926_WATCHFAIL_STATUS_SHIFT 4 +#define MAX98926_WATCHFAIL_STATUS_WIDTH 1 +#define MAX98926_ALCINFH_STATUS_MASK (1<<3) +#define MAX98926_ALCINFH_STATUS_SHIFT 3 +#define MAX98926_ALCINFH_STATUS_WIDTH 1 +#define MAX98926_ALCACT_STATUS_MASK (1<<2) +#define MAX98926_ALCACT_STATUS_SHIFT 2 +#define MAX98926_ALCACT_STATUS_WIDTH 1 +#define MAX98926_ALCMUT_STATUS_MASK (1<<1) +#define MAX98926_ALCMUT_STATUS_SHIFT 1 +#define MAX98926_ALCMUT_STATUS_WIDTH 1 +#define MAX98926_ACLP_STATUS_MASK (1<<0) +#define MAX98926_ACLP_STATUS_SHIFT 0 +#define MAX98926_ACLP_STATUS_WIDTH 1 + +/* MAX98926_R004_LIVE_STATUS2 */ +#define MAX98926_SLOTOVRN_STATUS_MASK (1<<6) +#define MAX98926_SLOTOVRN_STATUS_SHIFT 6 +#define MAX98926_SLOTOVRN_STATUS_WIDTH 1 +#define MAX98926_INVALSLOT_STATUS_MASK (1<<5) +#define MAX98926_INVALSLOT_STATUS_SHIFT 5 +#define MAX98926_INVALSLOT_STATUS_WIDTH 1 +#define MAX98926_SLOTCNFLT_STATUS_MASK (1<<4) +#define MAX98926_SLOTCNFLT_STATUS_SHIFT 4 +#define MAX98926_SLOTCNFLT_STATUS_WIDTH 1 +#define MAX98926_VBSTOVFL_STATUS_MASK (1<<3) +#define MAX98926_VBSTOVFL_STATUS_SHIFT 3 +#define MAX98926_VBSTOVFL_STATUS_WIDTH 1 +#define MAX98926_VBATOVFL_STATUS_MASK (1<<2) +#define MAX98926_VBATOVFL_STATUS_SHIFT 2 +#define MAX98926_VBATOVFL_STATUS_WIDTH 1 +#define MAX98926_IMONOVFL_STATUS_MASK (1<<1) +#define MAX98926_IMONOVFL_STATUS_SHIFT 1 +#define MAX98926_IMONOVFL_STATUS_WIDTH 1 +#define MAX98926_VMONOVFL_STATUS_MASK (1<<0) +#define MAX98926_VMONOVFL_STATUS_SHIFT 0 +#define MAX98926_VMONOVFL_STATUS_WIDTH 1 + +/* MAX98926_R005_STATE0 */ +#define MAX98926_THERMWARN_END_STATE_MASK (1<<3) +#define MAX98926_THERMWARN_END_STATE_SHIFT 3 +#define MAX98926_THERMWARN_END_STATE_WIDTH 1 +#define MAX98926_THERMWARN_BGN_STATE_MASK (1<<2) +#define MAX98926_THERMWARN_BGN_STATE_SHIFT 1 +#define MAX98926_THERMWARN_BGN_STATE_WIDTH 1 +#define MAX98926_THERMSHDN_END_STATE_MASK (1<<1) +#define MAX98926_THERMSHDN_END_STATE_SHIFT 1 +#define MAX98926_THERMSHDN_END_STATE_WIDTH 1 +#define MAX98926_THERMSHDN_BGN_STATE_MASK (1<<0) +#define MAX98926_THERMSHDN_BGN_STATE_SHIFT 0 +#define MAX98926_THERMSHDN_BGN_STATE_WIDTH 1 + +/* MAX98926_R006_STATE1 */ +#define MAX98926_SPRCURNT_STATE_MASK (1<<5) +#define MAX98926_SPRCURNT_STATE_SHIFT 5 +#define MAX98926_SPRCURNT_STATE_WIDTH 1 +#define MAX98926_WATCHFAIL_STATE_MASK (1<<4) +#define MAX98926_WATCHFAIL_STATE_SHIFT 4 +#define MAX98926_WATCHFAIL_STATE_WIDTH 1 +#define MAX98926_ALCINFH_STATE_MASK (1<<3) +#define MAX98926_ALCINFH_STATE_SHIFT 3 +#define MAX98926_ALCINFH_STATE_WIDTH 1 +#define MAX98926_ALCACT_STATE_MASK (1<<2) +#define MAX98926_ALCACT_STATE_SHIFT 2 +#define MAX98926_ALCACT_STATE_WIDTH 1 +#define MAX98926_ALCMUT_STATE_MASK (1<<1) +#define MAX98926_ALCMUT_STATE_SHIFT 1 +#define MAX98926_ALCMUT_STATE_WIDTH 1 +#define MAX98926_ALCP_STATE_MASK (1<<0) +#define MAX98926_ALCP_STATE_SHIFT 0 +#define MAX98926_ALCP_STATE_WIDTH 1 + +/* MAX98926_R007_STATE2 */ +#define MAX98926_SLOTOVRN_STATE_MASK (1<<6) +#define MAX98926_SLOTOVRN_STATE_SHIFT 6 +#define MAX98926_SLOTOVRN_STATE_WIDTH 1 +#define MAX98926_INVALSLOT_STATE_MASK (1<<5) +#define MAX98926_INVALSLOT_STATE_SHIFT 5 +#define MAX98926_INVALSLOT_STATE_WIDTH 1 +#define MAX98926_SLOTCNFLT_STATE_MASK (1<<4) +#define MAX98926_SLOTCNFLT_STATE_SHIFT 4 +#define MAX98926_SLOTCNFLT_STATE_WIDTH 1 +#define MAX98926_VBSTOVFL_STATE_MASK (1<<3) +#define MAX98926_VBSTOVFL_STATE_SHIFT 3 +#define MAX98926_VBSTOVFL_STATE_WIDTH 1 +#define MAX98926_VBATOVFL_STATE_MASK (1<<2) +#define MAX98926_VBATOVFL_STATE_SHIFT 2 +#define MAX98926_VBATOVFL_STATE_WIDTH 1 +#define MAX98926_IMONOVFL_STATE_MASK (1<<1) +#define MAX98926_IMONOVFL_STATE_SHIFT 1 +#define MAX98926_IMONOVFL_STATE_WIDTH 1 +#define MAX98926_VMONOVFL_STATE_MASK (1<<0) +#define MAX98926_VMONOVFL_STATE_SHIFT 0 +#define MAX98926_VMONOVFL_STATE_WIDTH 1 + +/* MAX98926_R008_FLAG0 */ +#define MAX98926_THERMWARN_END_FLAG_MASK (1<<3) +#define MAX98926_THERMWARN_END_FLAG_SHIFT 3 +#define MAX98926_THERMWARN_END_FLAG_WIDTH 1 +#define MAX98926_THERMWARN_BGN_FLAG_MASK (1<<2) +#define MAX98926_THERMWARN_BGN_FLAG_SHIFT 2 +#define MAX98926_THERMWARN_BGN_FLAG_WIDTH 1 +#define MAX98926_THERMSHDN_END_FLAG_MASK (1<<1) +#define MAX98926_THERMSHDN_END_FLAG_SHIFT 1 +#define MAX98926_THERMSHDN_END_FLAG_WIDTH 1 +#define MAX98926_THERMSHDN_BGN_FLAG_MASK (1<<0) +#define MAX98926_THERMSHDN_BGN_FLAG_SHIFT 0 +#define MAX98926_THERMSHDN_BGN_FLAG_WIDTH 1 + +/* MAX98926_R009_FLAG1 */ +#define MAX98926_SPKCURNT_FLAG_MASK (1<<5) +#define MAX98926_SPKCURNT_FLAG_SHIFT 5 +#define MAX98926_SPKCURNT_FLAG_WIDTH 1 +#define MAX98926_WATCHFAIL_FLAG_MASK (1<<4) +#define MAX98926_WATCHFAIL_FLAG_SHIFT 4 +#define MAX98926_WATCHFAIL_FLAG_WIDTH 1 +#define MAX98926_ALCINFH_FLAG_MASK (1<<3) +#define MAX98926_ALCINFH_FLAG_SHIFT 3 +#define MAX98926_ALCINFH_FLAG_WIDTH 1 +#define MAX98926_ALCACT_FLAG_MASK (1<<2) +#define MAX98926_ALCACT_FLAG_SHIFT 2 +#define MAX98926_ALCACT_FLAG_WIDTH 1 +#define MAX98926_ALCMUT_FLAG_MASK (1<<1) +#define MAX98926_ALCMUT_FLAG_SHIFT 1 +#define MAX98926_ALCMUT_FLAG_WIDTH 1 +#define MAX98926_ALCP_FLAG_MASK (1<<0) +#define MAX98926_ALCP_FLAG_SHIFT 0 +#define MAX98926_ALCP_FLAG_WIDTH 1 + +/* MAX98926_R00A_FLAG2 */ +#define MAX98926_SLOTOVRN_FLAG_MASK (1<<6) +#define MAX98926_SLOTOVRN_FLAG_SHIFT 6 +#define MAX98926_SLOTOVRN_FLAG_WIDTH 1 +#define MAX98926_INVALSLOT_FLAG_MASK (1<<5) +#define MAX98926_INVALSLOT_FLAG_SHIFT 5 +#define MAX98926_INVALSLOT_FLAG_WIDTH 1 +#define MAX98926_SLOTCNFLT_FLAG_MASK (1<<4) +#define MAX98926_SLOTCNFLT_FLAG_SHIFT 4 +#define MAX98926_SLOTCNFLT_FLAG_WIDTH 1 +#define MAX98926_VBSTOVFL_FLAG_MASK (1<<3) +#define MAX98926_VBSTOVFL_FLAG_SHIFT 3 +#define MAX98926_VBSTOVFL_FLAG_WIDTH 1 +#define MAX98926_VBATOVFL_FLAG_MASK (1<<2) +#define MAX98926_VBATOVFL_FLAG_SHIFT 2 +#define MAX98926_VBATOVFL_FLAG_WIDTH 1 +#define MAX98926_IMONOVFL_FLAG_MASK (1<<1) +#define MAX98926_IMONOVFL_FLAG_SHIFT 1 +#define MAX98926_IMONOVFL_FLAG_WIDTH 1 +#define MAX98926_VMONOVFL_FLAG_MASK (1<<0) +#define MAX98926_VMONOVFL_FLAG_SHIFT 0 +#define MAX98926_VMONOVFL_FLAG_WIDTH 1 + +/* MAX98926_R00B_IRQ_ENABLE0 */ +#define MAX98926_THERMWARN_END_EN_MASK (1<<3) +#define MAX98926_THERMWARN_END_EN_SHIFT 3 +#define MAX98926_THERMWARN_END_EN_WIDTH 1 +#define MAX98926_THERMWARN_BGN_EN_MASK (1<<2) +#define MAX98926_THERMWARN_BGN_EN_SHIFT 2 +#define MAX98926_THERMWARN_BGN_EN_WIDTH 1 +#define MAX98926_THERMSHDN_END_EN_MASK (1<<1) +#define MAX98926_THERMSHDN_END_EN_SHIFT 1 +#define MAX98926_THERMSHDN_END_EN_WIDTH 1 +#define MAX98926_THERMSHDN_BGN_EN_MASK (1<<0) +#define MAX98926_THERMSHDN_BGN_EN_SHIFT 0 +#define MAX98926_THERMSHDN_BGN_EN_WIDTH 1 + +/* MAX98926_R00C_IRQ_ENABLE1 */ +#define MAX98926_SPKCURNT_EN_MASK (1<<5) +#define MAX98926_SPKCURNT_EN_SHIFT 5 +#define MAX98926_SPKCURNT_EN_WIDTH 1 +#define MAX98926_WATCHFAIL_EN_MASK (1<<4) +#define MAX98926_WATCHFAIL_EN_SHIFT 4 +#define MAX98926_WATCHFAIL_EN_WIDTH 1 +#define MAX98926_ALCINFH_EN_MASK (1<<3) +#define MAX98926_ALCINFH_EN_SHIFT 3 +#define MAX98926_ALCINFH_EN_WIDTH 1 +#define MAX98926_ALCACT_EN_MASK (1<<2) +#define MAX98926_ALCACT_EN_SHIFT 2 +#define MAX98926_ALCACT_EN_WIDTH 1 +#define MAX98926_ALCMUT_EN_MASK (1<<1) +#define MAX98926_ALCMUT_EN_SHIFT 1 +#define MAX98926_ALCMUT_EN_WIDTH 1 +#define MAX98926_ALCP_EN_MASK (1<<0) +#define MAX98926_ALCP_EN_SHIFT 0 +#define MAX98926_ALCP_EN_WIDTH 1 + +/* MAX98926_R00D_IRQ_ENABLE2 */ +#define MAX98926_SLOTOVRN_EN_MASK (1<<6) +#define MAX98926_SLOTOVRN_EN_SHIFT 6 +#define MAX98926_SLOTOVRN_EN_WIDTH 1 +#define MAX98926_INVALSLOT_EN_MASK (1<<5) +#define MAX98926_INVALSLOT_EN_SHIFT 5 +#define MAX98926_INVALSLOT_EN_WIDTH 1 +#define MAX98926_SLOTCNFLT_EN_MASK (1<<4) +#define MAX98926_SLOTCNFLT_EN_SHIFT 4 +#define MAX98926_SLOTCNFLT_EN_WIDTH 1 +#define MAX98926_VBSTOVFL_EN_MASK (1<<3) +#define MAX98926_VBSTOVFL_EN_SHIFT 3 +#define MAX98926_VBSTOVFL_EN_WIDTH 1 +#define MAX98926_VBATOVFL_EN_MASK (1<<2) +#define MAX98926_VBATOVFL_EN_SHIFT 2 +#define MAX98926_VBATOVFL_EN_WIDTH 1 +#define MAX98926_IMONOVFL_EN_MASK (1<<1) +#define MAX98926_IMONOVFL_EN_SHIFT 1 +#define MAX98926_IMONOVFL_EN_WIDTH 1 +#define MAX98926_VMONOVFL_EN_MASK (1<<0) +#define MAX98926_VMONOVFL_EN_SHIFT 0 +#define MAX98926_VMONOVFL_EN_WIDTH 1 + +/* MAX98926_R00E_IRQ_CLEAR0 */ +#define MAX98926_THERMWARN_END_CLR_MASK (1<<3) +#define MAX98926_THERMWARN_END_CLR_SHIFT 3 +#define MAX98926_THERMWARN_END_CLR_WIDTH 1 +#define MAX98926_THERMWARN_BGN_CLR_MASK (1<<2) +#define MAX98926_THERMWARN_BGN_CLR_SHIFT 2 +#define MAX98926_THERMWARN_BGN_CLR_WIDTH 1 +#define MAX98926_THERMSHDN_END_CLR_MASK (1<<1) +#define MAX98926_THERMSHDN_END_CLR_SHIFT 1 +#define MAX98926_THERMSHDN_END_CLR_WIDTH 1 +#define MAX98926_THERMSHDN_BGN_CLR_MASK (1<<0) +#define MAX98926_THERMSHDN_BGN_CLR_SHIFT 0 +#define MAX98926_THERMSHDN_BGN_CLR_WIDTH 1 + +/* MAX98926_R00F_IRQ_CLEAR1 */ +#define MAX98926_SPKCURNT_CLR_MASK (1<<5) +#define MAX98926_SPKCURNT_CLR_SHIFT 5 +#define MAX98926_SPKCURNT_CLR_WIDTH 1 +#define MAX98926_WATCHFAIL_CLR_MASK (1<<4) +#define MAX98926_WATCHFAIL_CLR_SHIFT 4 +#define MAX98926_WATCHFAIL_CLR_WIDTH 1 +#define MAX98926_ALCINFH_CLR_MASK (1<<3) +#define MAX98926_ALCINFH_CLR_SHIFT 3 +#define MAX98926_ALCINFH_CLR_WIDTH 1 +#define MAX98926_ALCACT_CLR_MASK (1<<2) +#define MAX98926_ALCACT_CLR_SHIFT 2 +#define MAX98926_ALCACT_CLR_WIDTH 1 +#define MAX98926_ALCMUT_CLR_MASK (1<<1) +#define MAX98926_ALCMUT_CLR_SHIFT 1 +#define MAX98926_ALCMUT_CLR_WIDTH 1 +#define MAX98926_ALCP_CLR_MASK (1<<0) +#define MAX98926_ALCP_CLR_SHIFT 0 +#define MAX98926_ALCP_CLR_WIDTH 1 + +/* MAX98926_R010_IRQ_CLEAR2 */ +#define MAX98926_SLOTOVRN_CLR_MASK (1<<6) +#define MAX98926_SLOTOVRN_CLR_SHIFT 6 +#define MAX98926_SLOTOVRN_CLR_WIDTH 1 +#define MAX98926_INVALSLOT_CLR_MASK (1<<5) +#define MAX98926_INVALSLOT_CLR_SHIFT 5 +#define MAX98926_INVALSLOT_CLR_WIDTH 1 +#define MAX98926_SLOTCNFLT_CLR_MASK (1<<4) +#define MAX98926_SLOTCNFLT_CLR_SHIFT 4 +#define MAX98926_SLOTCNFLT_CLR_WIDTH 1 +#define MAX98926_VBSTOVFL_CLR_MASK (1<<3) +#define MAX98926_VBSTOVFL_CLR_SHIFT 3 +#define MAX98926_VBSTOVFL_CLR_WIDTH 1 +#define MAX98926_VBATOVFL_CLR_MASK (1<<2) +#define MAX98926_VBATOVFL_CLR_SHIFT 2 +#define MAX98926_VBATOVFL_CLR_WIDTH 1 +#define MAX98926_IMONOVFL_CLR_MASK (1<<1) +#define MAX98926_IMONOVFL_CLR_SHIFT 1 +#define MAX98926_IMONOVFL_CLR_WIDTH 1 +#define MAX98926_VMONOVFL_CLR_MASK (1<<0) +#define MAX98926_VMONOVFL_CLR_SHIFT 0 +#define MAX98926_VMONOVFL_CLR_WIDTH 1 + +/* MAX98926_R011_MAP0 */ +#define MAX98926_ER_THERMWARN_EN_MASK (1<<7) +#define MAX98926_ER_THERMWARN_EN_SHIFT 7 +#define MAX98926_ER_THERMWARN_EN_WIDTH 1 +#define MAX98926_ER_THERMWARN_MAP_MASK (0x07<<4) +#define MAX98926_ER_THERMWARN_MAP_SHIFT 4 +#define MAX98926_ER_THERMWARN_MAP_WIDTH 3 + +/* MAX98926_R012_MAP1 */ +#define MAX98926_ER_ALCMUT_EN_MASK (1<<7) +#define MAX98926_ER_ALCMUT_EN_SHIFT 7 +#define MAX98926_ER_ALCMUT_EN_WIDTH 1 +#define MAX98926_ER_ALCMUT_MAP_MASK (0x07<<4) +#define MAX98926_ER_ALCMUT_MAP_SHIFT 4 +#define MAX98926_ER_ALCMUT_MAP_WIDTH 3 +#define MAX98926_ER_ALCP_EN_MASK (1<<3) +#define MAX98926_ER_ALCP_EN_SHIFT 3 +#define MAX98926_ER_ALCP_EN_WIDTH 1 +#define MAX98926_ER_ALCP_MAP_MASK (0x07<<0) +#define MAX98926_ER_ALCP_MAP_SHIFT 0 +#define MAX98926_ER_ALCP_MAP_WIDTH 3 + +/* MAX98926_R013_MAP2 */ +#define MAX98926_ER_ALCINFH_EN_MASK (1<<7) +#define MAX98926_ER_ALCINFH_EN_SHIFT 7 +#define MAX98926_ER_ALCINFH_EN_WIDTH 1 +#define MAX98926_ER_ALCINFH_MAP_MASK (0x07<<4) +#define MAX98926_ER_ALCINFH_MAP_SHIFT 4 +#define MAX98926_ER_ALCINFH_MAP_WIDTH 3 +#define MAX98926_ER_ALCACT_EN_MASK (1<<3) +#define MAX98926_ER_ALCACT_EN_SHIFT 3 +#define MAX98926_ER_ALCACT_EN_WIDTH 1 +#define MAX98926_ER_ALCACT_MAP_MASK (0x07<<0) +#define MAX98926_ER_ALCACT_MAP_SHIFT 0 +#define MAX98926_ER_ALCACT_MAP_WIDTH 3 + +/* MAX98926_R014_MAP3 */ +#define MAX98926_ER_SPKCURNT_EN_MASK (1<<7) +#define MAX98926_ER_SPKCURNT_EN_SHIFT 7 +#define MAX98926_ER_SPKCURNT_EN_WIDTH 1 +#define MAX98926_ER_SPKCURNT_MAP_MASK (0x07<<4) +#define MAX98926_ER_SPKCURNT_MAP_SHIFT 4 +#define MAX98926_ER_SPKCURNT_MAP_WIDTH 3 + +/* MAX98926_R015_MAP4 */ +/* RESERVED */ + +/* MAX98926_R016_MAP5 */ +#define MAX98926_ER_IMONOVFL_EN_MASK (1<<7) +#define MAX98926_ER_IMONOVFL_EN_SHIFT 7 +#define MAX98926_ER_IMONOVFL_EN_WIDTH 1 +#define MAX98926_ER_IMONOVFL_MAP_MASK (0x07<<4) +#define MAX98926_ER_IMONOVFL_MAP_SHIFT 4 +#define MAX98926_ER_IMONOVFL_MAP_WIDTH 3 +#define MAX98926_ER_VMONOVFL_EN_MASK (1<<3) +#define MAX98926_ER_VMONOVFL_EN_SHIFT 3 +#define MAX98926_ER_VMONOVFL_EN_WIDTH 1 +#define MAX98926_ER_VMONOVFL_MAP_MASK (0x07<<0) +#define MAX98926_ER_VMONOVFL_MAP_SHIFT 0 +#define MAX98926_ER_VMONOVFL_MAP_WIDTH 3 + +/* MAX98926_R017_MAP6 */ +#define MAX98926_ER_VBSTOVFL_EN_MASK (1<<7) +#define MAX98926_ER_VBSTOVFL_EN_SHIFT 7 +#define MAX98926_ER_VBSTOVFL_EN_WIDTH 1 +#define MAX98926_ER_VBSTOVFL_MAP_MASK (0x07<<4) +#define MAX98926_ER_VBSTOVFL_MAP_SHIFT 4 +#define MAX98926_ER_VBSTOVFL_MAP_WIDTH 3 +#define MAX98926_ER_VBATOVFL_EN_MASK (1<<3) +#define MAX98926_ER_VBATOVFL_EN_SHIFT 3 +#define MAX98926_ER_VBATOVFL_EN_WIDTH 1 +#define MAX98926_ER_VBATOVFL_MAP_MASK (0x07<<0) +#define MAX98926_ER_VBATOVFL_MAP_SHIFT 0 +#define MAX98926_ER_VBATOVFL_MAP_WIDTH 3 + +/* MAX98926_R018_MAP7 */ +#define MAX98926_ER_INVALSLOT_EN_MASK (1<<7) +#define MAX98926_ER_INVALSLOT_EN_SHIFT 7 +#define MAX98926_ER_INVALSLOT_EN_WIDTH 1 +#define MAX98926_ER_INVALSLOT_MAP_MASK (0x07<<4) +#define MAX98926_ER_INVALSLOT_MAP_SHIFT 4 +#define MAX98926_ER_INVALSLOT_MAP_WIDTH 3 +#define MAX98926_ER_SLOTCNFLT_EN_MASK (1<<3) +#define MAX98926_ER_SLOTCNFLT_EN_SHIFT 3 +#define MAX98926_ER_SLOTCNFLT_EN_WIDTH 1 +#define MAX98926_ER_SLOTCNFLT_MAP_MASK (0x07<<0) +#define MAX98926_ER_SLOTCNFLT_MAP_SHIFT 0 +#define MAX98926_ER_SLOTCNFLT_MAP_WIDTH 3 + +/* MAX98926_R019_MAP8 */ +#define MAX98926_ER_SLOTOVRN_EN_MASK (1<<3) +#define MAX98926_ER_SLOTOVRN_EN_SHIFT 3 +#define MAX98926_ER_SLOTOVRN_EN_WIDTH 1 +#define MAX98926_ER_SLOTOVRN_MAP_MASK (0x07<<0) +#define MAX98926_ER_SLOTOVRN_MAP_SHIFT 0 +#define MAX98926_ER_SLOTOVRN_MAP_WIDTH 3 + +/* MAX98926_R01A_DAI_CLK_MODE1 */ +#define MAX98926_DAI_CLK_SOURCE_MASK (1<<6) +#define MAX98926_DAI_CLK_SOURCE_SHIFT 6 +#define MAX98926_DAI_CLK_SOURCE_WIDTH 1 +#define MAX98926_MDLL_MULT_MASK (0x0F<<0) +#define MAX98926_MDLL_MULT_SHIFT 0 +#define MAX98926_MDLL_MULT_WIDTH 4 + +#define MAX98926_MDLL_MULT_MCLKx8 6 +#define MAX98926_MDLL_MULT_MCLKx16 8 + +/* MAX98926_R01B_DAI_CLK_MODE2 */ +#define MAX98926_DAI_SR_MASK (0x0F<<4) +#define MAX98926_DAI_SR_SHIFT 4 +#define MAX98926_DAI_SR_WIDTH 4 +#define MAX98926_DAI_MAS_MASK (1<<3) +#define MAX98926_DAI_MAS_SHIFT 3 +#define MAX98926_DAI_MAS_WIDTH 1 +#define MAX98926_DAI_BSEL_MASK (0x07<<0) +#define MAX98926_DAI_BSEL_SHIFT 0 +#define MAX98926_DAI_BSEL_WIDTH 3 + +#define MAX98926_DAI_BSEL_32 (0 << MAX98926_DAI_BSEL_SHIFT) +#define MAX98926_DAI_BSEL_48 (1 << MAX98926_DAI_BSEL_SHIFT) +#define MAX98926_DAI_BSEL_64 (2 << MAX98926_DAI_BSEL_SHIFT) +#define MAX98926_DAI_BSEL_256 (6 << MAX98926_DAI_BSEL_SHIFT) + +/* MAX98926_R01C_DAI_CLK_DIV_M_MSBS */ +#define MAX98926_DAI_M_MSBS_MASK (0xFF<<0) +#define MAX98926_DAI_M_MSBS_SHIFT 0 +#define MAX98926_DAI_M_MSBS_WIDTH 8 + +/* MAX98926_R01D_DAI_CLK_DIV_M_LSBS */ +#define MAX98926_DAI_M_LSBS_MASK (0xFF<<0) +#define MAX98926_DAI_M_LSBS_SHIFT 0 +#define MAX98926_DAI_M_LSBS_WIDTH 8 + +/* MAX98926_R01E_DAI_CLK_DIV_N_MSBS */ +#define MAX98926_DAI_N_MSBS_MASK (0x7F<<0) +#define MAX98926_DAI_N_MSBS_SHIFT 0 +#define MAX98926_DAI_N_MSBS_WIDTH 7 + +/* MAX98926_R01F_DAI_CLK_DIV_N_LSBS */ +#define MAX98926_DAI_N_LSBS_MASK (0xFF<<0) +#define MAX98926_DAI_N_LSBS_SHIFT 0 +#define MAX98926_DAI_N_LSBS_WIDTH 8 + +/* MAX98926_R020_FORMAT */ +#define MAX98926_DAI_CHANSZ_MASK (0x03<<6) +#define MAX98926_DAI_CHANSZ_SHIFT 6 +#define MAX98926_DAI_CHANSZ_WIDTH 2 +#define MAX98926_DAI_INTERLEAVE_MASK (1<<5) +#define MAX98926_DAI_INTERLEAVE_SHIFT 5 +#define MAX98926_DAI_INTERLEAVE_WIDTH 1 +#define MAX98926_DAI_EXTBCLK_HIZ_MASK (1<<4) +#define MAX98926_DAI_EXTBCLK_HIZ_SHIFT 4 +#define MAX98926_DAI_EXTBCLK_HIZ_WIDTH 1 +#define MAX98926_DAI_WCI_MASK (1<<3) +#define MAX98926_DAI_WCI_SHIFT 3 +#define MAX98926_DAI_WCI_WIDTH 1 +#define MAX98926_DAI_BCI_MASK (1<<2) +#define MAX98926_DAI_BCI_SHIFT 2 +#define MAX98926_DAI_BCI_WIDTH 1 +#define MAX98926_DAI_DLY_MASK (1<<1) +#define MAX98926_DAI_DLY_SHIFT 1 +#define MAX98926_DAI_DLY_WIDTH 1 +#define MAX98926_DAI_TDM_MASK (1<<0) +#define MAX98926_DAI_TDM_SHIFT 0 +#define MAX98926_DAI_TDM_WIDTH 1 + +#define MAX98926_DAI_CHANSZ_16 (1 << MAX98926_DAI_CHANSZ_SHIFT) +#define MAX98926_DAI_CHANSZ_24 (2 << MAX98926_DAI_CHANSZ_SHIFT) +#define MAX98926_DAI_CHANSZ_32 (3 << MAX98926_DAI_CHANSZ_SHIFT) + +/* MAX98926_R021_TDM_SLOT_SELECT */ +#define MAX98926_DAI_DO_EN_MASK (1<<7) +#define MAX98926_DAI_DO_EN_SHIFT 7 +#define MAX98926_DAI_DO_EN_WIDTH 1 +#define MAX98926_DAI_DIN_EN_MASK (1<<6) +#define MAX98926_DAI_DIN_EN_SHIFT 6 +#define MAX98926_DAI_DIN_EN_WIDTH 1 +#define MAX98926_DAI_INR_SOURCE_MASK (0x07<<3) +#define MAX98926_DAI_INR_SOURCE_SHIFT 3 +#define MAX98926_DAI_INR_SOURCE_WIDTH 3 +#define MAX98926_DAI_INL_SOURCE_MASK (0x07<<0) +#define MAX98926_DAI_INL_SOURCE_SHIFT 0 +#define MAX98926_DAI_INL_SOURCE_WIDTH 3 + +/* MAX98926_R022_DOUT_CFG_VMON */ +#define MAX98926_DAI_VMON_EN_MASK (1<<5) +#define MAX98926_DAI_VMON_EN_SHIFT 5 +#define MAX98926_DAI_VMON_EN_WIDTH 1 +#define MAX98926_DAI_VMON_SLOT_MASK (0x1F<<0) +#define MAX98926_DAI_VMON_SLOT_SHIFT 0 +#define MAX98926_DAI_VMON_SLOT_WIDTH 5 + +#define MAX98926_DAI_VMON_SLOT_00_01 (0 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_01_02 (1 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_02_03 (2 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_03_04 (3 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_04_05 (4 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_05_06 (5 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_06_07 (6 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_07_08 (7 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_08_09 (8 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_09_0A (9 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_0A_0B (10 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_0B_0C (11 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_0C_0D (12 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_0D_0E (13 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_0E_0F (14 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_0F_10 (15 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_10_11 (16 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_11_12 (17 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_12_13 (18 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_13_14 (19 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_14_15 (20 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_15_16 (21 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_16_17 (22 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_17_18 (23 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_18_19 (24 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_19_1A (25 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_1A_1B (26 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_1B_1C (27 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_1C_1D (28 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_1D_1E (29 << MAX98926_DAI_VMON_SLOT_SHIFT) +#define MAX98926_DAI_VMON_SLOT_1E_1F (30 << MAX98926_DAI_VMON_SLOT_SHIFT) + +/* MAX98926_R023_DOUT_CFG_IMON */ +#define MAX98926_DAI_IMON_EN_MASK (1<<5) +#define MAX98926_DAI_IMON_EN_SHIFT 5 +#define MAX98926_DAI_IMON_EN_WIDTH 1 +#define MAX98926_DAI_IMON_SLOT_MASK (0x1F<<0) +#define MAX98926_DAI_IMON_SLOT_SHIFT 0 +#define MAX98926_DAI_IMON_SLOT_WIDTH 5 + +#define MAX98926_DAI_IMON_SLOT_00_01 (0 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_01_02 (1 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_02_03 (2 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_03_04 (3 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_04_05 (4 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_05_06 (5 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_06_07 (6 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_07_08 (7 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_08_09 (8 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_09_0A (9 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_0A_0B (10 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_0B_0C (11 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_0C_0D (12 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_0D_0E (13 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_0E_0F (14 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_0F_10 (15 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_10_11 (16 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_11_12 (17 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_12_13 (18 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_13_14 (19 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_14_15 (20 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_15_16 (21 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_16_17 (22 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_17_18 (23 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_18_19 (24 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_19_1A (25 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_1A_1B (26 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_1B_1C (27 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_1C_1D (28 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_1D_1E (29 << MAX98926_DAI_IMON_SLOT_SHIFT) +#define MAX98926_DAI_IMON_SLOT_1E_1F (30 << MAX98926_DAI_IMON_SLOT_SHIFT) + +/* MAX98926_R024_DOUT_CFG_VBAT */ +#define MAX98926_DAI_INTERLEAVE_SLOT_MASK (0x1F<<0) +#define MAX98926_DAI_INTERLEAVE_SLOT_SHIFT 0 +#define MAX98926_DAI_INTERLEAVE_SLOT_WIDTH 5 + +/* MAX98926_R025_DOUT_CFG_VBST */ +#define MAX98926_DAI_VBST_EN_MASK (1<<5) +#define MAX98926_DAI_VBST_EN_SHIFT 5 +#define MAX98926_DAI_VBST_EN_WIDTH 1 +#define MAX98926_DAI_VBST_SLOT_MASK (0x1F<<0) +#define MAX98926_DAI_VBST_SLOT_SHIFT 0 +#define MAX98926_DAI_VBST_SLOT_WIDTH 5 + +/* MAX98926_R026_DOUT_CFG_FLAG */ +#define MAX98926_DAI_FLAG_EN_MASK (1<<5) +#define MAX98926_DAI_FLAG_EN_SHIFT 5 +#define MAX98926_DAI_FLAG_EN_WIDTH 1 +#define MAX98926_DAI_FLAG_SLOT_MASK (0x1F<<0) +#define MAX98926_DAI_FLAG_SLOT_SHIFT 0 +#define MAX98926_DAI_FLAG_SLOT_WIDTH 5 + +/* MAX98926_R027_DOUT_HIZ_CFG1 */ +#define MAX98926_DAI_SLOT_HIZ_CFG1_MASK (0xFF<<0) +#define MAX98926_DAI_SLOT_HIZ_CFG1_SHIFT 0 +#define MAX98926_DAI_SLOT_HIZ_CFG1_WIDTH 8 + +/* MAX98926_R028_DOUT_HIZ_CFG2 */ +#define MAX98926_DAI_SLOT_HIZ_CFG2_MASK (0xFF<<0) +#define MAX98926_DAI_SLOT_HIZ_CFG2_SHIFT 0 +#define MAX98926_DAI_SLOT_HIZ_CFG2_WIDTH 8 + +/* MAX98926_R029_DOUT_HIZ_CFG3 */ +#define MAX98926_DAI_SLOT_HIZ_CFG3_MASK (0xFF<<0) +#define MAX98926_DAI_SLOT_HIZ_CFG3_SHIFT 0 +#define MAX98926_DAI_SLOT_HIZ_CFG3_WIDTH 8 + +/* MAX98926_R02A_DOUT_HIZ_CFG4 */ +#define MAX98926_DAI_SLOT_HIZ_CFG4_MASK (0xFF<<0) +#define MAX98926_DAI_SLOT_HIZ_CFG4_SHIFT 0 +#define MAX98926_DAI_SLOT_HIZ_CFG4_WIDTH 8 + +/* MAX98926_R02B_DOUT_DRV_STRENGTH */ +#define MAX98926_DAI_OUT_DRIVE_MASK (0x03<<0) +#define MAX98926_DAI_OUT_DRIVE_SHIFT 0 +#define MAX98926_DAI_OUT_DRIVE_WIDTH 2 + +/* MAX98926_R02C_FILTERS */ +#define MAX98926_ADC_DITHER_EN_MASK (1<<7) +#define MAX98926_ADC_DITHER_EN_SHIFT 7 +#define MAX98926_ADC_DITHER_EN_WIDTH 1 +#define MAX98926_IV_DCB_EN_MASK (1<<6) +#define MAX98926_IV_DCB_EN_SHIFT 6 +#define MAX98926_IV_DCB_EN_WIDTH 1 +#define MAX98926_DAC_DITHER_EN_MASK (1<<4) +#define MAX98926_DAC_DITHER_EN_SHIFT 4 +#define MAX98926_DAC_DITHER_EN_WIDTH 1 +#define MAX98926_DAC_FILTER_MODE_MASK (1<<3) +#define MAX98926_DAC_FILTER_MODE_SHIFT 3 +#define MAX98926_DAC_FILTER_MODE_WIDTH 1 +#define MAX98926_DAC_HPF_MASK (0x07<<0) +#define MAX98926_DAC_HPF_SHIFT 0 +#define MAX98926_DAC_HPF_WIDTH 3 +#define MAX98926_DAC_HPF_DISABLE (0 << MAX98926_DAC_HPF_SHIFT) +#define MAX98926_DAC_HPF_DC_BLOCK (1 << MAX98926_DAC_HPF_SHIFT) +#define MAX98926_DAC_HPF_EN_100 (2 << MAX98926_DAC_HPF_SHIFT) +#define MAX98926_DAC_HPF_EN_200 (3 << MAX98926_DAC_HPF_SHIFT) +#define MAX98926_DAC_HPF_EN_400 (4 << MAX98926_DAC_HPF_SHIFT) +#define MAX98926_DAC_HPF_EN_800 (5 << MAX98926_DAC_HPF_SHIFT) + +/* MAX98926_R02D_GAIN */ +#define MAX98926_DAC_IN_SEL_MASK (0x03<<5) +#define MAX98926_DAC_IN_SEL_SHIFT 5 +#define MAX98926_DAC_IN_SEL_WIDTH 2 +#define MAX98926_SPK_GAIN_MASK (0x1F<<0) +#define MAX98926_SPK_GAIN_SHIFT 0 +#define MAX98926_SPK_GAIN_WIDTH 5 + +#define MAX98926_DAC_IN_SEL_LEFT_DAI (0 << MAX98926_DAC_IN_SEL_SHIFT) +#define MAX98926_DAC_IN_SEL_RIGHT_DAI (1 << MAX98926_DAC_IN_SEL_SHIFT) +#define MAX98926_DAC_IN_SEL_SUMMED_DAI (2 << MAX98926_DAC_IN_SEL_SHIFT) +#define MAX98926_DAC_IN_SEL_DIV2_SUMMED_DAI (3 << MAX98926_DAC_IN_SEL_SHIFT) + +/* MAX98926_R02E_GAIN_RAMPING */ +#define MAX98926_SPK_RMP_EN_MASK (1<<1) +#define MAX98926_SPK_RMP_EN_SHIFT 1 +#define MAX98926_SPK_RMP_EN_WIDTH 1 +#define MAX98926_SPK_ZCD_EN_MASK (1<<0) +#define MAX98926_SPK_ZCD_EN_SHIFT 0 +#define MAX98926_SPK_ZCD_EN_WIDTH 1 + +/* MAX98926_R02F_SPK_AMP */ +#define MAX98926_SPK_MODE_MASK (1<<0) +#define MAX98926_SPK_MODE_SHIFT 0 +#define MAX98926_SPK_MODE_WIDTH 1 +#define MAX98926_INSELECT_MODE_MASK (1<<1) +#define MAX98926_INSELECT_MODE_SHIFT 1 +#define MAX98926_INSELECT_MODE_WIDTH 1 + +/* MAX98926_R030_THRESHOLD */ +#define MAX98926_ALC_EN_MASK (1<<5) +#define MAX98926_ALC_EN_SHIFT 5 +#define MAX98926_ALC_EN_WIDTH 1 +#define MAX98926_ALC_TH_MASK (0x1F<<0) +#define MAX98926_ALC_TH_SHIFT 0 +#define MAX98926_ALC_TH_WIDTH 5 + +/* MAX98926_R031_ALC_ATTACK */ +#define MAX98926_ALC_ATK_STEP_MASK (0x0F<<4) +#define MAX98926_ALC_ATK_STEP_SHIFT 4 +#define MAX98926_ALC_ATK_STEP_WIDTH 4 +#define MAX98926_ALC_ATK_RATE_MASK (0x7<<0) +#define MAX98926_ALC_ATK_RATE_SHIFT 0 +#define MAX98926_ALC_ATK_RATE_WIDTH 3 + +/* MAX98926_R032_ALC_ATTEN_RLS */ +#define MAX98926_ALC_MAX_ATTEN_MASK (0x0F<<4) +#define MAX98926_ALC_MAX_ATTEN_SHIFT 4 +#define MAX98926_ALC_MAX_ATTEN_WIDTH 4 +#define MAX98926_ALC_RLS_RATE_MASK (0x7<<0) +#define MAX98926_ALC_RLS_RATE_SHIFT 0 +#define MAX98926_ALC_RLS_RATE_WIDTH 3 + +/* MAX98926_R033_ALC_HOLD_RLS */ +#define MAX98926_ALC_RLS_TGR_MASK (1<<0) +#define MAX98926_ALC_RLS_TGR_SHIFT 0 +#define MAX98926_ALC_RLS_TGR_WIDTH 1 + +/* MAX98926_R034_ALC_CONFIGURATION */ +#define MAX98926_ALC_MUTE_EN_MASK (1<<7) +#define MAX98926_ALC_MUTE_EN_SHIFT 7 +#define MAX98926_ALC_MUTE_EN_WIDTH 1 +#define MAX98926_ALC_MUTE_DLY_MASK (0x07<<4) +#define MAX98926_ALC_MUTE_DLY_SHIFT 4 +#define MAX98926_ALC_MUTE_DLY_WIDTH 3 +#define MAX98926_ALC_RLS_DBT_MASK (0x07<<0) +#define MAX98926_ALC_RLS_DBT_SHIFT 0 +#define MAX98926_ALC_RLS_DBT_WIDTH 3 + +/* MAX98926_R035_BOOST_CONVERTER */ +#define MAX98926_BST_SYNC_MASK (1<<7) +#define MAX98926_BST_SYNC_SHIFT 7 +#define MAX98926_BST_SYNC_WIDTH 1 +#define MAX98926_BST_PHASE_MASK (0x03<<4) +#define MAX98926_BST_PHASE_SHIFT 4 +#define MAX98926_BST_PHASE_WIDTH 2 +#define MAX98926_BST_SKIP_MODE_MASK (0x03<<0) +#define MAX98926_BST_SKIP_MODE_SHIFT 0 +#define MAX98926_BST_SKIP_MODE_WIDTH 2 + +/* MAX98926_R036_BLOCK_ENABLE */ +#define MAX98926_BST_EN_MASK (1<<7) +#define MAX98926_BST_EN_SHIFT 7 +#define MAX98926_BST_EN_WIDTH 1 +#define MAX98926_WATCH_EN_MASK (1<<6) +#define MAX98926_WATCH_EN_SHIFT 6 +#define MAX98926_WATCH_EN_WIDTH 1 +#define MAX98926_CLKMON_EN_MASK (1<<5) +#define MAX98926_CLKMON_EN_SHIFT 5 +#define MAX98926_CLKMON_EN_WIDTH 1 +#define MAX98926_SPK_EN_MASK (1<<4) +#define MAX98926_SPK_EN_SHIFT 4 +#define MAX98926_SPK_EN_WIDTH 1 +#define MAX98926_ADC_VBST_EN_MASK (1<<3) +#define MAX98926_ADC_VBST_EN_SHIFT 3 +#define MAX98926_ADC_VBST_EN_WIDTH 1 +#define MAX98926_ADC_VBAT_EN_MASK (1<<2) +#define MAX98926_ADC_VBAT_EN_SHIFT 2 +#define MAX98926_ADC_VBAT_EN_WIDTH 1 +#define MAX98926_ADC_IMON_EN_MASK (1<<1) +#define MAX98926_ADC_IMON_EN_SHIFT 1 +#define MAX98926_ADC_IMON_EN_WIDTH 1 +#define MAX98926_ADC_VMON_EN_MASK (1<<0) +#define MAX98926_ADC_VMON_EN_SHIFT 0 +#define MAX98926_ADC_VMON_EN_WIDTH 1 + +/* MAX98926_R037_CONFIGURATION */ +#define MAX98926_BST_VOUT_MASK (0x0F<<4) +#define MAX98926_BST_VOUT_SHIFT 4 +#define MAX98926_BST_VOUT_WIDTH 4 +#define MAX98926_THERMWARN_LEVEL_MASK (0x03<<2) +#define MAX98926_THERMWARN_LEVEL_SHIFT 2 +#define MAX98926_THERMWARN_LEVEL_WIDTH 2 +#define MAX98926_WATCH_TIME_MASK (0x03<<0) +#define MAX98926_WATCH_TIME_SHIFT 0 +#define MAX98926_WATCH_TIME_WIDTH 2 + +/* MAX98926_R038_GLOBAL_ENABLE */ +#define MAX98926_EN_MASK (1<<7) +#define MAX98926_EN_SHIFT 7 +#define MAX98926_EN_WIDTH 1 + +/* MAX98926_R03A_BOOST_LIMITER */ +#define MAX98926_BST_ILIM_MASK (0xF<<4) +#define MAX98926_BST_ILIM_SHIFT 4 +#define MAX98926_BST_ILIM_WIDTH 4 + +/* MAX98926_R0FF_VERSION */ +#define MAX98926_REV_ID_MASK (0xFF<<0) +#define MAX98926_REV_ID_SHIFT 0 +#define MAX98926_REV_ID_WIDTH 8 + +struct max98926_priv { + struct regmap *regmap; + struct snd_soc_codec *codec; + unsigned int sysclk; + unsigned int v_slot; + unsigned int i_slot; + unsigned int ch_size; + unsigned int interleave_mode; +}; +#endif -- cgit v1.2.3 From 99081589c5ad590e9828ae9febc384612f241164 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 28 Jan 2016 16:43:36 +0800 Subject: ASoC: rt5616: trivial: fix the typo This patch try to fix the trivial typo. Run "scripts/checkpatch.pl -f --subjective xxx" The enable more subjective tests. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 376 +++++++++++++++++++++++----------------------- 1 file changed, 191 insertions(+), 185 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 1c10d8ed39d2..d4bdf9f6f0af 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -53,6 +53,7 @@ static const struct reg_sequence init_list[] = { {RT5616_PR_BASE + 0x21, 0x4040}, {RT5616_PR_BASE + 0x23, 0x0004}, }; + #define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list) static const struct reg_default rt5616_reg[] = { @@ -162,9 +163,8 @@ static bool rt5616_volatile_register(struct device *dev, unsigned int reg) for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) { if (reg >= rt5616_ranges[i].range_min && - reg <= rt5616_ranges[i].range_max) { + reg <= rt5616_ranges[i].range_max) return true; - } } switch (reg) { @@ -190,9 +190,8 @@ static bool rt5616_readable_register(struct device *dev, unsigned int reg) for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) { if (reg >= rt5616_ranges[i].range_min && - reg <= rt5616_ranges[i].range_max) { + reg <= rt5616_ranges[i].range_max) return true; - } } switch (reg) { @@ -307,45 +306,45 @@ static unsigned int bst_tlv[] = { static const struct snd_kcontrol_new rt5616_snd_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL, - RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL, - RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), /* OUTPUT Control */ SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1, - RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1, - RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1), + RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1), SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1, - RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL, - RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, - 175, 0, dac_vol_tlv), + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, + 175, 0, dac_vol_tlv), /* IN1/IN2 Control */ SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2, - RT5616_BST_SFT1, 8, 0, bst_tlv), + RT5616_BST_SFT1, 8, 0, bst_tlv), SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2, - RT5616_BST_SFT2, 8, 0, bst_tlv), + RT5616_BST_SFT2, 8, 0, bst_tlv), /* INL/INR Volume Control */ SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL, - RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT, - 31, 1, in_vol_tlv), + RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT, + 31, 1, in_vol_tlv), /* ADC Digital Volume Control */ SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL, - RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL, - RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, - 127, 0, adc_vol_tlv), + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, + 127, 0, adc_vol_tlv), /* ADC Boost Volume Control */ SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL, - RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT, - 3, 0, adc_bst_tlv), + RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), }; static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) + struct snd_soc_dapm_widget *sink) { unsigned int val; @@ -462,20 +461,20 @@ static const struct snd_kcontrol_new rt5616_lout_mix[] = { }; static int rt5616_adc_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL, - RT5616_L_MUTE | RT5616_R_MUTE, 0); + RT5616_L_MUTE | RT5616_R_MUTE, 0); break; case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL, - RT5616_L_MUTE | RT5616_R_MUTE, - RT5616_L_MUTE | RT5616_R_MUTE); + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); break; default: @@ -486,7 +485,7 @@ static int rt5616_adc_event(struct snd_soc_dapm_widget *w, } static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); @@ -494,54 +493,55 @@ static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* depop parameters */ snd_soc_update_bits(codec, RT5616_DEPOP_M2, - RT5616_DEPOP_MASK, RT5616_DEPOP_MAN); + RT5616_DEPOP_MASK, RT5616_DEPOP_MAN); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_HP_CP_MASK | RT5616_HP_SG_MASK | - RT5616_HP_CB_MASK, RT5616_HP_CP_PU | - RT5616_HP_SG_DIS | RT5616_HP_CB_PU); + RT5616_HP_CP_MASK | RT5616_HP_SG_MASK | + RT5616_HP_CB_MASK, RT5616_HP_CP_PU | + RT5616_HP_SG_DIS | RT5616_HP_CB_PU); snd_soc_write(codec, RT5616_PR_BASE + - RT5616_HP_DCC_INT1, 0x9f00); + RT5616_HP_DCC_INT1, 0x9f00); /* headphone amp power on */ snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_FV1 | RT5616_PWR_FV2, 0); + RT5616_PWR_FV1 | RT5616_PWR_FV2, 0); snd_soc_update_bits(codec, RT5616_PWR_VOL, - RT5616_PWR_HV_L | RT5616_PWR_HV_R, - RT5616_PWR_HV_L | RT5616_PWR_HV_R); + RT5616_PWR_HV_L | RT5616_PWR_HV_R, + RT5616_PWR_HV_L | RT5616_PWR_HV_R); snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_HP_L | RT5616_PWR_HP_R | - RT5616_PWR_HA, RT5616_PWR_HP_L | - RT5616_PWR_HP_R | RT5616_PWR_HA); + RT5616_PWR_HP_L | RT5616_PWR_HP_R | + RT5616_PWR_HA, RT5616_PWR_HP_L | + RT5616_PWR_HP_R | RT5616_PWR_HA); msleep(50); snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_FV1 | RT5616_PWR_FV2, - RT5616_PWR_FV1 | RT5616_PWR_FV2); + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); snd_soc_update_bits(codec, RT5616_CHARGE_PUMP, - RT5616_PM_HP_MASK, RT5616_PM_HP_HV); + RT5616_PM_HP_MASK, RT5616_PM_HP_HV); snd_soc_update_bits(codec, RT5616_PR_BASE + - RT5616_CHOP_DAC_ADC, 0x0200, 0x0200); + RT5616_CHOP_DAC_ADC, 0x0200, 0x0200); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_HP_CO_MASK | RT5616_HP_SG_MASK, - RT5616_HP_CO_EN | RT5616_HP_SG_EN); + RT5616_HP_CO_MASK | RT5616_HP_SG_MASK, + RT5616_HP_CO_EN | RT5616_HP_SG_EN); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_update_bits(codec, RT5616_PR_BASE + - RT5616_CHOP_DAC_ADC, 0x0200, 0x0); + RT5616_CHOP_DAC_ADC, 0x0200, 0x0); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | - RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | - RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); + RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | + RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); /* headphone amp power down */ snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_SMT_TRIG_MASK | RT5616_HP_CD_PD_MASK | - RT5616_HP_CO_MASK | RT5616_HP_CP_MASK | - RT5616_HP_SG_MASK | RT5616_HP_CB_MASK, - RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN | - RT5616_HP_CO_DIS | RT5616_HP_CP_PD | - RT5616_HP_SG_EN | RT5616_HP_CB_PD); + RT5616_SMT_TRIG_MASK | + RT5616_HP_CD_PD_MASK | RT5616_HP_CO_MASK | + RT5616_HP_CP_MASK | RT5616_HP_SG_MASK | + RT5616_HP_CB_MASK, + RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN | + RT5616_HP_CO_DIS | RT5616_HP_CP_PD | + RT5616_HP_SG_EN | RT5616_HP_CB_PD); snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_HP_L | RT5616_PWR_HP_R | - RT5616_PWR_HA, 0); + RT5616_PWR_HP_L | RT5616_PWR_HP_R | + RT5616_PWR_HA, 0); break; default: return 0; @@ -551,7 +551,7 @@ static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w, } static int rt5616_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); @@ -559,57 +559,57 @@ static int rt5616_hp_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* headphone unmute sequence */ snd_soc_update_bits(codec, RT5616_DEPOP_M3, - RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | - RT5616_CP_FQ3_MASK, - (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT) | - (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) | - (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT)); + RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | + RT5616_CP_FQ3_MASK, + RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT | + RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT | + RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT); snd_soc_write(codec, RT5616_PR_BASE + - RT5616_MAMP_INT_REG2, 0xfc00); + RT5616_MAMP_INT_REG2, 0xfc00); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN); + RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_RSTN_MASK, RT5616_RSTN_EN); + RT5616_RSTN_MASK, RT5616_RSTN_EN); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK | - RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS | - RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); + RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS | + RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); snd_soc_update_bits(codec, RT5616_HP_VOL, - RT5616_L_MUTE | RT5616_R_MUTE, 0); + RT5616_L_MUTE | RT5616_R_MUTE, 0); msleep(100); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | - RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | - RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); + RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | + RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); msleep(20); snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET, - RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN); + RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN); break; case SND_SOC_DAPM_PRE_PMD: /* headphone mute sequence */ snd_soc_update_bits(codec, RT5616_DEPOP_M3, - RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | - RT5616_CP_FQ3_MASK, - (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT) | - (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) | - (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT)); + RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | + RT5616_CP_FQ3_MASK, + RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT | + RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT | + RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT); snd_soc_write(codec, RT5616_PR_BASE + - RT5616_MAMP_INT_REG2, 0xfc00); + RT5616_MAMP_INT_REG2, 0xfc00); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_HP_SG_MASK, RT5616_HP_SG_EN); + RT5616_HP_SG_MASK, RT5616_HP_SG_EN); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_RSTP_MASK, RT5616_RSTP_EN); + RT5616_RSTP_MASK, RT5616_RSTP_EN); snd_soc_update_bits(codec, RT5616_DEPOP_M1, - RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK | - RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS | - RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); + RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS | + RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET, - RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS); + RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS); msleep(90); snd_soc_update_bits(codec, RT5616_HP_VOL, - RT5616_L_MUTE | RT5616_R_MUTE, - RT5616_L_MUTE | RT5616_R_MUTE); + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); msleep(30); break; @@ -621,24 +621,24 @@ static int rt5616_hp_event(struct snd_soc_dapm_widget *w, } static int rt5616_lout_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_LM, RT5616_PWR_LM); + RT5616_PWR_LM, RT5616_PWR_LM); snd_soc_update_bits(codec, RT5616_LOUT_CTRL1, - RT5616_L_MUTE | RT5616_R_MUTE, 0); + RT5616_L_MUTE | RT5616_R_MUTE, 0); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_update_bits(codec, RT5616_LOUT_CTRL1, - RT5616_L_MUTE | RT5616_R_MUTE, - RT5616_L_MUTE | RT5616_R_MUTE); + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_LM, 0); + RT5616_PWR_LM, 0); break; default: @@ -649,19 +649,19 @@ static int rt5616_lout_event(struct snd_soc_dapm_widget *w, } static int rt5616_bst1_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, RT5616_PWR_ANLG2, - RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2); + RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_update_bits(codec, RT5616_PWR_ANLG2, - RT5616_PWR_BST1_OP2, 0); + RT5616_PWR_BST1_OP2, 0); break; default: @@ -672,19 +672,19 @@ static int rt5616_bst1_event(struct snd_soc_dapm_widget *w, } static int rt5616_bst2_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, RT5616_PWR_ANLG2, - RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2); + RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_update_bits(codec, RT5616_PWR_ANLG2, - RT5616_PWR_BST2_OP2, 0); + RT5616_PWR_BST2_OP2, 0); break; default: @@ -696,13 +696,13 @@ static int rt5616_bst2_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2, - RT5616_PWR_PLL_BIT, 0, NULL, 0), + RT5616_PWR_PLL_BIT, 0, NULL, 0), /* Input Side */ /* micbias */ SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1, - RT5616_PWR_LDO_BIT, 0, NULL, 0), + RT5616_PWR_LDO_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2, - RT5616_PWR_MB1_BIT, 0, NULL, 0), + RT5616_PWR_MB1_BIT, 0, NULL, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("MIC1"), @@ -714,45 +714,47 @@ static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = { /* Boost */ SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2, - RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2, - RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), /* Input Volume */ SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL, - RT5616_PWR_IN1_L_BIT, 0, NULL, 0), + RT5616_PWR_IN1_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL, - RT5616_PWR_IN1_R_BIT, 0, NULL, 0), + RT5616_PWR_IN1_R_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL, - RT5616_PWR_IN2_L_BIT, 0, NULL, 0), + RT5616_PWR_IN2_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL, - RT5616_PWR_IN2_R_BIT, 0, NULL, 0), + RT5616_PWR_IN2_R_BIT, 0, NULL, 0), /* REC Mixer */ SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0, - rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)), + rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)), SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0, - rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)), + rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)), /* ADCs */ SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1, - RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1, - RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), /* ADC Mixer */ SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2, - RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0), + RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0), SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, - rt5616_sto1_adc_l_mix, ARRAY_SIZE(rt5616_sto1_adc_l_mix)), + rt5616_sto1_adc_l_mix, + ARRAY_SIZE(rt5616_sto1_adc_l_mix)), SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, - rt5616_sto1_adc_r_mix, ARRAY_SIZE(rt5616_sto1_adc_r_mix)), + rt5616_sto1_adc_r_mix, + ARRAY_SIZE(rt5616_sto1_adc_r_mix)), /* Digital Interface */ SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1, - RT5616_PWR_I2S1_BIT, 0, NULL, 0), + RT5616_PWR_I2S1_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -770,68 +772,70 @@ static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = { /* Output Side */ /* DAC mixer before sound effect */ SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, - rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)), + rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)), SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, - rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)), + rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)), SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2, - RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0), + RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0), /* DAC Mixer */ SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, - rt5616_sto_dac_l_mix, ARRAY_SIZE(rt5616_sto_dac_l_mix)), + rt5616_sto_dac_l_mix, + ARRAY_SIZE(rt5616_sto_dac_l_mix)), SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, - rt5616_sto_dac_r_mix, ARRAY_SIZE(rt5616_sto_dac_r_mix)), + rt5616_sto_dac_r_mix, + ARRAY_SIZE(rt5616_sto_dac_r_mix)), /* DACs */ SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1, - RT5616_PWR_DAC_L1_BIT, 0), + RT5616_PWR_DAC_L1_BIT, 0), SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1, - RT5616_PWR_DAC_R1_BIT, 0), + RT5616_PWR_DAC_R1_BIT, 0), /* OUT Mixer */ SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT, - 0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)), + 0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)), SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT, - 0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)), + 0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)), /* Output Volume */ SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL, - RT5616_PWR_OV_L_BIT, 0, NULL, 0), + RT5616_PWR_OV_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL, - RT5616_PWR_OV_R_BIT, 0, NULL, 0), + RT5616_PWR_OV_R_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL, - RT5616_PWR_HV_L_BIT, 0, NULL, 0), + RT5616_PWR_HV_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL, - RT5616_PWR_HV_R_BIT, 0, NULL, 0), + RT5616_PWR_HV_R_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, - 0, 0, NULL, 0), + 0, 0, NULL, 0), SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, - 0, 0, NULL, 0), + 0, 0, NULL, 0), SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, - 0, 0, NULL, 0), + 0, 0, NULL, 0), SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL, - RT5616_PWR_IN1_L_BIT, 0, NULL, 0), + RT5616_PWR_IN1_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL, - RT5616_PWR_IN1_R_BIT, 0, NULL, 0), + RT5616_PWR_IN1_R_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL, - RT5616_PWR_IN2_L_BIT, 0, NULL, 0), + RT5616_PWR_IN2_L_BIT, 0, NULL, 0), SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL, - RT5616_PWR_IN2_R_BIT, 0, NULL, 0), + RT5616_PWR_IN2_R_BIT, 0, NULL, 0), /* HPO/LOUT/Mono Mixer */ SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, - rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)), + rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)), SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, - rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)), + rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)), SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, - rt5616_hp_event, SND_SOC_DAPM_PRE_PMD | - SND_SOC_DAPM_POST_PMU), + rt5616_hp_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, - rt5616_lout_event, SND_SOC_DAPM_PRE_PMD | - SND_SOC_DAPM_POST_PMU), + rt5616_lout_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0, - rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), /* Output Lines */ SND_SOC_DAPM_OUTPUT("HPOL"), @@ -950,7 +954,8 @@ static const struct snd_soc_dapm_route rt5616_dapm_routes[] = { }; static int rt5616_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; @@ -977,7 +982,7 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", rt5616->bclk[dai->id], rt5616->lrck[dai->id]); dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", - bclk_ms, pre_div, dai->id); + bclk_ms, pre_div, dai->id); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -998,10 +1003,9 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream, mask_clk = RT5616_I2S_PD1_MASK; val_clk = pre_div << RT5616_I2S_PD1_SFT; snd_soc_update_bits(codec, RT5616_I2S1_SDP, - RT5616_I2S_DL_MASK, val_len); + RT5616_I2S_DL_MASK, val_len); snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk); - return 0; } @@ -1050,15 +1054,14 @@ static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } snd_soc_update_bits(codec, RT5616_I2S1_SDP, - RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK | - RT5616_I2S_DF_MASK, reg_val); - + RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK | + RT5616_I2S_DF_MASK, reg_val); return 0; } static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) + int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = dai->codec; struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); @@ -1078,8 +1081,9 @@ static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai, dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; } + snd_soc_update_bits(codec, RT5616_GLB_CLK, - RT5616_SCLK_SRC_MASK, reg_val); + RT5616_SCLK_SRC_MASK, reg_val); rt5616->sysclk = freq; rt5616->sysclk_src = clk_id; @@ -1089,7 +1093,7 @@ static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai, } static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, - unsigned int freq_in, unsigned int freq_out) + unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = dai->codec; struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); @@ -1106,19 +1110,22 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, rt5616->pll_in = 0; rt5616->pll_out = 0; snd_soc_update_bits(codec, RT5616_GLB_CLK, - RT5616_SCLK_SRC_MASK, RT5616_SCLK_SRC_MCLK); + RT5616_SCLK_SRC_MASK, + RT5616_SCLK_SRC_MCLK); return 0; } switch (source) { case RT5616_PLL1_S_MCLK: snd_soc_update_bits(codec, RT5616_GLB_CLK, - RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_MCLK); + RT5616_PLL1_SRC_MASK, + RT5616_PLL1_SRC_MCLK); break; case RT5616_PLL1_S_BCLK1: case RT5616_PLL1_S_BCLK2: snd_soc_update_bits(codec, RT5616_GLB_CLK, - RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_BCLK1); + RT5616_PLL1_SRC_MASK, + RT5616_PLL1_SRC_BCLK1); break; default: dev_err(codec->dev, "Unknown PLL source %d\n", source); @@ -1136,10 +1143,11 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_code.n_code, pll_code.k_code); snd_soc_write(codec, RT5616_PLL_CTRL1, - pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code); + pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code); snd_soc_write(codec, RT5616_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5616_PLL_M_SFT | - pll_code.m_bp << RT5616_PLL_M_BP_SFT); + (pll_code.m_bp ? 0 : pll_code.m_code) << + RT5616_PLL_M_SFT | + pll_code.m_bp << RT5616_PLL_M_BP_SFT); rt5616->pll_in = freq_in; rt5616->pll_out = freq_out; @@ -1149,22 +1157,23 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, } static int rt5616_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) + enum snd_soc_bias_level level) { switch (level) { case SND_SOC_BIAS_STANDBY: if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_VREF1 | RT5616_PWR_MB | - RT5616_PWR_BG | RT5616_PWR_VREF2, - RT5616_PWR_VREF1 | RT5616_PWR_MB | - RT5616_PWR_BG | RT5616_PWR_VREF2); + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2); mdelay(10); snd_soc_update_bits(codec, RT5616_PWR_ANLG1, - RT5616_PWR_FV1 | RT5616_PWR_FV2, - RT5616_PWR_FV1 | RT5616_PWR_FV2); + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); snd_soc_update_bits(codec, RT5616_D_MISC, - RT5616_D_GATE_EN, RT5616_D_GATE_EN); + RT5616_D_GATE_EN, + RT5616_D_GATE_EN); } break; @@ -1222,7 +1231,6 @@ static int rt5616_resume(struct snd_soc_codec *codec) #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) - struct snd_soc_dai_ops rt5616_aif_dai_ops = { .hw_params = rt5616_hw_params, .set_fmt = rt5616_set_dai_fmt, @@ -1296,15 +1304,15 @@ MODULE_DEVICE_TABLE(of, rt5616_of_match); #endif static int rt5616_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct rt5616_priv *rt5616; unsigned int val; int ret; rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv), - GFP_KERNEL); - if (rt5616 == NULL) + GFP_KERNEL); + if (!rt5616) return -ENOMEM; i2c_set_clientdata(i2c, rt5616); @@ -1326,14 +1334,14 @@ static int rt5616_i2c_probe(struct i2c_client *i2c, } regmap_write(rt5616->regmap, RT5616_RESET, 0); regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, - RT5616_PWR_VREF1 | RT5616_PWR_MB | - RT5616_PWR_BG | RT5616_PWR_VREF2, - RT5616_PWR_VREF1 | RT5616_PWR_MB | - RT5616_PWR_BG | RT5616_PWR_VREF2); + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2); mdelay(10); regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, - RT5616_PWR_FV1 | RT5616_PWR_FV2, - RT5616_PWR_FV1 | RT5616_PWR_FV2); + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); ret = regmap_register_patch(rt5616->regmap, init_list, ARRAY_SIZE(init_list)); @@ -1341,11 +1349,10 @@ static int rt5616_i2c_probe(struct i2c_client *i2c, dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, - RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V); + RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V); return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616, - rt5616_dai, ARRAY_SIZE(rt5616_dai)); - + rt5616_dai, ARRAY_SIZE(rt5616_dai)); } static int rt5616_i2c_remove(struct i2c_client *i2c) @@ -1361,7 +1368,6 @@ static void rt5616_i2c_shutdown(struct i2c_client *client) regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8); regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8); - } static struct i2c_driver rt5616_i2c_driver = { -- cgit v1.2.3 From 76d3204eaa9364a662f0fe0f075dfe61e6bd14fe Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 28 Jan 2016 16:43:37 +0800 Subject: ASoC: rt5616: add the mclk for the codec driver This patch adds the code to enable the clock to the CODEC driver if it needs the clock enabled. In some case, We need to claim the clock which is driving the codec so that when we enable clock gating, we continue to clock the codec when needed. if mclk provided, to enable and disable the clock source. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index d4bdf9f6f0af..fdca63694b40 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,7 @@ struct rt5616_priv { struct snd_soc_codec *codec; struct delayed_work patch_work; struct regmap *regmap; + struct clk *mclk; int sysclk; int sysclk_src; @@ -1159,7 +1161,34 @@ static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, static int rt5616_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + int ret; + switch (level) { + + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* + * SND_SOC_BIAS_PREPARE is called while preparing for a + * transition to ON or away from ON. If current bias_level + * is SND_SOC_BIAS_ON, then it is preparing for a transition + * away from ON. Disable the clock in that case, otherwise + * enable it. + */ + if (IS_ERR(rt5616->mclk)) + break; + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { + clk_disable_unprepare(rt5616->mclk); + } else { + ret = clk_prepare_enable(rt5616->mclk); + if (ret) + return ret; + } + break; + case SND_SOC_BIAS_STANDBY: if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { snd_soc_update_bits(codec, RT5616_PWR_ANLG1, @@ -1198,6 +1227,11 @@ static int rt5616_probe(struct snd_soc_codec *codec) { struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + /* Check if MCLK provided */ + rt5616->mclk = devm_clk_get(codec->dev, "mclk"); + if (PTR_ERR(rt5616->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + rt5616->codec = codec; return 0; -- cgit v1.2.3 From f1188b898ec5aa2e94da8fb998648a2738f4fb3b Mon Sep 17 00:00:00 2001 From: "Damien.Horsley" Date: Thu, 28 Jan 2016 16:54:20 +0000 Subject: ASoC: pcm3168a: Call clk_set_rate in pcm3168a_set_dai_sysclk Call clk_set_rate in pcm3168a_set_dai_sysclk Signed-off-by: Damien.Horsley Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 44b268aa4dd8..0c7248ab6a37 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -299,10 +299,15 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec); + int ret; if (freq > PCM1368A_MAX_SYSCLK) return -EINVAL; + ret = clk_set_rate(pcm3168a->scki, freq); + if (ret) + return ret; + pcm3168a->sysclk = freq; return 0; -- cgit v1.2.3 From 0f9aa09d669b29ae536d51631bf035ad44ae0551 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Jan 2016 17:52:57 +0000 Subject: ASoC: wm5110: Fix up snd_soc_register_platform error path Whilst there is nothing wrong with the error path here it looks a little bit odd, this patches makes the code a little more idiomatic. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 6088d30962a9..83760b72aa03 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2366,7 +2366,7 @@ static int wm5110_probe(struct platform_device *pdev) ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - goto error; + return ret; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, @@ -2376,7 +2376,6 @@ static int wm5110_probe(struct platform_device *pdev) snd_soc_unregister_platform(&pdev->dev); } -error: return ret; } -- cgit v1.2.3 From e6d00f3403c439b8d1e6f9f09d5ae3048aa726e4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Jan 2016 17:52:58 +0000 Subject: ASoC: wm_adsp: Use more generic naming for regions and caps definitions The region definition will be shared by most firmwares so give this a more generic name and whilst we are there improve the naming of the voice control capabilities array as well. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 33806d487b8a..0392c58dfc5d 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -328,7 +328,7 @@ struct wm_adsp_buffer_region_def { unsigned int size_offset; }; -static struct wm_adsp_buffer_region_def ez2control_regions[] = { +static struct wm_adsp_buffer_region_def default_regions[] = { { .mem_type = WMFW_ADSP2_XM, .base_offset = HOST_BUFFER_FIELD(X_buf_base), @@ -353,7 +353,7 @@ struct wm_adsp_fw_caps { struct wm_adsp_buffer_region_def *region_defs; }; -static const struct wm_adsp_fw_caps ez2control_caps[] = { +static const struct wm_adsp_fw_caps ctrl_caps[] = { { .id = SND_AUDIOCODEC_BESPOKE, .desc = { @@ -362,8 +362,8 @@ static const struct wm_adsp_fw_caps ez2control_caps[] = { .num_sample_rates = 1, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .num_regions = ARRAY_SIZE(ez2control_regions), - .region_defs = ez2control_regions, + .num_regions = ARRAY_SIZE(default_regions), + .region_defs = default_regions, }, }; @@ -382,8 +382,8 @@ static const struct { [WM_ADSP_FW_CTRL] = { .file = "ctrl", .compr_direction = SND_COMPRESS_CAPTURE, - .num_caps = ARRAY_SIZE(ez2control_caps), - .caps = ez2control_caps, + .num_caps = ARRAY_SIZE(ctrl_caps), + .caps = ctrl_caps, }, [WM_ADSP_FW_ASR] = { .file = "asr" }, [WM_ADSP_FW_TRACE] = { .file = "trace" }, -- cgit v1.2.3 From 7ce4283ca405d459c186960ed39d41ec0e6fb2bf Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Jan 2016 17:52:59 +0000 Subject: ASoC: wm_adsp: Add debug audio trace firmware The audio trace firmware allows the capture of arbitrary streams of audio from the DSP and commonly used for debugging other firmwares. This patch adds support for this firwmare into the ADSP driver. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0392c58dfc5d..a81f568a9660 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -367,6 +367,24 @@ static const struct wm_adsp_fw_caps ctrl_caps[] = { }, }; +static const struct wm_adsp_fw_caps trace_caps[] = { + { + .id = SND_AUDIOCODEC_BESPOKE, + .desc = { + .max_ch = 8, + .sample_rates = { + 4000, 8000, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, + 96000, 176400, 192000 + }, + .num_sample_rates = 15, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .num_regions = ARRAY_SIZE(default_regions), + .region_defs = default_regions, + }, +}; + static const struct { const char *file; int compr_direction; @@ -386,7 +404,12 @@ static const struct { .caps = ctrl_caps, }, [WM_ADSP_FW_ASR] = { .file = "asr" }, - [WM_ADSP_FW_TRACE] = { .file = "trace" }, + [WM_ADSP_FW_TRACE] = { + .file = "trace", + .compr_direction = SND_COMPRESS_CAPTURE, + .num_caps = ARRAY_SIZE(trace_caps), + .caps = trace_caps, + }, [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, [WM_ADSP_FW_MISC] = { .file = "misc" }, }; -- cgit v1.2.3 From d82d767f0e61da5f1f872d40358904eb316af264 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Jan 2016 17:53:02 +0000 Subject: ASoC: wm_adsp: Move setting of DSP speed into CODEC specific code The ADSP code should be agnostic of which CODEC it runs upon, currently there is only one remaining part of the implementation that doesn't follow this. When the DSP is booted on ADSP2 we read ARIZONA_SYSTEM_CLOCK_1 and use that to set the initial speed for the DSP clock. This patch factors that out into CODEC specific code, leaving the ADSP code entirely CODEC agnostic. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 23 +++++++++++++++++++++-- sound/soc/codecs/wm5102.c | 6 +++--- sound/soc/codecs/wm5110.c | 27 +++++++++++++++++++++++---- sound/soc/codecs/wm_adsp.c | 40 +++++++++++++++------------------------- sound/soc/codecs/wm_adsp.h | 8 +++----- 5 files changed, 65 insertions(+), 39 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index dc5ae7f7a1bd..9dc77a4da35d 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -57,6 +57,25 @@ static const struct wm_adsp_region *cs47l24_dsp_regions[] = { cs47l24_dsp3_regions, }; +static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + unsigned int v; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v); + if (ret != 0) { + dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret); + return ret; + } + + v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; + + return wm_adsp2_early_event(w, kcontrol, event, v); +} + static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); @@ -405,8 +424,8 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, NULL, 0), -WM_ADSP2("DSP2", 1), -WM_ADSP2("DSP3", 2), +WM_ADSP2("DSP2", 1, cs47l24_adsp_power_ev), +WM_ADSP2("DSP3", 2, cs47l24_adsp_power_ev), SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 64637d1cf4e5..7c0860df3204 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -619,7 +619,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - unsigned int v; + unsigned int v = 0; int ret; switch (event) { @@ -654,7 +654,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w, break; } - return wm_adsp2_early_event(w, kcontrol, event); + return wm_adsp2_early_event(w, kcontrol, event, v); } static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, @@ -1408,7 +1408,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), -WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev), +WM_ADSP2("DSP1", 0, wm5102_adsp_power_ev), SND_SOC_DAPM_OUTPUT("HPOUT1L"), SND_SOC_DAPM_OUTPUT("HPOUT1R"), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 83760b72aa03..b47bc4418e30 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -191,6 +191,25 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + unsigned int v; + int ret; + + ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v); + if (ret != 0) { + dev_err(codec->dev, "Failed to read SYSCLK state: %d\n", ret); + return ret; + } + + v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; + + return wm_adsp2_early_event(w, kcontrol, event, v); +} + static const struct reg_sequence wm5110_no_dre_left_enable[] = { { 0x3024, 0xE410 }, { 0x3025, 0x0056 }, @@ -1179,10 +1198,10 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, NULL, 0), -WM_ADSP2("DSP1", 0), -WM_ADSP2("DSP2", 1), -WM_ADSP2("DSP3", 2), -WM_ADSP2("DSP4", 3), +WM_ADSP2("DSP1", 0, wm5110_adsp_power_ev), +WM_ADSP2("DSP2", 1, wm5110_adsp_power_ev), +WM_ADSP2("DSP3", 2, wm5110_adsp_power_ev), +WM_ADSP2("DSP4", 3, wm5110_adsp_power_ev), SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a81f568a9660..76ab52d2c670 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -32,9 +32,6 @@ #include #include -#include - -#include "arizona.h" #include "wm_adsp.h" #define adsp_crit(_dsp, fmt, ...) \ @@ -2146,30 +2143,9 @@ static void wm_adsp2_boot_work(struct work_struct *work) struct wm_adsp, boot_work); int ret; - unsigned int val; mutex_lock(&dsp->pwr_lock); - /* - * For simplicity set the DSP clock rate to be the - * SYSCLK rate rather than making it configurable. - */ - ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); - if (ret != 0) { - adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); - goto err_mutex; - } - val = (val & ARIZONA_SYSCLK_FREQ_MASK) - >> ARIZONA_SYSCLK_FREQ_SHIFT; - - ret = regmap_update_bits_async(dsp->regmap, - dsp->base + ADSP2_CLOCKING, - ADSP2_CLK_SEL_MASK, val); - if (ret != 0) { - adsp_err(dsp, "Failed to set clock rate: %d\n", ret); - goto err_mutex; - } - ret = wm_adsp2_ena(dsp); if (ret != 0) goto err_mutex; @@ -2209,8 +2185,21 @@ err_mutex: mutex_unlock(&dsp->pwr_lock); } +static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq) +{ + int ret; + + ret = regmap_update_bits_async(dsp->regmap, + dsp->base + ADSP2_CLOCKING, + ADSP2_CLK_SEL_MASK, + freq << ADSP2_CLK_SEL_SHIFT); + if (ret != 0) + adsp_err(dsp, "Failed to set clock rate: %d\n", ret); +} + int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event, + unsigned int freq) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); @@ -2220,6 +2209,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + wm_adsp2_set_dspclk(dsp, freq); queue_work(system_unbound_wq, &dsp->boot_work); break; default: diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 1a928ec54741..b61cb57e600f 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -80,7 +80,7 @@ struct wm_adsp { SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) -#define WM_ADSP2_E(wname, num, event_fn) \ +#define WM_ADSP2(wname, num, event_fn) \ { .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \ @@ -88,9 +88,6 @@ struct wm_adsp { .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } -#define WM_ADSP2(wname, num) \ - WM_ADSP2_E(wname, num, wm_adsp2_early_event) - extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; int wm_adsp1_init(struct wm_adsp *dsp); @@ -100,7 +97,8 @@ int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); + struct snd_kcontrol *kcontrol, int event, + unsigned int freq); int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -- cgit v1.2.3 From 1b347b6891335a30131899dd16ec6ca843c578f0 Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Fri, 22 Jan 2016 13:39:53 +0100 Subject: ASoC: pcm179x: Split into core and SPI parts The pcm179x family supports both SPI and I2C for configuration. This patch splits the driver into core and SPI parts, in preparation for I2C support. Signed-off-by: Jacob Siverskog Reviewed-by: Johan Hovold Acked-by: Michael Trimarchi Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 11 +++++-- sound/soc/codecs/Makefile | 2 ++ sound/soc/codecs/pcm179x-spi.c | 72 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/pcm179x.c | 52 +++++++----------------------- sound/soc/codecs/pcm179x.h | 5 +++ 5 files changed, 99 insertions(+), 43 deletions(-) create mode 100644 sound/soc/codecs/pcm179x-spi.c (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50693c867e71..ae720f1b15e8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -87,7 +87,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ML26124 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_PCM1681 if I2C - select SND_SOC_PCM179X if SPI_MASTER + select SND_SOC_PCM179X_SPI if SPI_MASTER select SND_SOC_PCM3008 select SND_SOC_PCM3168A_I2C if I2C select SND_SOC_PCM3168A_SPI if SPI_MASTER @@ -527,8 +527,15 @@ config SND_SOC_PCM1681 depends on I2C config SND_SOC_PCM179X - tristate "Texas Instruments PCM179X CODEC" + tristate + +config SND_SOC_PCM179X_SPI + tristate "Texas Instruments PCM179X CODEC (SPI)" depends on SPI_MASTER + select SND_SOC_PCM179X + help + Enable support for Texas Instruments PCM179x CODEC. + Select this if your PCM179x is connected via an SPI bus. config SND_SOC_PCM3008 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d44f7d347183..56e94d88693f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -81,6 +81,7 @@ snd-soc-ml26124-objs := ml26124.o snd-soc-nau8825-objs := nau8825.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm179x-codec-objs := pcm179x.o +snd-soc-pcm179x-spi-objs := pcm179x-spi.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm3168a-objs := pcm3168a.o snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o @@ -285,6 +286,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o +obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o diff --git a/sound/soc/codecs/pcm179x-spi.c b/sound/soc/codecs/pcm179x-spi.c new file mode 100644 index 000000000000..da924d444083 --- /dev/null +++ b/sound/soc/codecs/pcm179x-spi.c @@ -0,0 +1,72 @@ +/* + * PCM179X ASoC SPI driver + * + * Copyright (c) Amarula Solutions B.V. 2013 + * + * Michael Trimarchi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pcm179x.h" + +static int pcm179x_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_spi(spi, &pcm179x_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&spi->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + return pcm179x_common_init(&spi->dev, regmap); +} + +static int pcm179x_spi_remove(struct spi_device *spi) +{ + return pcm179x_common_exit(&spi->dev); +} + +static const struct of_device_id pcm179x_of_match[] = { + { .compatible = "ti,pcm1792a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm179x_of_match); + +static const struct spi_device_id pcm179x_spi_ids[] = { + { "pcm179x", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids); + +static struct spi_driver pcm179x_spi_driver = { + .driver = { + .name = "pcm179x", + .of_match_table = of_match_ptr(pcm179x_of_match), + }, + .id_table = pcm179x_spi_ids, + .probe = pcm179x_spi_probe, + .remove = pcm179x_spi_remove, +}; + +module_spi_driver(pcm179x_spi_driver); + +MODULE_DESCRIPTION("ASoC PCM179X SPI driver"); +MODULE_AUTHOR("Michael Trimarchi "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index a56c7b767d90..8f20f70af23e 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -29,7 +28,6 @@ #include #include #include -#include #include "pcm179x.h" @@ -194,13 +192,7 @@ static struct snd_soc_dai_driver pcm179x_dai = { .ops = &pcm179x_dai_ops, }; -static const struct of_device_id pcm179x_of_match[] = { - { .compatible = "ti,pcm1792a", }, - { } -}; -MODULE_DEVICE_TABLE(of, pcm179x_of_match); - -static const struct regmap_config pcm179x_regmap = { +const struct regmap_config pcm179x_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 23, @@ -209,6 +201,7 @@ static const struct regmap_config pcm179x_regmap = { .writeable_reg = pcm179x_writeable_reg, .readable_reg = pcm179x_accessible_reg, }; +EXPORT_SYMBOL_GPL(pcm179x_regmap_config); static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { .controls = pcm179x_controls, @@ -219,52 +212,29 @@ static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), }; -static int pcm179x_spi_probe(struct spi_device *spi) +int pcm179x_common_init(struct device *dev, struct regmap *regmap) { struct pcm179x_private *pcm179x; - int ret; - pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private), + pcm179x = devm_kzalloc(dev, sizeof(struct pcm179x_private), GFP_KERNEL); if (!pcm179x) return -ENOMEM; - spi_set_drvdata(spi, pcm179x); - - pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap); - if (IS_ERR(pcm179x->regmap)) { - ret = PTR_ERR(pcm179x->regmap); - dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); - return ret; - } + pcm179x->regmap = regmap; + dev_set_drvdata(dev, pcm179x); - return snd_soc_register_codec(&spi->dev, + return snd_soc_register_codec(dev, &soc_codec_dev_pcm179x, &pcm179x_dai, 1); } +EXPORT_SYMBOL_GPL(pcm179x_common_init); -static int pcm179x_spi_remove(struct spi_device *spi) +int pcm179x_common_exit(struct device *dev) { - snd_soc_unregister_codec(&spi->dev); + snd_soc_unregister_codec(dev); return 0; } - -static const struct spi_device_id pcm179x_spi_ids[] = { - { "pcm179x", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids); - -static struct spi_driver pcm179x_codec_driver = { - .driver = { - .name = "pcm179x", - .of_match_table = of_match_ptr(pcm179x_of_match), - }, - .id_table = pcm179x_spi_ids, - .probe = pcm179x_spi_probe, - .remove = pcm179x_spi_remove, -}; - -module_spi_driver(pcm179x_codec_driver); +EXPORT_SYMBOL_GPL(pcm179x_common_exit); MODULE_DESCRIPTION("ASoC PCM179X driver"); MODULE_AUTHOR("Michael Trimarchi "); diff --git a/sound/soc/codecs/pcm179x.h b/sound/soc/codecs/pcm179x.h index c6fdc062a497..c4eea4df915b 100644 --- a/sound/soc/codecs/pcm179x.h +++ b/sound/soc/codecs/pcm179x.h @@ -24,4 +24,9 @@ #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE) +extern const struct regmap_config pcm179x_regmap_config; + +int pcm179x_common_init(struct device *dev, struct regmap *regmap); +int pcm179x_common_exit(struct device *dev); + #endif -- cgit v1.2.3 From 70e3e56e6c3d499be47322037ed4a42314a8e509 Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Fri, 22 Jan 2016 13:39:54 +0100 Subject: ASoC: pcm179x: Add I2C interface driver The PCM179x family supports both SPI and I2C. This patch adds support for the I2C interface. Signed-off-by: Jacob Siverskog Reviewed-by: Johan Hovold Acked-by: Michael Trimarchi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/pcm179x.txt | 11 +++- sound/soc/codecs/Kconfig | 9 +++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/pcm179x-i2c.c | 73 ++++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/pcm179x-i2c.c (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/pcm179x.txt b/Documentation/devicetree/bindings/sound/pcm179x.txt index 4ae70d3462d6..436c2b247693 100644 --- a/Documentation/devicetree/bindings/sound/pcm179x.txt +++ b/Documentation/devicetree/bindings/sound/pcm179x.txt @@ -1,6 +1,6 @@ Texas Instruments pcm179x DT bindings -This driver supports the SPI bus. +This driver supports both the I2C and SPI bus. Required properties: @@ -9,6 +9,11 @@ Required properties: For required properties on SPI, please consult Documentation/devicetree/bindings/spi/spi-bus.txt +Required properties on I2C: + + - reg: the I2C address + + Examples: codec_spi: 1792a@0 { @@ -16,3 +21,7 @@ Examples: spi-max-frequency = <600000>; }; + codec_i2c: 1792a@4c { + compatible = "ti,pcm1792a"; + reg = <0x4c>; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ae720f1b15e8..3a8fcf13200f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -87,6 +87,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ML26124 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_PCM1681 if I2C + select SND_SOC_PCM179X_I2C if I2C select SND_SOC_PCM179X_SPI if SPI_MASTER select SND_SOC_PCM3008 select SND_SOC_PCM3168A_I2C if I2C @@ -529,6 +530,14 @@ config SND_SOC_PCM1681 config SND_SOC_PCM179X tristate +config SND_SOC_PCM179X_I2C + tristate "Texas Instruments PCM179X CODEC (I2C)" + depends on I2C + select SND_SOC_PCM179X + help + Enable support for Texas Instruments PCM179x CODEC. + Select this if your PCM179x is connected via an I2C bus. + config SND_SOC_PCM179X_SPI tristate "Texas Instruments PCM179X CODEC (SPI)" depends on SPI_MASTER diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 56e94d88693f..9acd777a7a98 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -81,6 +81,7 @@ snd-soc-ml26124-objs := ml26124.o snd-soc-nau8825-objs := nau8825.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm179x-codec-objs := pcm179x.o +snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o snd-soc-pcm179x-spi-objs := pcm179x-spi.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm3168a-objs := pcm3168a.o @@ -286,6 +287,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o +obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c new file mode 100644 index 000000000000..4118106abb8d --- /dev/null +++ b/sound/soc/codecs/pcm179x-i2c.c @@ -0,0 +1,73 @@ +/* + * PCM179X ASoC I2C driver + * + * Copyright (c) Teenage Engineering AB 2016 + * + * Jacob Siverskog + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pcm179x.h" + +static int pcm179x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &pcm179x_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + return pcm179x_common_init(&client->dev, regmap); +} + +static int pcm179x_i2c_remove(struct i2c_client *client) +{ + return pcm179x_common_exit(&client->dev); +} + +static const struct of_device_id pcm179x_of_match[] = { + { .compatible = "ti,pcm1792a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm179x_of_match); + +static const struct i2c_device_id pcm179x_i2c_ids[] = { + { "pcm179x", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm179x_i2c_ids); + +static struct i2c_driver pcm179x_i2c_driver = { + .driver = { + .name = "pcm179x", + .of_match_table = of_match_ptr(pcm179x_of_match), + }, + .id_table = pcm179x_i2c_ids, + .probe = pcm179x_i2c_probe, + .remove = pcm179x_i2c_remove, +}; + +module_i2c_driver(pcm179x_i2c_driver); + +MODULE_DESCRIPTION("ASoC PCM179X I2C driver"); +MODULE_AUTHOR("Jacob Siverskog "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e0236f541e68aa2187a9a402bf74bec6f007eb84 Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Fri, 22 Jan 2016 13:39:55 +0100 Subject: ASoC: pcm179x: Support continuous rates According to the PCM179x data sheets sampling frequencies between 10 kHz and 200 kHz are supported. Specify support in the driver. Tested with PCM1791A. References: http://www.ti.com/lit/ds/symlink/pcm1791a.pdf http://www.ti.com/lit/ds/symlink/pcm1792a.pdf http://www.ti.com/lit/ds/symlink/pcm1795.pdf http://www.ti.com/lit/ds/symlink/pcm1796.pdf Signed-off-by: Jacob Siverskog Reviewed-by: Johan Hovold Acked-by: Michael Trimarchi Signed-off-by: Mark Brown --- sound/soc/codecs/pcm179x.c | 4 +++- sound/soc/codecs/pcm179x.h | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index 8f20f70af23e..06a66579ca6d 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -187,7 +187,9 @@ static struct snd_soc_dai_driver pcm179x_dai = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = PCM1792A_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 10000, + .rate_max = 200000, .formats = PCM1792A_FORMATS, }, .ops = &pcm179x_dai_ops, }; diff --git a/sound/soc/codecs/pcm179x.h b/sound/soc/codecs/pcm179x.h index c4eea4df915b..11e331268aae 100644 --- a/sound/soc/codecs/pcm179x.h +++ b/sound/soc/codecs/pcm179x.h @@ -17,10 +17,6 @@ #ifndef __PCM179X_H__ #define __PCM179X_H__ -#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_192000) - #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S16_LE) -- cgit v1.2.3 From b0639bd2428d61a13b69d2ff247cfceae90b8366 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Jan 2016 01:47:12 +0000 Subject: ASoC: soc-pcm: copy dpcm->hw_params and call be_hw_params_fixup every time Current DPCM doesn't copy dpcm->hw_params and doesn't call be_hw_params if some FE are connected. But 2nd or later FE might want to know BE hw_params. This patch solves this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e898b427be7e..be2fd5e46182 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1866,18 +1866,6 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) if (!snd_soc_dpcm_be_can_update(fe, be, stream)) continue; - /* only allow hw_params() if no connected FEs are running */ - if (!snd_soc_dpcm_can_be_params(fe, be, stream)) - continue; - - if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) - continue; - - dev_dbg(be->dev, "ASoC: hw_params BE %s\n", - dpcm->fe->dai_link->name); - /* copy params for each dpcm */ memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params, sizeof(struct snd_pcm_hw_params)); @@ -1894,6 +1882,18 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) } } + /* only allow hw_params() if no connected FEs are running */ + if (!snd_soc_dpcm_can_be_params(fe, be, stream)) + continue; + + if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) + continue; + + dev_dbg(be->dev, "ASoC: hw_params BE %s\n", + dpcm->fe->dai_link->name); + ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); if (ret < 0) { dev_err(dpcm->be->dev, -- cgit v1.2.3 From 4e26ad80cbd3a6b0d606201892e81a9a9c6864ce Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Fri, 29 Jan 2016 01:47:12 +0000 Subject: ASoC: rt5616: Add support sample rate to 192KHz Reference the TRM, the ALC5616 support one 24bit/8KHz ~ 192KHz I2S/PCM Interface for stereo DAC and stereo ADC. Signed-off-by: Xing Zheng Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index fdca63694b40..3704d0716c04 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1261,7 +1261,7 @@ static int rt5616_resume(struct snd_soc_codec *codec) #define rt5616_resume NULL #endif -#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_192000 #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -- cgit v1.2.3 From 31889507fd84a6a1c8dce36a214a070cec1fc559 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Jan 2016 17:53:00 +0000 Subject: ASoC: wm5110: Add support for audio trace firmware Mainly this adds DAI links for the audio trace, however, it is also necessary to update the data IRQ handler to check more cores. We have the handler check every core so it should not be necessary to update this function if more compressed firmwares are added in the future. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.h | 2 +- sound/soc/codecs/wm5110.c | 43 +++++++++++++++++++++++++++++++++++++++---- sound/soc/codecs/wm_adsp.c | 1 - 3 files changed, 40 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 8b6adb5419bb..0c64a5731513 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -57,7 +57,7 @@ #define ARIZONA_CLK_98MHZ 5 #define ARIZONA_CLK_147MHZ 6 -#define ARIZONA_MAX_DAI 8 +#define ARIZONA_MAX_DAI 10 #define ARIZONA_MAX_ADSP 4 #define ARIZONA_DVFS_SR1_RQ 0x001 diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b47bc4418e30..92b6a6a564df 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1828,6 +1828,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "Voice Control DSP", NULL, "DSP3" }, { "Voice Control DSP", NULL, "SYSCLK" }, + { "Audio Trace DSP", NULL, "DSP1" }, + { "Audio Trace DSP", NULL, "SYSCLK" }, + { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -2171,6 +2174,27 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .formats = WM5110_FORMATS, }, }, + { + .name = "wm5110-cpu-trace", + .capture = { + .stream_name = "Audio Trace CPU", + .channels_min = 1, + .channels_max = 6, + .rates = WM5110_RATES, + .formats = WM5110_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "wm5110-dsp-trace", + .capture = { + .stream_name = "Audio Trace DSP", + .channels_min = 1, + .channels_max = 6, + .rates = WM5110_RATES, + .formats = WM5110_FORMATS, + }, + }, }; static int wm5110_open(struct snd_compr_stream *stream) @@ -2182,6 +2206,8 @@ static int wm5110_open(struct snd_compr_stream *stream) if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) { n_adsp = 2; + } else if (strcmp(rtd->codec_dai->name, "wm5110-dsp-trace") == 0) { + n_adsp = 0; } else { dev_err(arizona->dev, "No suitable compressed stream for DAI '%s'\n", @@ -2194,12 +2220,21 @@ static int wm5110_open(struct snd_compr_stream *stream) static irqreturn_t wm5110_adsp2_irq(int irq, void *data) { - struct wm5110_priv *florida = data; - int ret; + struct wm5110_priv *priv = data; + struct arizona *arizona = priv->core.arizona; + int serviced = 0; + int i, ret; + + for (i = 0; i < WM5110_NUM_ADSP; ++i) { + ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); + if (ret != -ENODEV) + serviced++; + } - ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]); - if (ret == -ENODEV) + if (!serviced) { + dev_err(arizona->dev, "Spurious compressed data IRQ\n"); return IRQ_NONE; + } return IRQ_HANDLED; } diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 76ab52d2c670..653dbff81fee 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2823,7 +2823,6 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) mutex_lock(&dsp->pwr_lock); if (!buf) { - adsp_err(dsp, "Spurious buffer IRQ\n"); ret = -ENODEV; goto out; } -- cgit v1.2.3 From 69fa80584f69554275ef1257d41b90f4e0d417fc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 21 Jan 2016 17:53:01 +0000 Subject: ASoC: wm5102: Add support for the audio trace firmware wm5102 also supports the audio trace firmware, this patch adds support for this into the wm5102 driver. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 7c0860df3204..aa1e96ab4bd2 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1599,6 +1599,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "Slim2 Capture", NULL, "SYSCLK" }, { "Slim3 Capture", NULL, "SYSCLK" }, + { "Audio Trace DSP", NULL, "DSP1" }, + { "Audio Trace DSP", NULL, "SYSCLK" }, + { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -1864,14 +1867,67 @@ static struct snd_soc_dai_driver wm5102_dai[] = { }, .ops = &arizona_simple_dai_ops, }, + { + .name = "wm5102-cpu-trace", + .capture = { + .stream_name = "Audio Trace CPU", + .channels_min = 1, + .channels_max = 6, + .rates = WM5102_RATES, + .formats = WM5102_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "wm5102-dsp-trace", + .capture = { + .stream_name = "Audio Trace DSP", + .channels_min = 1, + .channels_max = 4, + .rates = WM5102_RATES, + .formats = WM5102_FORMATS, + }, + }, }; +static int wm5102_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + + return wm_adsp_compr_open(&priv->core.adsp[0], stream); +} + +static irqreturn_t wm5102_adsp2_irq(int irq, void *data) +{ + struct wm5102_priv *priv = data; + struct arizona *arizona = priv->core.arizona; + int ret; + + ret = wm_adsp_compr_handle_irq(&priv->core.adsp[0]); + if (ret == -ENODEV) { + dev_err(arizona->dev, "Spurious compressed data IRQ\n"); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + static int wm5102_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int ret; + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5102_adsp2_irq, + priv); + if (ret != 0) { + dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec); if (ret) return ret; @@ -1946,6 +2002,20 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), }; +static struct snd_compr_ops wm5102_compr_ops = { + .open = wm5102_open, + .free = wm_adsp_compr_free, + .set_params = wm_adsp_compr_set_params, + .get_caps = wm_adsp_compr_get_caps, + .trigger = wm_adsp_compr_trigger, + .pointer = wm_adsp_compr_pointer, + .copy = wm_adsp_compr_copy, +}; + +static struct snd_soc_platform_driver wm5102_compr_platform = { + .compr_ops = &wm5102_compr_ops, +}; + static int wm5102_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -2005,12 +2075,25 @@ static int wm5102_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102, + ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102, wm5102_dai, ARRAY_SIZE(wm5102_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + snd_soc_unregister_platform(&pdev->dev); + } + + return ret; } static int wm5102_remove(struct platform_device *pdev) { + snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 7eec55d7a2f2932b3b4a799bc5d0d6718e1ee9e2 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 22 Jan 2016 13:49:59 +0000 Subject: ASoC: cs47l24: Add voice control compressed stream This patch adds firmware compressed stream capture support and DAI hookups for voice control firmware (based on the wm5110 implementation.) Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 98 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 9dc77a4da35d..b8d3cd031d7d 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -798,6 +798,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "AIF2 Capture", NULL, "SYSCLK" }, { "AIF3 Capture", NULL, "SYSCLK" }, + { "Voice Control DSP", NULL, "DSP3" }, + { "Voice Control DSP", NULL, "SYSCLK" }, + { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -992,12 +995,68 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { .symmetric_rates = 1, .symmetric_samplebits = 1, }, + { + .name = "cs47l24-cpu-voicectrl", + .capture = { + .stream_name = "Voice Control CPU", + .channels_min = 1, + .channels_max = 1, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "cs47l24-dsp-voicectrl", + .capture = { + .stream_name = "Voice Control DSP", + .channels_min = 1, + .channels_max = 1, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + }, }; +static int cs47l24_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct arizona *arizona = priv->core.arizona; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) { + n_adsp = 2; + } else { + dev_err(arizona->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream); +} + +static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) +{ + struct cs47l24_priv *priv = data; + struct arizona *arizona = priv->core.arizona; + int ret; + + ret = wm_adsp_compr_handle_irq(&priv->core.adsp[2]); + if (ret == -ENODEV) { + dev_err(arizona->dev, "Spurious compressed data IRQ\n"); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + static int cs47l24_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int ret; priv->core.arizona->dapm = dapm; @@ -1006,6 +1065,14 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_mono(codec); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, + priv); + if (ret != 0) { + dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec); if (ret) goto err_adsp2_codec_probe; @@ -1033,13 +1100,14 @@ err_adsp2_codec_probe: static int cs47l24_codec_remove(struct snd_soc_codec *codec) { struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); - + struct arizona *arizona = priv->core.arizona; wm_adsp2_codec_remove(&priv->core.adsp[1], codec); wm_adsp2_codec_remove(&priv->core.adsp[2], codec); priv->core.arizona->dapm = NULL; + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); return 0; } @@ -1076,6 +1144,19 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), }; +static struct snd_compr_ops cs47l24_compr_ops = { + .open = cs47l24_open, + .free = wm_adsp_compr_free, + .set_params = wm_adsp_compr_set_params, + .get_caps = wm_adsp_compr_get_caps, + .trigger = wm_adsp_compr_trigger, + .pointer = wm_adsp_compr_pointer, + .copy = wm_adsp_compr_copy, +}; + +static struct snd_soc_platform_driver cs47l24_compr_platform = { + .compr_ops = &cs47l24_compr_ops, +}; static int cs47l24_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -1139,12 +1220,25 @@ static int cs47l24_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, + ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); + return ret; + } + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); + + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + snd_soc_unregister_platform(&pdev->dev); + } + + return ret; } static int cs47l24_remove(struct platform_device *pdev) { + snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 3a9686c4ba7eec9201c6e8793705d32f24748771 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 1 Feb 2016 15:22:34 +0000 Subject: ASoC: wm_adsp: Add missing const from region definitions Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 653dbff81fee..28d3851c5063 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -325,7 +325,7 @@ struct wm_adsp_buffer_region_def { unsigned int size_offset; }; -static struct wm_adsp_buffer_region_def default_regions[] = { +static const struct wm_adsp_buffer_region_def default_regions[] = { { .mem_type = WMFW_ADSP2_XM, .base_offset = HOST_BUFFER_FIELD(X_buf_base), @@ -347,7 +347,7 @@ struct wm_adsp_fw_caps { u32 id; struct snd_codec_desc desc; int num_regions; - struct wm_adsp_buffer_region_def *region_defs; + const struct wm_adsp_buffer_region_def *region_defs; }; static const struct wm_adsp_fw_caps ctrl_caps[] = { -- cgit v1.2.3 From da2b33589013b4cb3dad163f50fae060896cb8b6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 2 Feb 2016 16:41:36 +0000 Subject: ASoC: wm_adsp: Return sample rate in wm_adsp_compr_pointer We should return a valid sample rate from the pointer callback, this patch adds this into the driver. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 33806d487b8a..68b85ee67586 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -295,6 +295,8 @@ struct wm_adsp_compr { u32 *raw_buf; unsigned int copied_total; + + unsigned int sample_rate; }; #define WM_ADSP_DATA_WORD_SIZE 3 @@ -2471,6 +2473,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream, if (!compr->raw_buf) return -ENOMEM; + compr->sample_rate = params->codec.sample_rate; + return 0; } EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); @@ -2911,6 +2915,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, tstamp->copied_total = compr->copied_total; tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE; + tstamp->sampling_rate = compr->sample_rate; out: mutex_unlock(&dsp->pwr_lock); -- cgit v1.2.3 From 4a6180ea7399b945cd380dc63e2e8118f9b432d3 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 3 Feb 2016 19:53:24 +0800 Subject: ASoC: rt5514: add rt5514 codec driver This is the initial codec driver for rt5514. The codec includes a low power DSP for voice wake up. The register address is incremental by 4 in the DSP memory map. In order to recover the codec settings in the codec mode and manipulate the DSP mode for voice wake up, we use the multi-level register map. One is for ALSA API in codec mode that can be recovered by cache before recording. Another is for DSP related settings that can be accessed with 32bit address of the DSP in the application of voice wake up. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5514.txt | 25 + sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt5514.c | 982 +++++++++++++++++++++ sound/soc/codecs/rt5514.h | 252 ++++++ 5 files changed, 1267 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt5514.txt create mode 100644 sound/soc/codecs/rt5514.c create mode 100644 sound/soc/codecs/rt5514.h (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/rt5514.txt b/Documentation/devicetree/bindings/sound/rt5514.txt new file mode 100644 index 000000000000..e24436fc5ea9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5514.txt @@ -0,0 +1,25 @@ +RT5514 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5514". + +- reg : The I2C address of the device. + +Pins on the device (for linking into audio routes) for RT5514: + + * DMIC1L + * DMIC1R + * DMIC2L + * DMIC2R + * AMICL + * AMICR + +Example: + +codec: rt5514@57 { + compatible = "realtek,rt5514"; + reg = <0x57>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50693c867e71..dabd479bf1f0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -95,6 +95,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C select SND_SOC_RT298 if I2C + select SND_SOC_RT5514 if I2C select SND_SOC_RT5616 if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C @@ -565,6 +566,7 @@ config SND_SOC_PCM512x_SPI config SND_SOC_RL6231 tristate + default y if SND_SOC_RT5514=y default y if SND_SOC_RT5616=y default y if SND_SOC_RT5640=y default y if SND_SOC_RT5645=y @@ -572,6 +574,7 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5659=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y + default m if SND_SOC_RT5514=m default m if SND_SOC_RT5616=m default m if SND_SOC_RT5640=m default m if SND_SOC_RT5645=m @@ -595,6 +598,9 @@ config SND_SOC_RT298 tristate depends on I2C +config SND_SOC_RT5514 + tristate + config SND_SOC_RT5616 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d44f7d347183..79f95dd4ed68 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -92,6 +92,7 @@ snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt286-objs := rt286.o snd-soc-rt298-objs := rt298.o +snd-soc-rt5514-objs := rt5514.o snd-soc-rt5616-objs := rt5616.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o @@ -296,6 +297,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o +obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c new file mode 100644 index 000000000000..879bf60f4965 --- /dev/null +++ b/sound/soc/codecs/rt5514.c @@ -0,0 +1,982 @@ +/* + * rt5514.c -- RT5514 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Oder Chiou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6231.h" +#include "rt5514.h" + +static const struct reg_sequence rt5514_i2c_patch[] = { + {0x1800101c, 0x00000000}, + {0x18001100, 0x0000031f}, + {0x18001104, 0x00000007}, + {0x18001108, 0x00000000}, + {0x1800110c, 0x00000000}, + {0x18001110, 0x00000000}, + {0x18001114, 0x00000001}, + {0x18001118, 0x00000000}, + {0x18002f08, 0x00000006}, + {0x18002f00, 0x00055149}, + {0x18002f00, 0x0005514b}, + {0x18002f00, 0x00055149}, + {0xfafafafa, 0x00000001}, + {0x18002f10, 0x00000001}, + {0x18002f10, 0x00000000}, + {0x18002f10, 0x00000001}, + {0xfafafafa, 0x00000001}, + {0x18002000, 0x000010ec}, + {0xfafafafa, 0x00000000}, +}; + +static const struct reg_sequence rt5514_patch[] = { + {RT5514_DIG_IO_CTRL, 0x00000040}, + {RT5514_CLK_CTRL1, 0x38020041}, + {RT5514_SRC_CTRL, 0x44000eee}, + {RT5514_ANA_CTRL_LDO10, 0x00028604}, + {RT5514_ANA_CTRL_ADCFED, 0x00000800}, +}; + +static const struct reg_default rt5514_reg[] = { + {RT5514_RESET, 0x00000000}, + {RT5514_PWR_ANA1, 0x00808880}, + {RT5514_PWR_ANA2, 0x00220000}, + {RT5514_I2S_CTRL1, 0x00000330}, + {RT5514_I2S_CTRL2, 0x20000000}, + {RT5514_VAD_CTRL6, 0xc00007d2}, + {RT5514_EXT_VAD_CTRL, 0x80000080}, + {RT5514_DIG_IO_CTRL, 0x00000040}, + {RT5514_PAD_CTRL1, 0x00804000}, + {RT5514_DMIC_DATA_CTRL, 0x00000005}, + {RT5514_DIG_SOURCE_CTRL, 0x00000002}, + {RT5514_SRC_CTRL, 0x44000eee}, + {RT5514_DOWNFILTER2_CTRL1, 0x0000882f}, + {RT5514_PLL_SOURCE_CTRL, 0x00000004}, + {RT5514_CLK_CTRL1, 0x38020041}, + {RT5514_CLK_CTRL2, 0x00000000}, + {RT5514_PLL3_CALIB_CTRL1, 0x00400200}, + {RT5514_PLL3_CALIB_CTRL5, 0x40220012}, + {RT5514_DELAY_BUF_CTRL1, 0x7fff006a}, + {RT5514_DELAY_BUF_CTRL3, 0x00000000}, + {RT5514_DOWNFILTER0_CTRL1, 0x00020c2f}, + {RT5514_DOWNFILTER0_CTRL2, 0x00020c2f}, + {RT5514_DOWNFILTER0_CTRL3, 0x00000362}, + {RT5514_DOWNFILTER1_CTRL1, 0x00020c2f}, + {RT5514_DOWNFILTER1_CTRL2, 0x00020c2f}, + {RT5514_DOWNFILTER1_CTRL3, 0x00000362}, + {RT5514_ANA_CTRL_LDO10, 0x00028604}, + {RT5514_ANA_CTRL_LDO18_16, 0x02000345}, + {RT5514_ANA_CTRL_ADC12, 0x0000a2a8}, + {RT5514_ANA_CTRL_ADC21, 0x00001180}, + {RT5514_ANA_CTRL_ADC22, 0x0000aaa8}, + {RT5514_ANA_CTRL_ADC23, 0x00151427}, + {RT5514_ANA_CTRL_MICBST, 0x00002000}, + {RT5514_ANA_CTRL_ADCFED, 0x00000800}, + {RT5514_ANA_CTRL_INBUF, 0x00000143}, + {RT5514_ANA_CTRL_VREF, 0x00008d50}, + {RT5514_ANA_CTRL_PLL3, 0x0000000e}, + {RT5514_ANA_CTRL_PLL1_1, 0x00000000}, + {RT5514_ANA_CTRL_PLL1_2, 0x00030220}, + {RT5514_DMIC_LP_CTRL, 0x00000000}, + {RT5514_MISC_CTRL_DSP, 0x00000000}, + {RT5514_DSP_CTRL1, 0x00055149}, + {RT5514_DSP_CTRL3, 0x00000006}, + {RT5514_DSP_CTRL4, 0x00000001}, + {RT5514_VENDOR_ID1, 0x00000001}, + {RT5514_VENDOR_ID2, 0x10ec5514}, +}; + +static bool rt5514_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5514_VENDOR_ID1: + case RT5514_VENDOR_ID2: + return true; + + default: + return false; + } +} + +static bool rt5514_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5514_RESET: + case RT5514_PWR_ANA1: + case RT5514_PWR_ANA2: + case RT5514_I2S_CTRL1: + case RT5514_I2S_CTRL2: + case RT5514_VAD_CTRL6: + case RT5514_EXT_VAD_CTRL: + case RT5514_DIG_IO_CTRL: + case RT5514_PAD_CTRL1: + case RT5514_DMIC_DATA_CTRL: + case RT5514_DIG_SOURCE_CTRL: + case RT5514_SRC_CTRL: + case RT5514_DOWNFILTER2_CTRL1: + case RT5514_PLL_SOURCE_CTRL: + case RT5514_CLK_CTRL1: + case RT5514_CLK_CTRL2: + case RT5514_PLL3_CALIB_CTRL1: + case RT5514_PLL3_CALIB_CTRL5: + case RT5514_DELAY_BUF_CTRL1: + case RT5514_DELAY_BUF_CTRL3: + case RT5514_DOWNFILTER0_CTRL1: + case RT5514_DOWNFILTER0_CTRL2: + case RT5514_DOWNFILTER0_CTRL3: + case RT5514_DOWNFILTER1_CTRL1: + case RT5514_DOWNFILTER1_CTRL2: + case RT5514_DOWNFILTER1_CTRL3: + case RT5514_ANA_CTRL_LDO10: + case RT5514_ANA_CTRL_LDO18_16: + case RT5514_ANA_CTRL_ADC12: + case RT5514_ANA_CTRL_ADC21: + case RT5514_ANA_CTRL_ADC22: + case RT5514_ANA_CTRL_ADC23: + case RT5514_ANA_CTRL_MICBST: + case RT5514_ANA_CTRL_ADCFED: + case RT5514_ANA_CTRL_INBUF: + case RT5514_ANA_CTRL_VREF: + case RT5514_ANA_CTRL_PLL3: + case RT5514_ANA_CTRL_PLL1_1: + case RT5514_ANA_CTRL_PLL1_2: + case RT5514_DMIC_LP_CTRL: + case RT5514_MISC_CTRL_DSP: + case RT5514_DSP_CTRL1: + case RT5514_DSP_CTRL3: + case RT5514_DSP_CTRL4: + case RT5514_VENDOR_ID1: + case RT5514_VENDOR_ID2: + return true; + + default: + return false; + } +} + +static bool rt5514_i2c_readable_register(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case RT5514_DSP_MAPPING | RT5514_RESET: + case RT5514_DSP_MAPPING | RT5514_PWR_ANA1: + case RT5514_DSP_MAPPING | RT5514_PWR_ANA2: + case RT5514_DSP_MAPPING | RT5514_I2S_CTRL1: + case RT5514_DSP_MAPPING | RT5514_I2S_CTRL2: + case RT5514_DSP_MAPPING | RT5514_VAD_CTRL6: + case RT5514_DSP_MAPPING | RT5514_EXT_VAD_CTRL: + case RT5514_DSP_MAPPING | RT5514_DIG_IO_CTRL: + case RT5514_DSP_MAPPING | RT5514_PAD_CTRL1: + case RT5514_DSP_MAPPING | RT5514_DMIC_DATA_CTRL: + case RT5514_DSP_MAPPING | RT5514_DIG_SOURCE_CTRL: + case RT5514_DSP_MAPPING | RT5514_SRC_CTRL: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER2_CTRL1: + case RT5514_DSP_MAPPING | RT5514_PLL_SOURCE_CTRL: + case RT5514_DSP_MAPPING | RT5514_CLK_CTRL1: + case RT5514_DSP_MAPPING | RT5514_CLK_CTRL2: + case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL1: + case RT5514_DSP_MAPPING | RT5514_PLL3_CALIB_CTRL5: + case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL1: + case RT5514_DSP_MAPPING | RT5514_DELAY_BUF_CTRL3: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL1: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL2: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER0_CTRL3: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL1: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL2: + case RT5514_DSP_MAPPING | RT5514_DOWNFILTER1_CTRL3: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_LDO10: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_LDO18_16: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC12: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC21: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC22: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADC23: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_MICBST: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_ADCFED: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_INBUF: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_VREF: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL3: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL1_1: + case RT5514_DSP_MAPPING | RT5514_ANA_CTRL_PLL1_2: + case RT5514_DSP_MAPPING | RT5514_DMIC_LP_CTRL: + case RT5514_DSP_MAPPING | RT5514_MISC_CTRL_DSP: + case RT5514_DSP_MAPPING | RT5514_DSP_CTRL1: + case RT5514_DSP_MAPPING | RT5514_DSP_CTRL3: + case RT5514_DSP_MAPPING | RT5514_DSP_CTRL4: + case RT5514_DSP_MAPPING | RT5514_VENDOR_ID1: + case RT5514_DSP_MAPPING | RT5514_VENDOR_ID2: + return true; + + default: + return false; + } +} + +/* {-3, 0, +3, +4.5, +7.5, +9.5, +12, +14, +17} dB */ +static const DECLARE_TLV_DB_RANGE(bst_tlv, + 0, 2, TLV_DB_SCALE_ITEM(-300, 300, 0), + 3, 3, TLV_DB_SCALE_ITEM(450, 0, 0), + 4, 4, TLV_DB_SCALE_ITEM(750, 0, 0), + 5, 5, TLV_DB_SCALE_ITEM(950, 0, 0), + 6, 6, TLV_DB_SCALE_ITEM(1200, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(1400, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0) +); + +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); + +static const struct snd_kcontrol_new rt5514_snd_controls[] = { + SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, + RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), + SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1, + RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, + adc_vol_tlv), + SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1, + RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, + adc_vol_tlv), +}; + +/* ADC Mixer*/ +static const struct snd_kcontrol_new rt5514_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER0_CTRL1, + RT5514_AD_DMIC_MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER0_CTRL1, + RT5514_AD_AD_MIX_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5514_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER0_CTRL2, + RT5514_AD_DMIC_MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER0_CTRL2, + RT5514_AD_AD_MIX_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5514_sto2_adc_l_mix[] = { + SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER1_CTRL1, + RT5514_AD_DMIC_MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER1_CTRL1, + RT5514_AD_AD_MIX_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5514_sto2_adc_r_mix[] = { + SOC_DAPM_SINGLE("DMIC Switch", RT5514_DOWNFILTER1_CTRL2, + RT5514_AD_DMIC_MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("ADC Switch", RT5514_DOWNFILTER1_CTRL2, + RT5514_AD_AD_MIX_BIT, 1, 1), +}; + +/* DMIC Source */ +static const char * const rt5514_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5514_stereo1_dmic_enum, RT5514_DIG_SOURCE_CTRL, + RT5514_AD0_DMIC_INPUT_SEL_SFT, rt5514_dmic_src); + +static const struct snd_kcontrol_new rt5514_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5514_stereo1_dmic_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5514_stereo2_dmic_enum, RT5514_DIG_SOURCE_CTRL, + RT5514_AD1_DMIC_INPUT_SEL_SFT, rt5514_dmic_src); + +static const struct snd_kcontrol_new rt5514_sto2_dmic_mux = + SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5514_stereo2_dmic_enum); + +/** + * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic. + * + * @rate: base clock rate. + * + * Choose divider parameter that gives the highest possible DMIC frequency in + * 1MHz - 3MHz range. + */ +static int rt5514_calc_dmic_clk(struct snd_soc_codec *codec, int rate) +{ + int div[] = {2, 3, 4, 8, 12, 16, 24, 32}; + int i; + + if (rate < 1000000 * div[0]) { + pr_warn("Base clock rate %d is too low\n", rate); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(div); i++) { + /* find divider that gives DMIC frequency below 3.072MHz */ + if (3072000 * div[i] >= rate) + return i; + } + + dev_warn(codec->dev, "Base clock rate %d is too high\n", rate); + return -EINVAL; +} + +static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + int idx; + + idx = rt5514_calc_dmic_clk(codec, rt5514->sysclk); + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else + regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL1, + RT5514_CLK_DMIC_OUT_SEL_MASK, + idx << RT5514_CLK_DMIC_OUT_SEL_SFT); + + return idx; +} + +static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + + if (rt5514->sysclk_src == RT5514_SCLK_S_PLL1) + return 1; + else + return 0; +} + +static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC1L"), + SND_SOC_DAPM_INPUT("DMIC1R"), + SND_SOC_DAPM_INPUT("DMIC2L"), + SND_SOC_DAPM_INPUT("DMIC2R"), + + SND_SOC_DAPM_INPUT("AMICL"), + SND_SOC_DAPM_INPUT("AMICR"), + + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + rt5514_set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY("ADC CLK", RT5514_CLK_CTRL1, + RT5514_CLK_AD_ANA1_EN_BIT, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("LDO18 IN", RT5514_PWR_ANA1, + RT5514_POW_LDO18_IN_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO18 ADC", RT5514_PWR_ANA1, + RT5514_POW_LDO18_ADC_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO21", RT5514_PWR_ANA1, RT5514_POW_LDO21_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("BG LDO18 IN", RT5514_PWR_ANA1, + RT5514_POW_BG_LDO18_IN_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BG LDO21", RT5514_PWR_ANA1, + RT5514_POW_BG_LDO21_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BG MBIAS", RT5514_PWR_ANA2, + RT5514_POW_BG_MBIAS_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MBIAS", RT5514_PWR_ANA2, RT5514_POW_MBIAS_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("VREF2", RT5514_PWR_ANA2, RT5514_POW_VREF2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("VREF1", RT5514_PWR_ANA2, RT5514_POW_VREF1_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Power", SND_SOC_NOPM, 0, 0, NULL, 0), + + + SND_SOC_DAPM_SUPPLY("LDO16L", RT5514_PWR_ANA2, RT5514_POWL_LDO16_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1L", RT5514_PWR_ANA2, RT5514_POW_ADC1_L_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("BSTL2", RT5514_PWR_ANA2, RT5514_POW2_BSTL_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("BSTL", RT5514_PWR_ANA2, RT5514_POW_BSTL_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("ADCFEDL", RT5514_PWR_ANA2, RT5514_POW_ADCFEDL_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADCL Power", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("LDO16R", RT5514_PWR_ANA2, RT5514_POWR_LDO16_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1R", RT5514_PWR_ANA2, RT5514_POW_ADC1_R_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("BSTR2", RT5514_PWR_ANA2, RT5514_POW2_BSTR_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("BSTR", RT5514_PWR_ANA2, RT5514_POW_BSTR_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("ADCFEDR", RT5514_PWR_ANA2, RT5514_POW_ADCFEDR_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADCR Power", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("PLL1 LDO ENABLE", RT5514_ANA_CTRL_PLL1_2, + RT5514_EN_LDO_PLL1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL1 LDO", RT5514_PWR_ANA2, + RT5514_POW_PLL1_LDO_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL1", RT5514_PWR_ANA2, RT5514_POW_PLL1_BIT, 0, + NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC Mux", SND_SOC_NOPM, 0, 0, + &rt5514_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo2 DMIC Mux", SND_SOC_NOPM, 0, 0, + &rt5514_sto2_dmic_mux), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5514_CLK_CTRL1, + RT5514_CLK_AD0_EN_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("adc stereo2 filter", RT5514_CLK_CTRL1, + RT5514_CLK_AD1_EN_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5514_sto1_adc_l_mix, ARRAY_SIZE(rt5514_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5514_sto1_adc_r_mix, ARRAY_SIZE(rt5514_sto1_adc_r_mix)), + SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5514_sto2_adc_l_mix, ARRAY_SIZE(rt5514_sto2_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto2 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5514_sto2_adc_r_mix, ARRAY_SIZE(rt5514_sto2_adc_r_mix)), + + SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5514_DOWNFILTER0_CTRL1, + RT5514_AD_AD_MUTE_BIT, 1), + SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5514_DOWNFILTER0_CTRL2, + RT5514_AD_AD_MUTE_BIT, 1), + SND_SOC_DAPM_ADC("Stereo2 ADC MIXL", NULL, RT5514_DOWNFILTER1_CTRL1, + RT5514_AD_AD_MUTE_BIT, 1), + SND_SOC_DAPM_ADC("Stereo2 ADC MIXR", NULL, RT5514_DOWNFILTER1_CTRL2, + RT5514_AD_AD_MUTE_BIT, 1), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { + { "DMIC1", NULL, "DMIC1L" }, + { "DMIC1", NULL, "DMIC1R" }, + { "DMIC2", NULL, "DMIC2L" }, + { "DMIC2", NULL, "DMIC2R" }, + + { "DMIC1L", NULL, "DMIC CLK" }, + { "DMIC1R", NULL, "DMIC CLK" }, + { "DMIC2L", NULL, "DMIC CLK" }, + { "DMIC2R", NULL, "DMIC CLK" }, + + { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, + { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, + + { "Sto1 ADC MIXL", "DMIC Switch", "Stereo1 DMIC Mux" }, + { "Sto1 ADC MIXL", "ADC Switch", "AMICL" }, + { "Sto1 ADC MIXR", "DMIC Switch", "Stereo1 DMIC Mux" }, + { "Sto1 ADC MIXR", "ADC Switch", "AMICR" }, + + { "ADC Power", NULL, "LDO18 IN" }, + { "ADC Power", NULL, "LDO18 ADC" }, + { "ADC Power", NULL, "LDO21" }, + { "ADC Power", NULL, "BG LDO18 IN" }, + { "ADC Power", NULL, "BG LDO21" }, + { "ADC Power", NULL, "BG MBIAS" }, + { "ADC Power", NULL, "MBIAS" }, + { "ADC Power", NULL, "VREF2" }, + { "ADC Power", NULL, "VREF1" }, + + { "ADCL Power", NULL, "LDO16L" }, + { "ADCL Power", NULL, "ADC1L" }, + { "ADCL Power", NULL, "BSTL2" }, + { "ADCL Power", NULL, "BSTL" }, + { "ADCL Power", NULL, "ADCFEDL" }, + + { "ADCR Power", NULL, "LDO16R" }, + { "ADCR Power", NULL, "ADC1R" }, + { "ADCR Power", NULL, "BSTR2" }, + { "ADCR Power", NULL, "BSTR" }, + { "ADCR Power", NULL, "ADCFEDR" }, + + { "AMICL", NULL, "ADC CLK" }, + { "AMICL", NULL, "ADC Power" }, + { "AMICL", NULL, "ADCL Power" }, + { "AMICR", NULL, "ADC CLK" }, + { "AMICR", NULL, "ADC Power" }, + { "AMICR", NULL, "ADCR Power" }, + + { "PLL1 LDO", NULL, "PLL1 LDO ENABLE" }, + { "PLL1", NULL, "PLL1 LDO" }, + + { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, + { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, + + { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL" }, + { "Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR" }, + { "Stereo1 ADC MIX", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll }, + + { "Stereo2 DMIC Mux", "DMIC1", "DMIC1" }, + { "Stereo2 DMIC Mux", "DMIC2", "DMIC2" }, + + { "Sto2 ADC MIXL", "DMIC Switch", "Stereo2 DMIC Mux" }, + { "Sto2 ADC MIXL", "ADC Switch", "AMICL" }, + { "Sto2 ADC MIXR", "DMIC Switch", "Stereo2 DMIC Mux" }, + { "Sto2 ADC MIXR", "ADC Switch", "AMICR" }, + + { "Stereo2 ADC MIXL", NULL, "Sto2 ADC MIXL" }, + { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" }, + + { "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL" }, + { "Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR" }, + { "Stereo2 ADC MIX", NULL, "adc stereo2 filter" }, + { "adc stereo2 filter", NULL, "PLL1", rt5514_is_sys_clk_from_pll }, + + { "AIF1TX", NULL, "Stereo1 ADC MIX"}, + { "AIF1TX", NULL, "Stereo2 ADC MIX"}, +}; + +static int rt5514_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + int pre_div, bclk_ms, frame_size; + unsigned int val_len = 0; + + rt5514->lrck = params_rate(params); + pre_div = rl6231_get_clk_info(rt5514->sysclk, rt5514->lrck); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + bclk_ms = frame_size > 32; + rt5514->bclk = rt5514->lrck * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5514->bclk, rt5514->lrck); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val_len = RT5514_I2S_DL_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val_len = RT5514_I2S_DL_24; + break; + case SNDRV_PCM_FORMAT_S8: + val_len = RT5514_I2S_DL_8; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_I2S_DL_MASK, + val_len); + regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2, + RT5514_CLK_SYS_DIV_OUT_MASK | RT5514_SEL_ADC_OSR_MASK, + pre_div << RT5514_CLK_SYS_DIV_OUT_SFT | + pre_div << RT5514_SEL_ADC_OSR_SFT); + + return 0; +} + +static int rt5514_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + + case SND_SOC_DAIFMT_NB_IF: + reg_val |= RT5514_I2S_LR_INV; + break; + + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5514_I2S_BP_INV; + break; + + case SND_SOC_DAIFMT_IB_IF: + reg_val |= RT5514_I2S_BP_INV | RT5514_I2S_LR_INV; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5514_I2S_DF_LEFT; + break; + + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5514_I2S_DF_PCM_A; + break; + + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5514_I2S_DF_PCM_B; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, + RT5514_I2S_DF_MASK | RT5514_I2S_BP_MASK | RT5514_I2S_LR_MASK, + reg_val); + + return 0; +} + +static int rt5514_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5514->sysclk && clk_id == rt5514->sysclk_src) + return 0; + + switch (clk_id) { + case RT5514_SCLK_S_MCLK: + reg_val |= RT5514_CLK_SYS_PRE_SEL_MCLK; + break; + + case RT5514_SCLK_S_PLL1: + reg_val |= RT5514_CLK_SYS_PRE_SEL_PLL; + break; + + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2, + RT5514_CLK_SYS_PRE_SEL_MASK, reg_val); + + rt5514->sysclk = freq; + rt5514->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5514_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5514->pll_in = 0; + rt5514->pll_out = 0; + regmap_update_bits(rt5514->regmap, RT5514_CLK_CTRL2, + RT5514_CLK_SYS_PRE_SEL_MASK, + RT5514_CLK_SYS_PRE_SEL_MCLK); + + return 0; + } + + if (source == rt5514->pll_src && freq_in == rt5514->pll_in && + freq_out == rt5514->pll_out) + return 0; + + switch (source) { + case RT5514_PLL1_S_MCLK: + regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, + RT5514_PLL_1_SEL_MASK, RT5514_PLL_1_SEL_MCLK); + break; + + case RT5514_PLL1_S_BCLK: + regmap_update_bits(rt5514->regmap, RT5514_PLL_SOURCE_CTRL, + RT5514_PLL_1_SEL_MASK, RT5514_PLL_1_SEL_SCLK); + break; + + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + regmap_write(rt5514->regmap, RT5514_ANA_CTRL_PLL1_1, + pll_code.k_code << RT5514_PLL_K_SFT | + pll_code.n_code << RT5514_PLL_N_SFT | + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5514_PLL_M_SFT); + regmap_update_bits(rt5514->regmap, RT5514_ANA_CTRL_PLL1_2, + RT5514_PLL_M_BP, pll_code.m_bp << RT5514_PLL_M_BP_SFT); + + rt5514->pll_in = freq_in; + rt5514->pll_out = freq_out; + rt5514->pll_src = source; + + return 0; +} + +static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= RT5514_TDM_MODE; + + if (slots == 4) + val |= RT5514_TDMSLOT_SEL_RX_4CH | RT5514_TDMSLOT_SEL_TX_4CH; + + + switch (slot_width) { + case 20: + val |= RT5514_CH_LEN_RX_20 | RT5514_CH_LEN_TX_20; + break; + + case 24: + val |= RT5514_CH_LEN_RX_24 | RT5514_CH_LEN_TX_24; + break; + + case 32: + val |= RT5514_CH_LEN_RX_32 | RT5514_CH_LEN_TX_32; + break; + + case 16: + default: + break; + } + + regmap_update_bits(rt5514->regmap, RT5514_I2S_CTRL1, RT5514_TDM_MODE | + RT5514_TDMSLOT_SEL_RX_MASK | RT5514_TDMSLOT_SEL_TX_MASK | + RT5514_CH_LEN_RX_MASK | RT5514_CH_LEN_TX_MASK, val); + + return 0; +} + +static int rt5514_probe(struct snd_soc_codec *codec) +{ + struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); + + rt5514->codec = codec; + + return 0; +} + +static int rt5514_i2c_read(void *context, unsigned int reg, unsigned int *val) +{ + struct i2c_client *client = context; + struct rt5514_priv *rt5514 = i2c_get_clientdata(client); + + regmap_read(rt5514->i2c_regmap, reg | RT5514_DSP_MAPPING, val); + + return 0; +} + +static int rt5514_i2c_write(void *context, unsigned int reg, unsigned int val) +{ + struct i2c_client *client = context; + struct rt5514_priv *rt5514 = i2c_get_clientdata(client); + + regmap_write(rt5514->i2c_regmap, reg | RT5514_DSP_MAPPING, val); + + return 0; +} + +#define RT5514_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5514_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +struct snd_soc_dai_ops rt5514_aif_dai_ops = { + .hw_params = rt5514_hw_params, + .set_fmt = rt5514_set_dai_fmt, + .set_sysclk = rt5514_set_dai_sysclk, + .set_pll = rt5514_set_dai_pll, + .set_tdm_slot = rt5514_set_tdm_slot, +}; + +struct snd_soc_dai_driver rt5514_dai[] = { + { + .name = "rt5514-aif1", + .id = 0, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT5514_STEREO_RATES, + .formats = RT5514_FORMATS, + }, + .ops = &rt5514_aif_dai_ops, + } +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5514 = { + .probe = rt5514_probe, + .idle_bias_off = true, + .controls = rt5514_snd_controls, + .num_controls = ARRAY_SIZE(rt5514_snd_controls), + .dapm_widgets = rt5514_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5514_dapm_widgets), + .dapm_routes = rt5514_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5514_dapm_routes), +}; + +static const struct regmap_config rt5514_i2c_regmap = { + .name = "i2c", + .reg_bits = 32, + .val_bits = 32, + + .max_register = RT5514_DSP_MAPPING | RT5514_VENDOR_ID2, + .readable_reg = rt5514_i2c_readable_register, + + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_config rt5514_regmap = { + .reg_bits = 16, + .val_bits = 32, + + .max_register = RT5514_VENDOR_ID2, + .volatile_reg = rt5514_volatile_register, + .readable_reg = rt5514_readable_register, + .reg_read = rt5514_i2c_read, + .reg_write = rt5514_i2c_write, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5514_reg, + .num_reg_defaults = ARRAY_SIZE(rt5514_reg), + .use_single_rw = true, +}; + +static const struct i2c_device_id rt5514_i2c_id[] = { + { "rt5514", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5514_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id rt5514_of_match[] = { + { .compatible = "realtek,rt5514", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5514_of_match); +#endif + +static int rt5514_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5514_priv *rt5514; + int ret; + unsigned int val; + + rt5514 = devm_kzalloc(&i2c->dev, sizeof(struct rt5514_priv), + GFP_KERNEL); + if (rt5514 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5514); + + rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap); + if (IS_ERR(rt5514->i2c_regmap)) { + ret = PTR_ERR(rt5514->i2c_regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + rt5514->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5514_regmap); + if (IS_ERR(rt5514->regmap)) { + ret = PTR_ERR(rt5514->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5514->regmap, RT5514_VENDOR_ID2, &val); + if (val != RT5514_DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5514\n", val); + return -ENODEV; + } + + ret = regmap_register_patch(rt5514->i2c_regmap, rt5514_i2c_patch, + ARRAY_SIZE(rt5514_i2c_patch)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n", + ret); + + ret = regmap_register_patch(rt5514->regmap, rt5514_patch, + ARRAY_SIZE(rt5514_patch)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5514, + rt5514_dai, ARRAY_SIZE(rt5514_dai)); +} + +static int rt5514_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +struct i2c_driver rt5514_i2c_driver = { + .driver = { + .name = "rt5514", + .of_match_table = of_match_ptr(rt5514_of_match), + }, + .probe = rt5514_i2c_probe, + .remove = rt5514_i2c_remove, + .id_table = rt5514_i2c_id, +}; +module_i2c_driver(rt5514_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5514 driver"); +MODULE_AUTHOR("Oder Chiou "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h new file mode 100644 index 000000000000..6ad8a612f659 --- /dev/null +++ b/sound/soc/codecs/rt5514.h @@ -0,0 +1,252 @@ +/* + * rt5514.h -- RT5514 ALSA SoC audio driver + * + * Copyright 2015 Realtek Microelectronics + * Author: Oder Chiou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5514_H__ +#define __RT5514_H__ + +#define RT5514_DEVICE_ID 0x10ec5514 + +#define RT5514_RESET 0x2000 +#define RT5514_PWR_ANA1 0x2004 +#define RT5514_PWR_ANA2 0x2008 +#define RT5514_I2S_CTRL1 0x2010 +#define RT5514_I2S_CTRL2 0x2014 +#define RT5514_VAD_CTRL6 0x2030 +#define RT5514_EXT_VAD_CTRL 0x206c +#define RT5514_DIG_IO_CTRL 0x2070 +#define RT5514_PAD_CTRL1 0x2080 +#define RT5514_DMIC_DATA_CTRL 0x20a0 +#define RT5514_DIG_SOURCE_CTRL 0x20a4 +#define RT5514_SRC_CTRL 0x20ac +#define RT5514_DOWNFILTER2_CTRL1 0x20d0 +#define RT5514_PLL_SOURCE_CTRL 0x2100 +#define RT5514_CLK_CTRL1 0x2104 +#define RT5514_CLK_CTRL2 0x2108 +#define RT5514_PLL3_CALIB_CTRL1 0x2110 +#define RT5514_PLL3_CALIB_CTRL5 0x2124 +#define RT5514_DELAY_BUF_CTRL1 0x2140 +#define RT5514_DELAY_BUF_CTRL3 0x2148 +#define RT5514_DOWNFILTER0_CTRL1 0x2190 +#define RT5514_DOWNFILTER0_CTRL2 0x2194 +#define RT5514_DOWNFILTER0_CTRL3 0x2198 +#define RT5514_DOWNFILTER1_CTRL1 0x21a0 +#define RT5514_DOWNFILTER1_CTRL2 0x21a4 +#define RT5514_DOWNFILTER1_CTRL3 0x21a8 +#define RT5514_ANA_CTRL_LDO10 0x2200 +#define RT5514_ANA_CTRL_LDO18_16 0x2204 +#define RT5514_ANA_CTRL_ADC12 0x2210 +#define RT5514_ANA_CTRL_ADC21 0x2214 +#define RT5514_ANA_CTRL_ADC22 0x2218 +#define RT5514_ANA_CTRL_ADC23 0x221c +#define RT5514_ANA_CTRL_MICBST 0x2220 +#define RT5514_ANA_CTRL_ADCFED 0x2224 +#define RT5514_ANA_CTRL_INBUF 0x2228 +#define RT5514_ANA_CTRL_VREF 0x222c +#define RT5514_ANA_CTRL_PLL3 0x2240 +#define RT5514_ANA_CTRL_PLL1_1 0x2260 +#define RT5514_ANA_CTRL_PLL1_2 0x2264 +#define RT5514_DMIC_LP_CTRL 0x2e00 +#define RT5514_MISC_CTRL_DSP 0x2e04 +#define RT5514_DSP_CTRL1 0x2f00 +#define RT5514_DSP_CTRL3 0x2f08 +#define RT5514_DSP_CTRL4 0x2f10 +#define RT5514_VENDOR_ID1 0x2ff0 +#define RT5514_VENDOR_ID2 0x2ff4 + +#define RT5514_DSP_MAPPING 0x18000000 + +/* RT5514_PWR_ANA1 (0x2004) */ +#define RT5514_POW_LDO18_IN (0x1 << 5) +#define RT5514_POW_LDO18_IN_BIT 5 +#define RT5514_POW_LDO18_ADC (0x1 << 4) +#define RT5514_POW_LDO18_ADC_BIT 4 +#define RT5514_POW_LDO21 (0x1 << 3) +#define RT5514_POW_LDO21_BIT 3 +#define RT5514_POW_BG_LDO18_IN (0x1 << 2) +#define RT5514_POW_BG_LDO18_IN_BIT 2 +#define RT5514_POW_BG_LDO21 (0x1 << 1) +#define RT5514_POW_BG_LDO21_BIT 1 + +/* RT5514_PWR_ANA2 (0x2008) */ +#define RT5514_POW_PLL1 (0x1 << 18) +#define RT5514_POW_PLL1_BIT 18 +#define RT5514_POW_PLL1_LDO (0x1 << 16) +#define RT5514_POW_PLL1_LDO_BIT 16 +#define RT5514_POW_BG_MBIAS (0x1 << 15) +#define RT5514_POW_BG_MBIAS_BIT 15 +#define RT5514_POW_MBIAS (0x1 << 14) +#define RT5514_POW_MBIAS_BIT 14 +#define RT5514_POW_VREF2 (0x1 << 13) +#define RT5514_POW_VREF2_BIT 13 +#define RT5514_POW_VREF1 (0x1 << 12) +#define RT5514_POW_VREF1_BIT 12 +#define RT5514_POWR_LDO16 (0x1 << 11) +#define RT5514_POWR_LDO16_BIT 11 +#define RT5514_POWL_LDO16 (0x1 << 10) +#define RT5514_POWL_LDO16_BIT 10 +#define RT5514_POW_ADC2 (0x1 << 9) +#define RT5514_POW_ADC2_BIT 9 +#define RT5514_POW_INPUT_BUF (0x1 << 8) +#define RT5514_POW_INPUT_BUF_BIT 8 +#define RT5514_POW_ADC1_R (0x1 << 7) +#define RT5514_POW_ADC1_R_BIT 7 +#define RT5514_POW_ADC1_L (0x1 << 6) +#define RT5514_POW_ADC1_L_BIT 6 +#define RT5514_POW2_BSTR (0x1 << 5) +#define RT5514_POW2_BSTR_BIT 5 +#define RT5514_POW2_BSTL (0x1 << 4) +#define RT5514_POW2_BSTL_BIT 4 +#define RT5514_POW_BSTR (0x1 << 3) +#define RT5514_POW_BSTR_BIT 3 +#define RT5514_POW_BSTL (0x1 << 2) +#define RT5514_POW_BSTL_BIT 2 +#define RT5514_POW_ADCFEDR (0x1 << 1) +#define RT5514_POW_ADCFEDR_BIT 1 +#define RT5514_POW_ADCFEDL (0x1 << 0) +#define RT5514_POW_ADCFEDL_BIT 0 + +/* RT5514_I2S_CTRL1 (0x2010) */ +#define RT5514_TDM_MODE (0x1 << 28) +#define RT5514_TDM_MODE_SFT 28 +#define RT5514_I2S_LR_MASK (0x1 << 26) +#define RT5514_I2S_LR_SFT 26 +#define RT5514_I2S_LR_NOR (0x0 << 26) +#define RT5514_I2S_LR_INV (0x1 << 26) +#define RT5514_I2S_BP_MASK (0x1 << 25) +#define RT5514_I2S_BP_SFT 25 +#define RT5514_I2S_BP_NOR (0x0 << 25) +#define RT5514_I2S_BP_INV (0x1 << 25) +#define RT5514_I2S_DF_MASK (0x7 << 16) +#define RT5514_I2S_DF_SFT 16 +#define RT5514_I2S_DF_I2S (0x0 << 16) +#define RT5514_I2S_DF_LEFT (0x1 << 16) +#define RT5514_I2S_DF_PCM_A (0x2 << 16) +#define RT5514_I2S_DF_PCM_B (0x3 << 16) +#define RT5514_TDMSLOT_SEL_RX_MASK (0x3 << 10) +#define RT5514_TDMSLOT_SEL_RX_SFT 10 +#define RT5514_TDMSLOT_SEL_RX_4CH (0x1 << 10) +#define RT5514_CH_LEN_RX_MASK (0x3 << 8) +#define RT5514_CH_LEN_RX_SFT 8 +#define RT5514_CH_LEN_RX_16 (0x0 << 8) +#define RT5514_CH_LEN_RX_20 (0x1 << 8) +#define RT5514_CH_LEN_RX_24 (0x2 << 8) +#define RT5514_CH_LEN_RX_32 (0x3 << 8) +#define RT5514_TDMSLOT_SEL_TX_MASK (0x3 << 6) +#define RT5514_TDMSLOT_SEL_TX_SFT 6 +#define RT5514_TDMSLOT_SEL_TX_4CH (0x1 << 6) +#define RT5514_CH_LEN_TX_MASK (0x3 << 4) +#define RT5514_CH_LEN_TX_SFT 4 +#define RT5514_CH_LEN_TX_16 (0x0 << 4) +#define RT5514_CH_LEN_TX_20 (0x1 << 4) +#define RT5514_CH_LEN_TX_24 (0x2 << 4) +#define RT5514_CH_LEN_TX_32 (0x3 << 4) +#define RT5514_I2S_DL_MASK (0x3 << 0) +#define RT5514_I2S_DL_SFT 0 +#define RT5514_I2S_DL_16 (0x0 << 0) +#define RT5514_I2S_DL_20 (0x1 << 0) +#define RT5514_I2S_DL_24 (0x2 << 0) +#define RT5514_I2S_DL_8 (0x3 << 0) + +/* RT5514_DIG_SOURCE_CTRL (0x20a4) */ +#define RT5514_AD1_DMIC_INPUT_SEL (0x1 << 1) +#define RT5514_AD1_DMIC_INPUT_SEL_SFT 1 +#define RT5514_AD0_DMIC_INPUT_SEL (0x1 << 0) +#define RT5514_AD0_DMIC_INPUT_SEL_SFT 0 + +/* RT5514_PLL_SOURCE_CTRL (0x2100) */ +#define RT5514_PLL_1_SEL_MASK (0x7 << 12) +#define RT5514_PLL_1_SEL_SFT 12 +#define RT5514_PLL_1_SEL_SCLK (0x3 << 12) +#define RT5514_PLL_1_SEL_MCLK (0x4 << 12) + +/* RT5514_CLK_CTRL1 (0x2104) */ +#define RT5514_CLK_AD_ANA1_EN (0x1 << 31) +#define RT5514_CLK_AD_ANA1_EN_BIT 31 +#define RT5514_CLK_AD1_EN (0x1 << 24) +#define RT5514_CLK_AD1_EN_BIT 24 +#define RT5514_CLK_AD0_EN (0x1 << 23) +#define RT5514_CLK_AD0_EN_BIT 23 +#define RT5514_CLK_DMIC_OUT_SEL_MASK (0x7 << 8) +#define RT5514_CLK_DMIC_OUT_SEL_SFT 8 + +/* RT5514_CLK_CTRL2 (0x2108) */ +#define RT5514_CLK_SYS_DIV_OUT_MASK (0x7 << 8) +#define RT5514_CLK_SYS_DIV_OUT_SFT 8 +#define RT5514_SEL_ADC_OSR_MASK (0x7 << 4) +#define RT5514_SEL_ADC_OSR_SFT 4 +#define RT5514_CLK_SYS_PRE_SEL_MASK (0x3 << 0) +#define RT5514_CLK_SYS_PRE_SEL_SFT 0 +#define RT5514_CLK_SYS_PRE_SEL_MCLK (0x2 << 0) +#define RT5514_CLK_SYS_PRE_SEL_PLL (0x3 << 0) + +/* RT5514_DOWNFILTER_CTRL (0x2190 0x2194 0x21a0 0x21a4) */ +#define RT5514_AD_DMIC_MIX (0x1 << 11) +#define RT5514_AD_DMIC_MIX_BIT 11 +#define RT5514_AD_AD_MIX (0x1 << 10) +#define RT5514_AD_AD_MIX_BIT 10 +#define RT5514_AD_AD_MUTE (0x1 << 7) +#define RT5514_AD_AD_MUTE_BIT 7 +#define RT5514_AD_GAIN_MASK (0x7f << 0) +#define RT5514_AD_GAIN_SFT 0 + +/* RT5514_ANA_CTRL_MICBST (0x2220) */ +#define RT5514_SEL_BSTL_MASK (0xf << 4) +#define RT5514_SEL_BSTL_SFT 4 +#define RT5514_SEL_BSTR_MASK (0xf << 0) +#define RT5514_SEL_BSTR_SFT 0 + +/* RT5514_ANA_CTRL_PLL1_1 (0x2260) */ +#define RT5514_PLL_K_MAX 0x1f +#define RT5514_PLL_K_MASK (RT5514_PLL_K_MAX << 16) +#define RT5514_PLL_K_SFT 16 +#define RT5514_PLL_N_MAX 0x1ff +#define RT5514_PLL_N_MASK (RT5514_PLL_N_MAX << 7) +#define RT5514_PLL_N_SFT 4 +#define RT5514_PLL_M_MAX 0xf +#define RT5514_PLL_M_MASK (RT5514_PLL_M_MAX << 0) +#define RT5514_PLL_M_SFT 0 + +/* RT5514_ANA_CTRL_PLL1_2 (0x2264) */ +#define RT5514_PLL_M_BP (0x1 << 2) +#define RT5514_PLL_M_BP_SFT 2 +#define RT5514_PLL_K_BP (0x1 << 1) +#define RT5514_PLL_K_BP_SFT 1 +#define RT5514_EN_LDO_PLL1 (0x1 << 0) +#define RT5514_EN_LDO_PLL1_BIT 0 + +#define RT5514_PLL_INP_MAX 40000000 +#define RT5514_PLL_INP_MIN 256000 + +/* System Clock Source */ +enum { + RT5514_SCLK_S_MCLK, + RT5514_SCLK_S_PLL1, +}; + +/* PLL1 Source */ +enum { + RT5514_PLL1_S_MCLK, + RT5514_PLL1_S_BCLK, +}; + +struct rt5514_priv { + struct snd_soc_codec *codec; + struct regmap *i2c_regmap, *regmap; + int sysclk; + int sysclk_src; + int lrck; + int bclk; + int pll_src; + int pll_in; + int pll_out; +}; + +#endif /* __RT5514_H__ */ -- cgit v1.2.3 From 089dfaf7f7f9b18e3dffb6d9ee8b37089025b952 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sat, 30 Jan 2016 23:07:00 -0800 Subject: ASoC: fsl-asoc-card: Don't add DAPM routes for ASRC if it doesn't exist There are a pair of warnings when ASRC is absent in the DTB: fsl-asoc-card sound: ASoC: no source widget found for ASRC-Playback fsl-asoc-card sound: ASoC: Failed to add route ASRC-Playback -> direct -> CPU-Playback fsl-asoc-card sound: ASoC: no sink widget found for ASRC-Capture fsl-asoc-card sound: ASoC: Failed to add route CPU-Capture -> direct -> ASRC-Capture This is because the driver is still trying to add DAPM routes for ASRC even if it doesn't exist on that platform. The warnings are harmless but it might be annoying. So this patch drops the DAPM routes of ASRC when it's absent in the DAI link. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 562b3bd22d9a..3d40797e3bcc 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -99,19 +99,26 @@ struct fsl_asoc_card_priv { /** * This dapm route map exsits for DPCM link only. * The other routes shall go through Device Tree. + * + * Note: keep all ASRC routes in the second half + * to drop them easily for non-ASRC cases. */ static const struct snd_soc_dapm_route audio_map[] = { - {"CPU-Playback", NULL, "ASRC-Playback"}, + /* 1st half -- Normal DAPM routes */ {"Playback", NULL, "CPU-Playback"}, - {"ASRC-Capture", NULL, "CPU-Capture"}, {"CPU-Capture", NULL, "Capture"}, + /* 2nd half -- ASRC DAPM routes */ + {"CPU-Playback", NULL, "ASRC-Playback"}, + {"ASRC-Capture", NULL, "CPU-Capture"}, }; static const struct snd_soc_dapm_route audio_map_ac97[] = { - {"AC97 Playback", NULL, "ASRC-Playback"}, + /* 1st half -- Normal DAPM routes */ {"Playback", NULL, "AC97 Playback"}, - {"ASRC-Capture", NULL, "AC97 Capture"}, {"AC97 Capture", NULL, "Capture"}, + /* 2nd half -- ASRC DAPM routes */ + {"AC97 Playback", NULL, "ASRC-Playback"}, + {"ASRC-Capture", NULL, "AC97 Capture"}, }; /* Add all possible widgets into here without being redundant */ @@ -593,6 +600,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets); + /* Drop the second half of DAPM routes -- ASRC */ + if (!asrc_pdev) + priv->card.num_dapm_routes /= 2; + memcpy(priv->dai_link, fsl_asoc_card_dai, sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); -- cgit v1.2.3 From 1f1e60c9cdd573be271130e44a23efed48e0578d Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Tue, 24 Nov 2015 10:18:27 +0800 Subject: ASoC: cs42xx8: fix the noise in the right dac channel with mono playback When playback mono wav with record in background, there will be some nosie in the right dac channel. It seems that the ADC data has been routed to the dac channel. The cs42888 have 8 dac channels, it's appropriate to mute the unused dac channels, and the noise will disappear. Steps to reproduce this issue: arecord -D hw:0,0 -f S16_LE -r 48000 -c 1 a.wav & aplay -Dhw:0,0 audio48k16M.wav Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index d562e1b9a5d1..1179101b2b05 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -44,6 +44,7 @@ struct cs42xx8_priv { bool slave_mode; unsigned long sysclk; + u32 tx_channels; }; /* -127.5dB to 0dB with step of 0.5dB */ @@ -257,6 +258,9 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, u32 ratio = cs42xx8->sysclk / params_rate(params); u32 i, fm, val, mask; + if (tx) + cs42xx8->tx_channels = params_channels(params); + for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { if (cs42xx8_ratios[i].ratio == ratio) break; @@ -283,9 +287,11 @@ static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); + u8 dac_unmute = cs42xx8->tx_channels ? + ~((0x1 << cs42xx8->tx_channels) - 1) : 0; - regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE, - CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0); + regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, + mute ? CS42XX8_DACMUTE_ALL : dac_unmute); return 0; } -- cgit v1.2.3 From d81221ff9406a3918084bfaed752894e82c5d44b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 4 Feb 2016 16:29:01 +0000 Subject: ASoC: arizona: Add support for SNDRV_PCM_RATE_KNOT The Arizona CODECs support several rates that do not have simple defines in ALSA. This patch adds support for SNDRV_PCM_RATE_KNOT so that users can open stream at these rates. As part of this we should always set constraints in arizona_startup, currently we only set the constraints if we already have a clock to limit rates to that family of sample rates. This patch updates this to set a constraint of all rates supported by the chip if we do not already know which family of rates to limit to. Finally we also reduce the list of rates supported in the constraints to only include those that are supported on current parts. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 62 ++++++++++++---------------------------------- sound/soc/codecs/arizona.h | 2 ++ sound/soc/codecs/cs47l24.c | 2 +- sound/soc/codecs/wm5102.c | 2 +- sound/soc/codecs/wm5110.c | 2 +- sound/soc/codecs/wm8997.c | 2 +- sound/soc/codecs/wm8998.c | 2 +- 7 files changed, 23 insertions(+), 51 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 33143fe1de0b..a32cfb85f1ca 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1398,29 +1398,6 @@ static const int arizona_48k_bclk_rates[] = { 24576000, }; -static const unsigned int arizona_48k_rates[] = { - 12000, - 24000, - 48000, - 96000, - 192000, - 384000, - 768000, - 4000, - 8000, - 16000, - 32000, - 64000, - 128000, - 256000, - 512000, -}; - -static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = { - .count = ARRAY_SIZE(arizona_48k_rates), - .list = arizona_48k_rates, -}; - static const int arizona_44k1_bclk_rates[] = { -1, 44100, @@ -1443,22 +1420,7 @@ static const int arizona_44k1_bclk_rates[] = { 22579200, }; -static const unsigned int arizona_44k1_rates[] = { - 11025, - 22050, - 44100, - 88200, - 176400, - 352800, - 705600, -}; - -static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = { - .count = ARRAY_SIZE(arizona_44k1_rates), - .list = arizona_44k1_rates, -}; - -static int arizona_sr_vals[] = { +static const unsigned int arizona_sr_vals[] = { 0, 12000, 24000, @@ -1485,13 +1447,21 @@ static int arizona_sr_vals[] = { 512000, }; +#define ARIZONA_48K_RATE_MASK 0x0F003E +#define ARIZONA_44K1_RATE_MASK 0x003E00 +#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK) + +static const struct snd_pcm_hw_constraint_list arizona_constraint = { + .count = ARRAY_SIZE(arizona_sr_vals), + .list = arizona_sr_vals, +}; + static int arizona_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; - const struct snd_pcm_hw_constraint_list *constraint; unsigned int base_rate; if (!substream->runtime) @@ -1509,16 +1479,15 @@ static int arizona_startup(struct snd_pcm_substream *substream, } if (base_rate == 0) - return 0; - - if (base_rate % 8000) - constraint = &arizona_44k1_constraint; + dai_priv->constraint.mask = ARIZONA_RATE_MASK; + else if (base_rate % 8000) + dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK; else - constraint = &arizona_48k_constraint; + dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK; return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - constraint); + &dai_priv->constraint); } static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, @@ -1911,6 +1880,7 @@ int arizona_init_dai(struct arizona_priv *priv, int id) struct arizona_dai_priv *dai_priv = &priv->dai[id]; dai_priv->clk = ARIZONA_CLK_SYSCLK; + dai_priv->constraint = arizona_constraint; return 0; } diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 0c64a5731513..1ea8e4ecf8d4 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -68,6 +68,8 @@ struct wm_adsp; struct arizona_dai_priv { int clk; + + struct snd_pcm_hw_constraint_list constraint; }; struct arizona_priv { diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index b8d3cd031d7d..576087bda330 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -923,7 +923,7 @@ static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source, } } -#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000 +#define CS47L24_RATES SNDRV_PCM_RATE_KNOT #define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index aa1e96ab4bd2..a8b3e3f701f9 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1738,7 +1738,7 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, } } -#define WM5102_RATES SNDRV_PCM_RATE_8000_192000 +#define WM5102_RATES SNDRV_PCM_RATE_KNOT #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 92b6a6a564df..aa47955b68af 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2024,7 +2024,7 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, } } -#define WM5110_RATES SNDRV_PCM_RATE_8000_192000 +#define WM5110_RATES SNDRV_PCM_RATE_KNOT #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index b4dba3a02aba..52d766efe14f 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -943,7 +943,7 @@ static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source, } } -#define WM8997_RATES SNDRV_PCM_RATE_8000_192000 +#define WM8997_RATES SNDRV_PCM_RATE_KNOT #define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 7719bc509e50..012396074a8a 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1170,7 +1170,7 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = { { "DRC1 Signal Activity", NULL, "DRC1R" }, }; -#define WM8998_RATES SNDRV_PCM_RATE_8000_192000 +#define WM8998_RATES SNDRV_PCM_RATE_KNOT #define WM8998_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -- cgit v1.2.3 From 27d6e7d1c96c9f51379e0feb972fec26029098bc Mon Sep 17 00:00:00 2001 From: Andreas IrestÃ¥l Date: Thu, 4 Feb 2016 15:05:19 +0100 Subject: ASoC: adau17x1: Cache writes when core clock is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some configurations, the dai registers get written before the bias level is changed in the codec driver. This leads to a situation where an initial write to the serial port register gets ignored, and future writes may as well, since regmap thinks that the codec already holds the value. More specifically, configuring the codec as i2s master would in fact result in the codec running as slave, a situation where no i2s clocks are generated and hence no data is transferred. This change makes sure that regmap only caches writes when the core clock is disabled, and syncs regmap whenever enabling the core clock again. Signed-off-by: Andreas IrestÃ¥l Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 2f12477e539e..e7136b1956a3 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -456,13 +456,17 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: + regcache_cache_only(adau->regmap, false); regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, ADAU17X1_CLOCK_CONTROL_SYSCLK_EN); + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) + regcache_sync(adau->regmap); break; case SND_SOC_BIAS_OFF: regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL, ADAU17X1_CLOCK_CONTROL_SYSCLK_EN, 0); + regcache_cache_only(adau->regmap, true); break; } @@ -783,6 +787,10 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; + /* Enable cache only mode as we could miss writes before bias level + * reaches standby and the core clock is enabled */ + regcache_cache_only(regmap, true); + return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); } EXPORT_SYMBOL_GPL(adau1761_probe); -- cgit v1.2.3 From 436e056c4ba368f13a5709a5a4a7f26fc238a5a6 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Wed, 3 Feb 2016 13:18:20 +0000 Subject: ASoC: mxs-saif: check BUSY bit in hw_params() only if not mclk_in_use If something else, typically a codec, has enabled mclk, the BUSY bit may be set when hw_params() is called without this being an error. This check thus causes intermittent failures to configure the sound device when used in such a manner. Fix this by making the test conditional on !saif->mclk_in_use. Signed-off-by: Mans Rullgard Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index c866ade28ad0..cd04eb7ee753 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -408,7 +408,7 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, } stat = __raw_readl(saif->base + SAIF_STAT); - if (stat & BM_SAIF_STAT_BUSY) { + if (!saif->mclk_in_use && (stat & BM_SAIF_STAT_BUSY)) { dev_err(cpu_dai->dev, "error: busy\n"); return -EBUSY; } -- cgit v1.2.3 From 57e756d30268a0373cce97165bd57331554f4bfd Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Fri, 29 Jan 2016 11:01:00 +0000 Subject: ASoC: fsl-asoc-card: add cs4271 and cs4272 support add cs4271 and cs42727 support for fsl-asoc-card Signed-off-by: Felipe F. Tonello Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-asoc-card.txt | 9 +++++++++ sound/soc/fsl/Kconfig | 4 ++-- sound/soc/fsl/fsl-asoc-card.c | 7 +++++++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt index ce55c0a6f757..943b36d1b81b 100644 --- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt @@ -24,6 +24,9 @@ The compatible list for this generic sound card currently: "fsl,imx-audio-cs42888" + "fsl,imx-audio-cs427x" + (compatible with CS4271 and CS4272) + "fsl,imx-audio-wm8962" (compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt) @@ -61,6 +64,12 @@ Optional properties: - audio-asrc : The phandle of ASRC. It can be absent if there's no need to add ASRC support via DPCM. +Optional unless SSI is selected as a CPU DAI: + + - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) + + - mux-ext-port : The external port of the i.MX audio muxer + Example: sound-cs42888 { compatible = "fsl,imx-audio-cs42888"; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 14dfdee05fd5..35aabf9dc503 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -292,8 +292,8 @@ config SND_SOC_FSL_ASOC_CARD select SND_SOC_FSL_SSI help ALSA SoC Audio support with ASRC feature for Freescale SoCs that have - ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 - and SGTL5000. + ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888, + CS4271, CS4272 and SGTL5000. Say Y if you want to add support for Freescale Generic ASoC Sound Card. endif # SND_IMX_SOC diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 3d40797e3bcc..dffd549a0e2a 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -28,6 +28,8 @@ #include "../codecs/wm8962.h" #include "../codecs/wm8960.h" +#define CS427x_SYSCLK_MCLK 0 + #define RX 0 #define TX 1 @@ -535,6 +537,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.slot_width = 32; priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) { + codec_dai_name = "cs4271-hifi"; + priv->codec_priv.mclk_id = CS427x_SYSCLK_MCLK; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { codec_dai_name = "sgtl5000"; priv->codec_priv.mclk_id = SGTL5000_SYSCLK; @@ -692,6 +698,7 @@ fail: static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-ac97", }, { .compatible = "fsl,imx-audio-cs42888", }, + { .compatible = "fsl,imx-audio-cs427x", }, { .compatible = "fsl,imx-audio-sgtl5000", }, { .compatible = "fsl,imx-audio-wm8962", }, { .compatible = "fsl,imx-audio-wm8960", }, -- cgit v1.2.3 From 33420d66354134b9369d0984a6ca418752c781a6 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 5 Feb 2016 12:19:04 +0530 Subject: ASoC: Intel: Skylake: Update the delay check Delay check was using ternary operator, it can be simplified to simple if condition, so update it Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index b6e6b61d10ec..cc9a5599ab9d 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -863,7 +863,9 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, else delay += hstream->bufsize; } - delay = (hstream->bufsize == delay) ? 0 : delay; + + if (hstream->bufsize == delay) + delay = 0; if (delay >= hstream->period_bytes) { dev_info(bus->dev, -- cgit v1.2.3 From 4fdf810fc5c82f57aa7c54ac9384f1201087724a Mon Sep 17 00:00:00 2001 From: "Dharageswari.R" Date: Fri, 5 Feb 2016 12:19:05 +0530 Subject: ASoC: Intel: Skylake: Get node id using helper skl_setup_cpr_gateway_cfg() retrieves gateway settings which are required for copier module configuration. For upcoming DMA control IPC we need similar retrieval, so separate this piece into skl_get_node_id() helper which will be common for these functions Signed-off-by: Dharageswari R Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 4629372d7c8e..60f9fe389887 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -238,9 +238,8 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, * Calculate the gatewat settings required for copier module, type of * gateway and index of gateway to use */ -static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, - struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) +static u32 skl_get_node_id(struct skl_sst *ctx, + struct skl_module_cfg *mconfig) { union skl_connector_node_id node_id = {0}; union skl_ssp_dma_node ssp_node = {0}; @@ -289,13 +288,24 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, break; default: - cpr_mconfig->gtw_cfg.node_id = SKL_NON_GATEWAY_CPR_NODE_ID; + node_id.val = 0xFFFFFFFF; + break; + } + + return node_id.val; +} + +static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_cpr_cfg *cpr_mconfig) +{ + cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); + + if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { cpr_mconfig->cpr_feature_mask = 0; return; } - cpr_mconfig->gtw_cfg.node_id = node_id.val; - if (SKL_CONN_SOURCE == mconfig->hw_conn_type) cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs; else -- cgit v1.2.3 From 718a42b5eaddb3180e2589590732d61e047858fb Mon Sep 17 00:00:00 2001 From: "Dharageswari.R" Date: Fri, 5 Feb 2016 12:19:06 +0530 Subject: ASoC: Intel: Skylake: Add skl_tplg_be_get_cpr_module() helper An I2S port can be connected to multiple BE pipes, get module config only for the active BE pipe. This helpers helps to do that and is used in subsequent patches Signed-off-by: Dharageswari R Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 60 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 2 ++ 2 files changed, 62 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index a294fee431f0..5c8661450349 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1091,6 +1091,66 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) return NULL; } +static struct skl_module_cfg *skl_get_mconfig_pb_cpr( + struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p; + struct skl_module_cfg *mconfig = NULL; + + snd_soc_dapm_widget_for_each_source_path(w, p) { + if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { + if (p->connect && + (p->sink->id == snd_soc_dapm_aif_out) && + p->source->priv) { + mconfig = p->source->priv; + return mconfig; + } + mconfig = skl_get_mconfig_pb_cpr(dai, p->source); + if (mconfig) + return mconfig; + } + } + return mconfig; +} + +static struct skl_module_cfg *skl_get_mconfig_cap_cpr( + struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p; + struct skl_module_cfg *mconfig = NULL; + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { + if (p->connect && + (p->source->id == snd_soc_dapm_aif_in) && + p->sink->priv) { + mconfig = p->sink->priv; + return mconfig; + } + mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); + if (mconfig) + return mconfig; + } + } + return mconfig; +} + +struct skl_module_cfg * +skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) +{ + struct snd_soc_dapm_widget *w; + struct skl_module_cfg *mconfig; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + w = dai->playback_widget; + mconfig = skl_get_mconfig_pb_cpr(dai, w); + } else { + w = dai->capture_widget; + mconfig = skl_get_mconfig_cap_cpr(dai, w); + } + return mconfig; +} + static u8 skl_tplg_be_link_type(int dev_type) { int ret; diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 9aa2a2b6598a..5f0707cf1f54 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -345,5 +345,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); +struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, + int stream); enum skl_bitdepth skl_get_bit_depth(int params); #endif -- cgit v1.2.3 From c115fa5ec06a647c5aeff95d73e56d488145ec2e Mon Sep 17 00:00:00 2001 From: "Dharageswari.R" Date: Fri, 5 Feb 2016 12:19:07 +0530 Subject: ASoC: Intel: Skylake: Add MCLK configuration The SoC has MCLK output which is typically required by codecs. The MCLK is controlled by DSP FW, so driver can configure that by sending DMA_CONTROL IPC. The configuration for MCLK is present in the endpoint blob. So if block has this configuration, send IPC to DSP for MCLK configuration. This is done by new function skl_dsp_set_dma_control() which is invoked by BE prepare. Signed-off-by: Dharageswari R Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 40 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-pcm.c | 18 +++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 25 +++++++++++++++++++++ 3 files changed, 83 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 60f9fe389887..737934cc620d 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -317,6 +317,46 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, skl_copy_copier_caps(mconfig, cpr_mconfig); } +#define DMA_CONTROL_ID 5 + +int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +{ + struct skl_dma_control *dma_ctrl; + struct skl_i2s_config_blob config_blob; + struct skl_ipc_large_config_msg msg = {0}; + int err = 0; + + + /* + * if blob size is same as capablity size, then no dma control + * present so return + */ + if (mconfig->formats_config.caps_size == sizeof(config_blob)) + return 0; + + msg.large_param_id = DMA_CONTROL_ID; + msg.param_data_size = sizeof(struct skl_dma_control) + + mconfig->formats_config.caps_size; + + dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL); + if (dma_ctrl == NULL) + return -ENOMEM; + + dma_ctrl->node_id = skl_get_node_id(ctx, mconfig); + + /* size in dwords */ + dma_ctrl->config_length = sizeof(config_blob) / 4; + + memcpy(dma_ctrl->config_data, mconfig->formats_config.caps, + mconfig->formats_config.caps_size); + + err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl); + + kfree(dma_ctrl); + + return err; +} + static void skl_setup_out_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_audio_data_format *out_fmt) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index cc9a5599ab9d..092450ac1c78 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -206,6 +206,23 @@ static int skl_get_format(struct snd_pcm_substream *substream, return format_val; } +static int skl_be_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct skl *skl = get_skl_ctx(dai->dev); + struct skl_sst *ctx = skl->skl_sst; + struct skl_module_cfg *mconfig; + + if ((dai->playback_active > 1) || (dai->capture_active > 1)) + return 0; + + mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); + if (mconfig == NULL) + return -EINVAL; + + return skl_dsp_set_dma_control(ctx, mconfig); +} + static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -588,6 +605,7 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = { static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { .hw_params = skl_be_hw_params, + .prepare = skl_be_prepare, }; static struct snd_soc_dai_ops skl_link_dai_ops = { diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 5f0707cf1f54..de3c401284d9 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -113,6 +113,29 @@ struct skl_cpr_gtw_cfg { u32 config_data[1]; } __packed; +struct skl_i2s_config_blob { + u32 gateway_attrib; + u32 tdm_ts_group[8]; + u32 ssc0; + u32 ssc1; + u32 sscto; + u32 sspsp; + u32 sstsa; + u32 ssrsa; + u32 ssc2; + u32 sspsp2; + u32 ssc3; + u32 ssioc; + u32 mdivc; + u32 mdivr; +} __packed; + +struct skl_dma_control { + u32 node_id; + u32 config_length; + u32 config_data[1]; +} __packed; + struct skl_cpr_cfg { struct skl_base_cfg base_cfg; struct skl_audio_data_format out_fmt; @@ -313,6 +336,8 @@ static inline struct skl *get_skl_ctx(struct device *dev) int skl_tplg_be_update_params(struct snd_soc_dai *dai, struct skl_pipe_params *params); +int skl_dsp_set_dma_control(struct skl_sst *ctx, + struct skl_module_cfg *mconfig); void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai, struct skl_pipe_params *params, int stream); int skl_tplg_init(struct snd_soc_platform *platform, -- cgit v1.2.3 From cc6a4044bdeeb7a7769b7aedf9afe9e1464aadf0 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 5 Feb 2016 12:19:08 +0530 Subject: ASoC: Intel: Skylake: Allow module parameter set after bind Some modules require params to be set after the module is bound to all the pins connected. The module provider initializes set_param flag for such modules and we send params after binding. This is done by the function skl_tplg_set_module_bind_params() Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 72 ++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-tplg-interface.h | 3 +- 2 files changed, 74 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 5c8661450349..a7be03665dd4 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -545,6 +545,66 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } +/* + * Some modules require params to be set after the module is bound to + * all pins connected. + * + * The module provider initializes set_param flag for such modules and we + * send params after binding + */ +static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, + struct skl_module_cfg *mcfg, struct skl_sst *ctx) +{ + int i, ret; + struct skl_module_cfg *mconfig = w->priv; + const struct snd_kcontrol_new *k; + struct soc_bytes_ext *sb; + struct skl_algo_data *bc; + struct skl_specific_cfg *sp_cfg; + + /* + * check all out/in pins are in bind state. + * if so set the module param + */ + for (i = 0; i < mcfg->max_out_queue; i++) { + if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) + return 0; + } + + for (i = 0; i < mcfg->max_in_queue; i++) { + if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) + return 0; + } + + if (mconfig->formats_config.caps_size > 0 && + mconfig->formats_config.set_params == SKL_PARAM_BIND) { + sp_cfg = &mconfig->formats_config; + ret = skl_set_module_params(ctx, sp_cfg->caps, + sp_cfg->caps_size, + sp_cfg->param_id, mconfig); + if (ret < 0) + return ret; + } + + for (i = 0; i < w->num_kcontrols; i++) { + k = &w->kcontrol_news[i]; + if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (void *) k->private_value; + bc = (struct skl_algo_data *)sb->dobj.private; + + if (bc->set_params == SKL_PARAM_BIND) { + ret = skl_set_module_params(ctx, + (u32 *)bc->params, bc->max, + bc->param_id, mconfig); + if (ret < 0) + return ret; + } + } + } + + return 0; +} + static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, struct skl *skl, struct snd_soc_dapm_widget *src_w, @@ -579,11 +639,19 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, sink = p->sink; sink_mconfig = sink->priv; + if (src_mconfig->m_state == SKL_MODULE_UNINIT || + sink_mconfig->m_state == SKL_MODULE_UNINIT) + continue; + /* Bind source to sink, mixin is always source */ ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); if (ret) return ret; + /* set module params after bind */ + skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx); + skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + /* Start sinks pipe first */ if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { if (sink_mconfig->pipe->conn_type != @@ -714,6 +782,10 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, if (ret) return ret; + /* set module params after bind */ + skl_tplg_set_module_bind_params(source, src_mconfig, ctx); + skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) ret = skl_run_pipe(ctx, sink_mconfig->pipe); } diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index c9ae010b3cc8..1db88a63ac17 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -144,7 +144,8 @@ enum module_pin_type { enum skl_module_param_type { SKL_PARAM_DEFAULT = 0, SKL_PARAM_INIT, - SKL_PARAM_SET + SKL_PARAM_SET, + SKL_PARAM_BIND }; struct skl_dfw_module_pin { -- cgit v1.2.3 From c5a76a246989c8155d372142089ccfc9dc022388 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 5 Feb 2016 12:19:09 +0530 Subject: ASoC: Intel: Skylake: Add shutdown callback While going to shutdown, we need to bring HW to clean state. This is done by cleaning up stream descriptor registers. This cleanup is already done by decoupling of stream and stopping the chip, so invoke these from shutdown handler. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 092705e73db4..06f4b2c13423 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -634,6 +634,31 @@ out_free: return err; } +static void skl_shutdown(struct pci_dev *pci) +{ + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_stream *s; + struct hdac_ext_stream *stream; + struct skl *skl; + + if (ebus == NULL) + return; + + skl = ebus_to_skl(ebus); + + if (skl->init_failed) + return; + + snd_hdac_ext_stop_streams(ebus); + list_for_each_entry(s, &bus->stream_list, list) { + stream = stream_to_hdac_ext_stream(s); + snd_hdac_ext_stream_decouple(ebus, stream, false); + } + + snd_hdac_bus_stop_chip(bus); +} + static void skl_remove(struct pci_dev *pci) { struct hdac_ext_bus *ebus = pci_get_drvdata(pci); @@ -677,6 +702,7 @@ static struct pci_driver skl_driver = { .id_table = skl_ids, .probe = skl_probe, .remove = skl_remove, + .shutdown = skl_shutdown, .driver = { .pm = &skl_pm, }, -- cgit v1.2.3 From 2d1419a329e7de825c03738ad2ac532153239388 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 5 Feb 2016 12:19:10 +0530 Subject: ASoC: Intel: Skylake: Fill BE blob with default params When we have a path that connects to DSP sink and source, we need to query the blob using the default params. So add a function to query the params for such path Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index a7be03665dd4..216d7a8e5680 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -260,6 +260,64 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, multiplier; } +static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, + struct skl_sst *ctx) +{ + struct skl_module_cfg *m_cfg = w->priv; + int link_type, dir; + u32 ch, s_freq, s_fmt; + struct nhlt_specific_cfg *cfg; + struct skl *skl = get_skl_ctx(ctx->dev); + + /* check if we already have blob */ + if (m_cfg->formats_config.caps_size > 0) + return 0; + + switch (m_cfg->dev_type) { + case SKL_DEVICE_DMIC: + link_type = NHLT_LINK_DMIC; + dir = 1; + s_freq = m_cfg->in_fmt[0].s_freq; + s_fmt = m_cfg->in_fmt[0].bit_depth; + ch = m_cfg->in_fmt[0].channels; + break; + + case SKL_DEVICE_I2S: + link_type = NHLT_LINK_SSP; + if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { + dir = 1; + s_freq = m_cfg->in_fmt[0].s_freq; + s_fmt = m_cfg->in_fmt[0].bit_depth; + ch = m_cfg->in_fmt[0].channels; + } else { + dir = 0; + s_freq = m_cfg->out_fmt[0].s_freq; + s_fmt = m_cfg->out_fmt[0].bit_depth; + ch = m_cfg->out_fmt[0].channels; + } + break; + + default: + return -EINVAL; + } + + /* update the blob based on virtual bus_id and default params */ + cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type, + s_fmt, ch, s_freq, dir); + if (cfg) { + m_cfg->formats_config.caps_size = cfg->size; + m_cfg->formats_config.caps = (u32 *) &cfg->caps; + } else { + dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", + m_cfg->vbus_id, link_type, dir); + dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", + ch, s_freq, s_fmt); + return -EIO; + } + + return 0; +} + static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, struct skl_sst *ctx) { @@ -433,6 +491,9 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) return ret; } + /* update blob if blob is null for be with default value */ + skl_tplg_update_be_blob(w, ctx); + /* * apply fix/conversion to module params based on * FE/BE params -- cgit v1.2.3 From c308abe45e2a7bc58e22d9b6d04dccf76a1b2012 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Feb 2016 07:04:09 +0000 Subject: ASoC: rsnd: rsnd_ssi_is_multi_slave() macro uses rsnd_ssi_multi_slaves() b4c83b171 ("ASoC: rsnd: add Multi channel support") added Multi channel support, and current rsnd_ssi_is_multi_slave()'s check method is !SSI equals SSIM1/2/3. But, SSI parent also hit to this macro. Because of this reason, some stream which needs SSI parent clock can't work correctly. This patch uses rsnd_ssi_multi_slaves() to solve this issue. This issue was reported by Dung. Reported-by: Nguyen Viet Dung Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 803e9ae65915..592505a4bc13 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -94,7 +94,8 @@ struct rsnd_ssi { #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_mode_flags(p) ((p)->flags) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) -#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io)) +#define rsnd_ssi_is_multi_slave(mod, io) \ + (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { @@ -167,9 +168,6 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod, u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) { struct rsnd_mod *mod; - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); enum rsnd_mod_type types[] = { RSND_MOD_SSIM1, RSND_MOD_SSIM2, @@ -177,16 +175,6 @@ u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) }; int i, mask; - switch (runtime->channels) { - case 2: /* Multi channel is not needed for Stereo */ - return 0; - case 6: - break; - default: - dev_err(dev, "unsupported channel\n"); - return 0; - } - mask = 0; for (i = 0; i < ARRAY_SIZE(types); i++) { mod = rsnd_io_to_mod(io, types[i]); -- cgit v1.2.3 From 8faa268ab780a7379cfe54b882c6f6e0083233f2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Feb 2016 09:30:17 -0800 Subject: ASoC: qcom: Don't specify LE device endianness This reverts commit 18560a4e3 (ASoC: qcom: Specify LE device endianness). The commit that caused us to specify LE device endianness here, 29bb45f25ff3 (regmap-mmio: Use native endianness for read/write, 2015-10-29), has been reverted in mainline so now when we specify LE it actively breaks big endian kernels because the byte swapping in regmap-mmio is incorrect. Let's revert this change because it will 1) fix the big endian kernels and 2) be redundant to specify LE because that will become the default soon. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 00b6c9d039cf..e5101e0d2d37 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -355,7 +355,6 @@ static struct regmap_config lpass_cpu_regmap_config = { .readable_reg = lpass_cpu_regmap_readable, .volatile_reg = lpass_cpu_regmap_volatile, .cache_type = REGCACHE_FLAT, - .val_format_endian = REGMAP_ENDIAN_LITTLE, }; int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) -- cgit v1.2.3 From 64527e8a352968bda529f01df1c9dd5fe581ff04 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Fri, 15 Jan 2016 16:13:28 +0800 Subject: ASoC: topology: Add FE DAIs dynamically Topology will create FE DAIs dynamically from the PCM objects, and register them to the component. A PCM topoplogy object describes a FE DAI and DAI link. Later patch will add FE DAI links as well. Change tplg load ops for DAI: - Only process a DAI. - Pass the DAI driver pointer to the component driver for extra initialization. Signed-off-by: Mengdong Lin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 15 ++--- include/sound/soc.h | 2 +- sound/soc/soc-topology.c | 129 +++++++++++++++++++++++++++++-------------- 3 files changed, 92 insertions(+), 54 deletions(-) (limited to 'sound/soc') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 5b68e3f5aa85..78813adca2a1 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -56,12 +56,6 @@ struct snd_soc_dobj_widget { unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */ }; -/* dynamic PCM DAI object */ -struct snd_soc_dobj_pcm_dai { - struct snd_soc_tplg_pcm_dai *pd; - unsigned int count; -}; - /* generic dynamic object - all dynamic objects belong to this struct */ struct snd_soc_dobj { enum snd_soc_dobj_type type; @@ -71,7 +65,6 @@ struct snd_soc_dobj { union { struct snd_soc_dobj_control control; struct snd_soc_dobj_widget widget; - struct snd_soc_dobj_pcm_dai pcm_dai; }; void *private; /* core does not touch this */ }; @@ -126,10 +119,10 @@ struct snd_soc_tplg_ops { int (*widget_unload)(struct snd_soc_component *, struct snd_soc_dobj *); - /* FE - used for any driver specific init */ - int (*pcm_dai_load)(struct snd_soc_component *, - struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe); - int (*pcm_dai_unload)(struct snd_soc_component *, + /* FE DAI - used for any driver specific init */ + int (*dai_load)(struct snd_soc_component *, + struct snd_soc_dai_driver *dai_drv); + int (*dai_unload)(struct snd_soc_component *, struct snd_soc_dobj *); /* callback to handle vendor bespoke data */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 7afb72ceac56..02b4a215fd75 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -27,7 +27,6 @@ #include #include #include -#include /* * Convenience kcontrol builders @@ -404,6 +403,7 @@ struct snd_soc_jack_zone; struct snd_soc_jack_pin; #include #include +#include struct snd_soc_jack_gpio; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6963ba20991c..446ac9a93aef 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -330,12 +330,12 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg, return 0; } -/* pass dynamic FEs configurations to component driver */ -static int soc_tplg_pcm_dai_load(struct soc_tplg *tplg, - struct snd_soc_tplg_pcm_dai *pcm_dai, int num_pcm_dai) +/* pass DAI configurations to component driver for extra intialization */ +static int soc_tplg_dai_load(struct soc_tplg *tplg, + struct snd_soc_dai_driver *dai_drv) { - if (tplg->comp && tplg->ops && tplg->ops->pcm_dai_load) - return tplg->ops->pcm_dai_load(tplg->comp, pcm_dai, num_pcm_dai); + if (tplg->comp && tplg->ops && tplg->ops->dai_load) + return tplg->ops->dai_load(tplg->comp, dai_drv); return 0; } @@ -495,18 +495,21 @@ static void remove_widget(struct snd_soc_component *comp, /* widget w is freed by soc-dapm.c */ } -/* remove PCM DAI configurations */ -static void remove_pcm_dai(struct snd_soc_component *comp, +/* remove DAI configurations */ +static void remove_dai(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) { + struct snd_soc_dai_driver *dai_drv = + container_of(dobj, struct snd_soc_dai_driver, dobj); + if (pass != SOC_TPLG_PASS_PCM_DAI) return; - if (dobj->ops && dobj->ops->pcm_dai_unload) - dobj->ops->pcm_dai_unload(comp, dobj); + if (dobj->ops && dobj->ops->dai_unload) + dobj->ops->dai_unload(comp, dobj); list_del(&dobj->list); - kfree(dobj); + kfree(dai_drv); } /* bind a kcontrol to it's IO handlers */ @@ -1544,18 +1547,79 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) return 0; } -static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg, +static int soc_tplg_dai_create(struct soc_tplg *tplg, + struct snd_soc_tplg_pcm *pcm) +{ + struct snd_soc_dai_driver *dai_drv; + struct snd_soc_pcm_stream *stream; + struct snd_soc_tplg_stream_caps *caps; + int ret; + + dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL); + if (dai_drv == NULL) + return -ENOMEM; + + dai_drv->name = pcm->dai_name; + dai_drv->id = pcm->dai_id; + + if (pcm->playback) { + stream = &dai_drv->playback; + caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; + + stream->stream_name = kstrdup(caps->name, GFP_KERNEL); + stream->channels_min = caps->channels_min; + stream->channels_max = caps->channels_max; + stream->rates = snd_pcm_rate_range_to_bits(caps->rate_min, + caps->rate_max); + stream->formats = caps->formats; + } + + if (pcm->capture) { + stream = &dai_drv->capture; + caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE]; + + stream->stream_name = kstrdup(caps->name, GFP_KERNEL); + stream->channels_min = caps->channels_min; + stream->channels_max = caps->channels_max; + stream->rates = snd_pcm_rate_range_to_bits(caps->rate_min, + caps->rate_max); + stream->formats = caps->formats; + } + + /* pass control to component driver for optional further init */ + ret = soc_tplg_dai_load(tplg, dai_drv); + if (ret < 0) { + dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + kfree(dai_drv); + return ret; + } + + dai_drv->dobj.index = tplg->index; + dai_drv->dobj.ops = tplg->ops; + dai_drv->dobj.type = SND_SOC_DOBJ_PCM; + list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); + + /* register the DAI to the component */ + return snd_soc_register_dai(tplg->comp, dai_drv); +} + +static int soc_tplg_pcm_create(struct soc_tplg *tplg, + struct snd_soc_tplg_pcm *pcm) +{ + return soc_tplg_dai_create(tplg, pcm); +} + +static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_pcm_dai *pcm_dai; - struct snd_soc_dobj *dobj; + struct snd_soc_tplg_pcm *pcm; int count = hdr->count; - int ret; + int i; if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) return 0; - pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos; + pcm = (struct snd_soc_tplg_pcm *)tplg->pos; if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_pcm), count, @@ -1565,31 +1629,16 @@ static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg, return -EINVAL; } + /* create the FE DAIs and DAI links */ + for (i = 0; i < count; i++) { + soc_tplg_pcm_create(tplg, pcm); + pcm++; + } + dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count; - dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL); - if (dobj == NULL) - return -ENOMEM; - - /* Call the platform driver call back to register the dais */ - ret = soc_tplg_pcm_dai_load(tplg, pcm_dai, count); - if (ret < 0) { - dev_err(tplg->comp->dev, "ASoC: PCM DAI loading failed\n"); - goto err; - } - - dobj->type = get_dobj_type(hdr, NULL); - dobj->pcm_dai.count = count; - dobj->pcm_dai.pd = pcm_dai; - dobj->ops = tplg->ops; - dobj->index = tplg->index; - list_add(&dobj->list, &tplg->comp->dobj_list); return 0; - -err: - kfree(dobj); - return ret; } static int soc_tplg_manifest_load(struct soc_tplg *tplg, @@ -1681,9 +1730,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, case SND_SOC_TPLG_TYPE_DAPM_WIDGET: return soc_tplg_dapm_widget_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_PCM: - case SND_SOC_TPLG_TYPE_DAI_LINK: - case SND_SOC_TPLG_TYPE_CODEC_LINK: - return soc_tplg_pcm_dai_elems_load(tplg, hdr); + return soc_tplg_pcm_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_MANIFEST: return soc_tplg_manifest_load(tplg, hdr); default: @@ -1841,9 +1888,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) remove_widget(comp, dobj, pass); break; case SND_SOC_DOBJ_PCM: - case SND_SOC_DOBJ_DAI_LINK: - case SND_SOC_DOBJ_CODEC_LINK: - remove_pcm_dai(comp, dobj, pass); + remove_dai(comp, dobj, pass); break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", -- cgit v1.2.3 From acfc7d46cddcf71cf18772bbe8717b84eac5f672 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Fri, 15 Jan 2016 16:13:37 +0800 Subject: ASoC: topology: Add FE DAI links dynamically Topology will also create FE DAI links dynamically from the PCM objects. These links will be removed when the component is removed and its topology info is unloaded. The component driver can implement link_load/unload ops for extra intialization (e.g. error check) and destruction. Signed-off-by: Mengdong Lin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 6 ++++ sound/soc/soc-topology.c | 70 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 78813adca2a1..b897b9d63161 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -125,6 +125,12 @@ struct snd_soc_tplg_ops { int (*dai_unload)(struct snd_soc_component *, struct snd_soc_dobj *); + /* DAI link - used for any driver specific init */ + int (*link_load)(struct snd_soc_component *, + struct snd_soc_dai_link *link); + int (*link_unload)(struct snd_soc_component *, + struct snd_soc_dobj *); + /* callback to handle vendor bespoke data */ int (*vendor_load)(struct snd_soc_component *, struct snd_soc_tplg_hdr *); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 446ac9a93aef..0eb01e8155f1 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -340,6 +340,16 @@ static int soc_tplg_dai_load(struct soc_tplg *tplg, return 0; } +/* pass link configurations to component driver for extra intialization */ +static int soc_tplg_dai_link_load(struct soc_tplg *tplg, + struct snd_soc_dai_link *link) +{ + if (tplg->comp && tplg->ops && tplg->ops->link_load) + return tplg->ops->link_load(tplg->comp, link); + + return 0; +} + /* tell the component driver that all firmware has been loaded in this request */ static void soc_tplg_complete(struct soc_tplg *tplg) { @@ -512,6 +522,24 @@ static void remove_dai(struct snd_soc_component *comp, kfree(dai_drv); } +/* remove link configurations */ +static void remove_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + struct snd_soc_dai_link *link = + container_of(dobj, struct snd_soc_dai_link, dobj); + + if (pass != SOC_TPLG_PASS_PCM_DAI) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + list_del(&dobj->list); + snd_soc_remove_dai_link(comp->card, link); + kfree(link); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -1603,10 +1631,47 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, return snd_soc_register_dai(tplg->comp, dai_drv); } +static int soc_tplg_link_create(struct soc_tplg *tplg, + struct snd_soc_tplg_pcm *pcm) +{ + struct snd_soc_dai_link *link; + int ret; + + link = kzalloc(sizeof(struct snd_soc_dai_link), GFP_KERNEL); + if (link == NULL) + return -ENOMEM; + + link->name = pcm->pcm_name; + link->stream_name = pcm->pcm_name; + + /* pass control to component driver for optional further init */ + ret = soc_tplg_dai_link_load(tplg, link); + if (ret < 0) { + dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); + kfree(link); + return ret; + } + + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_DAI_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + + snd_soc_add_dai_link(tplg->comp->card, link); + return 0; +} + +/* create a FE DAI and DAI link from the PCM object */ static int soc_tplg_pcm_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { - return soc_tplg_dai_create(tplg, pcm); + int ret; + + ret = soc_tplg_dai_create(tplg, pcm); + if (ret < 0) + return ret; + + return soc_tplg_link_create(tplg, pcm); } static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, @@ -1890,6 +1955,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_PCM: remove_dai(comp, dobj, pass); break; + case SND_SOC_DOBJ_DAI_LINK: + remove_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); -- cgit v1.2.3 From b8a54545b00cbf2aff743578c5c69aafdcde1d64 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:01 +0530 Subject: ASoC: hdac_hdmi: Add hotplug notification and read ELD This patch uses i915 component framework to register for hotplug notification. In the hotplug notification, driver reads pin sense and ELD by sending PIN_SENSE and ELD verbs over HDA bus. Once it identifies valid pin sense and valid ELD, store the ELD into the corresponding pin map buffer. Also read the monitor present sense during resume and ignore the ELD notify from graphics during PM as is done in legacy hda, commit 8ae743e82f0b ("ALSA: hda - Skip ELD notification during system suspend") Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 217 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 5a1ec0f7a1a6..fff225d6539c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -34,6 +34,9 @@ #define HDA_MAX_CONNECTIONS 32 +#define ELD_MAX_SIZE 256 +#define ELD_FIXED_BYTES 20 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -48,11 +51,22 @@ struct hdac_hdmi_cvt { struct hdac_hdmi_cvt_params params; }; +struct hdac_hdmi_eld { + bool monitor_present; + bool eld_valid; + int eld_size; + char eld_buffer[ELD_MAX_SIZE]; +}; + struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; + struct hdac_hdmi_eld eld; + struct hdac_ext_device *edev; + int repoll_count; + struct delayed_work work; }; struct hdac_hdmi_dai_pin_map { @@ -76,6 +90,80 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) return to_ehdac_device(hdac); } + /* HDMI ELD routines */ +static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, + hda_nid_t nid, int byte_index) +{ + unsigned int val; + + val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, + byte_index); + + dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", + byte_index, val); + + return val; +} + +static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) +{ + return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, + AC_DIPSIZE_ELD_BUF); +} + +/* + * This function queries the ELD size and ELD data and fills in the buffer + * passed by user + */ +static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size) +{ + int i, size, ret = 0; + + /* + * ELD size is initialized to zero in caller function. If no errors and + * ELD is valid, actual eld_size is assigned. + */ + + size = hdac_hdmi_get_eld_size(codec, nid); + if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { + dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); + return -ERANGE; + } + + /* set ELD buffer */ + for (i = 0; i < size; i++) { + unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); + /* + * Graphics driver might be writing to ELD buffer right now. + * Just abort. The caller will repoll after a while. + */ + if (!(val & AC_ELDD_ELD_VALID)) { + dev_err(&codec->dev, + "HDMI: invalid ELD data byte %d\n", i); + ret = -EINVAL; + goto error; + } + val &= AC_ELDD_ELD_DATA; + /* + * The first byte cannot be zero. This can happen on some DVI + * connections. Some Intel chips may also need some 250ms delay + * to return non-zero ELD data, even when the graphics driver + * correctly writes ELD content before setting ELD_valid bit. + */ + if (!val && !i) { + dev_err(&codec->dev, "HDMI: 0 ELD data\n"); + ret = -EINVAL; + goto error; + } + buf[i] = val; + } + + *eld_size = size; +error: + return ret; +} + static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -246,7 +334,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; - int val; if (dai->id > 0) { dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); @@ -255,12 +342,14 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; - val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val); + if ((!dai_map->pin->eld.monitor_present) || + (!dai_map->pin->eld.eld_valid)) { + + dev_err(&hdac->hdac.dev, + "Failed: montior present? %d ELD valid?: %d\n", + dai_map->pin->eld.monitor_present, + dai_map->pin->eld.eld_valid); - if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) { - dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val); return -ENODEV; } @@ -410,6 +499,71 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); } +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +{ + struct hdac_ext_device *edev = pin->edev; + int val; + + if (!edev) + return; + + pin->repoll_count = repoll; + + pm_runtime_get_sync(&edev->hdac.dev); + val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + + dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", + val, pin->nid); + + pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); + pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + + if (!pin->eld.monitor_present || !pin->eld.eld_valid) { + + dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", + __func__, pin->nid); + goto put_hdac_device; + } + + if (pin->eld.monitor_present && pin->eld.eld_valid) { + /* TODO: use i915 component for reading ELD later */ + if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, + pin->eld.eld_buffer, + &pin->eld.eld_size) == 0) { + + print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, + pin->eld.eld_buffer, pin->eld.eld_size); + } else { + pin->eld.monitor_present = false; + pin->eld.eld_valid = false; + } + } + + /* + * Sometimes the pin_sense may present invalid monitor + * present and eld_valid. If ELD data is not valid, loop few + * more times to get correct pin sense and valid ELD. + */ + if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) + schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); + +put_hdac_device: + pm_runtime_put_sync(&edev->hdac.dev); +} + +static void hdac_hdmi_repoll_eld(struct work_struct *work) +{ + struct hdac_hdmi_pin *pin = + container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); + + /* picked from legacy HDA driver */ + if (pin->repoll_count++ > 6) + pin->repoll_count = 0; + + hdac_hdmi_present_sense(pin, pin->repoll_count); +} + static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) { struct hdac_hdmi_priv *hdmi = edev->private_data; @@ -424,6 +578,9 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) list_add_tail(&pin->head, &hdmi->pin_list); hdmi->num_pin++; + pin->edev = edev; + INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); + return 0; } @@ -482,17 +639,65 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) return hdac_hdmi_init_dai_map(edev); } +static void hdac_hdmi_eld_notify_cb(void *aptr, int port) +{ + struct hdac_ext_device *edev = aptr; + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin; + struct snd_soc_codec *codec = edev->scodec; + + /* Don't know how this mapping is derived */ + hda_nid_t pin_nid = port + 0x04; + + dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); + + /* + * skip notification during system suspend (but not in runtime PM); + * the state will be updated at resume. Also since the ELD and + * connection states are updated in anyway at the end of the resume, + * we can skip it when received during PM process. + */ + if (snd_power_get_state(codec->component.card->snd_card) != + SNDRV_CTL_POWER_D0) + return; + + if (atomic_read(&edev->hdac.in_pm)) + return; + + list_for_each_entry(pin, &hdmi->pin_list, head) { + if (pin->nid == pin_nid) + hdac_hdmi_present_sense(pin, 1); + } +} + +static struct i915_audio_component_audio_ops aops = { + .pin_eld_notify = hdac_hdmi_eld_notify_cb, +}; + static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); struct hdac_hdmi_priv *hdmi = edev->private_data; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); + struct hdac_hdmi_pin *pin; + int ret; edev->scodec = codec; create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); + aops.audio_ptr = edev; + ret = snd_hdac_i915_register_notifier(&aops); + if (ret < 0) { + dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n", + ret); + return ret; + } + + list_for_each_entry(pin, &hdmi->pin_list, head) + hdac_hdmi_present_sense(pin, 1); + /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; -- cgit v1.2.3 From 2428bca305e082885e08e7f3399db616daf3a51a Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:02 +0530 Subject: ASoC: hdac_hdmi: Apply constraints based on ELD Uses the drm ELD core framework to apply rate and channel Also compute the format to be set based on ELD. Even though the channel constraint is based on ELD, infoframe is set with stereo only. Multichannel support will be added later. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/hdac_hdmi.c | 51 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50693c867e71..8c86239cc3f2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -490,6 +490,7 @@ config SND_SOC_GTM601 config SND_SOC_HDAC_HDMI tristate select SND_HDA_EXT_CORE + select SND_PCM_ELD select HDMI config SND_SOC_ICS43432 diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index fff225d6539c..d22fa6b66c80 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -22,10 +22,12 @@ #include #include #include +#include #include #include #include #include +#include #include "../../hda/local.h" #define AMP_OUT_MUTE 0xb080 @@ -90,6 +92,45 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) return to_ehdac_device(hdac); } +static unsigned int sad_format(const u8 *sad) +{ + return ((sad[0] >> 0x3) & 0x1f); +} + +static unsigned int sad_sample_bits_lpcm(const u8 *sad) +{ + return (sad[2] & 7); +} + +static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime, + void *eld) +{ + u64 formats = SNDRV_PCM_FMTBIT_S16; + int i; + const u8 *sad, *eld_buf = eld; + + sad = drm_eld_sad(eld_buf); + if (!sad) + goto format_constraint; + + for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) { + if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */ + + /* + * the controller support 20 and 24 bits in 32 bit + * container so we set S32 + */ + if (sad_sample_bits_lpcm(sad) & 0x6) + formats |= SNDRV_PCM_FMTBIT_S32; + } + } + +format_constraint: + return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, + formats); + +} + /* HDMI ELD routines */ static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, hda_nid_t nid, int byte_index) @@ -334,6 +375,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; + int ret; if (dai->id > 0) { dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); @@ -358,10 +400,13 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, 2); + ret = hdac_hdmi_eld_limit_formats(substream->runtime, + dai_map->pin->eld.eld_buffer); + if (ret < 0) + return ret; - return 0; + return snd_pcm_hw_constraint_eld(substream->runtime, + dai_map->pin->eld.eld_buffer); } static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, -- cgit v1.2.3 From 211caab73b20dcc91ac103db0f68fe2388120d59 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:03 +0530 Subject: ASoC: hdac_hdmi: Enable DP1.2 and all converters/pins Skylake supports 3 pin and 3 converter widgets. But by default only one converter and pin widget are enabled. In skylake platform the DP port is on a different port which is not enabled by default. To enable playback on DP port, enable all pin and converter widget by sending a vendor VERB for a vendor widget to set required bits. As we are enabling the DP support enable the DP1.2 feature as well. Enabling DP1.2 and all widget changes are copied from patch_hdmi.c. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index d22fa6b66c80..b2e5e549b022 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -629,6 +629,46 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) return 0; } +#define INTEL_VENDOR_NID 0x08 +#define INTEL_GET_VENDOR_VERB 0xf81 +#define INTEL_SET_VENDOR_VERB 0x781 +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ + +static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) +{ + unsigned int vendor_param; + + vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + INTEL_GET_VENDOR_VERB, 0); + if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) + return; + + vendor_param |= INTEL_EN_ALL_PIN_CVTS; + vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + INTEL_SET_VENDOR_VERB, vendor_param); + if (vendor_param == -1) + return; +} + +static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) +{ + unsigned int vendor_param; + + vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + INTEL_GET_VENDOR_VERB, 0); + if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) + return; + + /* enable DP1.2 mode */ + vendor_param |= INTEL_EN_DP12; + vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, + INTEL_SET_VENDOR_VERB, vendor_param); + if (vendor_param == -1) + return; + +} + /* * Parse all nodes and store the cvt/pin nids in array * Add one time initialization for pin and cvt widgets @@ -641,6 +681,9 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) struct hdac_hdmi_priv *hdmi = edev->private_data; int ret; + hdac_hdmi_skl_enable_all_pins(hdac); + hdac_hdmi_skl_enable_dp12(hdac); + num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); if (!nid || num_nodes <= 0) { dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); -- cgit v1.2.3 From 17a42c4500b05a6af4c32eb8e9cfc44bab945d1f Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:04 +0530 Subject: ASoC: hdac_hdmi: create dais based on number of cvts After enabling all pins/cvts, Skylake HDMI codec enumerates 3 converters. Three independent streams can be supported with 3 cvts. This patch removes the static dai creation and creates dais based on the number of cvts queried. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 123 ++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 32 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b2e5e549b022..c85deae68064 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -30,6 +30,8 @@ #include #include "../../hda/local.h" +#define NAME_SIZE 32 + #define AMP_OUT_MUTE 0xb080 #define AMP_OUT_UNMUTE 0xb000 #define PIN_OUT (AC_PINCTL_OUT_EN) @@ -669,11 +671,82 @@ static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) } +static struct snd_soc_dai_ops hdmi_dai_ops = { + .startup = hdac_hdmi_pcm_open, + .shutdown = hdac_hdmi_pcm_close, + .hw_params = hdac_hdmi_set_hw_params, + .prepare = hdac_hdmi_playback_prepare, + .hw_free = hdac_hdmi_playback_cleanup, +}; + +/* + * Each converter can support a stream independently. So a dai is created + * based on the number of converter queried. + */ +static int hdac_hdmi_create_dais(struct hdac_device *hdac, + struct snd_soc_dai_driver **dais, + struct hdac_hdmi_priv *hdmi, int num_dais) +{ + struct snd_soc_dai_driver *hdmi_dais; + struct hdac_hdmi_cvt *cvt; + char name[NAME_SIZE], dai_name[NAME_SIZE]; + int i = 0; + u32 rates, bps; + unsigned int rate_max = 384000, rate_min = 8000; + u64 formats; + int ret; + + hdmi_dais = devm_kzalloc(&hdac->dev, + (sizeof(*hdmi_dais) * num_dais), + GFP_KERNEL); + if (!hdmi_dais) + return -ENOMEM; + + list_for_each_entry(cvt, &hdmi->cvt_list, head) { + ret = snd_hdac_query_supported_pcm(hdac, cvt->nid, + &rates, &formats, &bps); + if (ret) + return ret; + + sprintf(dai_name, "intel-hdmi-hifi%d", i+1); + hdmi_dais[i].name = devm_kstrdup(&hdac->dev, + dai_name, GFP_KERNEL); + + if (!hdmi_dais[i].name) + return -ENOMEM; + + snprintf(name, sizeof(name), "hifi%d", i+1); + hdmi_dais[i].playback.stream_name = + devm_kstrdup(&hdac->dev, name, GFP_KERNEL); + if (!hdmi_dais[i].playback.stream_name) + return -ENOMEM; + + /* + * Set caps based on capability queried from the converter. + * It will be constrained runtime based on ELD queried. + */ + hdmi_dais[i].playback.formats = formats; + hdmi_dais[i].playback.rates = rates; + hdmi_dais[i].playback.rate_max = rate_max; + hdmi_dais[i].playback.rate_min = rate_min; + hdmi_dais[i].playback.channels_min = 2; + hdmi_dais[i].playback.channels_max = 2; + hdmi_dais[i].ops = &hdmi_dai_ops; + + i++; + } + + *dais = hdmi_dais; + + return 0; +} + /* * Parse all nodes and store the cvt/pin nids in array * Add one time initialization for pin and cvt widgets */ -static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) +static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, + struct snd_soc_dai_driver **dais, int *num_dais) { hda_nid_t nid; int i, num_nodes; @@ -724,6 +797,15 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) if (!hdmi->num_pin || !hdmi->num_cvt) return -EIO; + ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt); + if (ret) { + dev_err(&hdac->dev, "Failed to create dais with err: %d\n", + ret); + return ret; + } + + *num_dais = hdmi->num_cvt; + return hdac_hdmi_init_dai_map(edev); } @@ -814,38 +896,12 @@ static struct snd_soc_codec_driver hdmi_hda_codec = { .idle_bias_off = true, }; -static struct snd_soc_dai_ops hdmi_dai_ops = { - .startup = hdac_hdmi_pcm_open, - .shutdown = hdac_hdmi_pcm_close, - .hw_params = hdac_hdmi_set_hw_params, - .prepare = hdac_hdmi_playback_prepare, - .hw_free = hdac_hdmi_playback_cleanup, -}; - -static struct snd_soc_dai_driver hdmi_dais[] = { - { .name = "intel-hdmi-hif1", - .playback = { - .stream_name = "hif1", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - - }, - .ops = &hdmi_dai_ops, - }, -}; - static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) { struct hdac_device *codec = &edev->hdac; struct hdac_hdmi_priv *hdmi_priv; + struct snd_soc_dai_driver *hdmi_dais = NULL; + int num_dais = 0; int ret = 0; hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); @@ -859,13 +915,16 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) INIT_LIST_HEAD(&hdmi_priv->pin_list); INIT_LIST_HEAD(&hdmi_priv->cvt_list); - ret = hdac_hdmi_parse_and_map_nid(edev); - if (ret < 0) + ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); + if (ret < 0) { + dev_err(&codec->dev, + "Failed in parse and map nid with err: %d\n", ret); return ret; + } /* ASoC specific initialization */ return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, - hdmi_dais, ARRAY_SIZE(hdmi_dais)); + hdmi_dais, num_dais); } static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) -- cgit v1.2.3 From 79f4e922b54771a4d41b1da67caf109ba92ed95a Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:05 +0530 Subject: ASoC: hdac_hdmi: Create widget/route based on nodes enumerated In skylake, HDMI codec enumerates 3 pins and 3 cvts. Stream can be routed from any cvt to any pin based on the connection list queried from the pin. This patch removes the static modelling of widget/route and creates it dynamically based on the codec widgets enumerated. Mux widgets are added to represent the map between a cvt and pin. Ideally the mux widgets should be created based on the connection list queried from the pin widget. But due to HW behavior, if an external display is not connected on a port, querying the connection list returns zero. So create mux widgets to map all the cvt to all pins. At runtime, playback support on a pin can be verified based on the connection list query. Few function in driver have additional arguments now to support this. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 241 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 219 insertions(+), 22 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c85deae68064..6fb44c4cc8c7 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -446,46 +446,241 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) return err; } -static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, - enum snd_soc_dapm_type id, - const char *wname, const char *stream) +static int hdac_hdmi_fill_widget_info(struct device *dev, + struct snd_soc_dapm_widget *w, + enum snd_soc_dapm_type id, void *priv, + const char *wname, const char *stream, + struct snd_kcontrol_new *wc, int numkc) { w->id = id; - w->name = wname; + w->name = devm_kstrdup(dev, wname, GFP_KERNEL); + if (!w->name) + return -ENOMEM; + w->sname = stream; w->reg = SND_SOC_NOPM; w->shift = 0; - w->kcontrol_news = NULL; - w->num_kcontrols = 0; - w->priv = NULL; + w->kcontrol_news = wc; + w->num_kcontrols = numkc; + w->priv = priv; + + return 0; } static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, - const char *sink, const char *control, const char *src) + const char *sink, const char *control, const char *src, + int (*handler)(struct snd_soc_dapm_widget *src, + struct snd_soc_dapm_widget *sink)) { route->sink = sink; route->source = src; route->control = control; - route->connected = NULL; + route->connected = handler; } -static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, - struct hdac_hdmi_dai_pin_map *dai_map) +/* + * Ideally the Mux inputs should be based on the num_muxs enumerated, but + * the display driver seem to be programming the connection list for the pin + * widget runtime. + * + * So programming all the possible inputs for the mux, the user has to take + * care of selecting the right one and leaving all other inputs selected to + * "NONE" + */ +static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, + struct hdac_hdmi_pin *pin, + struct snd_soc_dapm_widget *widget, + const char *widget_name) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct snd_kcontrol_new *kc; + struct hdac_hdmi_cvt *cvt; + struct soc_enum *se; + char kc_name[NAME_SIZE]; + char mux_items[NAME_SIZE]; + /* To hold inputs to the Pin mux */ + char *items[HDA_MAX_CONNECTIONS]; + int i = 0; + int num_items = hdmi->num_cvt + 1; + + kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL); + if (!kc) + return -ENOMEM; + + se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL); + if (!se) + return -ENOMEM; + + sprintf(kc_name, "Pin %d Input", pin->nid); + kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); + if (!kc->name) + return -ENOMEM; + + kc->private_value = (long)se; + kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc->access = 0; + kc->info = snd_soc_info_enum_double; + kc->put = snd_soc_dapm_put_enum_double; + kc->get = snd_soc_dapm_get_enum_double; + + se->reg = SND_SOC_NOPM; + + /* enum texts: ["NONE", "cvt #", "cvt #", ...] */ + se->items = num_items; + se->mask = roundup_pow_of_two(se->items) - 1; + + sprintf(mux_items, "NONE"); + items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); + if (!items[i]) + return -ENOMEM; + + list_for_each_entry(cvt, &hdmi->cvt_list, head) { + i++; + sprintf(mux_items, "cvt %d", cvt->nid); + items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); + if (!items[i]) + return -ENOMEM; + } + + se->texts = devm_kmemdup(&edev->hdac.dev, items, + (num_items * sizeof(char *)), GFP_KERNEL); + if (!se->texts) + return -ENOMEM; + + return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, + snd_soc_dapm_mux, &pin->nid, widget_name, + NULL, kc, 1); +} + +/* Add cvt <- input <- mux route map */ +static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, + struct snd_soc_dapm_widget *widgets, + struct snd_soc_dapm_route *route, int rindex) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + const struct snd_kcontrol_new *kc; + struct soc_enum *se; + int mux_index = hdmi->num_cvt + hdmi->num_pin; + int i, j; + + for (i = 0; i < hdmi->num_pin; i++) { + kc = widgets[mux_index].kcontrol_news; + se = (struct soc_enum *)kc->private_value; + for (j = 0; j < hdmi->num_cvt; j++) { + hdac_hdmi_fill_route(&route[rindex], + widgets[mux_index].name, + se->texts[j + 1], + widgets[j].name, NULL); + + rindex++; + } + + mux_index++; + } +} + +/* + * Widgets are added in the below sequence + * Converter widgets for num converters enumerated + * Pin widgets for num pins enumerated + * Pin mux widgets to represent connenction list of pin widget + * + * Total widgets elements = num_cvt + num_pin + num_pin; + * + * Routes are added as below: + * pin mux -> pin (based on num_pins) + * cvt -> "Input sel control" -> pin_mux + * + * Total route elements: + * num_pins + (pin_muxes * num_cvt) + */ +static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) { - struct snd_soc_dapm_route route[1]; - struct snd_soc_dapm_widget widgets[2] = { {0} }; + struct snd_soc_dapm_widget *widgets; + struct snd_soc_dapm_route *route; + struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; + char widget_name[NAME_SIZE]; + struct hdac_hdmi_cvt *cvt; + struct hdac_hdmi_pin *pin; + int ret, i = 0, num_routes = 0; - memset(&route, 0, sizeof(route)); + if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) + return -EINVAL; - hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, - "hif1 Output", NULL); - hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, - "Coverter 1", "hif1"); + widgets = devm_kzalloc(dapm->dev, + (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), + GFP_KERNEL); - hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); + if (!widgets) + return -ENOMEM; + + /* DAPM widgets to represent each converter widget */ + list_for_each_entry(cvt, &hdmi->cvt_list, head) { + sprintf(widget_name, "Converter %d", cvt->nid); + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_aif_in, &cvt->nid, + widget_name, dai_drv[i].playback.stream_name, NULL, 0); + if (ret < 0) + return ret; + i++; + } + + list_for_each_entry(pin, &hdmi->pin_list, head) { + sprintf(widget_name, "hif%d Output", pin->nid); + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_output, &pin->nid, + widget_name, NULL, NULL, 0); + if (ret < 0) + return ret; + i++; + } + + /* DAPM widgets to represent the connection list to pin widget */ + list_for_each_entry(pin, &hdmi->pin_list, head) { + sprintf(widget_name, "Pin %d Mux", pin->nid); + ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], + widget_name); + if (ret < 0) + return ret; + i++; + + /* For cvt to pin_mux mapping */ + num_routes += hdmi->num_cvt; + + /* For pin_mux to pin mapping */ + num_routes++; + } + + route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), + GFP_KERNEL); + if (!route) + return -ENOMEM; + + i = 0; + /* Add pin <- NULL <- mux route map */ + list_for_each_entry(pin, &hdmi->pin_list, head) { + int sink_index = i + hdmi->num_cvt; + int src_index = sink_index + hdmi->num_pin; + + hdac_hdmi_fill_route(&route[i], + widgets[sink_index].name, NULL, + widgets[src_index].name, NULL); + i++; + + } + + hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i); + + snd_soc_dapm_new_controls(dapm, widgets, + ((2 * hdmi->num_pin) + hdmi->num_cvt)); + + snd_soc_dapm_add_routes(dapm, route, num_routes); + snd_soc_dapm_new_widgets(dapm->card); + + return 0; - snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); - snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); } static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) @@ -855,7 +1050,9 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) edev->scodec = codec; - create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); + ret = create_fill_widget_route_map(dapm); + if (ret < 0) + return ret; aops.audio_ptr = edev; ret = snd_hdac_i915_register_notifier(&aops); -- cgit v1.2.3 From 4a3478debf36c0aa0cf0860daec245b13cd4448f Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 12 Feb 2016 07:46:06 +0530 Subject: ASoC: hdac_hdmi: Add jack reporting Jack is created based on pcm devices enumerated, so we will create Jack as "HDMI/DP, pcm=x Jack". This style is expected by current usermode like PulseAudio and CRAS. This patch exports an API which can be used to register Jack based on PCM. This API also establishes the map between PCM and cvt. Further cvt to pin mapping is established with the help of usermode selection based on the board topology. During device probe as the PCMs may not be registered, initial pin sense don't report jack events. So, first time jack reporting is done during user selection of mux control. Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 160 ++++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/hdac_hdmi.h | 6 ++ 2 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 sound/soc/codecs/hdac_hdmi.h (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6fb44c4cc8c7..839148688744 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -24,11 +24,13 @@ #include #include #include +#include #include #include #include #include #include "../../hda/local.h" +#include "hdac_hdmi.h" #define NAME_SIZE 32 @@ -52,6 +54,7 @@ struct hdac_hdmi_cvt_params { struct hdac_hdmi_cvt { struct list_head head; hda_nid_t nid; + const char *name; struct hdac_hdmi_cvt_params params; }; @@ -73,6 +76,14 @@ struct hdac_hdmi_pin { struct delayed_work work; }; +struct hdac_hdmi_pcm { + struct list_head head; + int pcm_id; + struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt; + struct snd_jack *jack; +}; + struct hdac_hdmi_dai_pin_map { int dai_id; struct hdac_hdmi_pin *pin; @@ -83,8 +94,10 @@ struct hdac_hdmi_priv { struct hdac_hdmi_dai_pin_map dai_map[3]; struct list_head pin_list; struct list_head cvt_list; + struct list_head pcm_list; int num_pin; int num_cvt; + struct mutex pin_mutex; }; static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) @@ -478,6 +491,67 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, route->connected = handler; } +static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, + struct hdac_hdmi_pin *pin) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = NULL; + + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->pin == pin) + return pcm; + } + + return NULL; +} + +/* + * Based on user selection, map the PINs with the PCMs. + */ +static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_dapm_context *dapm = w->dapm; + struct hdac_hdmi_pin *pin = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm = NULL; + const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; + + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + if (ret < 0) + return ret; + + mutex_lock(&hdmi->pin_mutex); + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->pin == pin) + pcm->pin = NULL; + + /* + * Jack status is not reported during device probe as the + * PCMs are not registered by then. So report it here. + */ + if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { + pcm->pin = pin; + if (pin->eld.monitor_present && pin->eld.eld_valid) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + + snd_jack_report(pcm->jack, SND_JACK_AVOUT); + } + mutex_unlock(&hdmi->pin_mutex); + return ret; + } + } + mutex_unlock(&hdmi->pin_mutex); + + return ret; +} + /* * Ideally the Mux inputs should be based on the num_muxs enumerated, but * the display driver seem to be programming the connection list for the pin @@ -520,7 +594,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = 0; kc->info = snd_soc_info_enum_double; - kc->put = snd_soc_dapm_put_enum_double; + kc->put = hdac_hdmi_set_pin_mux; kc->get = snd_soc_dapm_get_enum_double; se->reg = SND_SOC_NOPM; @@ -548,8 +622,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, return -ENOMEM; return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, - snd_soc_dapm_mux, &pin->nid, widget_name, - NULL, kc, 1); + snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1); } /* Add cvt <- input <- mux route map */ @@ -728,12 +801,15 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_cvt *cvt; + char name[NAME_SIZE]; cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); if (!cvt) return -ENOMEM; cvt->nid = nid; + sprintf(name, "cvt %d", cvt->nid); + cvt->name = kstrdup(name, GFP_KERNEL); list_add_tail(&cvt->head, &hdmi->cvt_list); hdmi->num_cvt++; @@ -744,6 +820,8 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) { struct hdac_ext_device *edev = pin->edev; + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm; int val; if (!edev) @@ -758,13 +836,31 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", val, pin->nid); + + mutex_lock(&hdmi->pin_mutex); pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + pcm = hdac_hdmi_get_pcm(edev, pin); + if (!pin->eld.monitor_present || !pin->eld.eld_valid) { dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", __func__, pin->nid); + + /* + * PCMs are not registered during device probe, so don't + * report jack here. It will be done in usermode mux + * control select. + */ + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", pcm->pcm_id); + + snd_jack_report(pcm->jack, 0); + } + + mutex_unlock(&hdmi->pin_mutex); goto put_hdac_device; } @@ -774,14 +870,32 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) pin->eld.eld_buffer, &pin->eld.eld_size) == 0) { + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + + snd_jack_report(pcm->jack, SND_JACK_AVOUT); + } + print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, pin->eld.eld_buffer, pin->eld.eld_size); } else { pin->eld.monitor_present = false; pin->eld.eld_valid = false; + + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + + snd_jack_report(pcm->jack, 0); + } } } + mutex_unlock(&hdmi->pin_mutex); + /* * Sometimes the pin_sense may present invalid monitor * present and eld_valid. If ELD data is not valid, loop few @@ -1039,6 +1153,35 @@ static struct i915_audio_component_audio_ops aops = { .pin_eld_notify = hdac_hdmi_eld_notify_cb, }; +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) +{ + char jack_name[NAME_SIZE]; + struct snd_soc_codec *codec = dai->codec; + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(&codec->component); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm; + + /* + * this is a new PCM device, create new pcm and + * add to the pcm list + */ + pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + pcm->pcm_id = device; + pcm->cvt = hdmi->dai_map[dai->id].cvt; + + list_add_tail(&pcm->head, &hdmi->pcm_list); + + sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); + + return snd_jack_new(dapm->card->snd_card, jack_name, + SND_JACK_AVOUT, &pcm->jack, true, false); +} +EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); + static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); @@ -1111,6 +1254,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) INIT_LIST_HEAD(&hdmi_priv->pin_list); INIT_LIST_HEAD(&hdmi_priv->cvt_list); + INIT_LIST_HEAD(&hdmi_priv->pcm_list); + mutex_init(&hdmi_priv->pin_mutex); ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); if (ret < 0) { @@ -1129,11 +1274,20 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; + struct hdac_hdmi_pcm *pcm, *pcm_next; snd_soc_unregister_codec(&edev->hdac.dev); + list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { + pcm->cvt = NULL; + pcm->pin = NULL; + list_del(&pcm->head); + kfree(pcm); + } + list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { list_del(&cvt->head); + kfree(cvt->name); kfree(cvt); } diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h new file mode 100644 index 000000000000..8dfd1e0b57b3 --- /dev/null +++ b/sound/soc/codecs/hdac_hdmi.h @@ -0,0 +1,6 @@ +#ifndef __HDAC_HDMI_H__ +#define __HDAC_HDMI_H__ + +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm); + +#endif /* __HDAC_HDMI_H__ */ -- cgit v1.2.3 From 148569fddbc6d3ce97236c4344068b1293e51838 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:07 +0530 Subject: ASoC: hdac_hdmi: Enable playback on all enumerated ports Last patch added infrastructure to render over all the ports, PCM<->cvt<- pin mapping and user selection of controls. But we still have restriction of playback on the default port alone, so remove that. This patch removes the hardcoding of cvt<->pin map from the dai. Cvt and pin for a dai are now derived from the already stored pcm list of device opened. We query connection list of a pin from codec to validate the cvt<->pin map. If connection list returns zero, then monitor is not connected so fail playback. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 174 ++++++++++++++++++++++++++++++++----------- 1 file changed, 132 insertions(+), 42 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 839148688744..dcd1cb643145 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -40,6 +40,8 @@ #define HDA_MAX_CONNECTIONS 32 +#define HDA_MAX_CVTS 3 + #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20 @@ -91,7 +93,7 @@ struct hdac_hdmi_dai_pin_map { }; struct hdac_hdmi_priv { - struct hdac_hdmi_dai_pin_map dai_map[3]; + struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; struct list_head pin_list; struct list_head cvt_list; struct list_head pcm_list; @@ -384,44 +386,136 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, return 0; } +static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, + struct hdac_hdmi_dai_pin_map *dai_map) +{ + int mux_idx; + struct hdac_hdmi_pin *pin = dai_map->pin; + + for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) { + if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) { + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + AC_VERB_SET_CONNECT_SEL, mux_idx); + break; + } + } + + if (mux_idx == pin->num_mux_nids) + return -EIO; + + /* Enable out path for this pin widget */ + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); + + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + + return 0; +} + +static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, + struct hdac_hdmi_pin *pin) +{ + if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { + dev_warn(&hdac->hdac.dev, + "HDMI: pin %d wcaps %#x does not support connection list\n", + pin->nid, get_wcaps(&hdac->hdac, pin->nid)); + return -EINVAL; + } + + pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + pin->mux_nids, HDA_MAX_CONNECTIONS); + if (pin->num_mux_nids == 0) + dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", + pin->nid); + + dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", + pin->num_mux_nids, pin->nid); + + return pin->num_mux_nids; +} + +/* + * Query pcm list and return pin widget to which stream is routed. + * + * Also query connection list of the pin, to validate the cvt to pin map. + * + * Same stream rendering to multiple pins simultaneously can be done + * possibly, but not supported for now in driver. So return the first pin + * connected. + */ +static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( + struct hdac_ext_device *edev, + struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_cvt *cvt) +{ + struct hdac_hdmi_pcm *pcm; + struct hdac_hdmi_pin *pin = NULL; + int ret, i; + + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->cvt == cvt) { + pin = pcm->pin; + break; + } + } + + if (pin) { + ret = hdac_hdmi_query_pin_connlist(edev, pin); + if (ret < 0) + return NULL; + + for (i = 0; i < pin->num_mux_nids; i++) { + if (pin->mux_nids[i] == cvt->nid) + return pin; + } + } + + return NULL; +} + static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_cvt *cvt; + struct hdac_hdmi_pin *pin; int ret; - if (dai->id > 0) { - dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); - return -ENODEV; - } - dai_map = &hdmi->dai_map[dai->id]; - if ((!dai_map->pin->eld.monitor_present) || - (!dai_map->pin->eld.eld_valid)) { + cvt = dai_map->cvt; + pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); + if (!pin) + return -EIO; + + if ((!pin->eld.monitor_present) || + (!pin->eld.eld_valid)) { dev_err(&hdac->hdac.dev, - "Failed: montior present? %d ELD valid?: %d\n", - dai_map->pin->eld.monitor_present, - dai_map->pin->eld.eld_valid); + "Failed: montior present? %d ELD valid?: %d for pin: %d\n", + pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); return -ENODEV; } - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); + dai_map->pin = pin; - snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + ret = hdac_hdmi_enable_pin(hdac, dai_map); + if (ret < 0) + return ret; ret = hdac_hdmi_eld_limit_formats(substream->runtime, - dai_map->pin->eld.eld_buffer); + pin->eld.eld_buffer); if (ret < 0) return ret; return snd_pcm_hw_constraint_eld(substream->runtime, - dai_map->pin->eld.eld_buffer); + pin->eld.eld_buffer); } static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, @@ -437,6 +531,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + dai_map->pin = NULL; } static int @@ -759,40 +855,34 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0]; + struct hdac_hdmi_dai_pin_map *dai_map; struct hdac_hdmi_cvt *cvt; - struct hdac_hdmi_pin *pin; + int dai_id = 0; - if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) + if (list_empty(&hdmi->cvt_list)) return -EINVAL; - /* - * Currently on board only 1 pin and 1 converter is enabled for - * simplification, more will be added eventually - * So using fixed map for dai_id:pin:cvt - */ - cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head); - pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head); - - dai_map->dai_id = 0; - dai_map->pin = pin; + list_for_each_entry(cvt, &hdmi->cvt_list, head) { + dai_map = &hdmi->dai_map[dai_id]; + dai_map->dai_id = dai_id; + dai_map->cvt = cvt; - dai_map->cvt = cvt; + /* Enable transmission */ + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, 1); - /* Enable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + /* Category Code (CC) to zero */ + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0); - /* Enable transmission */ - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_1, 1); + dai_id++; - /* Category Code (CC) to zero */ - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_2, 0); - - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, - AC_VERB_SET_CONNECT_SEL, 0); + if (dai_id == HDA_MAX_CVTS) { + dev_warn(&edev->hdac.dev, + "Max dais supported: %d\n", dai_id); + break; + } + } return 0; } -- cgit v1.2.3 From 478f544e5b5538ccbcfdb18b4e9860a2f61ab921 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 12 Feb 2016 07:46:09 +0530 Subject: ASoC: hdac_hdmi: Add infoframe support for dp audio For DP audio support, infoframe needs to be different. Based on get_conn_type result we pack either HDMI or DP infoframe. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 74 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 10 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index dcd1cb643145..36f12004ae9c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -253,27 +253,75 @@ hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, AC_VERB_SET_HDMI_DIP_INDEX, val); } +struct dp_audio_infoframe { + u8 type; /* 0x84 */ + u8 len; /* 0x1b */ + u8 ver; /* 0x11 << 2 */ + + u8 CC02_CT47; /* match with HDMI infoframe from this on */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; +}; + static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; - u8 *dip = (u8 *)&frame; + struct dp_audio_infoframe dp_ai; + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_pin *pin; + u8 *dip; int ret; int i; + const u8 *eld_buf; + u8 conn_type; + int channels = 2; - hdmi_audio_infoframe_init(&frame); + list_for_each_entry(pin, &hdmi->pin_list, head) { + if (pin->nid == pin_nid) + break; + } - /* Default stereo for now */ - frame.channels = 2; + eld_buf = pin->eld.eld_buffer; + conn_type = drm_eld_get_conn_type(eld_buf); /* setup channel count */ snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1); + AC_VERB_SET_CVT_CHAN_COUNT, channels - 1); - ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (ret < 0) - return ret; + switch (conn_type) { + case DRM_ELD_CONN_TYPE_HDMI: + hdmi_audio_infoframe_init(&frame); + + /* Default stereo for now */ + frame.channels = channels; + + ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (ret < 0) + return ret; + + dip = (u8 *)&frame; + break; + + case DRM_ELD_CONN_TYPE_DP: + memset(&dp_ai, 0, sizeof(dp_ai)); + dp_ai.type = 0x84; + dp_ai.len = 0x1b; + dp_ai.ver = 0x11 << 2; + dp_ai.CC02_CT47 = channels - 1; + dp_ai.CA = 0; + + dip = (u8 *)&dp_ai; + break; + + default: + dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n", + conn_type); + return -EIO; + } /* stop infoframe transmission */ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); @@ -283,9 +331,15 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, /* Fill infoframe. Index auto-incremented */ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - for (i = 0; i < sizeof(frame); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { + for (i = 0; i < sizeof(frame); i++) + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, dip[i]); + } else { + for (i = 0; i < sizeof(dp_ai); i++) + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_DATA, dip[i]); + } /* Start infoframe */ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); -- cgit v1.2.3 From cd890ade492784ae06dadd20e688ba1760d3c801 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 17 Feb 2016 09:42:13 -0200 Subject: ASoC: hdac_hdmi: Remove 'edev' NULL check Commit 4a3478debf36 ("ASoC: hdac_hdmi: Add jack reporting") leads to the following Smatch complaint: sound/soc/codecs/hdac_hdmi.c:971 hdac_hdmi_present_sense() warn: variable dereferenced before check 'edev' (see line 967) As explained by Subhransu S. Prusty: "This NULL check is not required, can be removed. edev object is expected to be present when the present_sense is called. This is called from places where this edev object is already available." So remove the evdev NULL check. Reported-by: Dan Carpenter Signed-off-by: Fabio Estevam Acked-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 36f12004ae9c..2884dbf0bc07 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -968,9 +968,6 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) struct hdac_hdmi_pcm *pcm; int val; - if (!edev) - return; - pin->repoll_count = repoll; pm_runtime_get_sync(&edev->hdac.dev); -- cgit v1.2.3 From cffee535f0b09ab0801cbec01a8ae81595aa99bc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 17 Feb 2016 08:46:07 +0800 Subject: ASoC: max98926: Fix blr_clk_ratio calculation Current code calculates blr_clk_ratio before setting max98926->ch_size, fix it. Signed-off-by: Axel Lin Acked-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 66884ebdf2bb..5245e107de30 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -383,8 +383,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream, int rate = params_rate(params), i; struct snd_soc_codec *codec = dai->codec; struct max98926_priv *max98926 = snd_soc_codec_get_drvdata(codec); - /* BCLK/LRCLK ratio calculation */ - int blr_clk_ratio = params_channels(params) * max98926->ch_size; + int blr_clk_ratio; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -414,6 +413,9 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* BCLK/LRCLK ratio calculation */ + blr_clk_ratio = params_channels(params) * max98926->ch_size; + switch (blr_clk_ratio) { case 32: regmap_update_bits(max98926->regmap, -- cgit v1.2.3 From 805d132dcbbdbdf8339008f4f964490cf6ff3025 Mon Sep 17 00:00:00 2001 From: anish kumar Date: Wed, 17 Feb 2016 17:28:49 -0800 Subject: ASoC: Add max9867 codec driver Signed-off-by: anish kumar Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max9867.txt | 17 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 1 + sound/soc/codecs/max9867.c | 537 +++++++++++++++++++++ sound/soc/codecs/max9867.h | 83 ++++ 5 files changed, 642 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max9867.txt create mode 100755 sound/soc/codecs/max9867.c create mode 100755 sound/soc/codecs/max9867.h (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/max9867.txt b/Documentation/devicetree/bindings/sound/max9867.txt new file mode 100644 index 000000000000..394cd4eb17ec --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max9867.txt @@ -0,0 +1,17 @@ +max9867 codec + +This device supports I2C mode only. + +Required properties: + +- compatible : "maxim,max9867" +- reg : The chip select number on the I2C bus + +Example: + +&i2c { + max9867: max9867@0x18 { + compatible = "maxim,max9867"; + reg = <0x18>; + }; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ebaaa51823ef..f55a846efe54 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -79,6 +79,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C select SND_SOC_MAX98357A if GPIOLIB + select SND_SOC_MAX9867 if I2C select SND_SOC_MAX98925 if I2C select SND_SOC_MAX98926 if I2C select SND_SOC_MAX9850 if I2C @@ -517,6 +518,9 @@ config SND_SOC_MAX98095 config SND_SOC_MAX98357A tristate +config SND_SOC_MAX9867 + tristate + config SND_SOC_MAX98925 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 16c014a46ae8..b84fe9d75dfd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -74,6 +74,7 @@ snd-soc-max98088-objs := max98088.o snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o snd-soc-max98357a-objs := max98357a.o +snd-soc-max9867-objs := max9867.o snd-soc-max98925-objs := max98925.o snd-soc-max98926-objs := max98926.o snd-soc-max9850-objs := max9850.o diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c new file mode 100755 index 000000000000..b9d989f25515 --- /dev/null +++ b/sound/soc/codecs/max9867.c @@ -0,0 +1,537 @@ +/* + * max9867.c -- max9867 ALSA SoC Audio driver + * + * Copyright 2013-15 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "max9867.h" + +static const char *const max9867_spmode[] = { + "Stereo Diff", "Mono Diff", + "Stereo Cap", "Mono Cap", + "Stereo Single", "Mono Single", + "Stereo Single Fast", "Mono Single Fast" +}; +static const char *const max9867_sidetone_text[] = { + "None", "Left", "Right", "LeftRight", "LeftRightDiv2", +}; +static const char *const max9867_filter_text[] = {"IIR", "FIR"}; + +static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7, + max9867_filter_text); +static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0, + max9867_spmode); +static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6, + max9867_sidetone_text); +static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0); +static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1); +static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1); +static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1); +static const unsigned int max98088_micboost_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), + 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), +}; + +static const struct snd_kcontrol_new max9867_snd_controls[] = { + SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL, + MAX9867_RIGHTVOL, 0, 63, 1), + SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN, + MAX9867_RIGHTMICGAIN, + 0, 15, 1, max9860_capture_tlv), + SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN, + MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv), + SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN, + MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv), + SOC_ENUM("Digital Sidetone Src", max9867_sidetone), + SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1), + SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0), + SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1), + SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL, + 4, 15, 1, max9860_adc_left_tlv), + SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL, + 0, 15, 1, max9860_adc_right_tlv), + SOC_ENUM("Speaker Mode", max9867_spkmode), + SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), + SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0), + SOC_ENUM("DSP Filter", max9867_filter), +}; + +static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"}; + +static SOC_ENUM_SINGLE_DECL(max9867_mux_enum, + MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT, + max9867_mux); + +static const struct snd_kcontrol_new max9867_dapm_mux_controls = + SOC_DAPM_ENUM("Route", max9867_mux_enum); + +static const struct snd_kcontrol_new max9867_left_dapm_control = + SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0); +static const struct snd_kcontrol_new max9867_right_dapm_control = + SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0); +static const struct snd_kcontrol_new max9867_line_dapm_control = + SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1); + +static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0), + SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("HPOUT"), + + SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0), + SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0), + SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, + &max9867_dapm_mux_controls), + + SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1, + &max9867_left_dapm_control), + SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1, + &max9867_right_dapm_control), + SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0, + &max9867_line_dapm_control), + SND_SOC_DAPM_INPUT("LINE_IN"), +}; + +static const struct snd_soc_dapm_route max9867_audio_map[] = { + {"Left DAC", NULL, "DAI_OUT"}, + {"Right DAC", NULL, "DAI_OUT"}, + {"Output Mixer", NULL, "Left DAC"}, + {"Output Mixer", NULL, "Right DAC"}, + {"HPOUT", NULL, "Output Mixer"}, + + {"Left ADC", NULL, "DAI_IN"}, + {"Right ADC", NULL, "DAI_IN"}, + {"Input Mixer", NULL, "Left ADC"}, + {"Input Mixer", NULL, "Right ADC"}, + {"Input Mux", "Line", "Input Mixer"}, + {"Input Mux", "Mic", "Input Mixer"}, + {"Input Mux", "Mic_Line", "Input Mixer"}, + {"Right Line", "Switch", "Input Mux"}, + {"Left Line", "Switch", "Input Mux"}, + {"LINE_IN", NULL, "Left Line"}, + {"LINE_IN", NULL, "Right Line"}, +}; + +enum rates { + pcm_rate_8, pcm_rate_16, pcm_rate_24, + pcm_rate_32, pcm_rate_44, + pcm_rate_48, max_pcm_rate, +}; + +struct ni_div_rates { + u32 mclk; + u16 ni[max_pcm_rate]; +} ni_div[] = { + {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} }, + {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} }, + {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} }, + {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} }, + {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} }, + {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} }, + {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} }, + {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} }, +}; + +static inline int get_ni_value(int mclk, int rate) +{ + int i, ret = 0; + + /* find the closest rate index*/ + for (i = 0; i < ARRAY_SIZE(ni_div); i++) { + if (ni_div[i].mclk >= mclk) + break; + } + + switch (rate) { + case 8000: + return ni_div[i].ni[pcm_rate_8]; + case 16000: + return ni_div[i].ni[pcm_rate_16]; + case 32000: + return ni_div[i].ni[pcm_rate_32]; + case 44100: + return ni_div[i].ni[pcm_rate_44]; + case 48000: + return ni_div[i].ni[pcm_rate_48]; + default: + pr_err("%s wrong rate %d\n", __func__, rate); + ret = -EINVAL; + } + return ret; +} + +static int max9867_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); + unsigned int ni_h, ni_l, value; + + value = get_ni_value(max9867->sysclk, params_rate(params)); + if (value < 0) + return value; + + ni_h = (0xFF00 & value) >> 8; + ni_l = 0x00FF & value; + /* set up the ni value */ + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, + MAX9867_NI_HIGH_MASK, ni_h); + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, + MAX9867_NI_LOW_MASK, ni_l); + if (!max9867->master) { + /* + * digital pll locks on to any externally supplied LRCLK signal + * and also enable rapid lock mode. + */ + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, + MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, + MAX9867_PLL, MAX9867_PLL); + } else { + unsigned long int bclk_rate, pclk_bclk_ratio; + int bclk_value; + + bclk_rate = params_rate(params) * 2 * + snd_pcm_format_width(params_format(params)); + pclk_bclk_ratio = max9867->pclk/bclk_rate; + switch (snd_pcm_format_width(params_format(params))) { + case 8: + case 16: + if (pclk_bclk_ratio == 2) + bclk_value = MAX9867_IFC1B_PCLK_2; + else if (pclk_bclk_ratio == 4) + bclk_value = MAX9867_IFC1B_PCLK_4; + else if (pclk_bclk_ratio == 8) + bclk_value = MAX9867_IFC1B_PCLK_8; + else if (pclk_bclk_ratio == 16) + bclk_value = MAX9867_IFC1B_PCLK_16; + else { + dev_err(codec->dev, "unsupported sampling rate\n"); + return -EINVAL; + } + break; + case 24: + bclk_value = MAX9867_IFC1B_24BIT; + break; + case 32: + bclk_value = MAX9867_IFC1B_32BIT; + break; + default: + dev_err(codec->dev, "unsupported sampling rate\n"); + return -EINVAL; + } + regmap_update_bits(max9867->regmap, MAX9867_IFC1B, + MAX9867_IFC1B_BCLK_MASK, bclk_value); + } + return 0; +} + +static int max9867_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK); + return 0; +} + +static int max9867_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); + + if (mute) + regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, + MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK); + else + regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, + MAX9867_DAC_MUTE_MASK, 0); + return 0; +} + +static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); + int value = 0; + + /* Set the prescaler based on the master clock frequency*/ + if (freq >= 10000000 && freq <= 20000000) { + value |= MAX9867_PSCLK_10_20; + max9867->pclk = freq; + } else if (freq >= 20000000 && freq <= 40000000) { + value |= MAX9867_PSCLK_20_40; + max9867->pclk = freq/2; + } else if (freq >= 40000000 && freq <= 60000000) { + value |= MAX9867_PSCLK_40_60; + max9867->pclk = freq/4; + } else { + pr_err("bad clock frequency %d", freq); + return -EINVAL; + } + value = value << MAX9867_PSCLK_SHIFT; + max9867->sysclk = freq; + /* exact integer mode is not supported */ + value &= ~MAX9867_FREQ_MASK; + regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, + MAX9867_PSCLK_MASK, value); + return 0; +} + +static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); + u8 iface1A = 0, iface1B = 0; + int ret; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + max9867->master = 1; + iface1A |= MAX9867_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFS: + max9867->master = 0; + iface1A &= ~MAX9867_MASTER; + break; + default: + return -EINVAL; + } + + /* for i2s compatible mode */ + iface1A |= MAX9867_I2S_DLY; + /* SDOUT goes to hiz state after all data is transferred */ + iface1A |= MAX9867_SDOUT_HIZ; + + /* Clock inversion bits, BCI and WCI */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface1A |= MAX9867_WCI_MODE | MAX9867_BCI_MODE; + break; + case SND_SOC_DAIFMT_IB_NF: + iface1A |= MAX9867_BCI_MODE; + break; + case SND_SOC_DAIFMT_NB_IF: + iface1A |= MAX9867_WCI_MODE; + break; + default: + return -EINVAL; + } + + ret = regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); + ret = regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B); + return 0; +} + +static struct snd_soc_dai_ops max9867_dai_ops = { + .set_fmt = max9867_dai_set_fmt, + .set_sysclk = max9867_set_dai_sysclk, + .prepare = max9867_prepare, + .digital_mute = max9867_mute, + .hw_params = max9867_dai_hw_params, +}; + +#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +static struct snd_soc_dai_driver max9867_dai[] = { + { + .name = "max9867-aif1", + .playback = { + .stream_name = "HiFi Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MAX9867_RATES, + .formats = MAX9867_FORMATS, + }, + .capture = { + .stream_name = "HiFi Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MAX9867_RATES, + .formats = MAX9867_FORMATS, + }, + .ops = &max9867_dai_ops, + } +}; + +#ifdef CONFIG_PM_SLEEP +static int max9867_suspend(struct device *dev) +{ + struct max9867_priv *max9867 = dev_get_drvdata(dev); + + /* Drop down to power saving mode when system is suspended */ + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK); + return 0; +} + +static int max9867_resume(struct device *dev) +{ + struct max9867_priv *max9867 = dev_get_drvdata(dev); + + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK); + return 0; +} +#endif + +static int max9867_probe(struct snd_soc_codec *codec) +{ + struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "max98090_probe\n"); + max9867->codec = codec; + return 0; +} + +static struct snd_soc_codec_driver max9867_codec = { + .probe = max9867_probe, + .controls = max9867_snd_controls, + .num_controls = ARRAY_SIZE(max9867_snd_controls), + .dapm_routes = max9867_audio_map, + .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), + .dapm_widgets = max9867_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), +}; + +static bool max9867_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX9867_STATUS: + case MAX9867_JACKSTATUS: + case MAX9867_AUXHIGH: + case MAX9867_AUXLOW: + return true; + default: + return false; + } +} + +static struct reg_default max9867_reg[] = { + { 0x04, 0x00 }, + { 0x05, 0x00 }, + { 0x06, 0x00 }, + { 0x07, 0x00 }, + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0A, 0x00 }, + { 0x0B, 0x00 }, + { 0x0C, 0x00 }, + { 0x0D, 0x00 }, + { 0x0E, 0x00 }, + { 0x0F, 0x00 }, + { 0x10, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x13, 0x00 }, + { 0x14, 0x00 }, + { 0x15, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, +}; + +static struct regmap_config max9867_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX9867_REVISION, + .reg_defaults = max9867_reg, + .num_reg_defaults = ARRAY_SIZE(max9867_reg), + .volatile_reg = max9867_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int max9867_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max9867_priv *max9867; + int ret = 0, reg; + + max9867 = devm_kzalloc(&i2c->dev, + sizeof(*max9867), GFP_KERNEL); + if (!max9867) + return -ENOMEM; + + i2c_set_clientdata(i2c, max9867); + max9867->regmap = devm_regmap_init_i2c(i2c, &max9867_regmap); + if (IS_ERR(max9867->regmap)) { + ret = PTR_ERR(max9867->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + return ret; + } + ret = regmap_read(max9867->regmap, + MAX9867_REVISION, ®); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read: %d\n", ret); + return ret; + } + dev_info(&i2c->dev, "device revision: %x\n", reg); + ret = snd_soc_register_codec(&i2c->dev, &max9867_codec, + max9867_dai, ARRAY_SIZE(max9867_dai)); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + return ret; + } + return ret; +} + +static int max9867_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max9867_i2c_id[] = { + { "max9867", 0 }, +}; + +static const struct of_device_id max9867_of_match[] = { + { .compatible = "maxim,max9867", }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, max9867_i2c_id); + +static const struct dev_pm_ops max9867_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume) +}; + +static struct i2c_driver max9867_i2c_driver = { + .driver = { + .name = "max9867", + .of_match_table = of_match_ptr(max9867_of_match), + .pm = &max9867_pm_ops, + }, + .probe = max9867_i2c_probe, + .remove = max9867_i2c_remove, + .id_table = max9867_i2c_id, +}; + +module_i2c_driver(max9867_i2c_driver); + +MODULE_AUTHOR("anish kumar "); +MODULE_DESCRIPTION("ALSA SoC MAX9867 driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h new file mode 100755 index 000000000000..65590b4ad62a --- /dev/null +++ b/sound/soc/codecs/max9867.h @@ -0,0 +1,83 @@ +/* + * max9867.h -- MAX9867 ALSA SoC Audio driver + * + * Copyright 2013-2015 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _MAX9867_H +#define _MAX9867_H + +/* MAX9867 register space */ + +#define MAX9867_STATUS 0x00 +#define MAX9867_JACKSTATUS 0x01 +#define MAX9867_AUXHIGH 0x02 +#define MAX9867_AUXLOW 0x03 +#define MAX9867_INTEN 0x04 +#define MAX9867_SYSCLK 0x05 +#define MAX9867_FREQ_MASK 0xF +#define MAX9867_PSCLK_SHIFT 0x4 +#define MAX9867_PSCLK_WIDTH 0x2 +#define MAX9867_PSCLK_MASK (0x03< Date: Thu, 18 Feb 2016 10:36:20 -0800 Subject: ASoC: max9867: Changed the if-else case to switch case Signed-off-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index b9d989f25515..5a8481bf20c2 100755 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -212,16 +212,22 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream, switch (snd_pcm_format_width(params_format(params))) { case 8: case 16: - if (pclk_bclk_ratio == 2) + switch (pclk_bclk_ratio) { + case 2: bclk_value = MAX9867_IFC1B_PCLK_2; - else if (pclk_bclk_ratio == 4) + break; + case 4: bclk_value = MAX9867_IFC1B_PCLK_4; - else if (pclk_bclk_ratio == 8) + break; + case 8: bclk_value = MAX9867_IFC1B_PCLK_8; - else if (pclk_bclk_ratio == 16) + break; + case 16: bclk_value = MAX9867_IFC1B_PCLK_16; - else { - dev_err(codec->dev, "unsupported sampling rate\n"); + break; + default: + dev_err(codec->dev, + "unsupported sampling rate\n"); return -EINVAL; } break; -- cgit v1.2.3 From 4b235c43deb8283802281a299cb730001a6ad1da Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Feb 2016 11:42:34 +0530 Subject: ASoC: Intel: Skylake: Generate topology name for NHLT table header NHLT table [1] header has fields like oem_id, oem_table_id and oem_revision. Use that to load a unique topology binary specific to that platform NHLT Table is documented at: [1]: https://01.org/blogs/2016/intel-smart-sound-technology-audio-dsp Signed-off-by: Yang A Fang Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 34 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.c | 11 ++++++++--- sound/soc/intel/skylake/skl.c | 4 ++++ sound/soc/intel/skylake/skl.h | 3 +++ 4 files changed, 49 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 6e4b21cdb1bd..14d1916ea9f8 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -145,3 +145,37 @@ struct nhlt_specific_cfg return NULL; } + +static void skl_nhlt_trim_space(struct skl *skl) +{ + char *s = skl->tplg_name; + int cnt; + int i; + + cnt = 0; + for (i = 0; s[i]; i++) { + if (!isspace(s[i])) + s[cnt++] = s[i]; + } + + s[cnt] = '\0'; +} + +int skl_nhlt_update_topology_bin(struct skl *skl) +{ + struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct device *dev = bus->dev; + + dev_dbg(dev, "oem_id %.6s, oem_table_id %8s oem_revision %d\n", + nhlt->header.oem_id, nhlt->header.oem_table_id, + nhlt->header.oem_revision); + + snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s", + skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, + nhlt->header.oem_revision, "-tplg.bin"); + + skl_nhlt_trim_space(skl); + + return 0; +} diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 216d7a8e5680..ba0d02d1613e 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1716,11 +1716,16 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl *skl = ebus_to_skl(ebus); - ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); + ret = request_firmware(&fw, skl->tplg_name, bus->dev); if (ret < 0) { dev_err(bus->dev, "tplg fw %s load failed with %d\n", - "dfw_sst.bin", ret); - return ret; + skl->tplg_name, ret); + ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); + if (ret < 0) { + dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", + "dfw_sst.bin", ret); + return ret; + } } /* diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 06f4b2c13423..f89abb179efe 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -573,11 +573,15 @@ static int skl_probe(struct pci_dev *pci, if (err < 0) goto out_free; + skl->pci_id = pci->device; + skl->nhlt = skl_nhlt_init(bus->dev); if (skl->nhlt == NULL) goto out_free; + skl_nhlt_update_topology_bin(skl); + pci_set_drvdata(skl->pci, ebus); /* check if dsp is there */ diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4d18293b5537..1ca1911f1587 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -73,6 +73,8 @@ struct skl { struct list_head ppl_list; const char *fw_name; + char tplg_name[64]; + unsigned short pci_id; const struct firmware *tplg; int supend_active; @@ -96,6 +98,7 @@ void skl_nhlt_free(void *addr); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); +int skl_nhlt_update_topology_bin(struct skl *skl); int skl_init_dsp(struct skl *skl); void skl_free_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl); -- cgit v1.2.3 From d2240f0dad488c66e14c45762bd23999901f57a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:13:13 +0000 Subject: ASoC: rsnd: rename RSND_DVC_CHANNELS to RSND_MAX_CHANNELS The channels number is not only for DVC. Let's rename it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/dvc.c | 6 +++--- sound/soc/sh/rcar/rsnd.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 704ba7ae9eaf..f86d62730614 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -988,7 +988,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, int ch_size, u32 max) { - if (ch_size > RSND_DVC_CHANNELS) + if (ch_size > RSND_MAX_CHANNELS) return -EINVAL; _cfg->cfg.max = max; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 302c193f674d..d757f1316385 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -83,15 +83,15 @@ static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 val[RSND_DVC_CHANNELS]; + u32 val[RSND_MAX_CHANNELS]; int i; /* Enable Ramp */ if (dvc->ren.val) - for (i = 0; i < RSND_DVC_CHANNELS; i++) + for (i = 0; i < RSND_MAX_CHANNELS; i++) val[i] = dvc->volume.cfg.max; else - for (i = 0; i < RSND_DVC_CHANNELS; i++) + for (i = 0; i < RSND_MAX_CHANNELS; i++) val[i] = dvc->volume.val[i]; /* Enable Digital Volume */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index bbaf89b6de8a..61cb4aefdfd9 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -550,10 +550,10 @@ struct rsnd_kctrl_cfg { struct snd_kcontrol *kctrl; }; -#define RSND_DVC_CHANNELS 8 +#define RSND_MAX_CHANNELS 8 struct rsnd_kctrl_cfg_m { struct rsnd_kctrl_cfg cfg; - u32 val[RSND_DVC_CHANNELS]; + u32 val[RSND_MAX_CHANNELS]; }; struct rsnd_kctrl_cfg_s { -- cgit v1.2.3 From 0fbab951db17085fbb521b3a50550990b763bdf4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:13:45 +0000 Subject: ASoC: rsnd: setup SRC_ROUTE_MODE0 before SRC_SRCIR SRC_ROUTE_MODE0 determines whether to use SRC. Thus, it should be setup before SRC_SRCIR. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index ab5f13155055..dab0954196b7 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -249,6 +249,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, break; } + rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); + rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ rsnd_mod_write(mod, SRC_ADINR, adinr); rsnd_mod_write(mod, SRC_IFSCR, ifscr); @@ -258,7 +260,6 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_BSISR, bsisr); rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ - rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1); rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); -- cgit v1.2.3 From 1120dbff2abd3dd9ca3f0736d0690b9592cdadb3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:14:09 +0000 Subject: ASoC: rsnd: indicates status failed SSI Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 592505a4bc13..a72ce284e34b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -140,7 +140,8 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, udelay(50); } - dev_warn(dev, "status check failed\n"); + dev_warn(dev, "%s[%d] status check failed\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); } static int rsnd_ssi_irq(struct rsnd_mod *mod, -- cgit v1.2.3 From 26d34b11af6a344da6191beca2e2883f65d2597a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:14:37 +0000 Subject: ASoC: rsnd: SSI function parameter uses "mod" instead of "ssi" To reduce confusion, SSI uses "mod" instead of "ssi" as function parameter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index a72ce284e34b..c5c4510afb2d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -188,14 +188,14 @@ u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) return mask; } -static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, +static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_io_to_priv(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); int slots = rsnd_get_slot_width(io); int j, ret; @@ -255,11 +255,11 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, return -EIO; } -static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, +static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); if (!rsnd_rdai_is_clk_master(rdai)) @@ -277,11 +277,12 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, rsnd_adg_ssi_clk_stop(mod); } -static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, +static int rsnd_ssi_config_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); u32 cr_own; u32 cr_mode; u32 wsr; @@ -317,7 +318,7 @@ static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, return -EINVAL; } - if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) { + if (rsnd_ssi_is_dma_mode(mod)) { cr_mode = UIEN | OIEN | /* over/under run */ DMEN; /* DMA : enable DMA */ } else { @@ -356,14 +357,14 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, rsnd_mod_power_on(mod); - ret = rsnd_ssi_master_clk_start(ssi, io); + ret = rsnd_ssi_master_clk_start(mod, io); if (ret < 0) return ret; if (rsnd_ssi_is_parent(mod, io)) return 0; - ret = rsnd_ssi_config_init(ssi, io); + ret = rsnd_ssi_config_init(mod, io); if (ret < 0) return ret; @@ -389,7 +390,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, if (!rsnd_ssi_is_parent(mod, io)) ssi->cr_own = 0; - rsnd_ssi_master_clk_stop(ssi, io); + rsnd_ssi_master_clk_stop(mod, io); rsnd_mod_power_off(mod); -- cgit v1.2.3 From 5bf5d8fc7f5a8a1e75413939e4bdb00ebc2d5610 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:16:04 +0000 Subject: ASoC: rsnd: fixup forever loop bug on SSI commit b5b442abd9 ("ASoC: rsnd: add .irq callback") added .irq support, and it cares both parent SSI and normal SSI. But it should care only normal SSI. Otherwise SSI might be forever loop if SSI is used as both parent SSI and normal SSI (= 2 users), and if under/over run error happen. Because irq disable do nothing in such case. This patch solve this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index c5c4510afb2d..90c3f58821db 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -149,13 +149,12 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod, struct rsnd_priv *priv, int enable) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); u32 val = 0; if (rsnd_is_gen1(priv)) return 0; - if (ssi->usrcnt != 1) + if (rsnd_ssi_is_parent(mod, io)) return 0; if (enable) -- cgit v1.2.3 From c8e969a85ecb982dccf2ba13ba9aff9f1a68eab2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:16:43 +0000 Subject: ASoC: rsnd: add missing .irq callback for DMA commit b5b442abd9d5 ("ASoC: rsnd: add .irq callback") added .irq callback but SSI DMA is missing it. This patch adds it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 90c3f58821db..b1a29e28b251 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -694,6 +694,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, + .irq = rsnd_ssi_irq, .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, }; -- cgit v1.2.3 From 0dc6bf75023a42895962800020583c19e0b87159 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:17:18 +0000 Subject: ASoC: rsnd: tidyup SSI init/start sequence SSI want to have SSIWSR settings and SSICR settings without EN bit when init, and SSICR EN bit only when start timing. Otherwise, SSI output signal might be unstable. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b1a29e28b251..120587270fe7 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -276,7 +276,7 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, rsnd_adg_ssi_clk_stop(mod); } -static int rsnd_ssi_config_init(struct rsnd_mod *mod, +static void rsnd_ssi_config_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); @@ -313,8 +313,6 @@ static int rsnd_ssi_config_init(struct rsnd_mod *mod, case 32: cr_own |= DWL_24; break; - default: - return -EINVAL; } if (rsnd_ssi_is_dma_mode(mod)) { @@ -338,8 +336,16 @@ static int rsnd_ssi_config_init(struct rsnd_mod *mod, ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; ssi->wsr = wsr; +} - return 0; +static void rsnd_ssi_register_setup(struct rsnd_mod *mod) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + rsnd_mod_write(mod, SSIWSR, ssi->wsr); + rsnd_mod_write(mod, SSICR, ssi->cr_own | + ssi->cr_clk | + ssi->cr_mode); /* without EN */ } /* @@ -360,12 +366,10 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (ret < 0) return ret; - if (rsnd_ssi_is_parent(mod, io)) - return 0; + if (!rsnd_ssi_is_parent(mod, io)) + rsnd_ssi_config_init(mod, io); - ret = rsnd_ssi_config_init(mod, io); - if (ret < 0) - return ret; + rsnd_ssi_register_setup(mod); /* clear error status */ rsnd_ssi_status_clear(mod); @@ -428,22 +432,14 @@ static int rsnd_ssi_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 cr; - - cr = ssi->cr_own | - ssi->cr_clk | - ssi->cr_mode; - /* * EN will be set via SSIU :: SSI_CONTROL * if Multi channel mode */ - if (!rsnd_ssi_multi_slaves(io)) - cr |= EN; + if (rsnd_ssi_multi_slaves(io)) + return 0; - rsnd_mod_write(mod, SSICR, cr); - rsnd_mod_write(mod, SSIWSR, ssi->wsr); + rsnd_mod_bset(mod, SSICR, EN, EN); return 0; } -- cgit v1.2.3 From 098bd8911a5eacc3b70fdc09fa4084657511c584 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:17:52 +0000 Subject: ASoC: rsnd: Parent SSI attach is not needed if not clock master Parent SSI is needed if it is PIN sharing and clock master, otherwise, not needed. But, whether clockk master is judged on .set_fmt, thus, it can't call rsnd_ssi_parent_attach() on .probe. Now, .pcm_new will be called after .set_fmt, so this patch reuses it at this point. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 120587270fe7..b5c6f0c274c3 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -545,12 +545,17 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) * SSI PIO */ static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) + struct rsnd_dai_stream *io) { + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + if (!__rsnd_ssi_is_pin_sharing(mod)) return; + if (!rsnd_rdai_is_clk_master(rdai)) + return; + switch (rsnd_mod_id(mod)) { case 1: case 2: @@ -565,6 +570,20 @@ static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, } } +static int rsnd_ssi_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + /* + * rsnd_rdai_is_clk_master() will be enabled after set_fmt, + * and, pcm_new will be called after it. + * This function reuse pcm_new at this point. + */ + rsnd_ssi_parent_attach(mod, io); + + return 0; +} + static int rsnd_ssi_common_probe(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -580,7 +599,10 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, if (rsnd_ssi_is_multi_slave(mod, io)) return 0; - rsnd_ssi_parent_attach(mod, io, priv); + /* + * It can't judge ssi parent at this point + * see rsnd_ssi_pcm_new() + */ ret = rsnd_ssiu_attach(io, mod); if (ret < 0) @@ -602,6 +624,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, .irq = rsnd_ssi_irq, + .pcm_new = rsnd_ssi_pcm_new, .hw_params = rsnd_ssi_hw_params, }; @@ -691,6 +714,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, .irq = rsnd_ssi_irq, + .pcm_new = rsnd_ssi_pcm_new, .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, }; -- cgit v1.2.3 From 615fb6c7b13b7f142f5f8e23e5f8593dd1e7b319 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:18:16 +0000 Subject: ASoC: rsnd: move rsnd_ssi_irq() position prepare for runtime judging for SSI work Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b5c6f0c274c3..d46bc08ad977 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -144,27 +144,6 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, rsnd_mod_name(mod), rsnd_mod_id(mod)); } -static int rsnd_ssi_irq(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, - int enable) -{ - u32 val = 0; - - if (rsnd_is_gen1(priv)) - return 0; - - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - if (enable) - val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; - - rsnd_mod_write(mod, SSI_INT_ENABLE, val); - - return 0; -} - u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) { struct rsnd_mod *mod; @@ -480,6 +459,27 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, return 0; } +static int rsnd_ssi_irq(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, + int enable) +{ + u32 val = 0; + + if (rsnd_is_gen1(priv)) + return 0; + + if (rsnd_ssi_is_parent(mod, io)) + return 0; + + if (enable) + val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; + + rsnd_mod_write(mod, SSI_INT_ENABLE, val); + + return 0; +} + static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { -- cgit v1.2.3 From 4f5c634d58e71963d3c34a0a4af9ec71785f094f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:18:54 +0000 Subject: ASoC: rsnd: judge multi SSI in runtime Current rsnd supports multi SSI (maximum 4 SSI for 8ch), and, it should determine whether using each SSI or not in runtime. Current judgement is vague, and had broken by c308abe45e2("ASoC: rsnd: rsnd_ssi_is_multi_slave() macro uses rsnd_ssi_multi_slaves()") This patch makes clean it, and solve this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/ssi.c | 15 +++++++++++++-- sound/soc/sh/rcar/ssiu.c | 6 +++--- 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f86d62730614..7bc5b724fbf5 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -230,7 +230,7 @@ int rsnd_get_slot_width(struct rsnd_dai_stream *io) int chan = runtime->channels; /* Multi channel Mode */ - if (rsnd_ssi_multi_slaves(io)) + if (rsnd_ssi_multi_slaves_runtime(io)) chan /= rsnd_get_slot_num(io); /* TDM Extend Mode needs 8ch */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 61cb4aefdfd9..5f613eb42614 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -599,7 +599,7 @@ void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); -u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io); +u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); #define rsnd_ssi_is_pin_sharing(io) \ __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d46bc08ad977..32f1f5fb82b6 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -144,7 +144,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, rsnd_mod_name(mod), rsnd_mod_id(mod)); } -u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) +static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) { struct rsnd_mod *mod; enum rsnd_mod_type types[] = { @@ -166,6 +166,17 @@ u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) return mask; } +u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + u32 mask = rsnd_ssi_multi_slaves(io); + + if (mask && (runtime->channels >= 6)) + return mask; + + return 0; +} + static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -415,7 +426,7 @@ static int rsnd_ssi_start(struct rsnd_mod *mod, * EN will be set via SSIU :: SSI_CONTROL * if Multi channel mode */ - if (rsnd_ssi_multi_slaves(io)) + if (rsnd_ssi_multi_slaves_runtime(io)) return 0; rsnd_mod_bset(mod, SSICR, EN, EN); diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 11e55889b401..1b8ea0e09bc2 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -27,7 +27,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io); + u32 multi_ssi_slaves = rsnd_ssi_multi_slaves_runtime(io); int use_busif = rsnd_ssi_use_busif(io); int id = rsnd_mod_id(mod); u32 mask1, val1; @@ -136,7 +136,7 @@ static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, rsnd_mod_write(mod, SSI_CTRL, 0x1); - if (rsnd_ssi_multi_slaves(io)) + if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0x1); return 0; @@ -151,7 +151,7 @@ static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, rsnd_mod_write(mod, SSI_CTRL, 0); - if (rsnd_ssi_multi_slaves(io)) + if (rsnd_ssi_multi_slaves_runtime(io)) rsnd_mod_write(mod, SSI_CONTROL, 0); return 0; -- cgit v1.2.3 From fd9adcfdc1434fdd4d0a14ddfe686449a6ffeeb3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 18 Feb 2016 08:19:12 +0000 Subject: ASoC: rsnd: judge work SSI in runtime Current rsnd supports multi SSI (maximum 4 SSI for 8ch), and, it should determine whether using each SSI or not in runtime. All SSIs are not used even if there are 4 SSI in case of stereo. Current driver setups un-used SSI in such case. It is no problem, but not needed. This patch judges it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 32f1f5fb82b6..0979db8af8f9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -96,6 +96,8 @@ struct rsnd_ssi { #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_is_multi_slave(mod, io) \ (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) +#define rsnd_ssi_is_run_mods(mod, io) \ + (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { @@ -166,6 +168,16 @@ static u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) return mask; } +static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + + return rsnd_ssi_multi_slaves_runtime(io) | + 1 << rsnd_mod_id(ssi_mod) | + 1 << rsnd_mod_id(ssi_parent_mod); +} + u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); @@ -348,6 +360,9 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + ssi->usrcnt++; rsnd_mod_power_on(mod); @@ -374,6 +389,9 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + if (!ssi->usrcnt) { dev_err(dev, "%s[%d] usrcnt error\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); @@ -422,6 +440,9 @@ static int rsnd_ssi_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + /* * EN will be set via SSIU :: SSI_CONTROL * if Multi channel mode @@ -441,6 +462,9 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); u32 cr; + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + /* * don't stop if not last user * see also @@ -483,6 +507,9 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod, if (rsnd_ssi_is_parent(mod, io)) return 0; + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + if (enable) val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; -- cgit v1.2.3 From 6793a3d70676c6f3d2ec0ce4e1e241617541702c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 17 Feb 2016 21:33:59 +0530 Subject: ASoC: hdac_hdmi: Fix possible memory leak in hw_params It's possible for hw_params to be called two times. So add NULL check to prevent memory leak. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 2884dbf0bc07..d2a2e1882fdd 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -405,9 +405,13 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return -ENODEV; } - dd = kzalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; + dd = snd_soc_dai_get_dma_data(dai, substream); + if (!dd) { + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + } + dd->format = snd_hdac_calc_stream_format(params_rate(hparams), params_channels(hparams), params_format(hparams), 24, 0); @@ -433,9 +437,11 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, AC_VERB_SET_STREAM_FORMAT, 0); dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); - snd_soc_dai_set_dma_data(dai, substream, NULL); - kfree(dd); + if (dd) { + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(dd); + } return 0; } -- cgit v1.2.3 From 54dfa1eaf4f8222811900922c67f539e60cc69c2 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 17 Feb 2016 21:34:00 +0530 Subject: ASoC: hdac_hdmi: Don't fail in dai startup to make userland happy In dai startup, driver was checking for ELD and would fail if no monitor is connected. This causes userland like PA, CRAS to be unhappy as they scan the device list at bootup. So move the ELD check to hw_params and fail if valid ELD is not found. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 48 ++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index d2a2e1882fdd..f12af62a2084 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -398,10 +398,20 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_pin *pin; struct hdac_ext_dma_params *dd; - if (dai->id > 0) { - dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + dai_map = &hdmi->dai_map[dai->id]; + pin = dai_map->pin; + + if (!pin) + return -ENODEV; + + if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { + dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", + pin->nid); return -ENODEV; } @@ -431,11 +441,6 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, 0); - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_STREAM_FORMAT, 0); - dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); if (dd) { @@ -536,6 +541,11 @@ static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( return NULL; } +/* + * This tries to get a valid pin and set the HW constraints based on the + * ELD. Even if a valid pin is not found return success so that device open + * doesn't fail. + */ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -550,17 +560,22 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, cvt = dai_map->cvt; pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); + + /* + * To make PA and other userland happy. + * userland scans devices so returning error does not help. + */ if (!pin) - return -EIO; + return 0; if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { - dev_err(&hdac->hdac.dev, + dev_warn(&hdac->hdac.dev, "Failed: montior present? %d ELD valid?: %d for pin: %d\n", pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); - return -ENODEV; + return 0; } dai_map->pin = pin; @@ -587,12 +602,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id]; - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); + if (dai_map->pin) { + snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_STREAM_FORMAT, 0); + + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); - snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, + snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - dai_map->pin = NULL; + dai_map->pin = NULL; + } } static int -- cgit v1.2.3 From aeaccef0bc0d364792ecc9455cb13d007fd7a371 Mon Sep 17 00:00:00 2001 From: Ramesh Babu Date: Wed, 17 Feb 2016 21:34:01 +0530 Subject: ASoC: hdac_hdmi: Fix to keep codec power active during enumeration. The codec power is turned OFF in the first explicit call to pm_runtime_suspend to keep the i915 refcount balanced. During regular operation, the power is turned ON/OFF in runtime PM handlers. Signed-off-by: Ramesh Babu Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f12af62a2084..57ab212b279b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1426,6 +1426,18 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) INIT_LIST_HEAD(&hdmi_priv->pcm_list); mutex_init(&hdmi_priv->pin_mutex); + /* + * Turned off in the runtime_suspend during the first explicit + * pm_runtime_suspend call. + */ + ret = snd_hdac_display_power(edev->hdac.bus, true); + if (ret < 0) { + dev_err(&edev->hdac.dev, + "Cannot turn on display power on i915 err: %d\n", + ret); + return ret; + } + ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&codec->dev, -- cgit v1.2.3 From ab85f5b36ea3474622303a36293e63cf78f4a797 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 17 Feb 2016 21:34:02 +0530 Subject: ASoC: hdac_hdmi: Fix to reconfigure registers in runtime resume The register are reset during the D3 to D0 transition. So reconfigure them. Also as all DAIs are now supported, remove the dai id check in prepare. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 57ab212b279b..2445b4351efb 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -374,11 +374,6 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, struct hdac_ext_dma_params *dd; int ret; - if (dai->id > 0) { - dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); - return -ENODEV; - } - dai_map = &hdmi->dai_map[dai->id]; dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); @@ -451,6 +446,18 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, return 0; } +static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map) +{ + /* Enable transmission */ + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, 1); + + /* Category Code (CC) to zero */ + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0); +} + static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, struct hdac_hdmi_dai_pin_map *dai_map) { @@ -580,6 +587,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, dai_map->pin = pin; + hdac_hdmi_enable_cvt(hdac, dai_map); ret = hdac_hdmi_enable_pin(hdac, dai_map); if (ret < 0) return ret; @@ -949,14 +957,6 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) dai_map->dai_id = dai_id; dai_map->cvt = cvt; - /* Enable transmission */ - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_1, 1); - - /* Category Code (CC) to zero */ - snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_2, 0); - dai_id++; if (dai_id == HDA_MAX_CVTS) { @@ -1527,6 +1527,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev) return err; } + hdac_hdmi_skl_enable_all_pins(&edev->hdac); + hdac_hdmi_skl_enable_dp12(&edev->hdac); + /* Power up afg */ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) snd_hdac_codec_write(hdac, hdac->afg, 0, -- cgit v1.2.3 From aceb5d20d725fdc9c9d42522944baed3370b472c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 17 Feb 2016 21:34:05 +0530 Subject: ASoC: Intel: Skylake: Fix possible memory corruption in codec dai dma params Set required parameters for hdac_ext_dma_params object instead of skl_dma_params. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 092450ac1c78..bbb6c2870b7f 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -475,7 +475,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct skl_dma_params *dma_params; + struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; @@ -487,11 +487,9 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); /* set the stream tag in the codec dai dma params */ - dma_params = (struct skl_dma_params *) - snd_soc_dai_get_dma_data(codec_dai, substream); + dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; - snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); -- cgit v1.2.3 From 6980c057ea1bca145e8fef39ddf541254f7c8747 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 17 Feb 2016 21:34:06 +0530 Subject: ASoC: Intel: Skylake: Add i915 enabling in skl probe The SKL also supports HDMI output so in probe we need to enable the HDMI using common i915 APIs to ensure it gets probed on the bus After S3 during the controller resequencing the codec domain need to be kept ON for successful reconfiguration of Codec. Once configured it will be turned OFF in codec driver. Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/skylake/skl.c | 51 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 803f95e40679..6e65085e8bc3 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -154,6 +154,7 @@ config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE select SND_SOC_TOPOLOGY + select SND_HDA_I915 select SND_SOC_INTEL_SST config SND_SOC_INTEL_SKL_RT286_MACH diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index f89abb179efe..0d38bdb8321b 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -28,6 +28,9 @@ #include #include #include "../common/sst-acpi.h" +#include +#include +#include #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" @@ -243,6 +246,16 @@ static int skl_resume(struct device *dev) struct hdac_bus *bus = ebus_to_hbus(ebus); int ret; + /* Turned OFF in HDMI codec driver after codec reconfiguration */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = snd_hdac_display_power(bus, true); + if (ret < 0) { + dev_err(bus->dev, + "Cannot turn on display power on i915\n"); + return ret; + } + } + /* * resume only when we are not in suspend active, otherwise need to * restore the device @@ -481,6 +494,27 @@ static int skl_create(struct pci_dev *pci, return 0; } +static int skl_i915_init(struct hdac_bus *bus) +{ + int err; + + /* + * The HDMI codec is in GPU so we need to ensure that it is powered + * up and ready for probe + */ + err = snd_hdac_i915_init(bus); + if (err < 0) + return err; + + err = snd_hdac_display_power(bus, true); + if (err < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915\n"); + return err; + } + + return err; +} + static int skl_first_init(struct hdac_ext_bus *ebus) { struct skl *skl = ebus_to_skl(ebus); @@ -543,6 +577,12 @@ static int skl_first_init(struct hdac_ext_bus *ebus) /* initialize chip */ skl_init_pci(skl); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + err = skl_i915_init(bus); + if (err < 0) + return err; + } + skl_init_chip(bus, true); /* codec detection */ @@ -617,6 +657,14 @@ static int skl_probe(struct pci_dev *pci, if (err < 0) goto out_unregister; + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + err = snd_hdac_display_power(bus, false); + if (err < 0) { + dev_err(bus->dev, "Cannot turn off display power on i915\n"); + return err; + } + } + /*configure PM */ pm_runtime_put_noidle(bus->dev); pm_runtime_allow(bus->dev); @@ -671,6 +719,9 @@ static void skl_remove(struct pci_dev *pci) if (skl->tplg) release_firmware(skl->tplg); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_i915_exit(&ebus->bus); + if (pci_dev_run_wake(pci)) pm_runtime_get_noresume(&pci->dev); pci_dev_put(pci); -- cgit v1.2.3 From 8cca87c073ac38c7866fb86205fc9ff312a3a575 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 17 Feb 2016 21:34:07 +0530 Subject: ASoC: Intel: Skylake: Add HDMI FE and BE cpu dais This patch enables HDMI support in passthrough mode in skylake. Skylake supports 3 pin widgets in HDMI codec, so add 3 FE and 3 BE dais Add required hw info, formats, rates to support HDMI. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 78 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index bbb6c2870b7f..dab0900eef26 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -676,6 +676,51 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +{ + .name = "HDMI1 Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "HDMI1 Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "HDMI2 Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "HDMI2 Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "HDMI3 Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "HDMI3 Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, /* BE CPU Dais */ { @@ -715,14 +760,41 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { - .name = "iDisp Pin", + .name = "iDisp1 Pin", .ops = &skl_link_dai_ops, .playback = { - .stream_name = "iDisp Tx", + .stream_name = "iDisp1 Tx", .channels_min = HDA_STEREO, .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "iDisp2 Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "iDisp2 Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "iDisp3 Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "iDisp3 Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, }, }, { -- cgit v1.2.3 From 144a98835d2b4fc8a732628eaa5c98c573d58baf Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:17 +0000 Subject: ASoC: qcom: use snd_dma_alloc/free* apis There is no point in having local allocation functions when the driver can use snd_dma_alloc/free() apis. This patch replaces the local versions of the dma allocation apis with the snd_dma_alloc/free() apis. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 42 ++++++----------------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 4aeb8e1a7160..ec2414dc089a 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -439,39 +439,6 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) return IRQ_HANDLED; } -static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *rt) -{ - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = rt->platform->dev; - buf->private_data = NULL; - buf->area = dma_alloc_coherent(rt->platform->dev, size, &buf->addr, - GFP_KERNEL); - if (!buf->area) { - dev_err(rt->platform->dev, "%s: Could not allocate DMA buffer\n", - __func__); - return -ENOMEM; - } - buf->bytes = size; - - return 0; -} - -static void lpass_platform_free_buffer(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *rt) -{ - struct snd_dma_buffer *buf = &substream->dma_buffer; - - if (buf->area) { - dma_free_coherent(rt->dev, buf->bytes, buf->area, - buf->addr); - } - buf->area = NULL; -} - static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; @@ -483,6 +450,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) struct lpass_variant *v = drvdata->variant; int ret; struct lpass_pcm_data *data; + size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -499,7 +467,9 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) snd_soc_pcm_set_drvdata(soc_runtime, data); - ret = lpass_platform_alloc_buffer(substream, soc_runtime); + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + soc_runtime->platform->dev, + size, &substream->dma_buffer); if (ret) return ret; @@ -514,7 +484,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) return 0; err_buf: - lpass_platform_free_buffer(substream, soc_runtime); + snd_dma_free_pages(&substream->dma_buffer); return ret; } @@ -533,7 +503,7 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm) if (v->free_dma_channel) v->free_dma_channel(drvdata, data->rdma_ch); - lpass_platform_free_buffer(substream, soc_runtime); + snd_dma_free_pages(&substream->dma_buffer); } static struct snd_soc_platform_driver lpass_platform_driver = { -- cgit v1.2.3 From ffc1325e1d3bb809dbd8c0b7f9682a22e51a69c3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:23 +0000 Subject: ASoC: qcom: add wrdma register details to lpass_variant This patch adds wrdma related register offsets, wrdma channel start and shifts into lpass variant structure. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 0b63e2e5bcc9..024a771be4dc 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -71,12 +71,16 @@ struct lpass_variant { u32 rdma_reg_base; u32 rdma_reg_stride; u32 rdma_channels; + u32 wrdma_reg_base; + u32 wrdma_reg_stride; + u32 wrdma_channels; /** * on SOCs like APQ8016 the channel control bits start * at different offset to ipq806x **/ u32 rdmactl_audif_start; + u32 wrdma_channel_start; /* SOC specific intialization like clocks */ int (*init)(struct platform_device *pdev); int (*exit)(struct platform_device *pdev); -- cgit v1.2.3 From ec5b82878c36f8c7c6d0d85eacd5185633e6c91b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:30 +0000 Subject: ASoC: qcom: rename rdmactl_audif_start to dmactrl_audif_start This patch renames rdmactl_audif_start to dmactrl_audif_start as this is common for both rdma and wrdma. Without this patch the name would be bit misleading to the readers. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 2 +- sound/soc/qcom/lpass-platform.c | 4 ++-- sound/soc/qcom/lpass.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 94efc01020c4..6cc7e72b6ff3 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -212,7 +212,7 @@ static struct lpass_variant apq8016_data = { .rdma_reg_base = 0x8400, .rdma_reg_stride = 0x1000, .rdma_channels = 2, - .rdmactl_audif_start = 1, + .dmactl_audif_start = 1, .dai_driver = apq8016_lpass_cpu_dai_driver, .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), .init = apq8016_lpass_init, diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index ec2414dc089a..7245c2ed4e8b 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); unsigned int regval; int bitwidth; - int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start; + int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { @@ -101,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, } regval = LPAIF_RDMACTL_BURSTEN_INCR4 | - LPAIF_RDMACTL_AUDINTF(rdma_port) | + LPAIF_RDMACTL_AUDINTF(dma_port) | LPAIF_RDMACTL_FIFOWM_8; switch (bitwidth) { diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 024a771be4dc..412399acfe3d 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -79,7 +79,7 @@ struct lpass_variant { * on SOCs like APQ8016 the channel control bits start * at different offset to ipq806x **/ - u32 rdmactl_audif_start; + u32 dmactl_audif_start; u32 wrdma_channel_start; /* SOC specific intialization like clocks */ int (*init)(struct platform_device *pdev); -- cgit v1.2.3 From 73c847b6d3670e4521cd3f603102332614d0b640 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:37 +0000 Subject: ASoC: qcom: pass direction to dma allocation This patch updates the internal dma allocation callbacks to take the stream direction so that it can allocate channels suitable for that stream direction. Before the capture support this was not necessary. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 3 ++- sound/soc/qcom/lpass-ipq806x.c | 2 +- sound/soc/qcom/lpass-platform.c | 3 ++- sound/soc/qcom/lpass.h | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 6cc7e72b6ff3..99061f42953e 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -133,7 +133,8 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { }, }; -static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata) +static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, + int direction) { struct lpass_variant *v = drvdata->variant; int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map, diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 7a4167952711..119048c016ec 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -63,7 +63,7 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { .ops = &asoc_qcom_lpass_cpu_dai_ops, }; -static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata) +static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir) { return IPQ806X_LPAIF_RDMA_CHAN_MI2S; } diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 7245c2ed4e8b..69c5ad8e2bd7 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -457,7 +457,8 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) return -ENOMEM; if (v->alloc_dma_channel) - data->rdma_ch = v->alloc_dma_channel(drvdata); + data->rdma_ch = v->alloc_dma_channel(drvdata, + SNDRV_PCM_STREAM_PLAYBACK); if (IS_ERR_VALUE(data->rdma_ch)) return data->rdma_ch; diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 412399acfe3d..8475b609f8ce 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -84,7 +84,7 @@ struct lpass_variant { /* SOC specific intialization like clocks */ int (*init)(struct platform_device *pdev); int (*exit)(struct platform_device *pdev); - int (*alloc_dma_channel)(struct lpass_data *data); + int (*alloc_dma_channel)(struct lpass_data *data, int direction); int (*free_dma_channel)(struct lpass_data *data, int ch); /* SOC specific dais */ -- cgit v1.2.3 From 0a536400ad2ea72c80e6257fa71aa78d17bd43e3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:45 +0000 Subject: ASoC: qcom: ipq806x: add error in dma allocation. ipq806x is only ever tested for playback so return error in dma allocation if the stream direction is capture. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-ipq806x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 119048c016ec..29a35296d8da 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -65,7 +65,10 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = { static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir) { - return IPQ806X_LPAIF_RDMA_CHAN_MI2S; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + return IPQ806X_LPAIF_RDMA_CHAN_MI2S; + else /* Capture currently not implemented */ + return -EINVAL; } static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) -- cgit v1.2.3 From 4d809fb12189aef9419f7337bb1767de85699003 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:51 +0000 Subject: ASoC: qcom: rename rdma_ch_bit_map to dma_ch_bit_map rdma_ch_bit_map can be reused for wrdma channel allocations as wrdma channel numbering start after rdma channel numbers. With capture support referring rdma_ch_bit_map for wrdma channel allocation is confusing, so renaming rdma_ch_bit_map to dma_ch_bit_map makes sense. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 6 +++--- sound/soc/qcom/lpass.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index 99061f42953e..ca3bbd58c81a 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -137,20 +137,20 @@ static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction) { struct lpass_variant *v = drvdata->variant; - int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map, + int chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, v->rdma_channels); if (chan >= v->rdma_channels) return -EBUSY; - set_bit(chan, &drvdata->rdma_ch_bit_map); + set_bit(chan, &drvdata->dma_ch_bit_map); return chan; } static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) { - clear_bit(chan, &drvdata->rdma_ch_bit_map); + clear_bit(chan, &drvdata->dma_ch_bit_map); return 0; } diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 8475b609f8ce..30714ad1e138 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -50,7 +50,7 @@ struct lpass_data { struct lpass_variant *variant; /* bit map to keep track of static channel allocations */ - unsigned long rdma_ch_bit_map; + unsigned long dma_ch_bit_map; /* used it for handling interrupt per dma channel */ struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS]; -- cgit v1.2.3 From 0a14a1bf2e81a75c5b814a3904f971fb5a53c068 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:17:57 +0000 Subject: ASoC: qcom: ipq806x: add wrdma related register offsets This patch adds wrdma related register offsets to the lpass variant data of ipq806x. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-ipq806x.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 29a35296d8da..608c1a92af8a 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -86,6 +86,10 @@ static struct lpass_variant ipq806x_data = { .rdma_reg_base = 0x6000, .rdma_reg_stride = 0x1000, .rdma_channels = 4, + .wrdma_reg_base = 0xB000, + .wrdma_reg_stride = 0x1000, + .wrdma_channel_start = 5, + .wrdma_channels = 4, .dai_driver = &ipq806x_lpass_cpu_dai_driver, .num_dai = 1, .alloc_dma_channel = ipq806x_lpass_alloc_dma_channel, -- cgit v1.2.3 From 39ad0ecd1e26a4138bf299b98265fceab60553a6 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:06 +0000 Subject: ASoC: qcom: add mic related i2s control register defines This patch adds mic related bitmasks and offsets in the i2c control register. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 95e22f131052..65997945cc25 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -47,6 +47,28 @@ #define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT) #define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT) +#define LPAIF_I2SCTL_MICEN_MASK GENMASK(8, 8) +#define LPAIF_I2SCTL_MICEN_SHIFT 8 +#define LPAIF_I2SCTL_MICEN_DISABLE (0 << LPAIF_I2SCTL_MICEN_SHIFT) +#define LPAIF_I2SCTL_MICEN_ENABLE (1 << LPAIF_I2SCTL_MICEN_SHIFT) + +#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4) +#define LPAIF_I2SCTL_MICMODE_SHIFT 4 +#define LPAIF_I2SCTL_MICMODE_NONE (0 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD0 (1 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD1 (2 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD2 (3 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_SD3 (4 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_QUAD01 (5 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_QUAD23 (6 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_6CH (7 << LPAIF_I2SCTL_MICMODE_SHIFT) +#define LPAIF_I2SCTL_MICMODE_8CH (8 << LPAIF_I2SCTL_MICMODE_SHIFT) + +#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3) +#define LPAIF_I2SCTL_MICMONO_SHIFT 3 +#define LPAIF_I2SCTL_MICMONO_STEREO (0 << LPAIF_I2SCTL_MICMONO_SHIFT) +#define LPAIF_I2SCTL_MICMONO_MONO (1 << LPAIF_I2SCTL_MICMONO_SHIFT) + #define LPAIF_I2SCTL_WSSRC_MASK 0x0004 #define LPAIF_I2SCTL_WSSRC_SHIFT 2 #define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT) -- cgit v1.2.3 From 71aaa600787faffd72a9b674c9e5c9ded7cd9a82 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:14 +0000 Subject: ASoC: qcom: add wrdma register definitions This patch adds wrdma registers into the lpaif-reg.h. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 65997945cc25..760d21905f90 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -145,4 +145,15 @@ #define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) #define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) +#define LPAIF_WRDMA_REG_ADDR(v, addr, chan) \ + (v->wrdma_reg_base + (addr) + \ + v->wrdma_reg_stride * (chan - v->wrdma_channel_start)) + +#define LPAIF_WRDMACTL_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x00, (chan)) +#define LPAIF_WRDMABASE_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x04, (chan)) +#define LPAIF_WRDMABUFF_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x08, (chan)) +#define LPAIF_WRDMACURR_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x0C, (chan)) +#define LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan)) +#define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan)) + #endif /* __LPASS_LPAIF_REG_H__ */ -- cgit v1.2.3 From ec9e0ec84476954f971feb5e0422b48cb25dde58 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:20 +0000 Subject: ASoC: qcom: add generic bit masks for RDMA and WRDMA This patch adds generic masks for accessing bits in rdma/wrdma registers. Doing this would simplify the driver and adding capture support would be much simpler. Also there is no point in having same bit masks for bits in both rdma and wrdma registers. This patch also deletes the RDMA specific bit masks and makes the code use the generic bit masks. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 83 ++++++++++++++++++++++++---------------- sound/soc/qcom/lpass-platform.c | 54 ++++++++++++++------------ 2 files changed, 79 insertions(+), 58 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 760d21905f90..2240bc68e6ec 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -112,39 +112,6 @@ #define LPAIF_RDMAPER_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x10, (chan)) #define LPAIF_RDMAPERCNT_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x14, (chan)) -#define LPAIF_RDMACTL_BURSTEN_MASK 0x800 -#define LPAIF_RDMACTL_BURSTEN_SHIFT 11 -#define LPAIF_RDMACTL_BURSTEN_SINGLE (0 << LPAIF_RDMACTL_BURSTEN_SHIFT) -#define LPAIF_RDMACTL_BURSTEN_INCR4 (1 << LPAIF_RDMACTL_BURSTEN_SHIFT) - -#define LPAIF_RDMACTL_WPSCNT_MASK 0x700 -#define LPAIF_RDMACTL_WPSCNT_SHIFT 8 -#define LPAIF_RDMACTL_WPSCNT_ONE (0 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_TWO (1 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_THREE (2 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_FOUR (3 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_SIX (5 << LPAIF_RDMACTL_WPSCNT_SHIFT) -#define LPAIF_RDMACTL_WPSCNT_EIGHT (7 << LPAIF_RDMACTL_WPSCNT_SHIFT) - -#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0 -#define LPAIF_RDMACTL_AUDINTF_SHIFT 4 - -#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E -#define LPAIF_RDMACTL_FIFOWM_SHIFT 1 -#define LPAIF_RDMACTL_FIFOWM_1 (0 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_2 (1 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_3 (2 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_4 (3 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_5 (4 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_6 (5 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_7 (6 << LPAIF_RDMACTL_FIFOWM_SHIFT) -#define LPAIF_RDMACTL_FIFOWM_8 (7 << LPAIF_RDMACTL_FIFOWM_SHIFT) - -#define LPAIF_RDMACTL_ENABLE_MASK 0x1 -#define LPAIF_RDMACTL_ENABLE_SHIFT 0 -#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT) -#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT) - #define LPAIF_WRDMA_REG_ADDR(v, addr, chan) \ (v->wrdma_reg_base + (addr) + \ v->wrdma_reg_stride * (chan - v->wrdma_channel_start)) @@ -156,4 +123,54 @@ #define LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan)) #define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan)) +#define __LPAIF_DMA_REG(v, chan, dir, reg) \ + (dir == SNDRV_PCM_STREAM_PLAYBACK) ? \ + LPAIF_RDMA##reg##_REG(v, chan) : \ + LPAIF_WRDMA##reg##_REG(v, chan) + +#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CTL) +#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BASE) +#define LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BUFF) +#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CURR) +#define LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER) +#define LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT) + +#define LPAIF_DMACTL_BURSTEN_MASK 0x800 +#define LPAIF_DMACTL_BURSTEN_SHIFT 11 +#define LPAIF_DMACTL_BURSTEN_SINGLE (0 << LPAIF_DMACTL_BURSTEN_SHIFT) +#define LPAIF_DMACTL_BURSTEN_INCR4 (1 << LPAIF_DMACTL_BURSTEN_SHIFT) + +#define LPAIF_DMACTL_WPSCNT_MASK 0x700 +#define LPAIF_DMACTL_WPSCNT_SHIFT 8 +#define LPAIF_DMACTL_WPSCNT_ONE (0 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_TWO (1 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_THREE (2 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_FOUR (3 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_SIX (5 << LPAIF_DMACTL_WPSCNT_SHIFT) +#define LPAIF_DMACTL_WPSCNT_EIGHT (7 << LPAIF_DMACTL_WPSCNT_SHIFT) + +#define LPAIF_DMACTL_AUDINTF_MASK 0x0F0 +#define LPAIF_DMACTL_AUDINTF_SHIFT 4 +#define LPAIF_DMACTL_AUDINTF(id) (id << LPAIF_DMACTL_AUDINTF_SHIFT) + +#define LPAIF_DMACTL_FIFOWM_MASK 0x00E +#define LPAIF_DMACTL_FIFOWM_SHIFT 1 +#define LPAIF_DMACTL_FIFOWM_1 (0 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_2 (1 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_3 (2 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_4 (3 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_5 (4 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_6 (5 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_7 (6 << LPAIF_DMACTL_FIFOWM_SHIFT) +#define LPAIF_DMACTL_FIFOWM_8 (7 << LPAIF_DMACTL_FIFOWM_SHIFT) + +#define LPAIF_DMACTL_ENABLE_MASK 0x1 +#define LPAIF_DMACTL_ENABLE_SHIFT 0 +#define LPAIF_DMACTL_ENABLE_OFF (0 << LPAIF_DMACTL_ENABLE_SHIFT) +#define LPAIF_DMACTL_ENABLE_ON (1 << LPAIF_DMACTL_ENABLE_SHIFT) + +#define LPAIF_DMACTL_DYNCLK_MASK BIT(12) +#define LPAIF_DMACTL_DYNCLK_SHIFT 12 +#define LPAIF_DMACTL_DYNCLK_OFF (0 << LPAIF_DMACTL_DYNCLK_SHIFT) +#define LPAIF_DMACTL_DYNCLK_ON (1 << LPAIF_DMACTL_DYNCLK_SHIFT) #endif /* __LPASS_LPAIF_REG_H__ */ diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 69c5ad8e2bd7..348e50bc8891 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -90,6 +90,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int regval; + int dir = substream->stream; int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; @@ -100,25 +101,25 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, return bitwidth; } - regval = LPAIF_RDMACTL_BURSTEN_INCR4 | - LPAIF_RDMACTL_AUDINTF(dma_port) | - LPAIF_RDMACTL_FIFOWM_8; + regval = LPAIF_DMACTL_BURSTEN_INCR4 | + LPAIF_DMACTL_AUDINTF(dma_port) | + LPAIF_DMACTL_FIFOWM_8; switch (bitwidth) { case 16: switch (channels) { case 1: case 2: - regval |= LPAIF_RDMACTL_WPSCNT_ONE; + regval |= LPAIF_DMACTL_WPSCNT_ONE; break; case 4: - regval |= LPAIF_RDMACTL_WPSCNT_TWO; + regval |= LPAIF_DMACTL_WPSCNT_TWO; break; case 6: - regval |= LPAIF_RDMACTL_WPSCNT_THREE; + regval |= LPAIF_DMACTL_WPSCNT_THREE; break; case 8: - regval |= LPAIF_RDMACTL_WPSCNT_FOUR; + regval |= LPAIF_DMACTL_WPSCNT_FOUR; break; default: dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", @@ -130,19 +131,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, case 32: switch (channels) { case 1: - regval |= LPAIF_RDMACTL_WPSCNT_ONE; + regval |= LPAIF_DMACTL_WPSCNT_ONE; break; case 2: - regval |= LPAIF_RDMACTL_WPSCNT_TWO; + regval |= LPAIF_DMACTL_WPSCNT_TWO; break; case 4: - regval |= LPAIF_RDMACTL_WPSCNT_FOUR; + regval |= LPAIF_DMACTL_WPSCNT_FOUR; break; case 6: - regval |= LPAIF_RDMACTL_WPSCNT_SIX; + regval |= LPAIF_DMACTL_WPSCNT_SIX; break; case 8: - regval |= LPAIF_RDMACTL_WPSCNT_EIGHT; + regval |= LPAIF_DMACTL_WPSCNT_EIGHT; break; default: dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n", @@ -157,7 +158,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, } ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval); + LPAIF_DMACTL_REG(v, pcm_data->rdma_ch, dir), regval); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -194,6 +195,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; int ret, ch = pcm_data->rdma_ch; + int dir = substream->stream; ret = regmap_write(drvdata->lpaif_map, LPAIF_RDMABASE_REG(v, ch), @@ -205,7 +207,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) } ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMABUFF_REG(v, ch), + LPAIF_DMABUFF_REG(v, ch, dir), (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n", @@ -214,7 +216,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) } ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMAPER_REG(v, ch), + LPAIF_DMAPER_REG(v, ch, dir), (snd_pcm_lib_period_bytes(substream) >> 2) - 1); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n", @@ -223,8 +225,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) } ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, ch), - LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON); + LPAIF_DMACTL_REG(v, ch, dir), + LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -243,6 +245,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; int ret, ch = pcm_data->rdma_ch; + int dir = substream->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -269,9 +272,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, } ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, ch), - LPAIF_RDMACTL_ENABLE_MASK, - LPAIF_RDMACTL_ENABLE_ON); + LPAIF_DMACTL_REG(v, ch, dir), + LPAIF_DMACTL_ENABLE_MASK, + LPAIF_DMACTL_ENABLE_ON); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -282,9 +285,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ret = regmap_update_bits(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, ch), - LPAIF_RDMACTL_ENABLE_MASK, - LPAIF_RDMACTL_ENABLE_OFF); + LPAIF_DMACTL_REG(v, ch, dir), + LPAIF_DMACTL_ENABLE_MASK, + LPAIF_DMACTL_ENABLE_OFF); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -315,9 +318,10 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; int ret, ch = pcm_data->rdma_ch; + int dir = substream->stream; ret = regmap_read(drvdata->lpaif_map, - LPAIF_RDMABASE_REG(v, ch), &base_addr); + LPAIF_DMABASE_REG(v, ch, dir), &base_addr); if (ret) { dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n", __func__, ret); @@ -325,7 +329,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( } ret = regmap_read(drvdata->lpaif_map, - LPAIF_RDMACURR_REG(v, ch), &curr_addr); + LPAIF_DMACURR_REG(v, ch, dir), &curr_addr); if (ret) { dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n", __func__, ret); -- cgit v1.2.3 From dad8061494d2a2ce6edc2ae5ab530b0d330b2685 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:27 +0000 Subject: ASoC: qcom: apq8016: set the correct max register for regmap Now that we are ready to access wrdma registers, set the max register and other regmap related configs to use correct values. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e5101e0d2d37..91774fc87fcc 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -294,6 +294,17 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) return true; } + for (i = 0; i < v->wrdma_channels; ++i) { + if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start)) + return true; + } + return false; } @@ -327,6 +338,19 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg) return true; } + for (i = 0; i < v->wrdma_channels; ++i) { + if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start)) + return true; + if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start)) + return true; + } + return false; } @@ -344,6 +368,10 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg) if (reg == LPAIF_RDMACURR_REG(v, i)) return true; + for (i = 0; i < v->wrdma_channels; ++i) + if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start)) + return true; + return false; } @@ -398,8 +426,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) return PTR_ERR((void const __force *)drvdata->lpaif); } - lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant, - variant->rdma_channels); + lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant, + variant->wrdma_channels + + variant->wrdma_channel_start); drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif, &lpass_cpu_regmap_config); -- cgit v1.2.3 From fb5d11524eda5561f6dd8cc03f9dc778027ce907 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:33 +0000 Subject: ASoC: qcom: add mic support This patch adds mic support to the lpass driver, most of the driver is reused as it is, only the register level access is changed depending on te direction of the stream. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 113 +++++++++++++++++++-------- sound/soc/qcom/lpass-platform.c | 167 +++++++++++++++++++++++++++++----------- 2 files changed, 204 insertions(+), 76 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 91774fc87fcc..3cde9fb977fa 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -120,31 +120,60 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - switch (channels) { - case 1: - regval |= LPAIF_I2SCTL_SPKMODE_SD0; - regval |= LPAIF_I2SCTL_SPKMONO_MONO; - break; - case 2: - regval |= LPAIF_I2SCTL_SPKMODE_SD0; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - case 4: - regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - case 6: - regval |= LPAIF_I2SCTL_SPKMODE_6CH; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - case 8: - regval |= LPAIF_I2SCTL_SPKMODE_8CH; - regval |= LPAIF_I2SCTL_SPKMONO_STEREO; - break; - default: - dev_err(dai->dev, "%s() invalid channels given: %u\n", - __func__, channels); - return -EINVAL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (channels) { + case 1: + regval |= LPAIF_I2SCTL_SPKMODE_SD0; + regval |= LPAIF_I2SCTL_SPKMONO_MONO; + break; + case 2: + regval |= LPAIF_I2SCTL_SPKMODE_SD0; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 4: + regval |= LPAIF_I2SCTL_SPKMODE_QUAD01; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 6: + regval |= LPAIF_I2SCTL_SPKMODE_6CH; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + case 8: + regval |= LPAIF_I2SCTL_SPKMODE_8CH; + regval |= LPAIF_I2SCTL_SPKMONO_STEREO; + break; + default: + dev_err(dai->dev, "%s() invalid channels given: %u\n", + __func__, channels); + return -EINVAL; + } + } else { + switch (channels) { + case 1: + regval |= LPAIF_I2SCTL_MICMODE_SD0; + regval |= LPAIF_I2SCTL_MICMONO_MONO; + break; + case 2: + regval |= LPAIF_I2SCTL_MICMODE_SD0; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + case 4: + regval |= LPAIF_I2SCTL_MICMODE_QUAD01; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + case 6: + regval |= LPAIF_I2SCTL_MICMODE_6CH; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + case 8: + regval |= LPAIF_I2SCTL_MICMODE_8CH; + regval |= LPAIF_I2SCTL_MICMONO_STEREO; + break; + default: + dev_err(dai->dev, "%s() invalid channels given: %u\n", + __func__, channels); + return -EINVAL; + } } ret = regmap_write(drvdata->lpaif_map, @@ -188,10 +217,19 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream, { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret; + unsigned int val, mask; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = LPAIF_I2SCTL_SPKEN_ENABLE; + mask = LPAIF_I2SCTL_SPKEN_MASK; + } else { + val = LPAIF_I2SCTL_MICEN_ENABLE; + mask = LPAIF_I2SCTL_MICEN_MASK; + } ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE); + mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); @@ -204,16 +242,24 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, { struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); int ret = -EINVAL; + unsigned int val, mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = LPAIF_I2SCTL_SPKEN_ENABLE; + mask = LPAIF_I2SCTL_SPKEN_MASK; + } else { + val = LPAIF_I2SCTL_MICEN_ENABLE; + mask = LPAIF_I2SCTL_MICEN_MASK; + } + ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - LPAIF_I2SCTL_SPKEN_MASK, - LPAIF_I2SCTL_SPKEN_ENABLE); + mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); @@ -221,11 +267,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val = LPAIF_I2SCTL_SPKEN_DISABLE; + mask = LPAIF_I2SCTL_SPKEN_MASK; + } else { + val = LPAIF_I2SCTL_MICEN_DISABLE; + mask = LPAIF_I2SCTL_MICEN_MASK; + } + ret = regmap_update_bits(drvdata->lpaif_map, LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), - LPAIF_I2SCTL_SPKEN_MASK, - LPAIF_I2SCTL_SPKEN_DISABLE); + mask, val); if (ret) dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n", __func__, ret); diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 348e50bc8891..6e8665430bd5 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -26,6 +26,7 @@ struct lpass_pcm_data { int rdma_ch; + int wrdma_ch; int i2s_port; }; @@ -90,10 +91,15 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, snd_pcm_format_t format = params_format(params); unsigned int channels = params_channels(params); unsigned int regval; - int dir = substream->stream; + int ch, dir = substream->stream; int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; + bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { dev_err(soc_runtime->dev, "%s() invalid bit width given: %d\n", @@ -158,7 +164,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, } ret = regmap_write(drvdata->lpaif_map, - LPAIF_DMACTL_REG(v, pcm_data->rdma_ch, dir), regval); + LPAIF_DMACTL_REG(v, ch, dir), regval); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -175,10 +181,15 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; + unsigned int reg; int ret; - ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch); + else + reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch); + + ret = regmap_write(drvdata->lpaif_map, reg, 0); if (ret) dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", __func__, ret); @@ -194,11 +205,15 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; - int ret, ch = pcm_data->rdma_ch; - int dir = substream->stream; + int ret, ch, dir = substream->stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; ret = regmap_write(drvdata->lpaif_map, - LPAIF_RDMABASE_REG(v, ch), + LPAIF_DMABASE_REG(v, ch, dir), runtime->dma_addr); if (ret) { dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n", @@ -244,8 +259,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; - int ret, ch = pcm_data->rdma_ch; - int dir = substream->stream; + int ret, ch, dir = substream->stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -317,8 +336,12 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; unsigned int base_addr, curr_addr; - int ret, ch = pcm_data->rdma_ch; - int dir = substream->stream; + int ret, ch, dir = substream->stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + ch = pcm_data->rdma_ch; + else + ch = pcm_data->wrdma_ch; ret = regmap_read(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), &base_addr); @@ -446,8 +469,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data) static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) { struct snd_pcm *pcm = soc_runtime->pcm; - struct snd_pcm_substream *substream = - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_pcm_substream *psubstream, *csubstream; struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai; struct lpass_data *drvdata = snd_soc_platform_get_drvdata(soc_runtime->platform); @@ -460,55 +482,108 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) if (!data) return -ENOMEM; - if (v->alloc_dma_channel) - data->rdma_ch = v->alloc_dma_channel(drvdata, - SNDRV_PCM_STREAM_PLAYBACK); + data->i2s_port = cpu_dai->driver->id; + snd_soc_pcm_set_drvdata(soc_runtime, data); - if (IS_ERR_VALUE(data->rdma_ch)) - return data->rdma_ch; + psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (psubstream) { + if (v->alloc_dma_channel) + data->rdma_ch = v->alloc_dma_channel(drvdata, + SNDRV_PCM_STREAM_PLAYBACK); - drvdata->substream[data->rdma_ch] = substream; - data->i2s_port = cpu_dai->driver->id; + if (IS_ERR_VALUE(data->rdma_ch)) + return data->rdma_ch; - snd_soc_pcm_set_drvdata(soc_runtime, data); + drvdata->substream[data->rdma_ch] = psubstream; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - soc_runtime->platform->dev, - size, &substream->dma_buffer); - if (ret) - return ret; + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + soc_runtime->platform->dev, + size, &psubstream->dma_buffer); + if (ret) + goto playback_alloc_err; - ret = regmap_write(drvdata->lpaif_map, + ret = regmap_write(drvdata->lpaif_map, LPAIF_RDMACTL_REG(v, data->rdma_ch), 0); - if (ret) { - dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", + if (ret) { + dev_err(soc_runtime->dev, + "%s() error writing to rdmactl reg: %d\n", __func__, ret); - goto err_buf; + goto capture_alloc_err; + } + } + + csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (csubstream) { + if (v->alloc_dma_channel) + data->wrdma_ch = v->alloc_dma_channel(drvdata, + SNDRV_PCM_STREAM_CAPTURE); + + if (IS_ERR_VALUE(data->wrdma_ch)) + goto capture_alloc_err; + + drvdata->substream[data->wrdma_ch] = csubstream; + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + soc_runtime->platform->dev, + size, &csubstream->dma_buffer); + if (ret) + goto capture_alloc_err; + + ret = regmap_write(drvdata->lpaif_map, + LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0); + if (ret) { + dev_err(soc_runtime->dev, + "%s() error writing to wrdmactl reg: %d\n", + __func__, ret); + goto capture_reg_err; + } } return 0; -err_buf: - snd_dma_free_pages(&substream->dma_buffer); +capture_reg_err: + if (csubstream) + snd_dma_free_pages(&csubstream->dma_buffer); + +capture_alloc_err: + if (psubstream) + snd_dma_free_pages(&psubstream->dma_buffer); + + playback_alloc_err: + dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n"); + return ret; } static void lpass_platform_pcm_free(struct snd_pcm *pcm) { - struct snd_pcm_substream *substream = - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct lpass_data *drvdata = - snd_soc_platform_get_drvdata(soc_runtime->platform); - struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime); - struct lpass_variant *v = drvdata->variant; - - drvdata->substream[data->rdma_ch] = NULL; - - if (v->free_dma_channel) - v->free_dma_channel(drvdata, data->rdma_ch); - - snd_dma_free_pages(&substream->dma_buffer); + struct snd_soc_pcm_runtime *rt; + struct lpass_data *drvdata; + struct lpass_pcm_data *data; + struct lpass_variant *v; + struct snd_pcm_substream *substream; + int ch, i; + + for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { + substream = pcm->streams[i].substream; + if (substream) { + rt = substream->private_data; + data = snd_soc_pcm_get_drvdata(rt); + drvdata = snd_soc_platform_get_drvdata(rt->platform); + + ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ? data->rdma_ch + : data->wrdma_ch; + v = drvdata->variant; + drvdata->substream[ch] = NULL; + if (v->free_dma_channel) + v->free_dma_channel(drvdata, ch); + + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } + } } static struct snd_soc_platform_driver lpass_platform_driver = { -- cgit v1.2.3 From bbedefb9e8c350bc7e8e7dc4732ba1974789e3e9 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:18:45 +0000 Subject: ASoC: qcom: apq8016-sbc: add mic support This patch add mic support on apq8016-sbc board aka db410c. Tested it with headset mic. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 1efdf0088ecd..1289543c8fb2 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -30,6 +30,7 @@ struct apq8016_sbc_data { struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ }; +#define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21) #define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17) #define MIC_CTRL_TLMM_SCLK_EN BIT(1) #define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16)) @@ -53,6 +54,12 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd) MIC_CTRL_TLMM_SCLK_EN, pdata->mic_iomux); break; + case MI2S_TERTIARY: + writel(readl(pdata->mic_iomux) | MIC_CTRL_TER_WS_SLAVE_SEL | + MIC_CTRL_TLMM_SCLK_EN, + pdata->mic_iomux); + + break; default: dev_err(card->dev, "unsupported cpu dai configuration\n"); @@ -126,9 +133,6 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) } link->platform_of_node = link->cpu_of_node; - /* For now we only support playback */ - link->playback_only = true; - ret = of_property_read_string(np, "link-name", &link->name); if (ret) { dev_err(card->dev, "error getting codec dai_link name\n"); -- cgit v1.2.3 From 6a9364ca6fa07ec215b0ba7c49d110b8236985d4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 11 Feb 2016 12:19:30 +0000 Subject: ASoC: qcom: apq8016: add wrdma support This patch adds wrdma support in lpass-apq8016 by providing the register offsets and adding support in dma channel allocation callback. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-apq8016.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c index ca3bbd58c81a..3eef0c37ba50 100644 --- a/sound/soc/qcom/lpass-apq8016.c +++ b/sound/soc/qcom/lpass-apq8016.c @@ -137,11 +137,23 @@ static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata, int direction) { struct lpass_variant *v = drvdata->variant; - int chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, + int chan = 0; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + chan = find_first_zero_bit(&drvdata->dma_ch_bit_map, v->rdma_channels); - if (chan >= v->rdma_channels) - return -EBUSY; + if (chan >= v->rdma_channels) + return -EBUSY; + } else { + chan = find_next_zero_bit(&drvdata->dma_ch_bit_map, + v->wrdma_channel_start + + v->wrdma_channels, + v->wrdma_channel_start); + + if (chan >= v->wrdma_channel_start + v->wrdma_channels) + return -EBUSY; + } set_bit(chan, &drvdata->dma_ch_bit_map); @@ -214,6 +226,10 @@ static struct lpass_variant apq8016_data = { .rdma_reg_stride = 0x1000, .rdma_channels = 2, .dmactl_audif_start = 1, + .wrdma_reg_base = 0xB000, + .wrdma_reg_stride = 0x1000, + .wrdma_channel_start = 5, + .wrdma_channels = 2, .dai_driver = apq8016_lpass_cpu_dai_driver, .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), .init = apq8016_lpass_init, -- cgit v1.2.3 From 2303b32f54289267adb75437cdeba50be92221f5 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 16 Feb 2016 22:27:19 +0100 Subject: ASoC: cht_bsw_rt5645: Enable jack detection Add missing DAPM pins and enable jack detection on those pins for Cherrytrail and Braswell. Signed-off-by: Carlo Caione Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index e6cf800ab231..c7af2715b3f9 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -147,6 +147,17 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Ext Spk"), }; +static struct snd_soc_jack_pin cht_bsw_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int cht_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -202,9 +213,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) else jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; - ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", + ret = snd_soc_card_jack_new(runtime->card, "Headset", jack_type, &ctx->jack, - NULL, 0); + cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins)); if (ret) { dev_err(runtime->dev, "Headset jack creation failed %d\n", ret); return ret; -- cgit v1.2.3 From f8260afa444b670016f22f2ba1440d9d2e74dcb6 Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Mon, 8 Feb 2016 18:09:21 +0100 Subject: ASoC: sunxi: Add support for the SPDIF block The sun4i, sun5i and sun7i SoC families have an SPDIF block which is capable of playback and capture. This patch enables the playback of this block for the sun4i families. Signed-off-by: Marcus Cooper Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 8 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun4i-spdif.c | 550 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 559 insertions(+) create mode 100644 sound/soc/sunxi/sun4i-spdif.c (limited to 'sound/soc') diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 84c72ec6ad73..ae42294ef688 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -8,4 +8,12 @@ config SND_SUN4I_CODEC Select Y or M to add support for the Codec embedded in the Allwinner A10 and affiliated SoCs. +config SND_SUN4I_SPDIF + tristate "Allwinner A10 SPDIF Support" + depends on OF + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y or M to add support for the S/PDIF audio block in the Allwinner + A10 and affiliated SoCs. endmenu diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index ea8a08c881d6..8f5e889667f1 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o +obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c new file mode 100644 index 000000000000..0b04fb02125c --- /dev/null +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -0,0 +1,550 @@ +/* + * ALSA SoC SPDIF Audio Layer + * + * Copyright 2015 Andrea Venturi + * Copyright 2015 Marcus Cooper + * + * Based on the Allwinner SDK driver, released under the GPL. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUN4I_SPDIF_CTL (0x00) + #define SUN4I_SPDIF_CTL_MCLKDIV(v) ((v) << 4) /* v even */ + #define SUN4I_SPDIF_CTL_MCLKOUTEN BIT(2) + #define SUN4I_SPDIF_CTL_GEN BIT(1) + #define SUN4I_SPDIF_CTL_RESET BIT(0) + +#define SUN4I_SPDIF_TXCFG (0x04) + #define SUN4I_SPDIF_TXCFG_SINGLEMOD BIT(31) + #define SUN4I_SPDIF_TXCFG_ASS BIT(17) + #define SUN4I_SPDIF_TXCFG_NONAUDIO BIT(16) + #define SUN4I_SPDIF_TXCFG_TXRATIO(v) ((v) << 4) + #define SUN4I_SPDIF_TXCFG_TXRATIO_MASK GENMASK(8, 4) + #define SUN4I_SPDIF_TXCFG_FMTRVD GENMASK(3, 2) + #define SUN4I_SPDIF_TXCFG_FMT16BIT (0 << 2) + #define SUN4I_SPDIF_TXCFG_FMT20BIT (1 << 2) + #define SUN4I_SPDIF_TXCFG_FMT24BIT (2 << 2) + #define SUN4I_SPDIF_TXCFG_CHSTMODE BIT(1) + #define SUN4I_SPDIF_TXCFG_TXEN BIT(0) + +#define SUN4I_SPDIF_RXCFG (0x08) + #define SUN4I_SPDIF_RXCFG_LOCKFLAG BIT(4) + #define SUN4I_SPDIF_RXCFG_CHSTSRC BIT(3) + #define SUN4I_SPDIF_RXCFG_CHSTCP BIT(1) + #define SUN4I_SPDIF_RXCFG_RXEN BIT(0) + +#define SUN4I_SPDIF_TXFIFO (0x0C) + +#define SUN4I_SPDIF_RXFIFO (0x10) + +#define SUN4I_SPDIF_FCTL (0x14) + #define SUN4I_SPDIF_FCTL_FIFOSRC BIT(31) + #define SUN4I_SPDIF_FCTL_FTX BIT(17) + #define SUN4I_SPDIF_FCTL_FRX BIT(16) + #define SUN4I_SPDIF_FCTL_TXTL(v) ((v) << 8) + #define SUN4I_SPDIF_FCTL_TXTL_MASK GENMASK(12, 8) + #define SUN4I_SPDIF_FCTL_RXTL(v) ((v) << 3) + #define SUN4I_SPDIF_FCTL_RXTL_MASK GENMASK(7, 3) + #define SUN4I_SPDIF_FCTL_TXIM BIT(2) + #define SUN4I_SPDIF_FCTL_RXOM(v) ((v) << 0) + #define SUN4I_SPDIF_FCTL_RXOM_MASK GENMASK(1, 0) + +#define SUN4I_SPDIF_FSTA (0x18) + #define SUN4I_SPDIF_FSTA_TXE BIT(14) + #define SUN4I_SPDIF_FSTA_TXECNTSHT (8) + #define SUN4I_SPDIF_FSTA_RXA BIT(6) + #define SUN4I_SPDIF_FSTA_RXACNTSHT (0) + +#define SUN4I_SPDIF_INT (0x1C) + #define SUN4I_SPDIF_INT_RXLOCKEN BIT(18) + #define SUN4I_SPDIF_INT_RXUNLOCKEN BIT(17) + #define SUN4I_SPDIF_INT_RXPARERREN BIT(16) + #define SUN4I_SPDIF_INT_TXDRQEN BIT(7) + #define SUN4I_SPDIF_INT_TXUIEN BIT(6) + #define SUN4I_SPDIF_INT_TXOIEN BIT(5) + #define SUN4I_SPDIF_INT_TXEIEN BIT(4) + #define SUN4I_SPDIF_INT_RXDRQEN BIT(2) + #define SUN4I_SPDIF_INT_RXOIEN BIT(1) + #define SUN4I_SPDIF_INT_RXAIEN BIT(0) + +#define SUN4I_SPDIF_ISTA (0x20) + #define SUN4I_SPDIF_ISTA_RXLOCKSTA BIT(18) + #define SUN4I_SPDIF_ISTA_RXUNLOCKSTA BIT(17) + #define SUN4I_SPDIF_ISTA_RXPARERRSTA BIT(16) + #define SUN4I_SPDIF_ISTA_TXUSTA BIT(6) + #define SUN4I_SPDIF_ISTA_TXOSTA BIT(5) + #define SUN4I_SPDIF_ISTA_TXESTA BIT(4) + #define SUN4I_SPDIF_ISTA_RXOSTA BIT(1) + #define SUN4I_SPDIF_ISTA_RXASTA BIT(0) + +#define SUN4I_SPDIF_TXCNT (0x24) + +#define SUN4I_SPDIF_RXCNT (0x28) + +#define SUN4I_SPDIF_TXCHSTA0 (0x2C) + #define SUN4I_SPDIF_TXCHSTA0_CLK(v) ((v) << 28) + #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ(v) ((v) << 24) + #define SUN4I_SPDIF_TXCHSTA0_SAMFREQ_MASK GENMASK(27, 24) + #define SUN4I_SPDIF_TXCHSTA0_CHNUM(v) ((v) << 20) + #define SUN4I_SPDIF_TXCHSTA0_CHNUM_MASK GENMASK(23, 20) + #define SUN4I_SPDIF_TXCHSTA0_SRCNUM(v) ((v) << 16) + #define SUN4I_SPDIF_TXCHSTA0_CATACOD(v) ((v) << 8) + #define SUN4I_SPDIF_TXCHSTA0_MODE(v) ((v) << 6) + #define SUN4I_SPDIF_TXCHSTA0_EMPHASIS(v) ((v) << 3) + #define SUN4I_SPDIF_TXCHSTA0_CP BIT(2) + #define SUN4I_SPDIF_TXCHSTA0_AUDIO BIT(1) + #define SUN4I_SPDIF_TXCHSTA0_PRO BIT(0) + +#define SUN4I_SPDIF_TXCHSTA1 (0x30) + #define SUN4I_SPDIF_TXCHSTA1_CGMSA(v) ((v) << 8) + #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ(v) ((v) << 4) + #define SUN4I_SPDIF_TXCHSTA1_ORISAMFREQ_MASK GENMASK(7, 4) + #define SUN4I_SPDIF_TXCHSTA1_SAMWORDLEN(v) ((v) << 1) + #define SUN4I_SPDIF_TXCHSTA1_MAXWORDLEN BIT(0) + +#define SUN4I_SPDIF_RXCHSTA0 (0x34) + #define SUN4I_SPDIF_RXCHSTA0_CLK(v) ((v) << 28) + #define SUN4I_SPDIF_RXCHSTA0_SAMFREQ(v) ((v) << 24) + #define SUN4I_SPDIF_RXCHSTA0_CHNUM(v) ((v) << 20) + #define SUN4I_SPDIF_RXCHSTA0_SRCNUM(v) ((v) << 16) + #define SUN4I_SPDIF_RXCHSTA0_CATACOD(v) ((v) << 8) + #define SUN4I_SPDIF_RXCHSTA0_MODE(v) ((v) << 6) + #define SUN4I_SPDIF_RXCHSTA0_EMPHASIS(v) ((v) << 3) + #define SUN4I_SPDIF_RXCHSTA0_CP BIT(2) + #define SUN4I_SPDIF_RXCHSTA0_AUDIO BIT(1) + #define SUN4I_SPDIF_RXCHSTA0_PRO BIT(0) + +#define SUN4I_SPDIF_RXCHSTA1 (0x38) + #define SUN4I_SPDIF_RXCHSTA1_CGMSA(v) ((v) << 8) + #define SUN4I_SPDIF_RXCHSTA1_ORISAMFREQ(v) ((v) << 4) + #define SUN4I_SPDIF_RXCHSTA1_SAMWORDLEN(v) ((v) << 1) + #define SUN4I_SPDIF_RXCHSTA1_MAXWORDLEN BIT(0) + +/* Defines for Sampling Frequency */ +#define SUN4I_SPDIF_SAMFREQ_44_1KHZ 0x0 +#define SUN4I_SPDIF_SAMFREQ_NOT_INDICATED 0x1 +#define SUN4I_SPDIF_SAMFREQ_48KHZ 0x2 +#define SUN4I_SPDIF_SAMFREQ_32KHZ 0x3 +#define SUN4I_SPDIF_SAMFREQ_22_05KHZ 0x4 +#define SUN4I_SPDIF_SAMFREQ_24KHZ 0x6 +#define SUN4I_SPDIF_SAMFREQ_88_2KHZ 0x8 +#define SUN4I_SPDIF_SAMFREQ_76_8KHZ 0x9 +#define SUN4I_SPDIF_SAMFREQ_96KHZ 0xa +#define SUN4I_SPDIF_SAMFREQ_176_4KHZ 0xc +#define SUN4I_SPDIF_SAMFREQ_192KHZ 0xe + +struct sun4i_spdif_dev { + struct platform_device *pdev; + struct clk *spdif_clk; + struct clk *apb_clk; + struct snd_soc_dai_driver cpu_dai_drv; + struct regmap *regmap; + struct snd_dmaengine_dai_dma_data dma_params_tx; +}; + +static void sun4i_spdif_configure(struct sun4i_spdif_dev *host) +{ + /* soft reset SPDIF */ + regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET); + + /* flush TX FIFO */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL, + SUN4I_SPDIF_FCTL_FTX, SUN4I_SPDIF_FCTL_FTX); + + /* clear TX counter */ + regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0); +} + +static void sun4i_snd_txctrl_on(struct snd_pcm_substream *substream, + struct sun4i_spdif_dev *host) +{ + if (substream->runtime->channels == 1) + regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG, + SUN4I_SPDIF_TXCFG_SINGLEMOD, + SUN4I_SPDIF_TXCFG_SINGLEMOD); + + /* SPDIF TX ENABLE */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG, + SUN4I_SPDIF_TXCFG_TXEN, SUN4I_SPDIF_TXCFG_TXEN); + + /* DRQ ENABLE */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_INT, + SUN4I_SPDIF_INT_TXDRQEN, SUN4I_SPDIF_INT_TXDRQEN); + + /* Global enable */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL, + SUN4I_SPDIF_CTL_GEN, SUN4I_SPDIF_CTL_GEN); +} + +static void sun4i_snd_txctrl_off(struct snd_pcm_substream *substream, + struct sun4i_spdif_dev *host) +{ + /* SPDIF TX DISABLE */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG, + SUN4I_SPDIF_TXCFG_TXEN, 0); + + /* DRQ DISABLE */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_INT, + SUN4I_SPDIF_INT_TXDRQEN, 0); + + /* Global disable */ + regmap_update_bits(host->regmap, SUN4I_SPDIF_CTL, + SUN4I_SPDIF_CTL_GEN, 0); +} + +static int sun4i_spdif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(rtd->cpu_dai); + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + + sun4i_spdif_configure(host); + + return 0; +} + +static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + int ret = 0; + int fmt; + unsigned long rate = params_rate(params); + u32 mclk_div = 0; + unsigned int mclk = 0; + u32 reg_val; + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai); + struct platform_device *pdev = host->pdev; + + /* Add the PCM and raw data select interface */ + switch (params_channels(params)) { + case 1: /* PCM mode */ + case 2: + fmt = 0; + break; + case 4: /* raw data mode */ + fmt = SUN4I_SPDIF_TXCFG_NONAUDIO; + break; + default: + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT; + break; + case SNDRV_PCM_FORMAT_S24_LE: + fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT; + break; + default: + return -EINVAL; + } + + switch (rate) { + case 22050: + case 44100: + case 88200: + case 176400: + mclk = 22579200; + break; + case 24000: + case 32000: + case 48000: + case 96000: + case 192000: + mclk = 24576000; + break; + default: + return -EINVAL; + } + + ret = clk_set_rate(host->spdif_clk, mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "Setting SPDIF clock rate for %d Hz failed!\n", mclk); + return ret; + } + + regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL, + SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM); + + switch (rate) { + case 22050: + case 24000: + mclk_div = 8; + break; + case 32000: + mclk_div = 6; + break; + case 44100: + case 48000: + mclk_div = 4; + break; + case 88200: + case 96000: + mclk_div = 2; + break; + case 176400: + case 192000: + mclk_div = 1; + break; + default: + return -EINVAL; + } + + reg_val = 0; + reg_val |= SUN4I_SPDIF_TXCFG_ASS; + reg_val |= fmt; /* set non audio and bit depth */ + reg_val |= SUN4I_SPDIF_TXCFG_CHSTMODE; + reg_val |= SUN4I_SPDIF_TXCFG_TXRATIO(mclk_div - 1); + regmap_write(host->regmap, SUN4I_SPDIF_TXCFG, reg_val); + + return 0; +} + +static int sun4i_spdif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int ret = 0; + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai); + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + sun4i_snd_txctrl_on(substream, host); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + sun4i_snd_txctrl_off(substream, host); + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai) +{ + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &host->dma_params_tx, NULL); + return 0; +} + +static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = { + .startup = sun4i_spdif_startup, + .trigger = sun4i_spdif_trigger, + .hw_params = sun4i_spdif_hw_params, +}; + +static const struct regmap_config sun4i_spdif_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN4I_SPDIF_RXCHSTA1, +}; + +#define SUN4I_RATES SNDRV_PCM_RATE_8000_192000 + +#define SUN4I_FORMATS (SNDRV_PCM_FORMAT_S16_LE | \ + SNDRV_PCM_FORMAT_S20_3LE | \ + SNDRV_PCM_FORMAT_S24_LE) + +static struct snd_soc_dai_driver sun4i_spdif_dai = { + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = SUN4I_RATES, + .formats = SUN4I_FORMATS, + }, + .probe = sun4i_spdif_soc_dai_probe, + .ops = &sun4i_spdif_dai_ops, + .name = "spdif", +}; + +static const struct snd_soc_dapm_widget dit_widgets[] = { + SND_SOC_DAPM_OUTPUT("spdif-out"), +}; + +static const struct snd_soc_dapm_route dit_routes[] = { + { "spdif-out", NULL, "Playback" }, +}; + +static const struct of_device_id sun4i_spdif_of_match[] = { + { .compatible = "allwinner,sun4i-a10-spdif", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match); + +static const struct snd_soc_component_driver sun4i_spdif_component = { + .name = "sun4i-spdif", +}; + +static int sun4i_spdif_runtime_suspend(struct device *dev) +{ + struct sun4i_spdif_dev *host = dev_get_drvdata(dev); + + clk_disable_unprepare(host->spdif_clk); + clk_disable_unprepare(host->apb_clk); + + return 0; +} + +static int sun4i_spdif_runtime_resume(struct device *dev) +{ + struct sun4i_spdif_dev *host = dev_get_drvdata(dev); + + clk_prepare_enable(host->spdif_clk); + clk_prepare_enable(host->apb_clk); + + return 0; +} + +static int sun4i_spdif_probe(struct platform_device *pdev) +{ + struct sun4i_spdif_dev *host; + struct resource *res; + int ret; + void __iomem *base; + + dev_dbg(&pdev->dev, "Entered %s\n", __func__); + + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->pdev = pdev; + + /* Initialize this copy of the CPU DAI driver structure */ + memcpy(&host->cpu_dai_drv, &sun4i_spdif_dai, sizeof(sun4i_spdif_dai)); + host->cpu_dai_drv.name = dev_name(&pdev->dev); + + /* Get the addresses */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + host->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &sun4i_spdif_regmap_config); + + /* Clocks */ + host->apb_clk = devm_clk_get(&pdev->dev, "apb"); + if (IS_ERR(host->apb_clk)) { + dev_err(&pdev->dev, "failed to get a apb clock.\n"); + return PTR_ERR(host->apb_clk); + } + + host->spdif_clk = devm_clk_get(&pdev->dev, "spdif"); + if (IS_ERR(host->spdif_clk)) { + dev_err(&pdev->dev, "failed to get a spdif clock.\n"); + ret = PTR_ERR(host->spdif_clk); + goto err_disable_apb_clk; + } + + host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO; + host->dma_params_tx.maxburst = 4; + host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + + platform_set_drvdata(pdev, host); + + ret = devm_snd_soc_register_component(&pdev->dev, + &sun4i_spdif_component, &sun4i_spdif_dai, 1); + if (ret) + goto err_disable_apb_clk; + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = sun4i_spdif_runtime_resume(&pdev->dev); + if (ret) + goto err_unregister; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_suspend; + return 0; +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + sun4i_spdif_runtime_suspend(&pdev->dev); +err_unregister: + pm_runtime_disable(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); +err_disable_apb_clk: + clk_disable_unprepare(host->apb_clk); + return ret; +} + +static int sun4i_spdif_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + sun4i_spdif_runtime_suspend(&pdev->dev); + + snd_soc_unregister_platform(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops sun4i_spdif_pm = { + SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend, + sun4i_spdif_runtime_resume, NULL) +}; + +static struct platform_driver sun4i_spdif_driver = { + .driver = { + .name = "sun4i-spdif", + .of_match_table = of_match_ptr(sun4i_spdif_of_match), + .pm = &sun4i_spdif_pm, + }, + .probe = sun4i_spdif_probe, + .remove = sun4i_spdif_remove, +}; + +module_platform_driver(sun4i_spdif_driver); + +MODULE_AUTHOR("Marcus Cooper "); +MODULE_AUTHOR("Andrea Venturi "); +MODULE_DESCRIPTION("Allwinner sun4i SPDIF SoC Interface"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun4i-spdif"); -- cgit v1.2.3 From c7dae7c4c60693286298e300b3d140c8cff46daa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Feb 2016 14:44:41 +0000 Subject: ASoC: wm_adsp: Avoid narrow race condition on compr pointer There is a very small window between then wm_adsp_compr_free gets call and when the DSP is actually powered down. If we get an IRQ from the DSP in this window then the wm_adsp_compr pointer will be NULL. This patch adds a check for this into the IRQ handler to avoid any issues when this happens. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 68b85ee67586..cb49a632462a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2845,7 +2845,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) goto out; } - if (compr->stream) + if (compr && compr->stream) snd_compr_fragment_elapsed(compr->stream); out: -- cgit v1.2.3 From cc815c4b86d14630a7d4ca4f4c7d2c2acb88cb52 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Feb 2016 14:44:42 +0000 Subject: ASoC: wm_adsp: Explicitly set the control access flags in all cases In the case where the firmware does not tell us the access flags for the control, we let ALSA select a default (READWRITE). But really we should be applying the volatile flag in this case, as we will read the control from the DSP if it is on in this case. This patch explicitly sets the access flags in all cases. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index cb49a632462a..ff0ce6ba1b69 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -857,6 +857,9 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ; if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; + } else { + kcontrol->access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; } ret = snd_soc_add_card_controls(dsp->card, -- cgit v1.2.3 From 7d00cd975a52e637da19548c1cc7d87a0a32b49c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Feb 2016 14:44:43 +0000 Subject: ASoC: wm_adsp: Fixup some odd line wrapping Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ff0ce6ba1b69..0f6eeb199351 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -862,15 +862,13 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; } - ret = snd_soc_add_card_controls(dsp->card, - kcontrol, 1); + ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); if (ret < 0) goto err_kcontrol; kfree(kcontrol); - ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, - ctl->name); + ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name); return 0; @@ -890,9 +888,7 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp) if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) continue; - ret = wm_coeff_read_control(ctl, - ctl->cache, - ctl->len); + ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); if (ret < 0) return ret; } @@ -909,9 +905,7 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp) if (!ctl->enabled) continue; if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { - ret = wm_coeff_write_control(ctl, - ctl->cache, - ctl->len); + ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len); if (ret < 0) return ret; } @@ -1507,8 +1501,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2); if (ret != 0) { - adsp_err(dsp, "Failed to read algorithm list: %d\n", - ret); + adsp_err(dsp, "Failed to read algorithm list: %d\n", ret); kfree(alg); return ERR_PTR(ret); } @@ -2007,8 +2000,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, goto err_mutex; } - val = (val & dsp->sysclk_mask) - >> dsp->sysclk_shift; + val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_31, @@ -2101,8 +2093,7 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) /* Wait for the RAM to start, should be near instantaneous */ for (count = 0; count < 10; ++count) { - ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, - &val); + ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); if (ret != 0) return ret; -- cgit v1.2.3 From 4f8ea6d759f6ed5d448472143cef7681e319c958 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Feb 2016 14:44:44 +0000 Subject: ASoC: wm_adsp: wm_coeff_{read|write}_control should use passed length wm_coeff_{read|write}_control were using the control length rather than the length parameter passed to them. This is not causing any issues as the two values are currently always the same, but this needs fixed to allow future improvements. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0f6eeb199351..36687db5da61 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -721,19 +721,19 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, reg = ctl->alg_region.base + ctl->offset; reg = wm_adsp_region_to_reg(mem, reg); - scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); + scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA); if (!scratch) return -ENOMEM; ret = regmap_raw_write(dsp->regmap, reg, scratch, - ctl->len); + len); if (ret) { adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", - ctl->len, reg, ret); + len, reg, ret); kfree(scratch); return ret; } - adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg); + adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg); kfree(scratch); @@ -780,20 +780,20 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, reg = ctl->alg_region.base + ctl->offset; reg = wm_adsp_region_to_reg(mem, reg); - scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); + scratch = kmalloc(len, GFP_KERNEL | GFP_DMA); if (!scratch) return -ENOMEM; - ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len); + ret = regmap_raw_read(dsp->regmap, reg, scratch, len); if (ret) { adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", ctl->len, reg, ret); kfree(scratch); return ret; } - adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg); + adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg); - memcpy(buf, scratch, ctl->len); + memcpy(buf, scratch, len); kfree(scratch); return 0; -- cgit v1.2.3 From e354d86e551656668e879c833de9890b5053cc88 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 20 Feb 2016 10:56:58 +0800 Subject: ASoC: max98926: Constify max98926_reg and max98926_regmap Signed-off-by: Axel Lin Acked-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max98926.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 5245e107de30..8d14adae5cc5 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -40,7 +40,7 @@ static const char *const max98926_hpf_cutoff_txt[] = { "200Hz", "400Hz", "800Hz", }; -static struct reg_default max98926_reg[] = { +static const struct reg_default max98926_reg[] = { { 0x0B, 0x00 }, /* IRQ Enable0 */ { 0x0C, 0x00 }, /* IRQ Enable1 */ { 0x0D, 0x00 }, /* IRQ Enable2 */ @@ -506,7 +506,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98926 = { .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), }; -static struct regmap_config max98926_regmap = { +static const struct regmap_config max98926_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = MAX98926_VERSION, -- cgit v1.2.3 From ee06b6f0675907191656b11a8405a03c6d599ea9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 20 Feb 2016 10:52:32 +0800 Subject: ASoC: max9867: Add CONFIG_SND_SOC_MAX9867 to build Signed-off-by: Axel Lin Acked-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b84fe9d75dfd..f35237d30f93 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -280,6 +280,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o +obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o -- cgit v1.2.3 From 1b36e4a2ab0cfcc322153337d2615bc6fa922567 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 20 Feb 2016 10:53:15 +0800 Subject: ASoC: max9867: Make max9867_i2c_id NULL terminated Signed-off-by: Axel Lin Acked-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 5a8481bf20c2..70b54069ad2a 100755 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -512,6 +512,7 @@ static int max9867_i2c_remove(struct i2c_client *client) static const struct i2c_device_id max9867_i2c_id[] = { { "max9867", 0 }, + { } }; static const struct of_device_id max9867_of_match[] = { -- cgit v1.2.3 From 250a99e70bf8628397901e10ad99a281dfc489d5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 20 Feb 2016 10:54:11 +0800 Subject: ASoC: max9867: Constify max9867_reg and max9867_regmap Signed-off-by: Axel Lin Acked-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 70b54069ad2a..ab7a94db8db7 100755 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -436,7 +436,7 @@ static bool max9867_volatile_register(struct device *dev, unsigned int reg) } } -static struct reg_default max9867_reg[] = { +static const struct reg_default max9867_reg[] = { { 0x04, 0x00 }, { 0x05, 0x00 }, { 0x06, 0x00 }, @@ -459,7 +459,7 @@ static struct reg_default max9867_reg[] = { { 0x17, 0x00 }, }; -static struct regmap_config max9867_regmap = { +static const struct regmap_config max9867_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = MAX9867_REVISION, -- cgit v1.2.3 From 6139b1b184d5f6257f692dc814dbcd47e4cf90f1 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 18 Jan 2016 20:07:44 +0100 Subject: ASoC: fsl_ssi: remove explicit register defaults There is no guarantee that on fsl_ssi module load SSI registers will have their power-on-reset values. In fact, if the driver is reloaded the values in registers will be whatever they were set to previously. However, the cache needs to be fully populated at probe time to avoid non-atomic allocations during register access. Special case here is imx21-class SSI, since according to datasheet it don't have SACC{ST,EN,DIS} regs. This fixes hard lockup on fsl_ssi module reload, at least in AC'97 mode. Fixes: 05cf237972fe ("ASoC: fsl_ssi: Add driver suspend and resume to support MEGA Fast") Signed-off-by: Maciej S. Szmigiero Tested-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 40dfd8a36484..ed8de1035cda 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -112,20 +112,6 @@ struct fsl_ssi_rxtx_reg_val { struct fsl_ssi_reg_val tx; }; -static const struct reg_default fsl_ssi_reg_defaults[] = { - {CCSR_SSI_SCR, 0x00000000}, - {CCSR_SSI_SIER, 0x00003003}, - {CCSR_SSI_STCR, 0x00000200}, - {CCSR_SSI_SRCR, 0x00000200}, - {CCSR_SSI_STCCR, 0x00040000}, - {CCSR_SSI_SRCCR, 0x00040000}, - {CCSR_SSI_SACNT, 0x00000000}, - {CCSR_SSI_STMSK, 0x00000000}, - {CCSR_SSI_SRMSK, 0x00000000}, - {CCSR_SSI_SACCEN, 0x00000000}, - {CCSR_SSI_SACCDIS, 0x00000000}, -}; - static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -190,8 +176,7 @@ static const struct regmap_config fsl_ssi_regconfig = { .val_bits = 32, .reg_stride = 4, .val_format_endian = REGMAP_ENDIAN_NATIVE, - .reg_defaults = fsl_ssi_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults), + .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1, .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, .precious_reg = fsl_ssi_precious_reg, @@ -201,6 +186,7 @@ static const struct regmap_config fsl_ssi_regconfig = { struct fsl_ssi_soc_data { bool imx; + bool imx21regs; /* imx21-class SSI - no SACC{ST,EN,DIS} regs */ bool offline_config; u32 sisr_write_mask; }; @@ -303,6 +289,7 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = { static struct fsl_ssi_soc_data fsl_ssi_imx21 = { .imx = true, + .imx21regs = true, .offline_config = true, .sisr_write_mask = 0, }; @@ -586,8 +573,12 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) */ regmap_write(regs, CCSR_SSI_SACNT, CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV); - regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); - regmap_write(regs, CCSR_SSI_SACCEN, 0x300); + + /* no SACC{ST,EN,DIS} regs on imx21-class SSI */ + if (!ssi_private->soc->imx21regs) { + regmap_write(regs, CCSR_SSI_SACCDIS, 0xff); + regmap_write(regs, CCSR_SSI_SACCEN, 0x300); + } /* * Enable SSI, Transmit and Receive. AC97 has to communicate with the @@ -1397,6 +1388,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) struct resource *res; void __iomem *iomem; char name[64]; + struct regmap_config regconfig = fsl_ssi_regconfig; of_id = of_match_device(fsl_ssi_ids, &pdev->dev); if (!of_id || !of_id->data) @@ -1444,15 +1436,25 @@ static int fsl_ssi_probe(struct platform_device *pdev) return PTR_ERR(iomem); ssi_private->ssi_phys = res->start; + if (ssi_private->soc->imx21regs) { + /* + * According to datasheet imx21-class SSI + * don't have SACC{ST,EN,DIS} regs. + */ + regconfig.max_register = CCSR_SSI_SRMSK; + regconfig.num_reg_defaults_raw = + CCSR_SSI_SRMSK / sizeof(uint32_t) + 1; + } + ret = of_property_match_string(np, "clock-names", "ipg"); if (ret < 0) { ssi_private->has_ipg_clk_name = false; ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, - &fsl_ssi_regconfig); + ®config); } else { ssi_private->has_ipg_clk_name = true; ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev, - "ipg", iomem, &fsl_ssi_regconfig); + "ipg", iomem, ®config); } if (IS_ERR(ssi_private->regs)) { dev_err(&pdev->dev, "Failed to init register map\n"); -- cgit v1.2.3 From edd7ea2d5486c12978fdc71c6efd493cbabeea60 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 22 Feb 2016 09:37:27 +0530 Subject: ASoC: Intel: Skylake: remove bogus comparison of an array with NULL dfw_ac->params is an array not a pointer. It will never be NULL. The check on ac->max appears sufficient. Signed-off-by: Alan Cox Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index ba0d02d1613e..c95bbce8ad5d 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1657,8 +1657,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, if (!ac->params) return -ENOMEM; - if (dfw_ac->params) - memcpy(ac->params, dfw_ac->params, ac->max); + memcpy(ac->params, dfw_ac->params, ac->max); } be->dobj.private = ac; -- cgit v1.2.3 From 255edcdfab3d1a45b78d1dacd845d6da5fc64b03 Mon Sep 17 00:00:00 2001 From: Jianqun Xu Date: Mon, 22 Feb 2016 16:32:05 +0800 Subject: ASoC: rockchip: add bindings for rk3399 i2s Add devicetree bindings for i2s controller found on rk3399 processors from rockchip. It's helpful to add full set of compatible strings for serials of Rockchip SoCs (rk3066, rk3188, rk3288, rk3399). Acked-by: Rob Herring Signed-off-by: Jianqun Xu Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rockchip-i2s.txt | 1 + sound/soc/rockchip/rockchip_i2s.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt index b7f3a9325ebd..6e86d8aa29b4 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt +++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt @@ -9,6 +9,7 @@ Required properties: - "rockchip,rk3066-i2s": for rk3066 - "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188 - "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288 + - "rockchip,rk3399-i2s", "rockchip,rk3066-i2s": for rk3399 - reg: physical base address of the controller and length of memory mapped region. - interrupts: should contain the I2S interrupt. diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 6561c4cc2edd..531a6d201d2e 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -575,6 +575,9 @@ static int rockchip_i2s_remove(struct platform_device *pdev) static const struct of_device_id rockchip_i2s_match[] = { { .compatible = "rockchip,rk3066-i2s", }, + { .compatible = "rockchip,rk3188-i2s", }, + { .compatible = "rockchip,rk3288-i2s", }, + { .compatible = "rockchip,rk3399-i2s", }, {}, }; -- cgit v1.2.3 From 3375cbe420a8987b30daf3c021bea6fb0b0fe344 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 22 Feb 2016 14:37:13 +0530 Subject: ASoC: topology: fix build warning We are getting build warning about: sound/soc/soc-topology.c:249:31: warning: 'get_dobj_type' defined but not used commit 64527e8a3529 has removed the only caller of get_dobj_type() but missed to remove the function which is now unused. And after removing get_dobj_type() we do not have any use of get_dobj_mixer_type(). Fixes: 64527e8a3529 ("ASoC: topology: Add FE DAIs dynamically") CC: Mengdong Lin Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 45 --------------------------------------------- 1 file changed, 45 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 0eb01e8155f1..07f61a67aef6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -223,51 +223,6 @@ static int get_widget_id(int tplg_type) return -EINVAL; } -static enum snd_soc_dobj_type get_dobj_mixer_type( - struct snd_soc_tplg_ctl_hdr *control_hdr) -{ - if (control_hdr == NULL) - return SND_SOC_DOBJ_NONE; - - switch (control_hdr->ops.info) { - case SND_SOC_TPLG_CTL_VOLSW: - case SND_SOC_TPLG_CTL_VOLSW_SX: - case SND_SOC_TPLG_CTL_VOLSW_XR_SX: - case SND_SOC_TPLG_CTL_RANGE: - case SND_SOC_TPLG_CTL_STROBE: - return SND_SOC_DOBJ_MIXER; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_CTL_ENUM_VALUE: - return SND_SOC_DOBJ_ENUM; - case SND_SOC_TPLG_CTL_BYTES: - return SND_SOC_DOBJ_BYTES; - default: - return SND_SOC_DOBJ_NONE; - } -} - -static enum snd_soc_dobj_type get_dobj_type(struct snd_soc_tplg_hdr *hdr, - struct snd_soc_tplg_ctl_hdr *control_hdr) -{ - switch (hdr->type) { - case SND_SOC_TPLG_TYPE_MIXER: - return get_dobj_mixer_type(control_hdr); - case SND_SOC_TPLG_TYPE_DAPM_GRAPH: - case SND_SOC_TPLG_TYPE_MANIFEST: - return SND_SOC_DOBJ_NONE; - case SND_SOC_TPLG_TYPE_DAPM_WIDGET: - return SND_SOC_DOBJ_WIDGET; - case SND_SOC_TPLG_TYPE_DAI_LINK: - return SND_SOC_DOBJ_DAI_LINK; - case SND_SOC_TPLG_TYPE_PCM: - return SND_SOC_DOBJ_PCM; - case SND_SOC_TPLG_TYPE_CODEC_LINK: - return SND_SOC_DOBJ_CODEC_LINK; - default: - return SND_SOC_DOBJ_NONE; - } -} - static inline void soc_bind_err(struct soc_tplg *tplg, struct snd_soc_tplg_ctl_hdr *hdr, int index) { -- cgit v1.2.3 From 513cb31120fb5a5b02d9e42eb1d0a0bf05e227c5 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 22 Feb 2016 14:14:31 +0530 Subject: ASoC: fix memory leak If dai_link is already bound then we just returned and leaked rtd and rtd->codec_dais which were allocated by soc_new_pcm_runtime(). We do not need this newly allocated rtd to check if dai_link is already binded. Lets check first if it is already binded before allocating this memory. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 790ee2bf1a47..d2e62b159610 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -986,16 +986,16 @@ static int soc_bind_dai_link(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); - rtd = soc_new_pcm_runtime(card, dai_link); - if (!rtd) - return -ENOMEM; - if (soc_is_dai_link_bound(card, dai_link)) { dev_dbg(card->dev, "ASoC: dai link %s already bound\n", dai_link->name); return 0; } + rtd = soc_new_pcm_runtime(card, dai_link); + if (!rtd) + return -ENOMEM; + cpu_dai_component.name = dai_link->cpu_name; cpu_dai_component.of_node = dai_link->cpu_of_node; cpu_dai_component.dai_name = dai_link->cpu_dai_name; -- cgit v1.2.3 From b6b6e4d670c9285225dc826bf69620f69717ade0 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Mon, 22 Feb 2016 16:29:19 +0800 Subject: ASoC: topology: Fix setting of stream rates, rate_min and rate_max Directly set a stream's rates, rate_min and rate_max from the topology info. Also define set_stream_info to wrap setting of the stream info. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 07f61a67aef6..1cf94d7fb9f4 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1530,6 +1530,18 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg) return 0; } +static void set_stream_info(struct snd_soc_pcm_stream *stream, + struct snd_soc_tplg_stream_caps *caps) +{ + stream->stream_name = kstrdup(caps->name, GFP_KERNEL); + stream->channels_min = caps->channels_min; + stream->channels_max = caps->channels_max; + stream->rates = caps->rates; + stream->rate_min = caps->rate_min; + stream->rate_max = caps->rate_max; + stream->formats = caps->formats; +} + static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { @@ -1548,25 +1560,13 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, if (pcm->playback) { stream = &dai_drv->playback; caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; - - stream->stream_name = kstrdup(caps->name, GFP_KERNEL); - stream->channels_min = caps->channels_min; - stream->channels_max = caps->channels_max; - stream->rates = snd_pcm_rate_range_to_bits(caps->rate_min, - caps->rate_max); - stream->formats = caps->formats; + set_stream_info(stream, caps); } if (pcm->capture) { stream = &dai_drv->capture; caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE]; - - stream->stream_name = kstrdup(caps->name, GFP_KERNEL); - stream->channels_min = caps->channels_min; - stream->channels_max = caps->channels_max; - stream->rates = snd_pcm_rate_range_to_bits(caps->rate_min, - caps->rate_max); - stream->formats = caps->formats; + set_stream_info(stream, caps); } /* pass control to component driver for optional further init */ -- cgit v1.2.3 From ea2e5b96bd6e835052981b777253def60cfd905f Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 22 Feb 2016 15:56:54 +0800 Subject: ASoC: rockchip: i2s: add default values for registers this patch add default values for registers according description from TRM. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 531a6d201d2e..2f8e20416bd3 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -440,11 +440,21 @@ static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) } } +static const struct reg_default rockchip_i2s_reg_defaults[] = { + {0x00, 0x0000000f}, + {0x04, 0x0000000f}, + {0x08, 0x00071f1f}, + {0x10, 0x001f0000}, + {0x14, 0x01f00000}, +}; + static const struct regmap_config rockchip_i2s_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, .max_register = I2S_RXDR, + .reg_defaults = rockchip_i2s_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rockchip_i2s_reg_defaults), .writeable_reg = rockchip_i2s_wr_reg, .readable_reg = rockchip_i2s_rd_reg, .volatile_reg = rockchip_i2s_volatile_reg, -- cgit v1.2.3 From 6049af00fc2fac8d27f8bd064ff68b16991a80f7 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Mon, 22 Feb 2016 15:56:55 +0800 Subject: ASoC: rt5640: add master clock handling for rt5640 enable/disable master clock when codec is active or not. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5640.txt | 3 +++ sound/soc/codecs/rt5640.c | 31 ++++++++++++++++++++++ sound/soc/codecs/rt5640.h | 2 ++ 3 files changed, 36 insertions(+) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt index 9e62f6eb348f..57fe64643050 100644 --- a/Documentation/devicetree/bindings/sound/rt5640.txt +++ b/Documentation/devicetree/bindings/sound/rt5640.txt @@ -12,6 +12,9 @@ Required properties: Optional properties: +- clocks: The phandle of the master clock to the CODEC +- clock-names: Should be "mclk" + - realtek,in1-differential - realtek,in2-differential - realtek,in3-differential diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 11d032cdc658..6cd84fb2196a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1949,7 +1949,33 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, static int rt5640_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + int ret; + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* + * SND_SOC_BIAS_PREPARE is called while preparing for a + * transition to ON or away from ON. If current bias_level + * is SND_SOC_BIAS_ON, then it is preparing for a transition + * away from ON. Disable the clock in that case, otherwise + * enable it. + */ + if (IS_ERR(rt5640->mclk)) + break; + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { + clk_disable_unprepare(rt5640->mclk); + } else { + ret = clk_prepare_enable(rt5640->mclk); + if (ret) + return ret; + } + break; + case SND_SOC_BIAS_STANDBY: if (SND_SOC_BIAS_OFF == snd_soc_codec_get_bias_level(codec)) { snd_soc_update_bits(codec, RT5640_PWR_ANLG1, @@ -2088,6 +2114,11 @@ static int rt5640_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + /* Check if MCLK provided */ + rt5640->mclk = devm_clk_get(codec->dev, "mclk"); + if (PTR_ERR(rt5640->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + rt5640->codec = codec; snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 83a7150ddc24..1761c3a98b76 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -12,6 +12,7 @@ #ifndef _RT5640_H #define _RT5640_H +#include #include /* Info */ @@ -2097,6 +2098,7 @@ struct rt5640_priv { struct snd_soc_codec *codec; struct rt5640_platform_data pdata; struct regmap *regmap; + struct clk *mclk; int sysclk; int sysclk_src; -- cgit v1.2.3 From 0f83f9296d5c91d08cf46cf1ba8a17fb870dedf0 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Fri, 19 Feb 2016 10:35:59 +0800 Subject: ASoC: mediatek: Add machine driver for ALC5650 codec This is the DPCM based machine driver with rt5650 Signed-off-by: Nicolas Boichat Signed-off-by: Koro Chen Signed-off-by: PC Liao Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt8173-rt5650.txt | 15 ++ sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/mt8173-rt5650.c | 236 +++++++++++++++++++++ 4 files changed, 262 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt8173-rt5650.txt create mode 100644 sound/soc/mediatek/mt8173-rt5650.c (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt new file mode 100644 index 000000000000..fe5a5ef1714d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt @@ -0,0 +1,15 @@ +MT8173 with RT5650 CODECS + +Required properties: +- compatible : "mediatek,mt8173-rt5650" +- mediatek,audio-codec: the phandles of rt5650 codecs +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650"; + mediatek,audio-codec = <&rt5650>; + mediatek,platform = <&afe>; + }; + diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 976967675387..6c8808798c6b 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -17,6 +17,16 @@ config SND_SOC_MT8173_MAX98090 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT8173_RT5650 + tristate "ASoC Audio driver for MT8173 with RT5650 codec" + depends on SND_SOC_MEDIATEK && I2C + select SND_SOC_RT5645 + help + This adds ASoC driver for Mediatek MT8173 boards + with the RT5650 audio codec. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173_RT5650_RT5676 tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" depends on SND_SOC_MEDIATEK && I2C diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 75effbec438d..bcdcb062e73a 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o # Machine support obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173-rt5650.c new file mode 100644 index 000000000000..bb09bb1b7f1c --- /dev/null +++ b/sound/soc/mediatek/mt8173-rt5650.c @@ -0,0 +1,236 @@ +/* + * mt8173-rt5650.c -- MT8173 machine driver with RT5650 codecs + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Koro Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "../codecs/rt5645.h" + +#define MCLK_FOR_CODECS 12288000 + +static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = { + {"Speaker", NULL, "SPOL"}, + {"Speaker", NULL, "SPOR"}, + {"DMIC L1", NULL, "Int Mic"}, + {"DMIC R1", NULL, "Int Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Headset Mic", NULL, "micbias1"}, + {"Headset Mic", NULL, "micbias2"}, + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new mt8173_rt5650_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int i, ret; + + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + + /* pll from mclk 12.288M */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, + params_rate(params) * 512); + if (ret) + return ret; + + /* sysclk from pll */ + ret = snd_soc_dai_set_sysclk(codec_dai, 1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + return 0; +} + +static struct snd_soc_ops mt8173_rt5650_ops = { + .hw_params = mt8173_rt5650_hw_params, +}; + +static struct snd_soc_jack mt8173_rt5650_jack; + +static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; + int ret; + + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + /* enable jack detection */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_jack, NULL, 0); + if (ret) { + dev_err(card->dev, "Can't new Headset Jack %d\n", ret); + return ret; + } + + return rt5645_set_jack_detect(codec, + &mt8173_rt5650_jack, + &mt8173_rt5650_jack, + &mt8173_rt5650_jack); +} + +static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { + { + .dai_name = "rt5645-aif1", + }, +}; + +enum { + DAI_LINK_PLAYBACK, + DAI_LINK_CAPTURE, + DAI_LINK_CODEC_I2S, +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link mt8173_rt5650_dais[] = { + /* Front End DAI links */ + [DAI_LINK_PLAYBACK] = { + .name = "rt5650 Playback", + .stream_name = "rt5650 Playback", + .cpu_dai_name = "DL1", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + }, + [DAI_LINK_CAPTURE] = { + .name = "rt5650 Capture", + .stream_name = "rt5650 Capture", + .cpu_dai_name = "VUL", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + }, + /* Back End DAI links */ + [DAI_LINK_CODEC_I2S] = { + .name = "Codec", + .cpu_dai_name = "I2S", + .no_pcm = 1, + .codecs = mt8173_rt5650_codecs, + .num_codecs = 1, + .init = mt8173_rt5650_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ops = &mt8173_rt5650_ops, + .ignore_pmdown_time = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +static struct snd_soc_card mt8173_rt5650_card = { + .name = "mtk-rt5650", + .owner = THIS_MODULE, + .dai_link = mt8173_rt5650_dais, + .num_links = ARRAY_SIZE(mt8173_rt5650_dais), + .controls = mt8173_rt5650_controls, + .num_controls = ARRAY_SIZE(mt8173_rt5650_controls), + .dapm_widgets = mt8173_rt5650_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_widgets), + .dapm_routes = mt8173_rt5650_routes, + .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_routes), +}; + +static int mt8173_rt5650_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt8173_rt5650_card; + struct device_node *platform_node; + int i, ret; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for (i = 0; i < card->num_links; i++) { + if (mt8173_rt5650_dais[i].platform_name) + continue; + mt8173_rt5650_dais[i].platform_of_node = platform_node; + } + + mt8173_rt5650_codecs[0].of_node = + of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0); + if (!mt8173_rt5650_codecs[0].of_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + return ret; +} + +static const struct of_device_id mt8173_rt5650_dt_match[] = { + { .compatible = "mediatek,mt8173-rt5650", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt8173_rt5650_dt_match); + +static struct platform_driver mt8173_rt5650_driver = { + .driver = { + .name = "mtk-rt5650", + .of_match_table = mt8173_rt5650_dt_match, +#ifdef CONFIG_PM + .pm = &snd_soc_pm_ops, +#endif + }, + .probe = mt8173_rt5650_dev_probe, +}; + +module_platform_driver(mt8173_rt5650_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8173 RT5650 SoC machine driver"); +MODULE_AUTHOR("Koro Chen "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtk-rt5650"); + -- cgit v1.2.3 From 7ed49700c4d6959dbfdf174023a57fc15a97c9ab Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 22 Feb 2016 07:50:32 +0530 Subject: ASoC: hdac_hdmi: Fix to wait for D3 before powering off codec Powering off codec immediately after sending D3 verb may not set the node to D3 state. So wait for a confirmation response before shutting down codec. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 2445b4351efb..aa953a5b57d4 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1486,6 +1486,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; struct hdac_bus *bus = hdac->bus; + unsigned long timeout; int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -1495,10 +1496,19 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) return 0; /* Power down afg */ - if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) + if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) { snd_hdac_codec_write(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + /* Wait till power state is set to D3 */ + timeout = jiffies + msecs_to_jiffies(1000); + while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3) + && time_before(jiffies, timeout)) { + + msleep(50); + } + } + err = snd_hdac_display_power(bus, false); if (err < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); -- cgit v1.2.3 From 571d507809812e1d9c06aa80be714bf39ece6b8e Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 22 Feb 2016 07:50:33 +0530 Subject: ASoC: hdac_hdmi: Add PM support The codec registers are reset during S3. So need to reconfigure all pins and DP1.2 feature again after resume from S3. Also reprogram the required registers if the S3 was triggered during playback. In suspended state ELD notify callback is not processed, So add ELD check for all pins as well. Also turn the codec power domain OFF which is kept ON during controller resequencing and codec reenumeration. Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index aa953a5b57d4..7851dd204a49 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -601,6 +601,26 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, pin->eld.eld_buffer); } +static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + int ret; + + dai_map = &hdmi->dai_map[dai->id]; + if (cmd == SNDRV_PCM_TRIGGER_RESUME) { + ret = hdac_hdmi_enable_pin(hdac, dai_map); + if (ret < 0) + return ret; + + return hdac_hdmi_playback_prepare(substream, dai); + } + + return 0; +} + static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1154,6 +1174,7 @@ static struct snd_soc_dai_ops hdmi_dai_ops = { .shutdown = hdac_hdmi_pcm_close, .hw_params = hdac_hdmi_set_hw_params, .prepare = hdac_hdmi_playback_prepare, + .trigger = hdac_hdmi_trigger, .hw_free = hdac_hdmi_playback_cleanup, }; @@ -1399,9 +1420,64 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec) return 0; } +#ifdef CONFIG_PM +static int hdmi_codec_resume(struct snd_soc_codec *codec) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin; + struct hdac_device *hdac = &edev->hdac; + struct hdac_bus *bus = hdac->bus; + int err; + unsigned long timeout; + + hdac_hdmi_skl_enable_all_pins(&edev->hdac); + hdac_hdmi_skl_enable_dp12(&edev->hdac); + + /* Power up afg */ + if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) { + + snd_hdac_codec_write(hdac, hdac->afg, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Wait till power state is set to D0 */ + timeout = jiffies + msecs_to_jiffies(1000); + while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0) + && time_before(jiffies, timeout)) { + msleep(50); + } + } + + /* + * As the ELD notify callback request is not entertained while the + * device is in suspend state. Need to manually check detection of + * all pins here. + */ + list_for_each_entry(pin, &hdmi->pin_list, head) + hdac_hdmi_present_sense(pin, 1); + + /* + * Codec power is turned ON during controller resume. + * Turn it OFF here + */ + err = snd_hdac_display_power(bus, false); + if (err < 0) { + dev_err(bus->dev, + "Cannot turn OFF display power on i915, err: %d\n", + err); + return err; + } + + return 0; +} +#else +#define hdmi_codec_resume NULL +#endif + static struct snd_soc_codec_driver hdmi_hda_codec = { .probe = hdmi_codec_probe, .remove = hdmi_codec_remove, + .resume = hdmi_codec_resume, .idle_bias_off = true, }; -- cgit v1.2.3 From 127a9cbb5860a7cf15f4d4703ab0454e4603e8ac Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 23 Feb 2016 07:45:14 +0100 Subject: ASoC: max9867: fix type of variable containing error codes value variable can contain error values and is compared with zero. Its type must be signed. The problem has been detected using coccinelle script scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci Signed-off-by: Andrzej Hajda Reviewed-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index ab7a94db8db7..4fb6fc7188c7 100755 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -180,7 +180,8 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec); - unsigned int ni_h, ni_l, value; + unsigned int ni_h, ni_l; + int value; value = get_ni_value(max9867->sysclk, params_rate(params)); if (value < 0) -- cgit v1.2.3 From 9dcc72efae313472d1d719e91b23e2bea3513789 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 23 Feb 2016 14:53:13 +0800 Subject: ASoC: max9867: Use params_width instead of open-coded Signed-off-by: Axel Lin Acked-by: anish kumar Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 4fb6fc7188c7..f371a52fe29d 100755 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -207,10 +207,9 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream, unsigned long int bclk_rate, pclk_bclk_ratio; int bclk_value; - bclk_rate = params_rate(params) * 2 * - snd_pcm_format_width(params_format(params)); + bclk_rate = params_rate(params) * 2 * params_width(params); pclk_bclk_ratio = max9867->pclk/bclk_rate; - switch (snd_pcm_format_width(params_format(params))) { + switch (params_width(params)) { case 8: case 16: switch (pclk_bclk_ratio) { -- cgit v1.2.3 From 2595b7fe1aa3a1dfc47e549b39f7c35c5ce8a56d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 23 Feb 2016 14:16:32 +0000 Subject: ASoC: arizona: Make logging of FLL calculations clearer The debug logging of FLL calculations was confusing. Values were printed in hex without indicating this by a leading 0x, and despite these normally being required in decimal. Also where the register value isn't the actual value (it s a power-of-two or 0 means 1, 1 means 2, ...) it was unclear whether the actual or register value was shown. This patch changes the log print so that all mathematical values are shown in decimal, all register values are shown in hex with a 0x prefix, and where the register value isn't the actual integer value the decimal integer value is shown in () after the hex register value. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a32cfb85f1ca..dd926f4da409 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2108,11 +2108,12 @@ static int arizona_calc_fll(struct arizona_fll *fll, return -EINVAL; } - arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", + arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n", cfg->n, cfg->theta, cfg->lambda); - arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", - cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv); - arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain); + arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n", + cfg->fratio, ratio, cfg->outdiv, + cfg->refdiv, 1 << cfg->refdiv); + arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain); return 0; -- cgit v1.2.3 From d6dde63e90cf0d34ae61e885a5eb254c59eb3358 Mon Sep 17 00:00:00 2001 From: Andreas IrestÃ¥l Date: Tue, 16 Feb 2016 13:56:42 +0100 Subject: ASoC: adau17x1: Correct typos in file headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas IrestÃ¥l Signed-off-by: Mark Brown --- include/linux/platform_data/adau17x1.h | 2 +- sound/soc/codecs/adau1761-i2c.c | 2 +- sound/soc/codecs/adau1761-spi.c | 2 +- sound/soc/codecs/adau1761.c | 2 +- sound/soc/codecs/adau1781.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/include/linux/platform_data/adau17x1.h b/include/linux/platform_data/adau17x1.h index a81766cae230..9db1b905df24 100644 --- a/include/linux/platform_data/adau17x1.h +++ b/include/linux/platform_data/adau17x1.h @@ -1,5 +1,5 @@ /* - * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961/ADAU1781/ADAU1781 codecs + * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961/ADAU1381/ADAU1781 codecs * * Copyright 2011-2014 Analog Devices Inc. * Author: Lars-Peter Clausen diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index 348ccb17d3cc..a1b12671c307 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -1,5 +1,5 @@ /* - * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec + * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec * * Copyright 2014 Analog Devices Inc. * Author: Lars-Peter Clausen diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index 8bc1fbd25fcc..188334928c23 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c @@ -1,5 +1,5 @@ /* - * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec + * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec * * Copyright 2014 Analog Devices Inc. * Author: Lars-Peter Clausen diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index e7136b1956a3..b95d29dbd13d 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -1,5 +1,5 @@ /* - * Driver for ADAU1761/ADAU1461/ADAU1761/ADAU1961 codec + * Driver for ADAU1361/ADAU1461/ADAU1761/ADAU1961 codec * * Copyright 2011-2013 Analog Devices Inc. * Author: Lars-Peter Clausen diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index fde9068550a6..bc1bb56dae63 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -1,5 +1,5 @@ /* - * Driver for ADAU1781/ADAU1781 codec + * Driver for ADAU1381/ADAU1781 codec * * Copyright 2011-2013 Analog Devices Inc. * Author: Lars-Peter Clausen -- cgit v1.2.3 From aaf0f3aeeb6f9e5e874fccc8a0e56b00fea537c3 Mon Sep 17 00:00:00 2001 From: Andreas IrestÃ¥l Date: Tue, 16 Feb 2016 13:56:44 +0100 Subject: ASoC: adau17x1: Add basic DT support for adau17x1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas IrestÃ¥l Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761-i2c.c | 12 ++++++++++++ sound/soc/codecs/adau1761-spi.c | 12 ++++++++++++ sound/soc/codecs/adau1781-i2c.c | 10 ++++++++++ sound/soc/codecs/adau1781-spi.c | 10 ++++++++++ 4 files changed, 44 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index a1b12671c307..8de010f758cd 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -44,9 +44,21 @@ static const struct i2c_device_id adau1761_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids); +#if defined(CONFIG_OF) +static const struct of_device_id adau1761_i2c_dt_ids[] = { + { .compatible = "adi,adau1361", }, + { .compatible = "adi,adau1461", }, + { .compatible = "adi,adau1761", }, + { .compatible = "adi,adau1961", }, + { }, +}; +MODULE_DEVICE_TABLE(of, adau1761_i2c_dt_ids); +#endif + static struct i2c_driver adau1761_i2c_driver = { .driver = { .name = "adau1761", + .of_match_table = of_match_ptr(adau1761_i2c_dt_ids), }, .probe = adau1761_i2c_probe, .remove = adau1761_i2c_remove, diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index 188334928c23..d9171245bd9f 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c @@ -61,9 +61,21 @@ static const struct spi_device_id adau1761_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, adau1761_spi_id); +#if defined(CONFIG_OF) +static const struct of_device_id adau1761_spi_dt_ids[] = { + { .compatible = "adi,adau1361", }, + { .compatible = "adi,adau1461", }, + { .compatible = "adi,adau1761", }, + { .compatible = "adi,adau1961", }, + { }, +}; +MODULE_DEVICE_TABLE(of, adau1761_spi_dt_ids); +#endif + static struct spi_driver adau1761_spi_driver = { .driver = { .name = "adau1761", + .of_match_table = of_match_ptr(adau1761_spi_dt_ids), }, .probe = adau1761_spi_probe, .remove = adau1761_spi_remove, diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 0e32bba92339..06cbca84cf02 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -42,9 +42,19 @@ static const struct i2c_device_id adau1781_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids); +#if defined(CONFIG_OF) +static const struct of_device_id adau1781_i2c_dt_ids[] = { + { .compatible = "adi,adau1381", }, + { .compatible = "adi,adau1781", }, + { }, +}; +MODULE_DEVICE_TABLE(of, adau1781_i2c_dt_ids); +#endif + static struct i2c_driver adau1781_i2c_driver = { .driver = { .name = "adau1781", + .of_match_table = of_match_ptr(adau1781_i2c_dt_ids), }, .probe = adau1781_i2c_probe, .remove = adau1781_i2c_remove, diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c index 33a73ff78de4..3d965a01b99c 100644 --- a/sound/soc/codecs/adau1781-spi.c +++ b/sound/soc/codecs/adau1781-spi.c @@ -59,9 +59,19 @@ static const struct spi_device_id adau1781_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, adau1781_spi_id); +#if defined(CONFIG_OF) +static const struct of_device_id adau1781_spi_dt_ids[] = { + { .compatible = "adi,adau1381", }, + { .compatible = "adi,adau1781", }, + { }, +}; +MODULE_DEVICE_TABLE(of, adau1781_spi_dt_ids); +#endif + static struct spi_driver adau1781_spi_driver = { .driver = { .name = "adau1781", + .of_match_table = of_match_ptr(adau1781_spi_dt_ids), }, .probe = adau1781_spi_probe, .remove = adau1781_spi_remove, -- cgit v1.2.3 From 4b2fe3822ae16436ed0aba379c500558f7846ce1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 24 Feb 2016 15:51:26 +0800 Subject: ASoC: rt298: enable IRQ for jack detection There are some registers needed for enabling rt298 IRQ missed on current driver. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 6 ++++++ sound/soc/codecs/rt298.h | 8 ++++++++ 2 files changed, 14 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 30c6de62ae6c..e67ef5f8d4f3 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1225,6 +1225,12 @@ static int rt298_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt298->regmap, RT298_WIND_FILTER_CTRL, 0x0082, 0x0082); regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); + + regmap_write(rt298->regmap, RT298_UNSOLICITED_INLINE_CMD, 0x81); + regmap_write(rt298->regmap, RT298_UNSOLICITED_HP_OUT, 0x82); + regmap_write(rt298->regmap, RT298_UNSOLICITED_MIC1, 0x84); + regmap_update_bits(rt298->regmap, RT298_IRQ_FLAG_CTRL, 0x2, 0x2); + rt298->is_hp_in = -1; if (rt298->i2c->irq) { diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h index 31da16265f2b..d66f8847b676 100644 --- a/sound/soc/codecs/rt298.h +++ b/sound/soc/codecs/rt298.h @@ -34,6 +34,7 @@ #define RT298_HP_OUT 0x21 #define RT298_MIXER_IN1 0x22 #define RT298_MIXER_IN2 0x23 +#define RT298_INLINE_CMD 0x55 #define RT298_SET_PIN_SFT 6 #define RT298_SET_PIN_ENABLE 0x40 @@ -124,6 +125,12 @@ VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0) #define RT298_PROC_COEF\ VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0) +#define RT298_UNSOLICITED_INLINE_CMD\ + VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_INLINE_CMD, 0) +#define RT298_UNSOLICITED_HP_OUT\ + VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_HP_OUT, 0) +#define RT298_UNSOLICITED_MIC1\ + VERB_CMD(AC_VERB_SET_UNSOLICITED_ENABLE, RT298_MIC1, 0) /* Index registers */ #define RT298_A_BIAS_CTRL1 0x01 @@ -148,6 +155,7 @@ #define RT298_DEPOP_CTRL2 0x67 #define RT298_DEPOP_CTRL3 0x68 #define RT298_DEPOP_CTRL4 0x69 +#define RT298_IRQ_FLAG_CTRL 0x7c /* SPDIF (0x06) */ #define RT298_SPDIF_SEL_SFT 0 -- cgit v1.2.3 From 0ce58cd6ce5e706c70c7b038ef5ddde0cc7d7385 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 24 Feb 2016 15:51:27 +0800 Subject: ASoC: rt298: Don't enable IRQ in i2c_probe The IRQ function should not be enabled before irq handler is registered. In fact, it is done in rt298_probe. So remove it from rt298_i2c_probe. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index e67ef5f8d4f3..f0e6c06e89ac 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1224,7 +1224,6 @@ static int rt298_i2c_probe(struct i2c_client *i2c, regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000); regmap_update_bits(rt298->regmap, RT298_WIND_FILTER_CTRL, 0x0082, 0x0082); - regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); regmap_write(rt298->regmap, RT298_UNSOLICITED_INLINE_CMD, 0x81); regmap_write(rt298->regmap, RT298_UNSOLICITED_HP_OUT, 0x82); -- cgit v1.2.3 From 23905cd1ca48cbc852a670a3dbbfc5e7d694580f Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Wed, 24 Feb 2016 11:27:38 +0530 Subject: ASoC: Intel: boards: Enable HDMI and DP on skl_rt286 machine Skylake platform has 3 pin widgets in HDMI codec. This patch adds 3 FE and BE dai links to support these in rt286 machine Also add jack initialization for each of the device. Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/boards/skl_rt286.c | 111 +++++++++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 6e65085e8bc3..9574b483f249 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -164,6 +164,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH select SND_SOC_INTEL_SKYLAKE select SND_SOC_RT286 select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI help This adds support for ASoC machine driver for Skylake platforms with RT286 I2S audio codec. diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 2cbcbe412661..00b84c1ff07f 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -26,8 +26,20 @@ #include #include #include "../../codecs/rt286.h" +#include "../../codecs/hdac_hdmi.h" static struct snd_soc_jack skylake_headset; + +enum { + SKL_DPCM_AUDIO_PB = 0, + SKL_DPCM_AUDIO_CP, + SKL_DPCM_AUDIO_REF_CP, + SKL_DPCM_AUDIO_DMIC_CP, + SKL_DPCM_AUDIO_HDMI1_PB, + SKL_DPCM_AUDIO_HDMI2_PB, + SKL_DPCM_AUDIO_HDMI3_PB, +}; + /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin skylake_headset_pins[] = { { @@ -53,6 +65,9 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("DMIC2", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SINK("WoV Sink"), + SND_SOC_DAPM_SPK("HDMI1", NULL), + SND_SOC_DAPM_SPK("HDMI2", NULL), + SND_SOC_DAPM_SPK("HDMI3", NULL), }; static const struct snd_soc_dapm_route skylake_rt286_map[] = { @@ -72,6 +87,10 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"WoV Sink", NULL, "hwd_in sink"}, + {"HDMI1", NULL, "hif5 Output"}, + {"HDMI2", NULL, "hif6 Output"}, + {"HDMI3", NULL, "hif7 Output"}, + /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, @@ -84,8 +103,12 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { { "dmic01_hifi", NULL, "DMIC01 Rx" }, { "DMIC01 Rx", NULL, "DMIC AIF" }, - { "hif1", NULL, "iDisp Tx"}, - { "iDisp Tx", NULL, "iDisp_out"}, + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, }; @@ -121,6 +144,13 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB + dai->id); +} + static unsigned int rates[] = { 48000, }; @@ -249,7 +279,7 @@ static struct snd_soc_ops skylake_dmic_ops = { /* skylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link skylake_rt286_dais[] = { /* Front End DAI links */ - { + [SKL_DPCM_AUDIO_PB] = { .name = "Skl Audio Port", .stream_name = "Audio", .cpu_dai_name = "System Pin", @@ -266,7 +296,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dpcm_playback = 1, .ops = &skylake_rt286_fe_ops, }, - { + [SKL_DPCM_AUDIO_CP] = { .name = "Skl Audio Capture Port", .stream_name = "Audio Record", .cpu_dai_name = "System Pin", @@ -282,7 +312,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dpcm_capture = 1, .ops = &skylake_rt286_fe_ops, }, - { + [SKL_DPCM_AUDIO_REF_CP] = { .name = "Skl Audio Reference cap", .stream_name = "refcap", .cpu_dai_name = "Reference Pin", @@ -295,7 +325,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .nonatomic = 1, .dynamic = 1, }, - { + [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", .stream_name = "dmiccap", .cpu_dai_name = "DMIC Pin", @@ -308,6 +338,42 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dynamic = 1, .ops = &skylake_dmic_ops, }, + [SKL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Skl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + [SKL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Skl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + [SKL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Skl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, /* Back End DAI links */ { @@ -341,6 +407,39 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dpcm_capture = 1, .no_pcm = 1, }, + { + .name = "iDisp1", + .be_id = 2, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .be_id = 3, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .be_id = 4, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, }; /* skylake audio machine driver for SPT + RT286S */ -- cgit v1.2.3 From bc5f6ac9a66f90f8e16e568ebd463cbe44f46b81 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Wed, 24 Feb 2016 11:27:39 +0530 Subject: ASoC: Intel: boards: Enable HDMI and DP on nau88l2 machine This patch adds 2 HDMI FE and BE dai links and also initializes the jack for each device. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 120 +++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 9574b483f249..e29a7c5295a5 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -179,6 +179,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH select SND_SOC_NAU8825 select SND_SOC_SSM4567 select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for NAU88L25 + SSM4567. diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index c071812f31e5..ccc3d4a4f4b6 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -26,6 +26,7 @@ #include #include #include "../../codecs/nau8825.h" +#include "../../codecs/hdac_hdmi.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi" @@ -33,6 +34,16 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; +enum { + SKL_DPCM_AUDIO_PB = 0, + SKL_DPCM_AUDIO_CP, + SKL_DPCM_AUDIO_REF_CP, + SKL_DPCM_AUDIO_DMIC_CP, + SKL_DPCM_AUDIO_HDMI1_PB, + SKL_DPCM_AUDIO_HDMI2_PB, + SKL_DPCM_AUDIO_HDMI3_PB, +}; + static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -131,8 +142,14 @@ static const struct snd_soc_dapm_route skylake_map[] = { /* DMIC */ { "dmic01_hifi", NULL, "DMIC01 Rx" }, { "DMIC01 Rx", NULL, "DMIC AIF" }, - { "hifi1", NULL, "iDisp Tx"}, - { "iDisp Tx", NULL, "iDisp_out"}, + + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, + { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, }; @@ -202,6 +219,28 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } +static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); +} + +static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); +} + + +static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); +} + static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dapm_context *dapm; @@ -362,7 +401,7 @@ static struct snd_soc_ops skylaye_refcap_ops = { /* skylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link skylake_dais[] = { /* Front End DAI links */ - { + [SKL_DPCM_AUDIO_PB] = { .name = "Skl Audio Port", .stream_name = "Audio", .cpu_dai_name = "System Pin", @@ -377,7 +416,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_playback = 1, .ops = &skylake_nau8825_fe_ops, }, - { + [SKL_DPCM_AUDIO_CP] = { .name = "Skl Audio Capture Port", .stream_name = "Audio Record", .cpu_dai_name = "System Pin", @@ -391,7 +430,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .ops = &skylake_nau8825_fe_ops, }, - { + [SKL_DPCM_AUDIO_REF_CP] = { .name = "Skl Audio Reference cap", .stream_name = "Wake on Voice", .cpu_dai_name = "Reference Pin", @@ -405,7 +444,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dynamic = 1, .ops = &skylaye_refcap_ops, }, - { + [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", .stream_name = "dmiccap", .cpu_dai_name = "DMIC Pin", @@ -418,15 +457,45 @@ static struct snd_soc_dai_link skylake_dais[] = { .dynamic = 1, .ops = &skylake_dmic_ops, }, - { - .name = "Skl HDMI Port", - .stream_name = "Hdmi", - .cpu_dai_name = "HDMI Pin", + [SKL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Skl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .platform_name = "0000:00:1f.3", .dpcm_playback = 1, .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [SKL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Skl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [SKL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Skl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, .nonatomic = 1, .dynamic = 1, }, @@ -452,7 +521,7 @@ static struct snd_soc_dai_link skylake_dais[] = { { /* SSP1 - Codec */ .name = "SSP1-Codec", - .be_id = 0, + .be_id = 1, .cpu_dai_name = "SSP1 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, @@ -469,7 +538,7 @@ static struct snd_soc_dai_link skylake_dais[] = { }, { .name = "dmic01", - .be_id = 1, + .be_id = 2, .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", @@ -480,13 +549,36 @@ static struct snd_soc_dai_link skylake_dais[] = { .no_pcm = 1, }, { - .name = "iDisp", + .name = "iDisp1", .be_id = 3, - .cpu_dai_name = "iDisp Pin", + .cpu_dai_name = "iDisp1 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi1", .platform_name = "0000:00:1f.3", .dpcm_playback = 1, + .init = skylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .be_id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .be_id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi3_init, + .dpcm_playback = 1, .no_pcm = 1, }, }; -- cgit v1.2.3 From 0ab338ff33762d50e5005d8d28b30b25f23aa934 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Wed, 24 Feb 2016 11:27:40 +0530 Subject: ASoC: Intel: boards: Enable HDMI and DP on SKL nau88l25_max98357 machine This patch adds 2 HDMI FE and BE dai links and also initializes the jack for each device. Signed-off-by: Sathyanarayana Nujella Signed-off-by: Fang, Yang A Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/boards/skl_nau88l25_max98357a.c | 119 +++++++++++++++++++++--- 2 files changed, 106 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index e29a7c5295a5..cb968da5a308 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -194,6 +194,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH select SND_SOC_NAU8825 select SND_SOC_MAX98357A select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for NAU88L25 + MAX98357A. diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index ab7da9c304b2..33bf5286c948 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -22,6 +22,7 @@ #include #include #include "../../codecs/nau8825.h" +#include "../../codecs/hdac_hdmi.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_MAXIM_CODEC_DAI "HiFi" @@ -29,6 +30,16 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; +enum { + SKL_DPCM_AUDIO_PB = 0, + SKL_DPCM_AUDIO_CP, + SKL_DPCM_AUDIO_REF_CP, + SKL_DPCM_AUDIO_DMIC_CP, + SKL_DPCM_AUDIO_HDMI1_PB, + SKL_DPCM_AUDIO_HDMI2_PB, + SKL_DPCM_AUDIO_HDMI3_PB, +}; + static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -124,8 +135,14 @@ static const struct snd_soc_dapm_route skylake_map[] = { /* DMIC */ { "dmic01_hifi", NULL, "DMIC01 Rx" }, { "DMIC01 Rx", NULL, "DMIC AIF" }, - { "hifi1", NULL, "iDisp Tx"}, - { "iDisp Tx", NULL, "iDisp_out"}, + + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, + { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, }; @@ -176,6 +193,27 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } +static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); +} + +static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); +} + +static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->codec_dai; + + return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); +} + static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dapm_context *dapm; @@ -318,7 +356,7 @@ static struct snd_soc_ops skylaye_refcap_ops = { /* skylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link skylake_dais[] = { /* Front End DAI links */ - { + [SKL_DPCM_AUDIO_PB] = { .name = "Skl Audio Port", .stream_name = "Audio", .cpu_dai_name = "System Pin", @@ -333,7 +371,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_playback = 1, .ops = &skylake_nau8825_fe_ops, }, - { + [SKL_DPCM_AUDIO_CP] = { .name = "Skl Audio Capture Port", .stream_name = "Audio Record", .cpu_dai_name = "System Pin", @@ -347,7 +385,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .ops = &skylake_nau8825_fe_ops, }, - { + [SKL_DPCM_AUDIO_REF_CP] = { .name = "Skl Audio Reference cap", .stream_name = "Wake on Voice", .cpu_dai_name = "Reference Pin", @@ -361,7 +399,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dynamic = 1, .ops = &skylaye_refcap_ops, }, - { + [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", .stream_name = "dmiccap", .cpu_dai_name = "DMIC Pin", @@ -374,15 +412,45 @@ static struct snd_soc_dai_link skylake_dais[] = { .dynamic = 1, .ops = &skylake_dmic_ops, }, - { - .name = "Skl HDMI Port", - .stream_name = "Hdmi", - .cpu_dai_name = "HDMI Pin", + [SKL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Skl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [SKL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Skl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .platform_name = "0000:00:1f.3", .dpcm_playback = 1, .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [SKL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Skl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, .nonatomic = 1, .dynamic = 1, }, @@ -407,7 +475,7 @@ static struct snd_soc_dai_link skylake_dais[] = { { /* SSP1 - Codec */ .name = "SSP1-Codec", - .be_id = 0, + .be_id = 1, .cpu_dai_name = "SSP1 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, @@ -424,7 +492,7 @@ static struct snd_soc_dai_link skylake_dais[] = { }, { .name = "dmic01", - .be_id = 1, + .be_id = 2, .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", @@ -435,13 +503,36 @@ static struct snd_soc_dai_link skylake_dais[] = { .no_pcm = 1, }, { - .name = "iDisp", + .name = "iDisp1", .be_id = 3, - .cpu_dai_name = "iDisp Pin", + .cpu_dai_name = "iDisp1 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi1", .platform_name = "0000:00:1f.3", .dpcm_playback = 1, + .init = skylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .be_id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .be_id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = skylake_hdmi3_init, + .dpcm_playback = 1, .no_pcm = 1, }, }; -- cgit v1.2.3 From 5093f9287c83665b9227640aea8a8d980684246f Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Wed, 24 Feb 2016 11:27:41 +0530 Subject: ASoC: Intel: boards: Add IV feedback route for nau88l25_ssm4567 machine SSM4567 supports IV feedback for feedback to the speaker protection algorithm Signed-off-by: Sathya Prakash M R Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index ccc3d4a4f4b6..68caf24f9fbd 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -133,6 +133,9 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "Right Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, + /* IV feedback path */ + { "codec0_lp_in", NULL, "ssp0 Rx"}, + { "Playback", NULL, "ssp1 Tx"}, { "ssp1 Tx", NULL, "codec1_out"}, @@ -154,6 +157,14 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "Headset Mic", NULL, "Platform Clock" }, }; +static const struct snd_soc_pcm_stream skl_ssm4567_loop_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 4, + .channels_max = 4, +}; + static struct snd_soc_codec_conf ssm4567_codec_conf[] = { { .dev_name = "i2c-INT343B:00", @@ -499,6 +510,16 @@ static struct snd_soc_dai_link skylake_dais[] = { .nonatomic = 1, .dynamic = 1, }, + /* Codec-codec link */ + { + .name = "Skylake IV loop", + .stream_name = "SKL IV Loop", + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .codecs = ssm4567_codec_components, + .num_codecs = ARRAY_SIZE(ssm4567_codec_components), + .params = &skl_ssm4567_loop_params, + }, /* Back End DAI links */ { -- cgit v1.2.3 From aac5cc88b107c316fdd2846fdac777726b9f725d Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Wed, 24 Feb 2016 11:27:42 +0530 Subject: ASoC: Intel: boards: Remove WoV sink in skl_rt286 WoV module needs to be triggered with PCM open, so remove this as DAPM Sink and will be connected to FE Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_rt286.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 00b84c1ff07f..2016397a8e75 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -64,7 +64,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("DMIC2", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SINK("WoV Sink"), SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), SND_SOC_DAPM_SPK("HDMI3", NULL), @@ -85,8 +84,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"}, - {"WoV Sink", NULL, "hwd_in sink"}, - {"HDMI1", NULL, "hif5 Output"}, {"HDMI2", NULL, "hif6 Output"}, {"HDMI3", NULL, "hif7 Output"}, @@ -139,7 +136,6 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) rt286_mic_detect(codec, &skylake_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); return 0; } -- cgit v1.2.3 From 98ee1745c81e9cf9553dd311524f9610331e784f Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Wed, 24 Feb 2016 11:27:43 +0530 Subject: ASoC: Intel: boards: Remove WoV sink in nau88125_ssm4567 machine WoV module needs to be triggered with PCM open, so remove this as DAPM Sink and will be connected to FE Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 68caf24f9fbd..a75c09343f84 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -103,7 +103,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SINK("WoV Sink"), SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, @@ -124,8 +123,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"}, - {"WoV Sink", NULL, "hwd_in sink"}, - {"HDMI", NULL, "hif5 Output"}, {"DP", NULL, "hif6 Output"}, /* CODEC BE connections */ @@ -225,7 +222,6 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) nau8825_enable_jack_detect(codec, &skylake_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); return ret; } -- cgit v1.2.3 From 8be3838af0e992846d4725fae152b818560c1068 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Wed, 24 Feb 2016 11:27:44 +0530 Subject: ASoC: Intel: boards: Remove WoV sink in nau88125_max98357a machine WoV module needs to be triggered with PCM open, so remove this as DAPM Sink and will be connected to FE Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 33bf5286c948..72176b79a18d 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -98,7 +98,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SINK("WoV Sink"), SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, @@ -118,7 +117,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" }, - {"WoV Sink", NULL, "hwd_in sink"}, {"HDMI", NULL, "hif5 Output"}, {"DP", NULL, "hif6 Output"}, @@ -188,7 +186,6 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) nau8825_enable_jack_detect(codec, &skylake_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); return ret; } -- cgit v1.2.3 From 90966391005e69a8964350278917a87fe49adf0f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Feb 2016 10:50:38 +0300 Subject: ASoC: max9867: silence and array overflow warning Smatch complains that we might reach the end of this loop without finding what we're looking for leading to a buffer overflow. Signed-off-by: Dan Carpenter Reviewed-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index f371a52fe29d..2a22fddeb6af 100755 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -156,6 +156,8 @@ static inline int get_ni_value(int mclk, int rate) if (ni_div[i].mclk >= mclk) break; } + if (i == ARRAY_SIZE(ni_div)) + return -EINVAL; switch (rate) { case 8000: -- cgit v1.2.3 From 0150e8c053e585dbd3f8141fbb942015532527ca Mon Sep 17 00:00:00 2001 From: John Lin Date: Thu, 25 Feb 2016 13:18:26 +0800 Subject: ASoC: rt5645: improve headphone pop when system resumes from S3 When playing audio through headphone, headphone makes pop noise if system resumes from S3 to S0. We modify the sequence of writing register for avoiding pop sound. Signed-off-by: John Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c61d38b585fb..c3dc371a7ef3 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3029,13 +3029,18 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, RT5645_PWR_BG | RT5645_PWR_VREF2, RT5645_PWR_VREF1 | RT5645_PWR_MB | RT5645_PWR_BG | RT5645_PWR_VREF2); + mdelay(10); snd_soc_update_bits(codec, RT5645_PWR_ANLG1, RT5645_PWR_FV1 | RT5645_PWR_FV2, RT5645_PWR_FV1 | RT5645_PWR_FV2); - if (rt5645->en_button_func && - snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) - queue_delayed_work(system_power_efficient_wq, - &rt5645->jack_detect_work, msecs_to_jiffies(0)); + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); + msleep(40); + if (rt5645->en_button_func) + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, + msecs_to_jiffies(0)); + } break; case SND_SOC_BIAS_OFF: -- cgit v1.2.3 From 3524be4b21ef911ff37f7d401b743cfb4e30cf98 Mon Sep 17 00:00:00 2001 From: John Lin Date: Thu, 25 Feb 2016 13:18:27 +0800 Subject: ASoC: rt5645: extend delay time for headphone pop noise Headphone needs enough delay time before unmuting for avoiding pop sound. We extend the delay time to make sure headphone doesn't pop. Signed-off-by: John Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c3dc371a7ef3..df9fee7f1b42 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1674,7 +1674,7 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on) regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); - msleep(70); + msleep(90); rt5645->hp_on = true; } else { /* depop parameters */ -- cgit v1.2.3 From aa3e838869d494c437c693b54d12fe02b96a0aa1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 25 Feb 2016 23:02:04 +0100 Subject: ASoC: pxa: remove unused variable As pointed out by Zhangfei Gao, the sspa_div variable in brownstone_wm8994_hw_params() is completely unused, so as a cleanup following a prior patch, this removes both the variable and the division. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/pxa/brownstone.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 416ea646c3b1..ec522e94b0e2 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -52,7 +52,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int freq_out, sspa_mclk, sysclk; - int sspa_div; if (params_rate(params) > 11025) { freq_out = params_rate(params) * 512; @@ -63,7 +62,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, sysclk = params_rate(params) * 512; sspa_mclk = params_rate(params) * 64; } - sspa_div = freq_out / sspa_mclk; snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); -- cgit v1.2.3 From 4d7cb66c8f9db37ffa2a72cc9b9233ae82e94d7e Mon Sep 17 00:00:00 2001 From: PC Liao Date: Tue, 23 Feb 2016 16:20:24 +0800 Subject: ASoC: mediatek: remove soft reset and add second I2S clock To improve I2S flow, this patch removes soft reset and adds second I2S clock to use. Signed-off-by: PC Liao Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-pcm.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 689c51f23d9f..3456bfab4617 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -283,20 +283,13 @@ static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) regmap_read(afe->regmap, AFE_I2S_CON2, &val); if (!!(val & AFE_I2S_CON2_EN) == enable) - return; /* must skip soft reset */ - - /* I2S soft reset begin */ - regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0x4); + return; /* input */ regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable); /* output */ regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable); - - /* I2S soft reset end */ - udelay(1); - regmap_update_bits(afe->regmap, AUDIO_TOP_CON1, 0x4, 0); } static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, @@ -365,6 +358,7 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, return 0; mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); + mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); return 0; @@ -384,6 +378,7 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); + mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); } static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, @@ -397,6 +392,9 @@ static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, mtk_afe_dais_set_clks(afe, afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256, NULL, 0); + mtk_afe_dais_set_clks(afe, + afe->clocks[MTK_CLK_I2S2_M], runtime->rate * 256, + NULL, 0); /* config I2S */ ret = mtk_afe_set_i2s(afe, substream->runtime->rate); if (ret) -- cgit v1.2.3 From 84f3a52421a41d0b129b519da9f39fcfb336a840 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Thu, 25 Feb 2016 15:12:33 +0800 Subject: ASoC: mediatek: Add I03/I04 widgets and corresponding routes Add these widgets to allow another path from I2S input. Signed-off-by: Koro Chen Signed-off-by: PC Liao Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-pcm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 3456bfab4617..f1c58a2c12fb 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -40,6 +40,7 @@ #define AFE_CONN1 0x0024 #define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002c #define AFE_CONN7 0x0460 #define AFE_CONN8 0x0464 #define AFE_HDMI_CONN0 0x0390 @@ -63,6 +64,7 @@ #define AFE_HDMI_OUT_CUR 0x0378 #define AFE_HDMI_OUT_END 0x037c +#define AFE_ADDA_TOP_CON0 0x0120 #define AFE_ADDA2_TOP_CON0 0x0600 #define AFE_HDMI_OUT_CON0 0x0370 @@ -259,6 +261,7 @@ static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) return -EINVAL; /* from external ADC */ + regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1); regmap_update_bits(afe->regmap, AFE_ADDA2_TOP_CON0, 0x1, 0x1); /* set input */ @@ -901,15 +904,19 @@ static const struct snd_kcontrol_new mtk_afe_o04_mix[] = { }; static const struct snd_kcontrol_new mtk_afe_o09_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0), }; static const struct snd_kcontrol_new mtk_afe_o10_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0), }; static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { /* inter-connections */ + SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -932,12 +939,16 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { {"I2S Playback", NULL, "O04"}, {"VUL", NULL, "O09"}, {"VUL", NULL, "O10"}, + {"I03", NULL, "I2S Capture"}, + {"I04", NULL, "I2S Capture"}, {"I17", NULL, "I2S Capture"}, {"I18", NULL, "I2S Capture"}, { "O03", "I05 Switch", "I05" }, { "O04", "I06 Switch", "I06" }, { "O09", "I17 Switch", "I17" }, + { "O09", "I03 Switch", "I03" }, { "O10", "I18 Switch", "I18" }, + { "O10", "I04 Switch", "I04" }, }; static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = { -- cgit v1.2.3 From dbc77eed6553362e08c1874ff30df640c96eca92 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Feb 2016 22:53:46 +0530 Subject: ASoC: intel: remove unused variable The variable cmd_id is only assigned some value and is never used. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_ipc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 3dc7358828b3..8afa6fe7b0b0 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -318,7 +318,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, union ipc_header_high msg_high; u32 msg_low; struct ipc_dsp_hdr *dsp_hdr; - unsigned int cmd_id; msg_high = msg->mrfld_header.p.header_high; msg_low = msg->mrfld_header.p.header_low_payload; @@ -357,7 +356,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, return; /* Copy command id so that we can use to put sst to reset */ dsp_hdr = (struct ipc_dsp_hdr *)data; - cmd_id = dsp_hdr->cmd_id; dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id); if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result, msg_high.part.drv_id, -- cgit v1.2.3 From c7c6c73604ed4018cf7c22575d336a448ef8ccf5 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 1 Mar 2016 07:59:10 +0530 Subject: ASoC: Intel: Skylake: correct direction in blob query The blob query for BE skl_tplg_update_be_blob() was not using right values for direction for blob query, so fix that. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index c95bbce8ad5d..af7722ab7207 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -273,10 +273,11 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, if (m_cfg->formats_config.caps_size > 0) return 0; + dev_dbg(ctx->dev, "Applying default cfg blob\n"); switch (m_cfg->dev_type) { case SKL_DEVICE_DMIC: link_type = NHLT_LINK_DMIC; - dir = 1; + dir = SNDRV_PCM_STREAM_CAPTURE; s_freq = m_cfg->in_fmt[0].s_freq; s_fmt = m_cfg->in_fmt[0].bit_depth; ch = m_cfg->in_fmt[0].channels; @@ -285,15 +286,15 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, case SKL_DEVICE_I2S: link_type = NHLT_LINK_SSP; if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { - dir = 1; - s_freq = m_cfg->in_fmt[0].s_freq; - s_fmt = m_cfg->in_fmt[0].bit_depth; - ch = m_cfg->in_fmt[0].channels; - } else { - dir = 0; + dir = SNDRV_PCM_STREAM_PLAYBACK; s_freq = m_cfg->out_fmt[0].s_freq; s_fmt = m_cfg->out_fmt[0].bit_depth; ch = m_cfg->out_fmt[0].channels; + } else { + dir = SNDRV_PCM_STREAM_CAPTURE; + s_freq = m_cfg->in_fmt[0].s_freq; + s_fmt = m_cfg->in_fmt[0].bit_depth; + ch = m_cfg->in_fmt[0].channels; } break; -- cgit v1.2.3 From 5188b95a60ce33d5445833f9b0a374a2ad3200f4 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 1 Mar 2016 07:59:11 +0530 Subject: ASoC: Intel: Skylake: Add IVI feedback path in nau88125_ssm4567 machine We can enable the IVI feedback path by connecting Left/Right speaker sensors (codec) to ssp0 Rx (soc-dsp). This way aDSP gets feedback data from codec to DSP algorithms Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index a75c09343f84..f6a672c55be9 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -132,6 +132,8 @@ static const struct snd_soc_dapm_route skylake_map[] = { /* IV feedback path */ { "codec0_lp_in", NULL, "ssp0 Rx"}, + { "ssp0 Rx", NULL, "Left Capture Sense" }, + { "ssp0 Rx", NULL, "Right Capture Sense" }, { "Playback", NULL, "ssp1 Tx"}, { "ssp1 Tx", NULL, "codec1_out"}, @@ -534,6 +536,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp_fixup, .dpcm_playback = 1, + .dpcm_capture = 1, }, { /* SSP1 - Codec */ -- cgit v1.2.3 From fdd69c57370dbd9f81072b14aaeb90d80ab0b2f9 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 1 Mar 2016 07:59:12 +0530 Subject: ASoC: Intel: Skylake: remove IVI codec loop in skl_nau88l25_ssm4567 machine The IVI loop is removed in skl_nau88l25_ssm4567 machine as we enable this path thru DAPM graph using the PCM device and not thru loop Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index f6a672c55be9..5f1ca99ae9b0 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -156,14 +156,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "Headset Mic", NULL, "Platform Clock" }, }; -static const struct snd_soc_pcm_stream skl_ssm4567_loop_params = { - .formats = SNDRV_PCM_FMTBIT_S24_LE, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 4, - .channels_max = 4, -}; - static struct snd_soc_codec_conf ssm4567_codec_conf[] = { { .dev_name = "i2c-INT343B:00", @@ -508,16 +500,6 @@ static struct snd_soc_dai_link skylake_dais[] = { .nonatomic = 1, .dynamic = 1, }, - /* Codec-codec link */ - { - .name = "Skylake IV loop", - .stream_name = "SKL IV Loop", - .cpu_dai_name = "SSP0 Pin", - .platform_name = "0000:00:1f.3", - .codecs = ssm4567_codec_components, - .num_codecs = ARRAY_SIZE(ssm4567_codec_components), - .params = &skl_ssm4567_loop_params, - }, /* Back End DAI links */ { -- cgit v1.2.3 From b3fc95ad025683180628f6896d1f82d2cf5d0266 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Feb 2016 05:26:51 +0000 Subject: ASoC: rsnd: rsnd_write() / rsnd_bset() uses regmap _force_ function Some R-Car sound requests picky register access which needs *force* register write. Some status register needs to set 1 to clear status, but we might read 1 from its register. In such case, current regmap does nothing and driver will be forever loop To reduce code complexity, this patch uses regmap _force_ function for all register access. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 21 ++------------------- sound/soc/sh/rcar/rsnd.h | 2 -- 2 files changed, 2 insertions(+), 21 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 271d29adac68..46c0ba7b6414 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -101,23 +101,6 @@ void rsnd_write(struct rsnd_priv *priv, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return; - - regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); - - dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), - rsnd_reg_name(gen, reg), reg, data); -} - -void rsnd_force_write(struct rsnd_priv *priv, - struct rsnd_mod *mod, - enum rsnd_reg reg, u32 data) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - if (!rsnd_is_accessible_reg(priv, gen, reg)) return; @@ -137,8 +120,8 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), - mask, data); + regmap_fields_force_update_bits(gen->regs[reg], + rsnd_mod_id(mod), mask, data); dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", rsnd_mod_name(mod), rsnd_mod_id(mod), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5f613eb42614..305cc086a0bc 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -182,8 +182,6 @@ struct rsnd_dai_stream; rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) #define rsnd_mod_write(m, r, d) \ rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) -#define rsnd_mod_force_write(m, r, d) \ - rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) #define rsnd_mod_bset(m, r, s, d) \ rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) -- cgit v1.2.3 From 0c71367d35115a7eb24483ffce2fad74f77dc4d0 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Thu, 25 Feb 2016 15:16:38 +0800 Subject: ASoC: mediatek: Add machine driver for rt5650 rt5514 codec This is the DPCM based machine driver with rt5650 and rt5514. Signed-off-by: Koro Chen Signed-off-by: PC Liao Signed-off-by: Mark Brown --- .../bindings/sound/mt8173-rt5650-rt5514.txt | 15 ++ sound/soc/mediatek/Kconfig | 28 ++- sound/soc/mediatek/Makefile | 3 +- sound/soc/mediatek/mt8173-rt5650-rt5514.c | 258 +++++++++++++++++++++ 4 files changed, 294 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt create mode 100644 sound/soc/mediatek/mt8173-rt5650-rt5514.c (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt new file mode 100644 index 000000000000..e8b3c80c6fff --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5514.txt @@ -0,0 +1,15 @@ +MT8173 with RT5650 RT5514 CODECS + +Required properties: +- compatible : "mediatek,mt8173-rt5650-rt5514" +- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650-rt5514"; + mediatek,audio-codec = <&rt5650 &rt5514>; + mediatek,platform = <&afe>; + }; + diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 6c8808798c6b..f7e789e97fbc 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -18,14 +18,25 @@ config SND_SOC_MT8173_MAX98090 If unsure select "N". config SND_SOC_MT8173_RT5650 - tristate "ASoC Audio driver for MT8173 with RT5650 codec" - depends on SND_SOC_MEDIATEK && I2C - select SND_SOC_RT5645 - help - This adds ASoC driver for Mediatek MT8173 boards - with the RT5650 audio codec. - Select Y if you have such device. - If unsure select "N". + tristate "ASoC Audio driver for MT8173 with RT5650 codec" + depends on SND_SOC_MEDIATEK && I2C + select SND_SOC_RT5645 + help + This adds ASoC driver for Mediatek MT8173 boards + with the RT5650 audio codec. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT8173_RT5650_RT5514 + tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs" + depends on SND_SOC_MEDIATEK && I2C + select SND_SOC_RT5645 + select SND_SOC_RT5514 + help + This adds ASoC driver for Mediatek MT8173 boards + with the RT5650 and RT5514 codecs. + Select Y if you have such device. + If unsure select "N". config SND_SOC_MT8173_RT5650_RT5676 tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" @@ -37,4 +48,3 @@ config SND_SOC_MT8173_RT5650_RT5676 with the RT5650 and RT5676 codecs. Select Y if you have such device. If unsure select "N". - diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index bcdcb062e73a..d486860c0a88 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o # Machine support obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o -obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173-rt5650-rt5514.c new file mode 100644 index 000000000000..58e083642dea --- /dev/null +++ b/sound/soc/mediatek/mt8173-rt5650-rt5514.c @@ -0,0 +1,258 @@ +/* + * mt8173-rt5650-rt5514.c -- MT8173 machine driver with RT5650/5514 codecs + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Koro Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "../codecs/rt5645.h" + +#define MCLK_FOR_CODECS 12288000 + +static const struct snd_soc_dapm_widget mt8173_rt5650_rt5514_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route mt8173_rt5650_rt5514_routes[] = { + {"Speaker", NULL, "SPOL"}, + {"Speaker", NULL, "SPOR"}, + {"Sub DMIC1L", NULL, "Int Mic"}, + {"Sub DMIC1R", NULL, "Int Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Headset Mic", NULL, "micbias1"}, + {"Headset Mic", NULL, "micbias2"}, + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, +}; + +static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int i, ret; + + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + + /* pll from mclk 12.288M */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, + params_rate(params) * 512); + if (ret) + return ret; + + /* sysclk from pll */ + ret = snd_soc_dai_set_sysclk(codec_dai, 1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + return 0; +} + +static struct snd_soc_ops mt8173_rt5650_rt5514_ops = { + .hw_params = mt8173_rt5650_rt5514_hw_params, +}; + +static struct snd_soc_jack mt8173_rt5650_rt5514_jack; + +static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; + int ret; + + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + + /* enable jack detection */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &mt8173_rt5650_rt5514_jack, NULL, 0); + if (ret) { + dev_err(card->dev, "Can't new Headset Jack %d\n", ret); + return ret; + } + + return rt5645_set_jack_detect(codec, + &mt8173_rt5650_rt5514_jack, + &mt8173_rt5650_rt5514_jack, + &mt8173_rt5650_rt5514_jack); +} + +static struct snd_soc_dai_link_component mt8173_rt5650_rt5514_codecs[] = { + { + .dai_name = "rt5645-aif1", + }, + { + .dai_name = "rt5514-aif1", + }, +}; + +enum { + DAI_LINK_PLAYBACK, + DAI_LINK_CAPTURE, + DAI_LINK_CODEC_I2S, +}; + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { + /* Front End DAI links */ + [DAI_LINK_PLAYBACK] = { + .name = "rt5650_rt5514 Playback", + .stream_name = "rt5650_rt5514 Playback", + .cpu_dai_name = "DL1", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + }, + [DAI_LINK_CAPTURE] = { + .name = "rt5650_rt5514 Capture", + .stream_name = "rt5650_rt5514 Capture", + .cpu_dai_name = "VUL", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + }, + /* Back End DAI links */ + [DAI_LINK_CODEC_I2S] = { + .name = "Codec", + .cpu_dai_name = "I2S", + .no_pcm = 1, + .codecs = mt8173_rt5650_rt5514_codecs, + .num_codecs = 2, + .init = mt8173_rt5650_rt5514_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ops = &mt8173_rt5650_rt5514_ops, + .ignore_pmdown_time = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +static struct snd_soc_codec_conf mt8173_rt5650_rt5514_codec_conf[] = { + { + .name_prefix = "Sub", + }, +}; + +static struct snd_soc_card mt8173_rt5650_rt5514_card = { + .name = "mtk-rt5650-rt5514", + .owner = THIS_MODULE, + .dai_link = mt8173_rt5650_rt5514_dais, + .num_links = ARRAY_SIZE(mt8173_rt5650_rt5514_dais), + .codec_conf = mt8173_rt5650_rt5514_codec_conf, + .num_configs = ARRAY_SIZE(mt8173_rt5650_rt5514_codec_conf), + .controls = mt8173_rt5650_rt5514_controls, + .num_controls = ARRAY_SIZE(mt8173_rt5650_rt5514_controls), + .dapm_widgets = mt8173_rt5650_rt5514_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5514_widgets), + .dapm_routes = mt8173_rt5650_rt5514_routes, + .num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5514_routes), +}; + +static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt8173_rt5650_rt5514_card; + struct device_node *platform_node; + int i, ret; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + + for (i = 0; i < card->num_links; i++) { + if (mt8173_rt5650_rt5514_dais[i].platform_name) + continue; + mt8173_rt5650_rt5514_dais[i].platform_of_node = platform_node; + } + + mt8173_rt5650_rt5514_codecs[0].of_node = + of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0); + if (!mt8173_rt5650_rt5514_codecs[0].of_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + mt8173_rt5650_rt5514_codecs[1].of_node = + of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); + if (!mt8173_rt5650_rt5514_codecs[1].of_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + mt8173_rt5650_rt5514_codec_conf[0].of_node = + mt8173_rt5650_rt5514_codecs[1].of_node; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + return ret; +} + +static const struct of_device_id mt8173_rt5650_rt5514_dt_match[] = { + { .compatible = "mediatek,mt8173-rt5650-rt5514", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5514_dt_match); + +static struct platform_driver mt8173_rt5650_rt5514_driver = { + .driver = { + .name = "mtk-rt5650-rt5514", + .of_match_table = mt8173_rt5650_rt5514_dt_match, +#ifdef CONFIG_PM + .pm = &snd_soc_pm_ops, +#endif + }, + .probe = mt8173_rt5650_rt5514_dev_probe, +}; + +module_platform_driver(mt8173_rt5650_rt5514_driver); + +/* Module information */ +MODULE_DESCRIPTION("MT8173 RT5650 and RT5514 SoC machine driver"); +MODULE_AUTHOR("Koro Chen "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtk-rt5650-rt5514"); + -- cgit v1.2.3 From 6d8044b4ff305238503edca7d75f3ab7410396ba Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 1 Mar 2016 17:39:19 +0100 Subject: ASoC: sh: rcar: core: don't open code of_device_get_match_data() This change will also make Coverity happy by avoiding a theoretical NULL pointer dereference; yet another reason is to use the above helper function to tighten the code and make it more readable. Signed-off-by: Wolfram Sang Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 21e13b3a356f..ba37b0d55b21 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1119,7 +1119,6 @@ static int rsnd_probe(struct platform_device *pdev) struct rsnd_priv *priv; struct device *dev = &pdev->dev; struct rsnd_dai *rdai; - const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); int (*probe_func[])(struct rsnd_priv *priv) = { rsnd_gen_probe, rsnd_dma_probe, @@ -1145,7 +1144,7 @@ static int rsnd_probe(struct platform_device *pdev) } priv->pdev = pdev; - priv->flags = (unsigned long)of_id->data; + priv->flags = (unsigned long)of_device_get_match_data(dev); spin_lock_init(&priv->lock); /* -- cgit v1.2.3 From 6a16c1765120abc8f58b2c5f275c95a33bb25572 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 1 Mar 2016 17:39:20 +0100 Subject: ASoC: sh: rcar: rsrc-card: don't open code of_device_get_match_data() This change will also make Coverity happy by avoiding a theoretical NULL pointer dereference; yet another reason is to use the above helper function to tighten the code and make it more readable. Signed-off-by: Wolfram Sang Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsrc-card.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 8a357fdf1077..545e94245e62 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -71,7 +71,6 @@ struct rsrc_card_priv { #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) #define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) #define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data) static int rsrc_card_startup(struct snd_pcm_substream *substream) { @@ -246,7 +245,7 @@ static int rsrc_card_parse_links(struct device_node *np, struct device *dev = rsrc_priv_to_dev(priv); const struct rsrc_card_of_data *of_data; - of_data = rsrc_dev_to_of_data(dev); + of_data = of_device_get_match_data(dev); /* FE is dummy */ dai_link->cpu_of_node = NULL; @@ -396,7 +395,7 @@ static int rsrc_card_parse_of(struct device_node *node, struct rsrc_card_priv *priv, struct device *dev) { - const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); + const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev); struct rsrc_card_dai *props; struct snd_soc_dai_link *links; int ret; -- cgit v1.2.3 From c706f2e55f04d25d212e34186521a38e8a6e459e Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Wed, 2 Mar 2016 12:15:25 +0100 Subject: ASoC: atmel_ssc_dai: distinguish the different SSC Cpu_dai id always equals 0, can't distinguish the different SSC. Use platform_device id to record and distinguish the different SSC. Signed-off-by: Songjun Wu Signed-off-by: Nicolas Ferre Signed-off-by: Mark Brown --- drivers/misc/atmel-ssc.c | 1 + sound/soc/atmel/atmel_ssc_dai.c | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'sound/soc') diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index e11a0bd6c66e..0516ecda54d3 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -34,6 +34,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num) if (ssc->pdev->dev.of_node) { if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc") == ssc_num) { + ssc->pdev->id = ssc_num; ssc_valid = 1; break; } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index ba8def5665c4..276897033639 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -285,7 +285,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct platform_device *pdev = to_platform_device(dai->dev); + struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; int ret; @@ -346,7 +347,8 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct platform_device *pdev = to_platform_device(dai->dev); + struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; @@ -392,7 +394,8 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + struct platform_device *pdev = to_platform_device(cpu_dai->dev); + struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id]; ssc_p->daifmt = fmt; return 0; @@ -404,7 +407,8 @@ static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + struct platform_device *pdev = to_platform_device(cpu_dai->dev); + struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id]; switch (div_id) { case ATMEL_SSC_CMR_DIV: @@ -445,7 +449,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - int id = dai->id; + struct platform_device *pdev = to_platform_device(dai->dev); + int id = pdev->id; struct atmel_ssc_info *ssc_p = &ssc_info[id]; struct ssc_device *ssc = ssc_p->ssc; struct atmel_pcm_dma_params *dma_params; @@ -772,7 +777,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, static int atmel_ssc_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct platform_device *pdev = to_platform_device(dai->dev); + struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id]; struct atmel_pcm_dma_params *dma_params; int dir; @@ -795,7 +801,8 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, static int atmel_ssc_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct platform_device *pdev = to_platform_device(dai->dev); + struct atmel_ssc_info *ssc_p = &ssc_info[pdev->id]; struct atmel_pcm_dma_params *dma_params; int dir; @@ -824,11 +831,12 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream, static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) { struct atmel_ssc_info *ssc_p; + struct platform_device *pdev = to_platform_device(cpu_dai->dev); if (!cpu_dai->active) return 0; - ssc_p = &ssc_info[cpu_dai->id]; + ssc_p = &ssc_info[pdev->id]; /* Save the status register before disabling transmit and receive */ ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); @@ -852,12 +860,13 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) { struct atmel_ssc_info *ssc_p; + struct platform_device *pdev = to_platform_device(cpu_dai->dev); u32 cr; if (!cpu_dai->active) return 0; - ssc_p = &ssc_info[cpu_dai->id]; + ssc_p = &ssc_info[pdev->id]; /* restore SSC register settings */ ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); -- cgit v1.2.3 From 288bc356a881fcdce05f9782736a6a3d9db359a9 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 4 Mar 2016 14:54:50 +0800 Subject: ASoC: rt5616: allow to build with CONFIG_SND_SOC_RT5616 This patch fixes that hasn't built the rt5616 driver with 'CONFIG_SND_SOC_RT5616=y' in .config. The tristate is the prompt on the 'make menuconfig', in other words, that can't show the prompt and select it if we don't say what's the tristate. Signed-off-by: Caesar Wang Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 50693c867e71..1de259860bc9 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -596,7 +596,7 @@ config SND_SOC_RT298 depends on I2C config SND_SOC_RT5616 - tristate + tristate "Realtek RT5616 CODEC" config SND_SOC_RT5631 tristate "Realtek ALC5631/RT5631 CODEC" -- cgit v1.2.3 From d8fc2198aab117a4bc16ee305caef19c4c7e7f5c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 2 Mar 2016 16:59:06 +0100 Subject: ASoC: rockchip: use __maybe_unused to hide st_irq_syscfg_resume The rockchip spdif driver uses SIMPLE_DEV_PM_OPS to conditionally set its power management functions, but we get a warning about rk_spdif_runtime_resume being unused when CONFIG_PM is not set: sound/soc/rockchip/rockchip_spdif.c:67:12: error: 'rk_spdif_runtime_resume' defined but not used [-Werror=unused-function] This adds a __maybe_unused annotation so the compiler knows it can silently drop it instead of warning. Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_spdif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 5a806da89f42..274599d4caeb 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -54,7 +54,7 @@ static const struct of_device_id rk_spdif_match[] = { }; MODULE_DEVICE_TABLE(of, rk_spdif_match); -static int rk_spdif_runtime_suspend(struct device *dev) +static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) { struct rk_spdif_dev *spdif = dev_get_drvdata(dev); @@ -64,7 +64,7 @@ static int rk_spdif_runtime_suspend(struct device *dev) return 0; } -static int rk_spdif_runtime_resume(struct device *dev) +static int __maybe_unused rk_spdif_runtime_resume(struct device *dev) { struct rk_spdif_dev *spdif = dev_get_drvdata(dev); int ret; -- cgit v1.2.3 From e7a508f2b137092500fbad09d9713d3a1c5d4826 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 4 Mar 2016 16:27:14 +0530 Subject: ASoC: pcm3168a: remove unused variable While building we were getting build warning about: sound/soc/codecs/pcm3168a.c:403:21: warning: variable 'channels' set but not used The variable channels were being assigned some value but that was never reused. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3168a.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 0c7248ab6a37..992a77edcd5d 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -400,13 +400,12 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); bool tx, master_mode; u32 val, mask, shift, reg; - unsigned int rate, channels, fmt, ratio, max_ratio; + unsigned int rate, fmt, ratio, max_ratio; int i, min_frame_size; snd_pcm_format_t format; rate = params_rate(params); format = params_format(params); - channels = params_channels(params); ratio = pcm3168a->sysclk / rate; -- cgit v1.2.3 From ab8773943ab3126d39eb41531c8e06aea2107aa1 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 4 Mar 2016 18:31:54 +0800 Subject: ASoC: rockchip: add bindings for spdif controller this patch add compatible for rk3366/rk3368/rk3399 spdif, these three spdifs share the same type. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rockchip-spdif.txt | 8 ++++++-- sound/soc/rockchip/rockchip_spdif.c | 13 ++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.txt b/Documentation/devicetree/bindings/sound/rockchip-spdif.txt index e64dbdea7db9..11046429a118 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-spdif.txt +++ b/Documentation/devicetree/bindings/sound/rockchip-spdif.txt @@ -7,8 +7,12 @@ a fibre cable. Required properties: - compatible: should be one of the following: - - "rockchip,rk3288-spdif", "rockchip,rk3188-spdif" or - "rockchip,rk3066-spdif" + - "rockchip,rk3066-spdif" + - "rockchip,rk3188-spdif" + - "rockchip,rk3288-spdif" + - "rockchip,rk3366-spdif" + - "rockchip,rk3368-spdif" + - "rockchip,rk3399-spdif" - reg: physical base address of the controller and length of memory mapped region. - interrupts: should contain the SPDIF interrupt. diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 274599d4caeb..100781e37848 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -28,6 +28,7 @@ enum rk_spdif_type { RK_SPDIF_RK3066, RK_SPDIF_RK3188, RK_SPDIF_RK3288, + RK_SPDIF_RK3366, }; #define RK3288_GRF_SOC_CON2 0x24c @@ -45,11 +46,17 @@ struct rk_spdif_dev { static const struct of_device_id rk_spdif_match[] = { { .compatible = "rockchip,rk3066-spdif", - .data = (void *) RK_SPDIF_RK3066 }, + .data = (void *)RK_SPDIF_RK3066 }, { .compatible = "rockchip,rk3188-spdif", - .data = (void *) RK_SPDIF_RK3188 }, + .data = (void *)RK_SPDIF_RK3188 }, { .compatible = "rockchip,rk3288-spdif", - .data = (void *) RK_SPDIF_RK3288 }, + .data = (void *)RK_SPDIF_RK3288 }, + { .compatible = "rockchip,rk3366-spdif", + .data = (void *)RK_SPDIF_RK3366 }, + { .compatible = "rockchip,rk3368-spdif", + .data = (void *)RK_SPDIF_RK3366 }, + { .compatible = "rockchip,rk3399-spdif", + .data = (void *)RK_SPDIF_RK3366 }, {}, }; MODULE_DEVICE_TABLE(of, rk_spdif_match); -- cgit v1.2.3 From cab473850226c3e41823453b5b80eb294dae6e0c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Mar 2016 21:36:34 -0600 Subject: ASoC: Intel: common: filter ACPI devices with _STA return value BIOS vendors typically list multiple audio codecs in the DSDT table and enable the relevant one by changing the return value of the _STA method. With the current code, all devices are reported by acpi_dev_present(), regardless of the _STA return values. This causes errors on probe with the wrong machine driver being loaded. This patch essentially reverts 'commit 6f08cbdaac5a ("ASoC: Intel: Use acpi_dev_present()")' and adds code to force the evaluation of the _STA method. A better solution might be to make sure the ACPI subsystem only reports devices with a _STA value of 0xf but apparently it's problematic so dealing with this in the audio subsystem directly. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-match-acpi.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index c429e2226d40..cf2c27cd8651 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -16,14 +16,30 @@ #include "sst-acpi.h" +static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, + void *context, void **ret) +{ + unsigned long long sta; + acpi_status status; + + *(bool *)context = true; + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) + *(bool *)context = false; + + return AE_OK; +} + struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) { struct sst_acpi_mach *mach; + bool found = false; for (mach = machines; mach->id[0]; mach++) - if (acpi_dev_present(mach->id)) + if (ACPI_SUCCESS(acpi_get_devices(mach->id, + sst_acpi_mach_match, + &found, NULL)) && found) return mach; - return NULL; } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); -- cgit v1.2.3 From 1fdb7c14a24689e9c7ec51aa16a3970a7ec0fdde Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Mar 2016 21:36:36 -0600 Subject: ASoC: Intel: common: add translation from HID to codec-name BIOS vendors sometimes declare multiple devices in the DSDT table that all refer to the same HID. This is not very smart but not illegal as long as only one device reports present with the _STA method. The ACPI subsystem tracks each device with an extension, e.g. 10EC5640:00 and 10EC5640:01 In the ASoC machine driver, the DAI codec name needs to refer to the ACPI device that reported present, e.g. "i2c-10EC5640:01". The extension will vary depending on how the BIOS is written and which ACPI device is activated. This patch adds a translation function that provides the codec name from the ACPI HID to avoid any hard-coded values in the machine driver. Suggested-by: Mika Westerberg Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-acpi.h | 3 +++ sound/soc/intel/common/sst-match-acpi.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 3ee3b7ab5d03..4dcfb7e5ed70 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -14,6 +14,9 @@ #include +/* translation fron HID to I2C name, needed for DAI codec_name */ +const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); + /* acpi match */ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index cf2c27cd8651..2c0e7fca97db 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -16,6 +16,39 @@ #include "sst-acpi.h" +static acpi_status sst_acpi_find_name(acpi_handle handle, u32 level, + void *context, void **ret) +{ + struct acpi_device *adev; + const char *name = NULL; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (adev->status.present && adev->status.functional) { + name = acpi_dev_name(adev); + *(const char **)ret = name; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) +{ + const char *name = NULL; + acpi_status status; + + status = acpi_get_devices(hid, sst_acpi_find_name, NULL, + (void **)&name); + + if (ACPI_FAILURE(status) || name[0] == '\0') + return NULL; + + return name; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_name_from_hid); + static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, void *context, void **ret) { -- cgit v1.2.3 From ab738e4e3040b0985ab45780a688705f334e609b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Mar 2016 21:36:37 -0600 Subject: ASoC: Intel: bytcr_rt5640: change quirk position No added functionality Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 9a1752df45a9..a06cd1f99190 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -32,6 +32,18 @@ #include "../atom/sst-atom-controls.h" #include "../common/sst-acpi.h" +enum { + BYT_RT5640_DMIC1_MAP, + BYT_RT5640_DMIC2_MAP, + BYT_RT5640_IN1_MAP, +}; + +#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5640_DMIC_EN BIT(16) + +static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN; + static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -70,18 +82,6 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { {"IN1P", NULL, "Internal Mic"}, }; -enum { - BYT_RT5640_DMIC1_MAP, - BYT_RT5640_DMIC2_MAP, - BYT_RT5640_IN1_MAP, -}; - -#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) -#define BYT_RT5640_DMIC_EN BIT(16) - -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN; - static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -174,7 +174,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; } - dmi_check_system(byt_rt5640_quirk_table); switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { case BYT_RT5640_IN1_MAP: custom_map = byt_rt5640_intmic_in1_map; @@ -351,6 +350,9 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) "%s%s%s", "i2c-", mach->id, ":00"); byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name; + /* check quirks before creating card */ + dmi_check_system(byt_rt5640_quirk_table); + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { -- cgit v1.2.3 From a232b96dcece4761793d39b8fb2c9d050df30357 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Mar 2016 21:36:38 -0600 Subject: ASoC: Intel: bytcr_rt5640: use HID translation util Remove hard-coded generation of codec name, use translation routine to avoid issues with codec name not matching what the ACPI subsystem registered Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a06cd1f99190..032a2e753f0b 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -340,15 +340,31 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { int ret_val = 0; struct sst_acpi_mach *mach; + const char *i2c_name = NULL; + int i; + int dai_index; /* register the soc card */ byt_rt5640_card.dev = &pdev->dev; mach = byt_rt5640_card.dev->platform_data; + /* fix index of codec dai */ + dai_index = MERR_DPCM_COMPR + 1; + for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) { + if (!strcmp(byt_rt5640_dais[i].codec_name, "i2c-10EC5640:00")) { + dai_index = i; + break; + } + } + /* fixup codec name based on HID */ - snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), - "%s%s%s", "i2c-", mach->id, ":00"); - byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name; + i2c_name = sst_acpi_find_name_from_hid(mach->id); + if (i2c_name != NULL) { + snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), + "%s%s", "i2c-", i2c_name); + + byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; + } /* check quirks before creating card */ dmi_check_system(byt_rt5640_quirk_table); -- cgit v1.2.3 From fdf841937e4fa08e767dbe83f1c65696cfec67c9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Mar 2016 21:36:39 -0600 Subject: ASoC: Intel: Atom: add support for CHT w/ RT5640 Some CHT-T platforms make use of the Realtek RT5640 codec. Make use of the machine driver developed for Baytrail. Tested on Tronsmart Ara X5. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 4fce03fc1870..3bc4b63b2f9d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -342,6 +342,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = { &chv_platform_data }, {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, + /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ + {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, + &chv_platform_data }, + {}, }; -- cgit v1.2.3 From d7289565483c65094d0473555625a4acd89567d3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2016 05:51:12 +0000 Subject: ASoC: rsnd: don't call update callback if it was NULL Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ba37b0d55b21..3a3dc2ff18c9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -927,7 +927,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, } } - if (change) + if (change && cfg->update) cfg->update(cfg->io, mod); return change; -- cgit v1.2.3 From f90432fc6ec41c5bb1d7b75edc1f2bc58799ece3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2016 05:51:44 +0000 Subject: ASoC: rsrc-card: add convert channels support Renesas sound device has CTU (= Channel Transfer Unit), and sound card needs its support. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsrc-card.txt | 1 + sound/soc/sh/rcar/rsrc-card.c | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt index 2b2caa281ce3..5abebf7898d9 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt @@ -30,6 +30,7 @@ Optional subnode properties: - frame-inversion : bool property. Add this if the dai-link uses frame clock inversion. - convert-rate : platform specified sampling rate convert +- convert-channels : platform specified channel size convert - audio-prefix : see audio-routing - audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 545e94245e62..1bc7ecfc42a9 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -66,6 +66,7 @@ struct rsrc_card_priv { struct snd_soc_dai_link *dai_link; int dai_num; u32 convert_rate; + u32 convert_channels; }; #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) @@ -144,11 +145,16 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); - if (!priv->convert_rate) - return 0; + if (priv->convert_rate) + rate->min = + rate->max = priv->convert_rate; - rate->min = rate->max = priv->convert_rate; + if (priv->convert_channels) + channels->min = + channels->max = priv->convert_channels; return 0; } @@ -436,9 +442,13 @@ static int rsrc_card_parse_of(struct device_node *node, /* sampling rate convert */ of_property_read_u32(node, "convert-rate", &priv->convert_rate); - dev_dbg(dev, "New rsrc-audio-card: %s (%d)\n", - priv->snd_card.name ? priv->snd_card.name : "", - priv->convert_rate); + /* channels transfer */ + of_property_read_u32(node, "convert-channels", &priv->convert_channels); + + dev_dbg(dev, "New rsrc-audio-card: %s\n", + priv->snd_card.name ? priv->snd_card.name : ""); + dev_dbg(dev, "SRC : convert_rate %d\n", priv->convert_rate); + dev_dbg(dev, "CTU : convert_channels %d\n", priv->convert_channels); ret = rsrc_card_dai_link_of(node, priv); if (ret < 0) -- cgit v1.2.3 From 135bb7d5c7b3fa40cd0559b5500a50d4e3663f6e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2016 05:52:13 +0000 Subject: ASoC: rsnd: tidyup rsnd_ssiu_init_gen2() remove unnecessary variable Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssiu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 1b8ea0e09bc2..0d964a0a3e31 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -115,13 +115,12 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, } if (rsnd_ssi_use_busif(io)) { - u32 val = rsnd_get_dalign(mod, io); - rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(mod, io) | rsnd_get_adinr_chan(mod, io)); rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); - rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val); + rsnd_mod_write(mod, SSI_BUSIF_DALIGN, + rsnd_get_dalign(mod, io)); } return 0; -- cgit v1.2.3 From 8a3a2211e97395694827f12552bbad7f2caf11ef Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2016 05:53:00 +0000 Subject: ASoC: rsnd: add CTU basic support This patch adds Renesas R-Car sound CTU (= Channel Transfer Unit) very basic support, but not yet enough feature at this point. Because CTU support needs more complex channel function for each modules. To avoid complex patch reviewing, this patch picked up very basic part only. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 50 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index a10d0f7b73fa..784515afefaf 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -14,6 +14,7 @@ struct rsnd_ctu { struct rsnd_mod mod; + int channels; }; #define rsnd_ctu_nr(priv) ((priv)->ctu_nr) @@ -23,6 +24,9 @@ struct rsnd_ctu { ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ i++) +#define rsnd_mod_to_ctu(_mod) \ + container_of((_mod), struct rsnd_ctu, mod) + #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) static void rsnd_ctu_activation(struct rsnd_mod *mod) @@ -37,6 +41,13 @@ static void rsnd_ctu_halt(struct rsnd_mod *mod) rsnd_mod_write(mod, CTU_SWRSR, 0); } +int rsnd_ctu_converted_channel(struct rsnd_mod *mod) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + + return ctu->channels; +} + static int rsnd_ctu_probe_(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -116,11 +127,49 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, return 0; } +static int rsnd_ctu_hw_params(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *fe_params) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + struct snd_soc_pcm_runtime *fe = substream->private_data; + + /* + * CTU assumes that it is used under DPCM if user want to use + * channel transfer. Then, CTU should be FE. + * And then, this function will be called *after* BE settings. + * this means, each BE already has fixuped hw_params. + * see + * dpcm_fe_dai_hw_params() + * dpcm_be_dai_hw_params() + */ + ctu->channels = 0; + if (fe->dai_link->dynamic) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_soc_dpcm *dpcm; + struct snd_pcm_hw_params *be_params; + int stream = substream->stream; + + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + be_params = &dpcm->hw_params; + if (params_channels(fe_params) != params_channels(be_params)) + ctu->channels = params_channels(be_params); + } + + dev_dbg(dev, "CTU convert channels %d\n", ctu->channels); + } + + return 0; +} + static struct rsnd_mod_ops rsnd_ctu_ops = { .name = CTU_NAME, .probe = rsnd_ctu_probe_, .init = rsnd_ctu_init, .quit = rsnd_ctu_quit, + .hw_params = rsnd_ctu_hw_params, }; struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 305cc086a0bc..bbc89bd1e918 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -638,6 +638,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, */ int rsnd_ctu_probe(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv); +int rsnd_ctu_converted_channel(struct rsnd_mod *mod); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); #define rsnd_ctu_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") -- cgit v1.2.3 From eed76bb811cd143119b4bdeca88606685222e687 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2016 05:54:58 +0000 Subject: ASoC: rsnd: add rsnd_runtime_channel_xxx() Current SSI is supporting Normal SSI/Multi mode SSI/TDM mode SSI and its behavior is based on input channels. This input channel might be converted by CTU, and SSI needs to be Multi SSI mode / TDM SSI mode if 6ch input EX) 6ch input, CTU for 2ch, playback 6ch 6ch 2ch 2ch 2ch 2ch -> SRC -> CTU -> MIX -> DVC -> SSIU -> SSI EX) 6ch input, no CTU, Multi SSI, playback 6ch 6ch 6ch 6ch 6ch 2ch -> SRC -> CTU -> MIX -> DVC -> SSIU -> SSI0/SSI1/SSI2 Current driver is using rsnd_get_adinr_chan() / rsnd_get_slot_width() for this purpose, but it is complicated enough without meaning. This patch adds new rsnd_runtime_channel_xxx() which is caring CTU/Multi SSI. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 69 +++++++++++++++++++++++++++++------------------- sound/soc/sh/rcar/ctu.c | 2 +- sound/soc/sh/rcar/dvc.c | 2 +- sound/soc/sh/rcar/mix.c | 2 +- sound/soc/sh/rcar/rsnd.h | 8 ++++-- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 15 +++++------ sound/soc/sh/rcar/ssiu.c | 6 +++-- 8 files changed, 62 insertions(+), 44 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3a3dc2ff18c9..3351a701c60e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -224,13 +224,36 @@ int rsnd_get_slot_num(struct rsnd_dai_stream *io) return rdai->slots_num; } -int rsnd_get_slot_width(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int chan = runtime->channels; - /* Multi channel Mode */ - if (rsnd_ssi_multi_slaves_runtime(io)) + return runtime->channels; +} + +int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) +{ + int chan = rsnd_runtime_channel_original(io); + struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); + + if (ctu_mod) { + u32 converted_chan = rsnd_ctu_converted_channel(ctu_mod); + + if (converted_chan) + return converted_chan; + } + + return chan; +} + +int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) +{ + int chan = rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu(io) : + rsnd_runtime_channel_original(io); + + /* Use Multi SSI */ + if (rsnd_runtime_is_ssi_multi(io)) chan /= rsnd_get_slot_num(io); /* TDM Extend Mode needs 8ch */ @@ -240,6 +263,21 @@ int rsnd_get_slot_width(struct rsnd_dai_stream *io) return chan; } +int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io) +{ + int slots = rsnd_get_slot_num(io); + int chan = rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu(io) : + rsnd_runtime_channel_original(io); + + return (chan >= 6) && (slots > 1); +} + +int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io) +{ + return rsnd_runtime_channel_for_ssi(io) >= 6; +} + /* * ADINR function */ @@ -261,29 +299,6 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) return 0; } -u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct device *dev = rsnd_priv_to_dev(priv); - u32 chan = runtime->channels; - - switch (chan) { - case 1: - case 2: - case 4: - case 6: - case 8: - break; - default: - dev_warn(dev, "not supported channel\n"); - chan = 0; - break; - } - - return chan; -} - /* * DALIGN function */ diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 784515afefaf..b326966ea407 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -60,7 +60,7 @@ static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, { rsnd_mod_write(mod, CTU_CTUIR, 1); - rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io)); + rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io)); rsnd_mod_write(mod, CTU_CPMDR, 0); rsnd_mod_write(mod, CTU_SCMDR, 0); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d757f1316385..93b11e1c5d7f 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -116,7 +116,7 @@ static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, u32 vrdbr = 0; adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_get_adinr_chan(mod, io); + rsnd_runtime_channel_after_ctu(io); /* Enable Digital Volume, Zero Cross Mute Mode */ dvucr |= 0x101; diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index e0e337ad4206..195fc7bb22af 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -51,7 +51,7 @@ static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, rsnd_mod_write(mod, MIX_MIXIR, 1); /* General Information */ - rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); + rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); /* volume step */ rsnd_mod_write(mod, MIX_MIXMR, 0); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index bbc89bd1e918..ff53f96e5006 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -193,7 +193,6 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); /* @@ -356,9 +355,14 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, void rsnd_set_slot(struct rsnd_dai *rdai, int slots, int slots_total); int rsnd_get_slot(struct rsnd_dai_stream *io); -int rsnd_get_slot_width(struct rsnd_dai_stream *io); int rsnd_get_slot_num(struct rsnd_dai_stream *io); +int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); +int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); +int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); +int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); +int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); + /* * R-Car sound DAI */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 03c6314871ff..8e1177aea6b1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -205,7 +205,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, * SRC_ADINR */ adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_get_adinr_chan(mod, io); + rsnd_runtime_channel_original(io); /* * SRC_IFSCR / SRC_IFSVR diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0979db8af8f9..540489755367 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -180,11 +180,8 @@ static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 mask = rsnd_ssi_multi_slaves(io); - - if (mask && (runtime->channels >= 6)) - return mask; + if (rsnd_runtime_is_ssi_multi(io)) + return rsnd_ssi_multi_slaves(io); return 0; } @@ -198,7 +195,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); - int slots = rsnd_get_slot_width(io); + int chan = rsnd_runtime_channel_for_ssi(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, @@ -231,10 +228,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, /* * this driver is assuming that - * system word is 32bit x slots + * system word is 32bit x chan * see rsnd_ssi_init() */ - main_rate = rate * 32 * slots * ssi_clk_mul_table[j]; + main_rate = rate * 32 * chan * ssi_clk_mul_table[j]; ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); if (0 == ret) { @@ -289,7 +286,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, u32 wsr; int is_tdm; - is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0; + is_tdm = rsnd_runtime_is_ssi_tdm(io); /* * always use 32bit system word. diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 0d964a0a3e31..6f9b388ec5a8 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -105,7 +105,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; - if (rsnd_get_slot_width(io) >= 6) { + if (rsnd_runtime_is_ssi_tdm(io)) { /* * TDM Extend Mode * see @@ -117,7 +117,9 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (rsnd_ssi_use_busif(io)) { rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(mod, io) | - rsnd_get_adinr_chan(mod, io)); + (rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu(io) : + rsnd_runtime_channel_original(io))); rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(mod, SSI_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); -- cgit v1.2.3 From ec2ac01afe001360b911e27c915579fd003339e8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2016 05:55:23 +0000 Subject: ASoC: rsnd: add CTU support This patch adds CTU (= Channel Transfer Unit) support on Renesas R-Car sound driver. It can Down/Up mixing and splitter. You need to check R-Car datasheet especially CTUn_CPMDR/CTUn_SV0xR/CTUn_SV1xR/CTUn_SV2xR/CTUn_SV3xR for setting parameter. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 234 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 197 insertions(+), 37 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index b326966ea407..9dcc1f9db026 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -12,8 +12,74 @@ #define CTU_NAME_SIZE 16 #define CTU_NAME "ctu" +/* + * User needs to setup CTU by amixer, and its settings are + * based on below registers + * + * CTUn_CPMDR : amixser set "CTU Pass" + * CTUn_SV0xR : amixser set "CTU SV0" + * CTUn_SV1xR : amixser set "CTU SV1" + * CTUn_SV2xR : amixser set "CTU SV2" + * CTUn_SV3xR : amixser set "CTU SV3" + * + * [CTU Pass] + * 0000: default + * 0001: Connect input data of channel 0 + * 0010: Connect input data of channel 1 + * 0011: Connect input data of channel 2 + * 0100: Connect input data of channel 3 + * 0101: Connect input data of channel 4 + * 0110: Connect input data of channel 5 + * 0111: Connect input data of channel 6 + * 1000: Connect input data of channel 7 + * 1001: Connect calculated data by scale values of matrix row 0 + * 1010: Connect calculated data by scale values of matrix row 1 + * 1011: Connect calculated data by scale values of matrix row 2 + * 1100: Connect calculated data by scale values of matrix row 3 + * + * [CTU SVx] + * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07] + * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17] + * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27] + * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37] + * [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * + * [SVxx] + * Plus Minus + * value time dB value time dB + * ----------------------------------------------------------------------- + * H'7F_FFFF 2 6 H'80_0000 2 6 + * ... + * H'40_0000 1 0 H'C0_0000 1 0 + * ... + * H'00_0001 2.38 x 10^-7 -132 + * H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132 + * + * + * Ex) Input ch -> Output ch + * 1ch -> 0ch + * 0ch -> 1ch + * + * amixer set "CTU Reset" on + * amixer set "CTU Pass" 9,10 + * amixer set "CTU SV0" 0,4194304 + * amixer set "CTU SV1" 4194304,0 + * or + * amixer set "CTU Reset" on + * amixer set "CTU Pass" 2,1 + */ + struct rsnd_ctu { struct rsnd_mod mod; + struct rsnd_kctrl_cfg_m pass; + struct rsnd_kctrl_cfg_m sv0; + struct rsnd_kctrl_cfg_m sv1; + struct rsnd_kctrl_cfg_m sv2; + struct rsnd_kctrl_cfg_m sv3; + struct rsnd_kctrl_cfg_s reset; int channels; }; @@ -58,51 +124,91 @@ static int rsnd_ctu_probe_(struct rsnd_mod *mod, static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + u32 cpmdr = 0; + u32 scmdr = 0; + int i; + + for (i = 0; i < RSND_MAX_CHANNELS; i++) { + u32 val = ctu->pass.val[i]; + + cpmdr |= val << (28 - (i * 4)); + + if ((val > 0x8) && (scmdr < (val - 0x8))) + scmdr = val - 0x8; + } + rsnd_mod_write(mod, CTU_CTUIR, 1); rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io)); - rsnd_mod_write(mod, CTU_CPMDR, 0); - rsnd_mod_write(mod, CTU_SCMDR, 0); - rsnd_mod_write(mod, CTU_SV00R, 0); - rsnd_mod_write(mod, CTU_SV01R, 0); - rsnd_mod_write(mod, CTU_SV02R, 0); - rsnd_mod_write(mod, CTU_SV03R, 0); - rsnd_mod_write(mod, CTU_SV04R, 0); - rsnd_mod_write(mod, CTU_SV05R, 0); - rsnd_mod_write(mod, CTU_SV06R, 0); - rsnd_mod_write(mod, CTU_SV07R, 0); - - rsnd_mod_write(mod, CTU_SV10R, 0); - rsnd_mod_write(mod, CTU_SV11R, 0); - rsnd_mod_write(mod, CTU_SV12R, 0); - rsnd_mod_write(mod, CTU_SV13R, 0); - rsnd_mod_write(mod, CTU_SV14R, 0); - rsnd_mod_write(mod, CTU_SV15R, 0); - rsnd_mod_write(mod, CTU_SV16R, 0); - rsnd_mod_write(mod, CTU_SV17R, 0); - - rsnd_mod_write(mod, CTU_SV20R, 0); - rsnd_mod_write(mod, CTU_SV21R, 0); - rsnd_mod_write(mod, CTU_SV22R, 0); - rsnd_mod_write(mod, CTU_SV23R, 0); - rsnd_mod_write(mod, CTU_SV24R, 0); - rsnd_mod_write(mod, CTU_SV25R, 0); - rsnd_mod_write(mod, CTU_SV26R, 0); - rsnd_mod_write(mod, CTU_SV27R, 0); - - rsnd_mod_write(mod, CTU_SV30R, 0); - rsnd_mod_write(mod, CTU_SV31R, 0); - rsnd_mod_write(mod, CTU_SV32R, 0); - rsnd_mod_write(mod, CTU_SV33R, 0); - rsnd_mod_write(mod, CTU_SV34R, 0); - rsnd_mod_write(mod, CTU_SV35R, 0); - rsnd_mod_write(mod, CTU_SV36R, 0); - rsnd_mod_write(mod, CTU_SV37R, 0); + rsnd_mod_write(mod, CTU_CPMDR, cpmdr); + + rsnd_mod_write(mod, CTU_SCMDR, scmdr); + + if (scmdr > 0) { + rsnd_mod_write(mod, CTU_SV00R, ctu->sv0.val[0]); + rsnd_mod_write(mod, CTU_SV01R, ctu->sv0.val[1]); + rsnd_mod_write(mod, CTU_SV02R, ctu->sv0.val[2]); + rsnd_mod_write(mod, CTU_SV03R, ctu->sv0.val[3]); + rsnd_mod_write(mod, CTU_SV04R, ctu->sv0.val[4]); + rsnd_mod_write(mod, CTU_SV05R, ctu->sv0.val[5]); + rsnd_mod_write(mod, CTU_SV06R, ctu->sv0.val[6]); + rsnd_mod_write(mod, CTU_SV07R, ctu->sv0.val[7]); + } + if (scmdr > 1) { + rsnd_mod_write(mod, CTU_SV10R, ctu->sv1.val[0]); + rsnd_mod_write(mod, CTU_SV11R, ctu->sv1.val[1]); + rsnd_mod_write(mod, CTU_SV12R, ctu->sv1.val[2]); + rsnd_mod_write(mod, CTU_SV13R, ctu->sv1.val[3]); + rsnd_mod_write(mod, CTU_SV14R, ctu->sv1.val[4]); + rsnd_mod_write(mod, CTU_SV15R, ctu->sv1.val[5]); + rsnd_mod_write(mod, CTU_SV16R, ctu->sv1.val[6]); + rsnd_mod_write(mod, CTU_SV17R, ctu->sv1.val[7]); + } + if (scmdr > 2) { + rsnd_mod_write(mod, CTU_SV20R, ctu->sv2.val[0]); + rsnd_mod_write(mod, CTU_SV21R, ctu->sv2.val[1]); + rsnd_mod_write(mod, CTU_SV22R, ctu->sv2.val[2]); + rsnd_mod_write(mod, CTU_SV23R, ctu->sv2.val[3]); + rsnd_mod_write(mod, CTU_SV24R, ctu->sv2.val[4]); + rsnd_mod_write(mod, CTU_SV25R, ctu->sv2.val[5]); + rsnd_mod_write(mod, CTU_SV26R, ctu->sv2.val[6]); + rsnd_mod_write(mod, CTU_SV27R, ctu->sv2.val[7]); + } + if (scmdr > 3) { + rsnd_mod_write(mod, CTU_SV30R, ctu->sv3.val[0]); + rsnd_mod_write(mod, CTU_SV31R, ctu->sv3.val[1]); + rsnd_mod_write(mod, CTU_SV32R, ctu->sv3.val[2]); + rsnd_mod_write(mod, CTU_SV33R, ctu->sv3.val[3]); + rsnd_mod_write(mod, CTU_SV34R, ctu->sv3.val[4]); + rsnd_mod_write(mod, CTU_SV35R, ctu->sv3.val[5]); + rsnd_mod_write(mod, CTU_SV36R, ctu->sv3.val[6]); + rsnd_mod_write(mod, CTU_SV37R, ctu->sv3.val[7]); + } rsnd_mod_write(mod, CTU_CTUIR, 0); } +static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + int i; + + if (!ctu->reset.val) + return; + + for (i = 0; i < RSND_MAX_CHANNELS; i++) { + ctu->pass.val[i] = 0; + ctu->sv0.val[i] = 0; + ctu->sv1.val[i] = 0; + ctu->sv2.val[i] = 0; + ctu->sv3.val[i] = 0; + } + ctu->reset.val = 0; +} + static int rsnd_ctu_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -164,12 +270,66 @@ static int rsnd_ctu_hw_params(struct rsnd_mod *mod, return 0; } +static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + int ret; + + /* CTU Pass */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", + NULL, + &ctu->pass, RSND_MAX_CHANNELS, + 0xC); + + /* ROW0 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", + NULL, + &ctu->sv0, RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* ROW1 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", + NULL, + &ctu->sv1, RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* ROW2 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", + NULL, + &ctu->sv2, RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* ROW3 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", + NULL, + &ctu->sv3, RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* Reset */ + ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", + rsnd_ctu_value_reset, + &ctu->reset, 1); + + return ret; +} + static struct rsnd_mod_ops rsnd_ctu_ops = { .name = CTU_NAME, .probe = rsnd_ctu_probe_, .init = rsnd_ctu_init, .quit = rsnd_ctu_quit, .hw_params = rsnd_ctu_hw_params, + .pcm_new = rsnd_ctu_pcm_new, }; struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) -- cgit v1.2.3 From 05f5afd3f0d915537b67d3cfcb464e6836a65caf Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 2 Mar 2016 15:49:06 +0100 Subject: ASoC: mediatek: address dai link array entries by enum This should be more robust to future changes than adressing array entries by index number. Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173-rt5650-rt5676.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 50ba538eccb3..5c4c58c69c51 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c @@ -131,10 +131,17 @@ static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = { }, }; +enum { + DAI_LINK_PLAYBACK, + DAI_LINK_CAPTURE, + DAI_LINK_CODEC_I2S, + DAI_LINK_INTERCODEC +}; + /* Digital audio interface glue - connects codec <---> CPU */ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { /* Front End DAI links */ - { + [DAI_LINK_PLAYBACK] = { .name = "rt5650_rt5676 Playback", .stream_name = "rt5650_rt5676 Playback", .cpu_dai_name = "DL1", @@ -144,7 +151,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .dynamic = 1, .dpcm_playback = 1, }, - { + [DAI_LINK_CAPTURE] = { .name = "rt5650_rt5676 Capture", .stream_name = "rt5650_rt5676 Capture", .cpu_dai_name = "VUL", @@ -156,7 +163,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { }, /* Back End DAI links */ - { + [DAI_LINK_CODEC_I2S] = { .name = "Codec", .cpu_dai_name = "I2S", .no_pcm = 1, @@ -170,7 +177,8 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .dpcm_playback = 1, .dpcm_capture = 1, }, - { /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ + /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ + [DAI_LINK_INTERCODEC] = { .name = "rt5650_rt5676 intercodec", .stream_name = "rt5650_rt5676 intercodec", .cpu_dai_name = "snd-soc-dummy-dai", @@ -240,7 +248,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) mt8173_rt5650_rt5676_codec_conf[0].of_node = mt8173_rt5650_rt5676_codecs[1].of_node; - mt8173_rt5650_rt5676_dais[3].codec_of_node = + mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node = mt8173_rt5650_rt5676_codecs[1].of_node; card->dev = &pdev->dev; -- cgit v1.2.3 From 4f2bf0ace0f96cc693002e1bbde967fa2356bc43 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 5 Feb 2016 16:32:14 +0100 Subject: ASoC: ads117x: Add device tree compatible string This patch adds the necessary device tree compatible string to allow DT probing. Signed-off-by: Florian Vaussard Signed-off-by: Mark Brown --- sound/soc/codecs/ads117x.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index 1222282e93c3..c5be1bdc2c9a 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -20,6 +20,8 @@ #include #include +#include + #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000) #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) @@ -75,9 +77,19 @@ static int ads117x_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id ads117x_dt_ids[] = { + { .compatible = "ti,ads1174" }, + { .compatible = "ti,ads1178" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ads117x_dt_ids); +#endif + static struct platform_driver ads117x_codec_driver = { .driver = { .name = "ads117x-codec", + .of_match_table = of_match_ptr(ads117x_dt_ids), }, .probe = ads117x_probe, -- cgit v1.2.3 From e066ea2214f77e13e24344313243f9b3a182d3c4 Mon Sep 17 00:00:00 2001 From: Rajan Vaja Date: Thu, 11 Feb 2016 11:23:35 +0530 Subject: ASoC: dapm: Remove unneeded variable ret returning 0 This patch fixes coccicheck report: Unneeded variable: "ret". Return "0" on line 2817 Remove unneccesary variable ret created to return zero. Signed-off-by: Rajan Vaja Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5a2812fa8946..8dc395f15049 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2805,7 +2805,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num) { - int i, ret = 0; + int i; mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); for (i = 0; i < num; i++) { @@ -2814,7 +2814,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, } mutex_unlock(&dapm->card->dapm_mutex); - return ret; + return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes); -- cgit v1.2.3 From d7fcd13663fe43ad938fec1acd46ff196dddf914 Mon Sep 17 00:00:00 2001 From: John Lin Date: Mon, 7 Mar 2016 12:12:11 +0800 Subject: ASoC: rt5616: add missing mute control for HPVOL Add missing kcontrol for HPVOL mute control. Signed-off-by: John Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 3704d0716c04..f527b5b2817b 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -309,6 +309,8 @@ static const struct snd_kcontrol_new rt5616_snd_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL, RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE("HPVOL Playback Switch", RT5616_HP_VOL, + RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1), SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL, RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), /* OUTPUT Control */ -- cgit v1.2.3 From c467fc0e010b66069c0d5bb3e8e869adf267115f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 7 Mar 2016 15:09:37 +0800 Subject: ASoC: rt5640: Set PLL src according to source rt5640_set_dai_pll set pll source according to given source and dai id. However, the pll source should be set according to given source only. Signed-off-by: Jack Yu Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 6cd84fb2196a..863c190c5076 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1902,21 +1902,12 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_MCLK); break; case RT5640_PLL1_S_BCLK1: + snd_soc_update_bits(codec, RT5640_GLB_CLK, + RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK1); + break; case RT5640_PLL1_S_BCLK2: - dai_sel = get_sdp_info(codec, dai->id); - if (dai_sel < 0) { - dev_err(codec->dev, - "Failed to get sdp info: %d\n", dai_sel); - return -EINVAL; - } - if (dai_sel & RT5640_U_IF1) { - snd_soc_update_bits(codec, RT5640_GLB_CLK, - RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK1); - } - if (dai_sel & RT5640_U_IF2) { - snd_soc_update_bits(codec, RT5640_GLB_CLK, - RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK2); - } + snd_soc_update_bits(codec, RT5640_GLB_CLK, + RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK2); break; default: dev_err(codec->dev, "Unknown PLL source %d\n", source); -- cgit v1.2.3 From 57586fb76471c5fc521b2e9c3a4eae259b06d479 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 7 Mar 2016 15:09:38 +0800 Subject: ASoC: rt5640: add supplys for dac power The DAC1/2 power is for both DACs and related mixer/mux. Add SUPPLY type widgets to support it. Signed-off-by: Jack Yu Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 863c190c5076..af9b5f18f0e0 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1217,11 +1217,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { SND_SOC_DAPM_MIXER("DIG MIXR", SND_SOC_NOPM, 0, 0, rt5640_dig_r_mix, ARRAY_SIZE(rt5640_dig_r_mix)), /* DACs */ - SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1, - RT5640_PWR_DAC_L1_BIT, 0), - SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1, - RT5640_PWR_DAC_R1_BIT, 0), - + SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, + 0, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, + 0, 0), + SND_SOC_DAPM_SUPPLY("DAC L1 Power", RT5640_PWR_DIG1, + RT5640_PWR_DAC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R1 Power", RT5640_PWR_DIG1, + RT5640_PWR_DAC_R1_BIT, 0, NULL, 0), /* SPK/OUT Mixer */ SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT, 0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)), @@ -1298,9 +1301,9 @@ static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)), - SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R2_BIT, + SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L2_BIT, + SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, @@ -1317,6 +1320,10 @@ static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = { rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, RT5640_PWR_MA_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5640_PWR_DIG1, + RT5640_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5640_PWR_DIG1, + RT5640_PWR_DAC_R2_BIT, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("MONOP"), SND_SOC_DAPM_OUTPUT("MONON"), @@ -1328,11 +1335,6 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)), - SND_SOC_DAPM_SUPPLY("DAC L2 Filter", RT5640_PWR_DIG1, - RT5640_PWR_DAC_L2_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC R2 Filter", RT5640_PWR_DIG1, - RT5640_PWR_DAC_R2_BIT, 0, NULL, 0), - SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, 0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)), SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, @@ -1493,8 +1495,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"DAC MIXL", "Stereo ADC Switch", "Stereo ADC MIXL"}, {"DAC MIXL", "INF1 Switch", "IF1 DAC L"}, + {"DAC MIXL", NULL, "DAC L1 Power"}, {"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"}, {"DAC MIXR", "INF1 Switch", "IF1 DAC R"}, + {"DAC MIXR", NULL, "DAC R1 Power"}, {"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, {"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, @@ -1507,8 +1511,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { {"DAC L1", NULL, "Stereo DAC MIXL"}, {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC L1", NULL, "DAC L1 Power"}, {"DAC R1", NULL, "Stereo DAC MIXR"}, {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC R1", NULL, "DAC R1 Power"}, {"SPK MIXL", "REC MIXL Switch", "RECMIXL"}, {"SPK MIXL", "INL Switch", "INL VOL"}, @@ -1595,8 +1601,9 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { {"DAC L2 Mux", "IF2", "IF2 DAC L"}, {"DAC L2 Mux", "Base L/R", "Audio DSP"}, - + {"DAC L2 Mux", NULL, "DAC L2 Power"}, {"DAC R2 Mux", "IF2", "IF2 DAC R"}, + {"DAC R2 Mux", NULL, "DAC R2 Power"}, {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, {"Stereo DAC MIXL", "ANC Switch", "ANC"}, @@ -1614,8 +1621,10 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { {"DAC L2", NULL, "Mono DAC MIXL"}, {"DAC L2", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC L2", NULL, "DAC L2 Power"}, {"DAC R2", NULL, "Mono DAC MIXR"}, {"DAC R2", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC R2", NULL, "DAC R2 Power"}, {"SPK MIXL", "DAC L2 Switch", "DAC L2"}, {"SPK MIXR", "DAC R2 Switch", "DAC R2"}, @@ -1656,8 +1665,8 @@ static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = { {"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"}, {"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"}, - {"IF2 DAC L", NULL, "DAC L2 Filter"}, - {"IF2 DAC R", NULL, "DAC R2 Filter"}, + {"IF2 DAC L", NULL, "DAC L2 Power"}, + {"IF2 DAC R", NULL, "DAC R2 Power"}, }; static int get_sdp_info(struct snd_soc_codec *codec, int dai_id) -- cgit v1.2.3 From 61a219fe192412bca6c26657a4b0c99c67a3e7fc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:06:17 +0000 Subject: ASoC: rsnd: don't enable SRC Sync mode when Capture with CMD It can't use SRC Synchronous convert when Capture if it uses CMD, because no one provide out side clocks. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 8e1177aea6b1..541a478cf157 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -475,7 +475,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, struct snd_soc_pcm_runtime *rtd) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_src *src = rsnd_mod_to_src(mod); int ret; @@ -490,9 +489,10 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, return 0; /* - * SRC In doesn't work if DVC was enabled + * It can't use SRC Synchronous convert + * when Capture if it uses CMD */ - if (dvc && !rsnd_io_is_play(io)) + if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io)) return 0; /* -- cgit v1.2.3 From b5ebbb3a16c631c776f6619dff8ee86da21cca6f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:06:46 +0000 Subject: ASoC: rsnd: SRC sync mode is not related to clock master mode SRC sync mode needs to control its clock (= for in/out). 1st but codec side clock Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 541a478cf157..ab974afe79eb 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -474,7 +474,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) { - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_src *src = rsnd_mod_to_src(mod); int ret; @@ -482,12 +481,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, * enable SRC sync convert if possible */ - /* - * SRC sync convert needs clock master - */ - if (!rsnd_rdai_is_clk_master(rdai)) - return 0; - /* * It can't use SRC Synchronous convert * when Capture if it uses CMD -- cgit v1.2.3 From 1a9be9ee194131465d945981969b85045f20e6af Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:07:29 +0000 Subject: ASoC: rsnd: SRC function parameter uses "mod" instead of "src" To reduce confusion, SRC uses "mod" instead of "src" as function parameter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index ab974afe79eb..d520690409a2 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -93,9 +93,10 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, } static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, - struct rsnd_src *src) + struct rsnd_mod *mod) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_src *src = rsnd_mod_to_src(mod); u32 convert_rate; if (!runtime) @@ -120,18 +121,14 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct snd_pcm_runtime *runtime) { struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct rsnd_src *src; unsigned int rate = 0; - if (src_mod) { - src = rsnd_mod_to_src(src_mod); - - /* - * return convert rate if SRC is used, - * otherwise, return runtime->rate as usual - */ - rate = rsnd_src_convert_rate(io, src); - } + /* + * return convert rate if SRC is used, + * otherwise, return runtime->rate as usual + */ + if (src_mod) + rate = rsnd_src_convert_rate(io, src_mod); if (!rate) rate = runtime->rate; @@ -179,7 +176,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); + u32 convert_rate = rsnd_src_convert_rate(io, mod); u32 ifscr, fsrate, adinr; u32 cr, route; u32 bsdsr, bsisr; -- cgit v1.2.3 From ab2049f9de72c901c07eec25eff74dae2e82df7e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:07:57 +0000 Subject: ASoC: rsnd: rename rsnd_enable_sync_convert() to rsnd_src_sync_is_enabled() rsnd_enable_sync_convert() is for checking, not for setting. In order to avoid confusion, this patch renamed it to rsnd_src_sync_is_enabled() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index d520690409a2..1d5aedb50213 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -33,7 +33,7 @@ struct rsnd_src { #define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) #define rsnd_src_to_dma(src) ((src)->dma) #define rsnd_src_nr(priv) ((priv)->src_nr) -#define rsnd_enable_sync_convert(src) ((src)->sen.val) +#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val) #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) @@ -102,7 +102,7 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, if (!runtime) return 0; - if (!rsnd_enable_sync_convert(src)) + if (!rsnd_src_sync_is_enabled(mod)) return src->convert_rate; convert_rate = src->sync.val; @@ -175,7 +175,6 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); u32 convert_rate = rsnd_src_convert_rate(io, mod); u32 ifscr, fsrate, adinr; u32 cr, route; @@ -222,7 +221,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, if (convert_rate) { route = 0x1; - if (rsnd_enable_sync_convert(src)) { + if (rsnd_src_sync_is_enabled(mod)) { cr |= 0x1; route |= rsnd_io_is_play(io) ? (0x1 << 24) : (0x1 << 25); @@ -296,9 +295,9 @@ static int rsnd_src_irq(struct rsnd_mod *mod, /* * WORKAROUND * - * ignore over flow error when rsnd_enable_sync_convert() + * ignore over flow error when rsnd_src_sync_is_enabled() */ - if (rsnd_enable_sync_convert(src)) + if (rsnd_src_sync_is_enabled(mod)) sys_int_val = sys_int_val & 0xffff; rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); @@ -318,7 +317,6 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod) static bool rsnd_src_error_occurred(struct rsnd_mod *mod) { - struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val0, val1; bool ret = false; @@ -327,9 +325,9 @@ static bool rsnd_src_error_occurred(struct rsnd_mod *mod) /* * WORKAROUND * - * ignore over flow error when rsnd_enable_sync_convert() + * ignore over flow error when rsnd_src_sync_is_enabled() */ - if (rsnd_enable_sync_convert(src)) + if (rsnd_src_sync_is_enabled(mod)) val0 = val0 & 0xffff; if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) || @@ -343,7 +341,6 @@ static int rsnd_src_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val; /* @@ -351,7 +348,7 @@ static int rsnd_src_start(struct rsnd_mod *mod, * * Enable SRC output if you want to use sync convert together with DVC */ - val = (rsnd_io_to_mod_dvc(io) && !rsnd_enable_sync_convert(src)) ? + val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ? 0x01 : 0x11; rsnd_mod_write(mod, SRC_CTRL, val); -- cgit v1.2.3 From cbf1494fbcc80d363477af1efefb2380e7660a24 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:08:33 +0000 Subject: ASoC: rsnd: add rsnd_src_get_in/out_rate() SRC will convert rate, and then, CMD and SSI want to know its rate (= SRC.in / SRC.out) for each purpose. Current driver is supporting only Playback, but SRC+Capture support needs more flexibility. This patch adds rsnd_src_get_in/out_rate() for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 10 +++++++--- sound/soc/sh/rcar/src.c | 20 +++++++++++++++++--- sound/soc/sh/rcar/ssi.c | 5 +++-- 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ff53f96e5006..4b77f33358fb 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -627,9 +627,13 @@ void rsnd_ssiu_remove(struct rsnd_priv *priv); int rsnd_src_probe(struct rsnd_priv *priv); void rsnd_src_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); -unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct snd_pcm_runtime *runtime); + +#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1) +#define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0) +unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + int is_in); + #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") #define rsnd_parse_connect_src(rdai, playback, capture) \ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 1d5aedb50213..d1a8741cc446 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -116,12 +116,26 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, return convert_rate; } -unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct snd_pcm_runtime *runtime) +unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + int is_in) { struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); unsigned int rate = 0; + int is_play = rsnd_io_is_play(io); + + /* + * + * Playback + * runtime_rate -> [SRC] -> convert_rate + * + * Capture + * convert_rate -> [SRC] -> runtime_rate + */ + + if (is_play == is_in) + return runtime->rate; /* * return convert rate if SRC is used, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 540489755367..5f848f054745 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -190,7 +190,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); @@ -201,7 +200,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, 1, 2, 4, 8, 16, 6, 12, }; unsigned int main_rate; - unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); + unsigned int rate = rsnd_io_is_play(io) ? + rsnd_src_get_out_rate(priv, io) : + rsnd_src_get_in_rate(priv, io); if (!rsnd_rdai_is_clk_master(rdai)) return 0; -- cgit v1.2.3 From 0102eed57c47371023c03b3b0c564f33d5e94570 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:09:14 +0000 Subject: ASoC: rsnd: SRC TIMSEL support for Capture SRC has Sync/Async mode, and it can't use Sync mode when Capture with CMD. In Async mode, it needs to care about in/out SRC rate for settings, but current driver supporting Playback case only. This patch supports Capture case. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 204 ++++++++++++++++++++++++++--------------------- sound/soc/sh/rcar/rsnd.h | 8 +- sound/soc/sh/rcar/src.c | 26 +++--- 3 files changed, 128 insertions(+), 110 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index d74e1ccc0f8f..f7e164c89f33 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -90,6 +90,108 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) return (0x6 + ws) << 8; } +static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + unsigned int target_rate, + unsigned int *target_val, + unsigned int *target_en) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + int idx, sel, div, step; + unsigned int val, en; + unsigned int min, diff; + unsigned int sel_rate[] = { + clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */ + clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */ + clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */ + adg->rbga_rate_for_441khz, /* 0011: RBGA */ + adg->rbgb_rate_for_48khz, /* 0100: RBGB */ + }; + + min = ~0; + val = 0; + en = 0; + for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { + idx = 0; + step = 2; + + if (!sel_rate[sel]) + continue; + + for (div = 2; div <= 98304; div += step) { + diff = abs(target_rate - sel_rate[sel] / div); + if (min > diff) { + val = (sel << 8) | idx; + min = diff; + en = 1 << (sel + 1); /* fixme */ + } + + /* + * step of 0_0000 / 0_0001 / 0_1101 + * are out of order + */ + if ((idx > 2) && (idx % 2)) + step *= 2; + if (idx == 0x1c) { + div += step; + step *= 2; + } + idx++; + } + } + + if (min == ~0) { + dev_err(dev, "no Input clock\n"); + return; + } + + *target_val = val; + if (target_en) + *target_en = en; +} + +static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + unsigned int in_rate, + unsigned int out_rate, + u32 *in, u32 *out, u32 *en) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + unsigned int target_rate; + u32 *target_val; + u32 _in; + u32 _out; + u32 _en; + + /* default = SSI WS */ + _in = + _out = rsnd_adg_ssi_ws_timing_gen2(io); + + target_rate = 0; + target_val = NULL; + _en = 0; + if (runtime->rate != in_rate) { + target_rate = out_rate; + target_val = &_out; + } else if (runtime->rate != out_rate) { + target_rate = in_rate; + target_val = &_in; + } + + if (target_rate) + __rsnd_adg_get_timesel_ratio(priv, io, + target_rate, + target_val, &_en); + + if (in) + *in = _in; + if (out) + *out = _out; + if (en) + *en = _en; +} + int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, struct rsnd_dai_stream *io) { @@ -110,25 +212,24 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, return 0; } -static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io, - u32 timsel) +int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, + struct rsnd_dai_stream *io, + unsigned int in_rate, + unsigned int out_rate) { struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int is_play = rsnd_io_is_play(io); + u32 in, out; + u32 mask, en; int id = rsnd_mod_id(src_mod); int shift = (id % 2) ? 16 : 0; - u32 mask, ws; - u32 in, out; rsnd_mod_confirm_src(src_mod); - ws = rsnd_adg_ssi_ws_timing_gen2(io); - - in = (is_play) ? timsel : ws; - out = (is_play) ? ws : timsel; + rsnd_adg_get_timesel_ratio(priv, io, + in_rate, out_rate, + &in, &out, &en); in = in << shift; out = out << shift; @@ -157,91 +258,12 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod, break; } - return 0; -} - -int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io, - unsigned int src_rate, - unsigned int dst_rate) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - struct device *dev = rsnd_priv_to_dev(priv); - int idx, sel, div, step, ret; - u32 val, en; - unsigned int min, diff; - unsigned int sel_rate [] = { - clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */ - clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */ - clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */ - adg->rbga_rate_for_441khz, /* 0011: RBGA */ - adg->rbgb_rate_for_48khz, /* 0100: RBGB */ - }; - - rsnd_mod_confirm_src(src_mod); - - min = ~0; - val = 0; - en = 0; - for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { - idx = 0; - step = 2; - - if (!sel_rate[sel]) - continue; - - for (div = 2; div <= 98304; div += step) { - diff = abs(src_rate - sel_rate[sel] / div); - if (min > diff) { - val = (sel << 8) | idx; - min = diff; - en = 1 << (sel + 1); /* fixme */ - } - - /* - * step of 0_0000 / 0_0001 / 0_1101 - * are out of order - */ - if ((idx > 2) && (idx % 2)) - step *= 2; - if (idx == 0x1c) { - div += step; - step *= 2; - } - idx++; - } - } - - if (min == ~0) { - dev_err(dev, "no Input clock\n"); - return -EIO; - } - - ret = rsnd_adg_set_src_timsel_gen2(src_mod, io, val); - if (ret < 0) { - dev_err(dev, "timsel error\n"); - return ret; - } - - rsnd_mod_bset(adg_mod, DIV_EN, en, en); - - dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate); + if (en) + rsnd_mod_bset(adg_mod, DIV_EN, en, en); return 0; } -int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io) -{ - u32 val = rsnd_adg_ssi_ws_timing_gen2(io); - - rsnd_mod_confirm_src(src_mod); - - return rsnd_adg_set_src_timsel_gen2(src_mod, io, val); -} - static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) { struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4b77f33358fb..fc89a67258ca 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -446,12 +446,10 @@ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); int rsnd_adg_probe(struct rsnd_priv *priv); void rsnd_adg_remove(struct rsnd_priv *priv); -int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, +int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, struct rsnd_dai_stream *io, - unsigned int src_rate, - unsigned int dst_rate); -int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io); + unsigned int in_rate, + unsigned int out_rate); int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index d1a8741cc446..15d6ffe8be74 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,7 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 convert_rate = rsnd_src_convert_rate(io, mod); + u32 fin, fout; u32 ifscr, fsrate, adinr; u32 cr, route; u32 bsdsr, bsisr; @@ -198,13 +198,16 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, if (!runtime) return; + fin = rsnd_src_get_in_rate(priv, io); + fout = rsnd_src_get_out_rate(priv, io); + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ - if (!convert_rate) + if (fin == fout) ratio = 0; - else if (convert_rate > runtime->rate) - ratio = 100 * convert_rate / runtime->rate; + else if (fin > fout) + ratio = 100 * fin / fout; else - ratio = 100 * runtime->rate / convert_rate; + ratio = 100 * fout / fin; if (ratio > 600) { dev_err(dev, "FSO/FSI ratio error\n"); @@ -222,9 +225,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, */ ifscr = 0; fsrate = 0; - if (convert_rate) { + if (fin != fout) { ifscr = 1; - fsrate = 0x0400000 / convert_rate * runtime->rate; + fsrate = 0x0400000 / fout * fin; } /* @@ -232,7 +235,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, */ cr = 0x00011110; route = 0x0; - if (convert_rate) { + if (fin != fout) { route = 0x1; if (rsnd_src_sync_is_enabled(mod)) { @@ -274,12 +277,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); - if (convert_rate) - rsnd_adg_set_convert_clk_gen2(mod, io, - runtime->rate, - convert_rate); - else - rsnd_adg_set_convert_timing_gen2(mod, io); + rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); } static int rsnd_src_irq(struct rsnd_mod *mod, -- cgit v1.2.3 From 09e59075496517206351cc28226ad7263a1a5c4f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 7 Mar 2016 05:09:34 +0000 Subject: ASoC: rsnd: CMD TIMSEL support for Capture CMD.out should use same as SRC.out for TIMSEL settings, but it cares Playback case only. This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index f7e164c89f33..606399de684d 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -202,7 +202,10 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, int shift = (id % 2) ? 16 : 0; u32 mask, val; - val = rsnd_adg_ssi_ws_timing_gen2(io); + rsnd_adg_get_timesel_ratio(priv, io, + rsnd_src_get_in_rate(priv, io), + rsnd_src_get_out_rate(priv, io), + NULL, &val, NULL); val = val << shift; mask = 0xffff << shift; -- cgit v1.2.3 From c77dd678a7659d58625bd3b3a36d1329d9e7d44c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 8 Mar 2016 13:35:31 +0530 Subject: ASoC: rt5640: remove unused variable We are getting build warning about: sound/soc/codecs/rt5640.c:1892:11: warning: unused variable 'dai_sel' The use of the variable was removed but the variable itself was not removed. Fixes: c467fc0e010b ("ASoC: rt5640: Set PLL src according to source") Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index af9b5f18f0e0..e8b5ba04417a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1889,7 +1889,7 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, struct snd_soc_codec *codec = dai->codec; struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); struct rl6231_pll_code pll_code; - int ret, dai_sel; + int ret; if (source == rt5640->pll_src && freq_in == rt5640->pll_in && freq_out == rt5640->pll_out) -- cgit v1.2.3 From 391005e8e3cd5bb641dff5abb1ad37254602cd7e Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 10 Mar 2016 09:04:07 +0530 Subject: ASoC: hdac_hdmi: Fix infoframe programming Audio infoframe used incorrect buffer, so fix it. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 7851dd204a49..4f7bd1fae0db 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -303,7 +303,6 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, if (ret < 0) return ret; - dip = (u8 *)&frame; break; case DRM_ELD_CONN_TYPE_DP: @@ -332,9 +331,9 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, /* Fill infoframe. Index auto-incremented */ hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { - for (i = 0; i < sizeof(frame); i++) + for (i = 0; i < sizeof(buffer); i++) snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, - AC_VERB_SET_HDMI_DIP_DATA, dip[i]); + AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); } else { for (i = 0; i < sizeof(dp_ai); i++) snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, -- cgit v1.2.3 From 5602a64318a4a6aad028141bb68e9bbd6bb5749a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 10 Mar 2016 10:46:07 +0000 Subject: ASoC: wm_adsp: Use correct local length in error message Fixes: 44029e9e1290 ("ASoC: wm_adsp: wm_coeff_{read|write}_control should use passed length") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 36687db5da61..ba9213c0ad53 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -787,7 +787,7 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, ret = regmap_raw_read(dsp->regmap, reg, scratch, len); if (ret) { adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", - ctl->len, reg, ret); + len, reg, ret); kfree(scratch); return ret; } -- cgit v1.2.3 From 4a11ff260053b1097a5afa6c51e8d5e064aa88a7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 11 Mar 2016 13:18:51 +0200 Subject: ASoC: davinci-mcasp: dai format runtime reconfiguration In case when the dai format is set via the dai_link the format configuration happens once when the links are probed. If the McASP lose context after this, the information will be lost and McASP will not going to work correctly. To overcome this issue, we save the fmt and set it within hw_params as well. Reported-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 3cf46afb353f..e1324989bd6b 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -77,6 +77,7 @@ struct davinci_mcasp { u32 fifo_base; struct device *dev; struct snd_pcm_substream *substreams[2]; + unsigned int dai_fmt; /* McASP specific data */ int tdm_slots; @@ -398,6 +399,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, bool fs_pol_rising; bool inv_fs = false; + if (!fmt) + return 0; + pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: @@ -529,6 +533,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL); mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL); } + + mcasp->dai_fmt = fmt; out: pm_runtime_put(mcasp->dev); return ret; @@ -1026,6 +1032,10 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int period_size = params_period_size(params); int ret; + ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); + if (ret) + return ret; + /* * If mcasp is BCLK master, and a BCLK divider was not provided by * the machine driver, we need to calculate the ratio. -- cgit v1.2.3 From dc6cdb420359103e1f20752d01cb1e2bbe8ba8b8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 11 Mar 2016 16:04:20 +0200 Subject: ASoC: davinci: Kconfig: Update the edma-pcm section's dependency and help Instead of depending on individual SoCs make the edma-pcm depend on the eDMA dmaengine driver (TI_EDMA). Update the help text and add DRA7xx family since they have eDMA integrated as well along with sDMA. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 3736d9aabc56..50ca291cc225 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -5,7 +5,7 @@ config SND_DAVINCI_SOC config SND_EDMA_SOC tristate "SoC Audio for Texas Instruments chips using eDMA" - depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI + depends on TI_EDMA select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M here if you want audio support for TI SoC which uses eDMA. @@ -13,6 +13,7 @@ config SND_EDMA_SOC - daVinci devices - AM335x - AM437x/AM438x + - DRA7xx family config SND_DAVINCI_SOC_I2S tristate -- cgit v1.2.3 From 568cecf42f35bf40bdf94107fb638997f82827f7 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 11 Mar 2016 23:42:52 +0530 Subject: ASoC: qcom: fix build error While building m32r allmodconfig the build failed with: ERROR: "bad_dma_ops" [sound/soc/qcom/snd-soc-lpass-platform.ko] undefined! ERROR: "dma_common_mmap" [sound/soc/qcom/snd-soc-lpass-platform.ko] undefined! To satisfy the dependency CONFIG_SND_SOC_LPASS_PLATFORM should depend on HAS_DMA. Some other configs also needs the dependency on HAS_DMA as they are directly or indirectly selecting SND_SOC_LPASS_PLATFORM. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 3cc252e55468..8ec9a074b38b 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -11,21 +11,24 @@ config SND_SOC_LPASS_CPU config SND_SOC_LPASS_PLATFORM tristate + depends on HAS_DMA select REGMAP_MMIO config SND_SOC_LPASS_IPQ806X tristate + depends on HAS_DMA select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM config SND_SOC_LPASS_APQ8016 tristate + depends on HAS_DMA select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM config SND_SOC_STORM tristate "ASoC I2S support for Storm boards" - depends on SND_SOC_QCOM + depends on SND_SOC_QCOM && HAS_DMA select SND_SOC_LPASS_IPQ806X select SND_SOC_MAX98357A help @@ -34,7 +37,7 @@ config SND_SOC_STORM config SND_SOC_APQ8016_SBC tristate "SoC Audio support for APQ8016 SBC platforms" - depends on SND_SOC_QCOM + depends on SND_SOC_QCOM && HAS_DMA select SND_SOC_LPASS_APQ8016 help Support for Qualcomm Technologies LPASS audio block in -- cgit v1.2.3 From 45d5eb3a342f2ef3d6dae16b074fdd9a01992fb5 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 11 Mar 2016 17:33:58 -0800 Subject: ASoC: nau8825: fix issue that pop noise when start playback Reduce pop noise in power up and down sequence when playback. The DAPM widgets graph is reconstructed to ensure the register write sequence at playback matches exactly to the v5 clickless sequence provided by Nuvoton. Signed-off-by: John Hsu Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 169 +++++++++++++++++++++++++++++++++------------ sound/soc/codecs/nau8825.h | 16 ++++- 2 files changed, 141 insertions(+), 44 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index c1b87c5800b1..1c8729984c2b 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -84,6 +84,7 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = { static const struct reg_default nau8825_reg_defaults[] = { { NAU8825_REG_ENA_CTRL, 0x00ff }, + { NAU8825_REG_IIC_ADDR_SET, 0x0 }, { NAU8825_REG_CLK_DIVIDER, 0x0050 }, { NAU8825_REG_FLL1, 0x0 }, { NAU8825_REG_FLL2, 0x3126 }, @@ -158,8 +159,7 @@ static const struct reg_default nau8825_reg_defaults[] = { static bool nau8825_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case NAU8825_REG_ENA_CTRL: - case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV: + case NAU8825_REG_ENA_CTRL ... NAU8825_REG_FLL_VCO_RSV: case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL: case NAU8825_REG_INTERRUPT_MASK ... NAU8825_REG_KEYDET_CTRL: case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL: @@ -184,8 +184,7 @@ static bool nau8825_readable_reg(struct device *dev, unsigned int reg) static bool nau8825_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case NAU8825_REG_RESET ... NAU8825_REG_ENA_CTRL: - case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV: + case NAU8825_REG_RESET ... NAU8825_REG_FLL_VCO_RSV: case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL: case NAU8825_REG_INTERRUPT_MASK: case NAU8825_REG_INT_CLR_KEY_STATUS ... NAU8825_REG_KEYDET_CTRL: @@ -227,10 +226,42 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg) static int nau8825_pump_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + switch (event) { case SND_SOC_DAPM_POST_PMU: /* Prevent startup click by letting charge pump to ramp up */ msleep(10); + regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_JAMNODCLOW, NAU8825_JAMNODCLOW); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_JAMNODCLOW, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Disables the TESTDAC to let DAC signal pass through. */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, + NAU8825_BIAS_TESTDAC_EN, 0); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, + NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN); break; default: return -EINVAL; @@ -316,10 +347,10 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { SND_SOC_DAPM_ADC("SAR", NULL, NAU8825_REG_SAR_CTRL, NAU8825_SAR_ADC_EN_SFT, 0), - SND_SOC_DAPM_DAC("ADACL", NULL, NAU8825_REG_RDAC, 12, 0), - SND_SOC_DAPM_DAC("ADACR", NULL, NAU8825_REG_RDAC, 13, 0), - SND_SOC_DAPM_SUPPLY("ADACL Clock", NAU8825_REG_RDAC, 8, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADACR Clock", NAU8825_REG_RDAC, 9, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACL Clock", 3, NAU8825_REG_RDAC, 8, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("ADACR Clock", 3, NAU8825_REG_RDAC, 9, 0, NULL, 0), SND_SOC_DAPM_DAC("DDACR", NULL, NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_DACR_SFT, 0), @@ -330,29 +361,48 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacl_mux), SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacr_mux), - SND_SOC_DAPM_PGA("HP amp L", NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("HP amp R", NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("HP amp power", NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, - 0), + SND_SOC_DAPM_PGA_S("HP amp L", 0, + NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("HP amp R", 0, + NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Charge Pump", NAU8825_REG_CHARGE_PUMP, 5, 0, - nau8825_pump_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8825_REG_CHARGE_PUMP, 5, 0, + nau8825_pump_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA("Output Driver R Stage 1", + SND_SOC_DAPM_PGA_S("Output Driver R Stage 1", 4, NAU8825_REG_POWER_UP_CONTROL, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Output Driver L Stage 1", + SND_SOC_DAPM_PGA_S("Output Driver L Stage 1", 4, NAU8825_REG_POWER_UP_CONTROL, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Output Driver R Stage 2", + SND_SOC_DAPM_PGA_S("Output Driver R Stage 2", 5, NAU8825_REG_POWER_UP_CONTROL, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Output Driver L Stage 2", + SND_SOC_DAPM_PGA_S("Output Driver L Stage 2", 5, NAU8825_REG_POWER_UP_CONTROL, 2, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 1, + SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 6, NAU8825_REG_POWER_UP_CONTROL, 1, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 1, + SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 6, NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("Output DACL", 2, NAU8825_REG_CHARGE_PUMP, 8, 1, NULL, 0), - SND_SOC_DAPM_PGA_S("Output DACR", 2, NAU8825_REG_CHARGE_PUMP, 9, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("Output DACL", 7, + NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_S("Output DACR", 7, + NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */ + SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8, + NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("HPOR Pulldown", 8, + NAU8825_REG_HSD_CTRL, 1, 1, NULL, 0), + + /* High current HPOL/R boost driver */ + SND_SOC_DAPM_PGA_S("HP Boost Driver", 9, + NAU8825_REG_BOOST, 9, 1, NULL, 0), + + /* Class G operation control*/ + SND_SOC_DAPM_PGA_S("Class G", 10, + NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), @@ -375,24 +425,27 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = { {"DACR Mux", "DACR", "DDACR"}, {"HP amp L", NULL, "DACL Mux"}, {"HP amp R", NULL, "DACR Mux"}, - {"HP amp L", NULL, "HP amp power"}, - {"HP amp R", NULL, "HP amp power"}, - {"ADACL", NULL, "HP amp L"}, - {"ADACR", NULL, "HP amp R"}, - {"ADACL", NULL, "ADACL Clock"}, - {"ADACR", NULL, "ADACR Clock"}, - {"Output Driver L Stage 1", NULL, "ADACL"}, - {"Output Driver R Stage 1", NULL, "ADACR"}, + {"Charge Pump", NULL, "HP amp L"}, + {"Charge Pump", NULL, "HP amp R"}, + {"ADACL", NULL, "Charge Pump"}, + {"ADACR", NULL, "Charge Pump"}, + {"ADACL Clock", NULL, "ADACL"}, + {"ADACR Clock", NULL, "ADACR"}, + {"Output Driver L Stage 1", NULL, "ADACL Clock"}, + {"Output Driver R Stage 1", NULL, "ADACR Clock"}, {"Output Driver L Stage 2", NULL, "Output Driver L Stage 1"}, {"Output Driver R Stage 2", NULL, "Output Driver R Stage 1"}, {"Output Driver L Stage 3", NULL, "Output Driver L Stage 2"}, {"Output Driver R Stage 3", NULL, "Output Driver R Stage 2"}, {"Output DACL", NULL, "Output Driver L Stage 3"}, {"Output DACR", NULL, "Output Driver R Stage 3"}, - {"HPOL", NULL, "Output DACL"}, - {"HPOR", NULL, "Output DACR"}, - {"HPOL", NULL, "Charge Pump"}, - {"HPOR", NULL, "Charge Pump"}, + {"HPOL Pulldown", NULL, "Output DACL"}, + {"HPOR Pulldown", NULL, "Output DACR"}, + {"HP Boost Driver", NULL, "HPOL Pulldown"}, + {"HP Boost Driver", NULL, "HPOR Pulldown"}, + {"Class G", NULL, "HP Boost Driver"}, + {"HPOL", NULL, "Class G"}, + {"HPOR", NULL, "Class G"}, }; static int nau8825_hw_params(struct snd_pcm_substream *substream, @@ -659,11 +712,10 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) break; } - if (type & SND_JACK_HEADPHONE) { - /* Unground HPL/R */ - regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0x3, 0); - } - + /* Leaving HPOL/R grounded after jack insert by default. They will be + * ungrounded as part of the widget power up sequence at the beginning + * of playback to reduce pop. + */ return type; } @@ -768,6 +820,8 @@ static void nau8825_init_regs(struct nau8825 *nau8825) { struct regmap *regmap = nau8825->regmap; + /* Latch IIC LSB value */ + regmap_write(regmap, NAU8825_REG_IIC_ADDR_SET, 0x0001); /* Enable Bias/Vmid */ regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, NAU8825_BIAS_VMID, NAU8825_BIAS_VMID); @@ -780,10 +834,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825) nau8825->vref_impedance << NAU8825_BIAS_VMID_SEL_SFT); /* Disable Boost Driver, Automatic Short circuit protection enable */ regmap_update_bits(regmap, NAU8825_REG_BOOST, - NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS | - NAU8825_SHORT_SHUTDOWN_EN, - NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS | - NAU8825_SHORT_SHUTDOWN_EN); + NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS | + NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN, + NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS | + NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN); regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL, NAU8825_JKDET_OUTPUT_EN, @@ -822,6 +876,35 @@ static void nau8825_init_regs(struct nau8825 *nau8825) NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128); regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128); + /* Disable DACR/L power */ + regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP, + NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, + NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL); + /* Enable TESTDAC. This sets the analog DAC inputs to a '0' input + * signal to avoid any glitches due to power up transients in both + * the analog and digital DAC circuit. + */ + regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, + NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN); + /* CICCLP off */ + regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, + NAU8825_DAC_CLIP_OFF, NAU8825_DAC_CLIP_OFF); + + /* Class AB bias current to 2x, DAC Capacitor enable MSB/LSB */ + regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_2, + NAU8825_HP_NON_CLASSG_CURRENT_2xADJ | + NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB, + NAU8825_HP_NON_CLASSG_CURRENT_2xADJ | + NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB); + /* Class G timer 64ms */ + regmap_update_bits(regmap, NAU8825_REG_CLASSG_CTRL, + NAU8825_CLASSG_TIMER_MASK, + 0x20 << NAU8825_CLASSG_TIMER_SFT); + /* DAC clock delay 2ns, VREF */ + regmap_update_bits(regmap, NAU8825_REG_RDAC, + NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK, + (0x2 << NAU8825_RDAC_CLK_DELAY_SFT) | + (0x3 << NAU8825_RDAC_VREF_SFT)); } static const struct regmap_config nau8825_regmap_config = { diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index dff8edb83bfd..8ceb5f385478 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -14,6 +14,7 @@ #define NAU8825_REG_RESET 0x00 #define NAU8825_REG_ENA_CTRL 0x01 +#define NAU8825_REG_IIC_ADDR_SET 0x02 #define NAU8825_REG_CLK_DIVIDER 0x03 #define NAU8825_REG_FLL1 0x04 #define NAU8825_REG_FLL2 0x05 @@ -129,7 +130,7 @@ /* HSD_CTRL (0xc) */ #define NAU8825_HSD_AUTO_MODE (1 << 6) -/* 0 - short to GND, 1 - open */ +/* 0 - open, 1 - short to GND */ #define NAU8825_SPKR_DWN1R (1 << 1) #define NAU8825_SPKR_DWN1L (1 << 0) @@ -251,12 +252,18 @@ /* DACR_CTRL (0x34) */ #define NAU8825_DACR_CH_SEL_SFT 9 +/* CLASSG_CTRL (0x50) */ +#define NAU8825_CLASSG_TIMER_SFT 8 +#define NAU8825_CLASSG_TIMER_MASK (0x3f << NAU8825_CLASSG_TIMER_SFT) +#define NAU8825_CLASSG_EN (1 << 0) + /* I2C_DEVICE_ID (0x58) */ #define NAU8825_GPIO2JD1 (1 << 7) #define NAU8825_SOFTWARE_ID_MASK 0x3 #define NAU8825_SOFTWARE_ID_NAU8825 0x0 /* BIAS_ADJ (0x66) */ +#define NAU8825_BIAS_TESTDAC_EN (0x3 << 8) #define NAU8825_BIAS_VMID (1 << 6) #define NAU8825_BIAS_VMID_SEL_SFT 4 #define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT) @@ -274,6 +281,12 @@ #define NAU8825_ADC_VREFSEL_VMID_PLUS_1DB (3 << 8) #define NAU8825_POWERUP_ADCL (1 << 6) +/* RDAC (0x73) */ +#define NAU8825_RDAC_CLK_DELAY_SFT 4 +#define NAU8825_RDAC_CLK_DELAY_MASK (0x7 << NAU8825_RDAC_CLK_DELAY_SFT) +#define NAU8825_RDAC_VREF_SFT 2 +#define NAU8825_RDAC_VREF_MASK (0x3 << NAU8825_RDAC_VREF_SFT) + /* MIC_BIAS (0x74) */ #define NAU8825_MICBIAS_JKSLV (1 << 14) #define NAU8825_MICBIAS_JKR2 (1 << 12) @@ -284,6 +297,7 @@ /* BOOST (0x76) */ #define NAU8825_PRECHARGE_DIS (1 << 13) #define NAU8825_GLOBAL_BIAS_EN (1 << 12) +#define NAU8825_HP_BOOST_DIS (1 << 9) #define NAU8825_HP_BOOST_G_DIS (1 << 8) #define NAU8825_SHORT_SHUTDOWN_EN (1 << 6) -- cgit v1.2.3 From e04fadaa169b09609fb55779236d35fb3197c932 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 11 Mar 2016 16:04:54 +0200 Subject: ASoC: omap-hdmi-audio: Support for DRA7xx family DRA7xx family is compatible with the OMAP5 HDMI. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-hdmi-audio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index f83cc2bc0fc4..64425d352962 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -345,6 +345,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) dai_drv = &omap4_hdmi_dai; break; case OMAPDSS_VER_OMAP5: + case OMAPDSS_VER_DRA7xx: dai_drv = &omap5_hdmi_dai; break; default: -- cgit v1.2.3 From 39fa37d51ae904968c49ef49165df7fec66fd9ea Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 11 Mar 2016 10:12:49 +0530 Subject: ASoC: Intel: Skylake: Move module id defines The module ID defines are common to other platforms so can be reused if moved to a common driver header so move it Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.h | 4 ++++ sound/soc/intel/skylake/skl-sst.c | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index cbb40751c37e..a82c3de1a228 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -53,6 +53,10 @@ struct sst_dsp_device; /* HIPCT */ #define SKL_ADSP_REG_HIPCT_BUSY BIT(31) +/* FW base IDs */ +#define SKL_INSTANCE_ID 0 +#define SKL_BASE_FW_MODULE_ID 0 + /* Intel HD Audio SRAM Window 1 */ #define SKL_ADSP_SRAM1_BASE 0xA000 diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index e26f4746afb7..348a734f8e24 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -35,9 +35,6 @@ #define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE #define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) -#define SKL_INSTANCE_ID 0 -#define SKL_BASE_FW_MODULE_ID 0 - #define SKL_NUM_MODULES 1 static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) -- cgit v1.2.3 From a360b623fc5593d896a8762153bacdabfe29dfb9 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 11 Mar 2016 10:12:50 +0530 Subject: ASoC: Intel: Skylake: Fix whitepsace issues Some double whitespaces issues existed in driver, so fix them up. Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.c | 14 +++++++------- sound/soc/intel/skylake/skl-sst-dsp.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 1bfb7f63b572..646d10a0d176 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -34,7 +34,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) mutex_unlock(&ctx->mutex); } -static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) +static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) { int ret; @@ -60,7 +60,7 @@ static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) return ret; } -static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) +static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) { int ret; @@ -87,7 +87,7 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) return ret; } -static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) +static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) { int val; bool is_enable; @@ -140,7 +140,7 @@ static int skl_dsp_start_core(struct sst_dsp *ctx) return ret; } -static int skl_dsp_core_power_up(struct sst_dsp *ctx) +static int skl_dsp_core_power_up(struct sst_dsp *ctx) { int ret; @@ -166,7 +166,7 @@ static int skl_dsp_core_power_up(struct sst_dsp *ctx) return ret; } -static int skl_dsp_core_power_down(struct sst_dsp *ctx) +static int skl_dsp_core_power_down(struct sst_dsp *ctx) { /* update bits */ sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, @@ -181,7 +181,7 @@ static int skl_dsp_core_power_down(struct sst_dsp *ctx) "Power down"); } -static int skl_dsp_enable_core(struct sst_dsp *ctx) +static int skl_dsp_enable_core(struct sst_dsp *ctx) { int ret; @@ -195,7 +195,7 @@ static int skl_dsp_enable_core(struct sst_dsp *ctx) return skl_dsp_start_core(ctx); } -int skl_dsp_disable_core(struct sst_dsp *ctx) +int skl_dsp_disable_core(struct sst_dsp *ctx) { int ret; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index a82c3de1a228..676e78be0169 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -148,7 +148,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); -int skl_dsp_disable_core(struct sst_dsp *ctx); +int skl_dsp_disable_core(struct sst_dsp *ctx); bool is_skl_dsp_running(struct sst_dsp *ctx); irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); int skl_dsp_wake(struct sst_dsp *ctx); -- cgit v1.2.3 From 130e69a4773fb65af284d3fd1f3de762324d06e6 Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Fri, 11 Mar 2016 10:12:51 +0530 Subject: ASoC: Intel: Skylake: Unstatify skl_dsp_enable_core The function skl_dsp_enable_core will be called by other parts of driver so this can no longer be a static function. Signed-off-by: Jayachandran B Signed-off-by: GuruprasadX Pawse Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.c | 2 +- sound/soc/intel/skylake/skl-sst-dsp.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 646d10a0d176..a5267e8a96e0 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -181,7 +181,7 @@ static int skl_dsp_core_power_down(struct sst_dsp *ctx) "Power down"); } -static int skl_dsp_enable_core(struct sst_dsp *ctx) +int skl_dsp_enable_core(struct sst_dsp *ctx) { int ret; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 676e78be0169..b6e310d49dd6 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -148,6 +148,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); +int skl_dsp_enable_core(struct sst_dsp *ctx); int skl_dsp_disable_core(struct sst_dsp *ctx); bool is_skl_dsp_running(struct sst_dsp *ctx); irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); -- cgit v1.2.3 From b822ee63586c7150c10b445ae6b4bb29486f01e4 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 11 Mar 2016 10:12:52 +0530 Subject: ASoC: Intel: add dmabuffer to common sst_dsp Broxton uses HDA DMA so needs to keep dmab in the driver context so add it Signed-off-by: GuruprasadX Pawse Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 81aa1ed64201..97dc1ae05e69 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -317,6 +317,7 @@ struct sst_dsp { struct skl_cl_dev cl_dev; u32 intr_status; const struct firmware *fw; + struct snd_dma_buffer dmab; }; /* Size optimised DRAM/IRAM memcpy */ -- cgit v1.2.3 From bc23ca35cfb18b0a98afa42de1df1efc7e2e9f8f Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 11 Mar 2016 10:12:53 +0530 Subject: ASoC: Intel: Skylake: Move Skylake dsp ops & loader ops The code loading for Skylake and other platforms is different, so add a dsp_ops and a loader_ops which can be defined for each platform. Move the dsp init, cleanup and loader ops (alloc and free dma) to these ops Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 62 +++++++++++++++++++++++++++++----- sound/soc/intel/skylake/skl.h | 12 ++++++- 2 files changed, 64 insertions(+), 10 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 737934cc620d..79c5089b85d6 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -72,17 +72,47 @@ static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask); } +static struct skl_dsp_loader_ops skl_get_loader_ops(void) +{ + struct skl_dsp_loader_ops loader_ops; + + memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops)); + + loader_ops.alloc_dma_buf = skl_alloc_dma_buf; + loader_ops.free_dma_buf = skl_free_dma_buf; + + return loader_ops; +}; + +static const struct skl_dsp_ops dsp_ops[] = { + { + .id = 0x9d70, + .loader_ops = skl_get_loader_ops, + .init = skl_sst_dsp_init, + .cleanup = skl_sst_dsp_cleanup + }, +}; + +static int skl_get_dsp_ops(int pci_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { + if (dsp_ops[i].id == pci_id) + return i; + } + + return -EINVAL; +} + int skl_init_dsp(struct skl *skl) { void __iomem *mmio_base; struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_bus *bus = ebus_to_hbus(ebus); - int irq = bus->irq; struct skl_dsp_loader_ops loader_ops; - int ret; - - loader_ops.alloc_dma_buf = skl_alloc_dma_buf; - loader_ops.free_dma_buf = skl_free_dma_buf; + int irq = bus->irq; + int ret, index; /* enable ppcap interrupt */ snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); @@ -95,8 +125,14 @@ int skl_init_dsp(struct skl *skl) return -ENXIO; } - ret = skl_sst_dsp_init(bus->dev, mmio_base, irq, + index = skl_get_dsp_ops(skl->pci->device); + if (index < 0) + return -EINVAL; + + loader_ops = dsp_ops[index].loader_ops(); + ret = dsp_ops[index].init(bus->dev, mmio_base, irq, skl->fw_name, loader_ops, &skl->skl_sst); + if (ret < 0) return ret; @@ -106,18 +142,26 @@ int skl_init_dsp(struct skl *skl) return ret; } -void skl_free_dsp(struct skl *skl) +int skl_free_dsp(struct skl *skl) { struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl_sst *ctx = skl->skl_sst; + struct skl_sst *ctx = skl->skl_sst; + int index; /* disable ppcap interrupt */ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); - skl_sst_dsp_cleanup(bus->dev, ctx); + index = skl_get_dsp_ops(skl->pci->device); + if (index < 0) + return -EIO; + + dsp_ops[index].cleanup(bus->dev, ctx); + if (ctx->dsp->addr.lpe) iounmap(ctx->dsp->addr.lpe); + + return 0; } int skl_suspend_dsp(struct skl *skl) diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 1ca1911f1587..39e16fa7a92b 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -90,6 +90,16 @@ struct skl_dma_params { u8 stream_tag; }; +struct skl_dsp_ops { + int id; + struct skl_dsp_loader_ops (*loader_ops)(void); + int (*init)(struct device *dev, void __iomem *mmio_base, + int irq, const char *fw_name, + struct skl_dsp_loader_ops loader_ops, + struct skl_sst **skl_sst); + void (*cleanup)(struct device *dev, struct skl_sst *ctx); +}; + int skl_platform_unregister(struct device *dev); int skl_platform_register(struct device *dev); @@ -100,7 +110,7 @@ struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, int skl_nhlt_update_topology_bin(struct skl *skl); int skl_init_dsp(struct skl *skl); -void skl_free_dsp(struct skl *skl); +int skl_free_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); #endif /* __SOUND_SOC_SKL_H */ -- cgit v1.2.3 From b379b1fad6e80274309f650f3a82c6f3c4fe9d6b Mon Sep 17 00:00:00 2001 From: Senthilnathan Veppur Date: Fri, 11 Mar 2016 10:12:54 +0530 Subject: ASoC: Intel: Bxtn: Add Broxton PCI ID Broxton is an Intel SoC which sports a DSP and system is quite like Skylake. So add this ID in Skylake driver Signed-off-by: Senthilnathan Veppur Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 0d38bdb8321b..ab5e25aaeee3 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -742,11 +742,18 @@ static struct sst_acpi_mach sst_skl_devdata[] = { {} }; +static struct sst_acpi_mach sst_bxtp_devdata[] = { + { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, +}; + /* PCI IDs */ static const struct pci_device_id skl_ids[] = { /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&sst_skl_devdata}, + /* BXT-P */ + { PCI_DEVICE(0x8086, 0x5a98), + .driver_data = (unsigned long)&sst_bxtp_devdata}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); -- cgit v1.2.3 From e2304803fd05eac509c8e37bb626c192510e4e77 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 11 Mar 2016 10:12:55 +0530 Subject: ASoC: hdac_hdmi: Add broxton device ID Broxton HDMI codec is similar to Skylake so add the device ID Signed-off-by: Jeeja KP Signed-off-by: GuruprasadX Pawse Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 7851dd204a49..cb0b036a1139 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1634,6 +1634,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = { static const struct hda_device_id hdmi_list[] = { HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), + HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), {} }; -- cgit v1.2.3 From f1511a14a4a94d063cf8f8f12f36cf2ebb0cc8a8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Mar 2016 05:29:21 +0000 Subject: ASoC: rsnd: add simplified module explanation Renesas sound driver user needs to read its datasheet when create DT. But it is difficult to understand, because it has many modules (SRC/CTU/MIX/DVC/SSIU/SSI/AudioDMAC/AudioDMACperiperi), and many features (Asynchronous/Synchronous mode on SRC, CTU matrix, DVC volume settings feature, Multi-SSI/TDM-SSI, etc). This patch adds simplified explanation to help setting/understanding. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/renesas,rsnd.txt | 340 +++++++++++++++++++++ sound/soc/sh/rcar/dvc.c | 23 ++ 2 files changed, 363 insertions(+) (limited to 'sound/soc') diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 8ee0fa91e4a0..c7b29df4a963 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -1,6 +1,337 @@ Renesas R-Car sound +============================================= +* Modules +============================================= + +Renesas R-Car sound is constructed from below modules +(for Gen2 or later) + + SCU : Sampling Rate Converter Unit + - SRC : Sampling Rate Converter + - CMD + - CTU : Channel Transfer Unit + - MIX : Mixer + - DVC : Digital Volume and Mute Function + SSIU : Serial Sound Interface Unit + SSI : Serial Sound Interface + +See detail of each module's channels, connection, limitation on datasheet + +============================================= +* Multi channel +============================================= + +Multi channel is supported by Multi-SSI, or TDM-SSI. + + Multi-SSI : 6ch case, you can use stereo x 3 SSI + TDM-SSI : 6ch case, you can use TDM + +============================================= +* Enable/Disable each modules +============================================= + +See datasheet to check SRC/CTU/MIX/DVC connect-limitation. +DT controls enabling/disabling module. +${LINUX}/arch/arm/boot/dts/r8a7790-lager.dts can be good example. +This is example of + +Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec] +Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec] + + &rcar_sound { + ... + rcar_sound,dai { + dai0 { + playback = <&ssi0 &src2 &dvc0>; + capture = <&ssi1 &src3 &dvc1>; + }; + }; + }; + +You can use below. +${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example. + + &src0 &ctu00 &mix0 &dvc0 &ssi0 + &src1 &ctu01 &mix1 &dvc1 &ssi1 + &src2 &ctu02 &ssi2 + &src3 &ctu03 &ssi3 + &src4 &ssi4 + &src5 &ctu10 &ssi5 + &src6 &ctu11 &ssi6 + &src7 &ctu12 &ssi7 + &src8 &ctu13 &ssi8 + &src9 &ssi9 + +============================================= +* SRC (Sampling Rate Converter) +============================================= + + [xx]Hz [yy]Hz + ------> [SRC] ------> + +SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes + + Asynchronous mode: input data / output data are based on different clocks. + you can use this mode on Playback / Capture + Synchronous mode: input data / output data are based on same clocks. + This mode will be used if system doesn't have its input clock, + for example digital TV case. + you can use this mode on Playback + +------------------ +** Asynchronous mode +------------------ + +You need to use "renesas,rsrc-card" sound card for it. +example) + + sound { + compatible = "renesas,rsrc-card"; + ... + /* + * SRC Asynchronous mode setting + * Playback: + * All input data will be converted to 48kHz + * Capture: + * Inputed 48kHz data will be converted to + * system specified Hz + */ + convert-rate = <48000>; + ... + cpu { + sound-dai = <&rcar_sound>; + }; + codec { + ... + }; + }; + +------------------ +** Synchronous mode +------------------ + + > amixer set "SRC Out Rate" on + > aplay xxxx.wav + > amixer set "SRC Out Rate" 48000 + > amixer set "SRC Out Rate" 44100 + +============================================= +* CTU (Channel Transfer Unit) +============================================= + + [xx]ch [yy]ch + ------> [CTU] --------> + +CTU can convert [xx]ch to [yy]ch, or exchange outputed channel. +CTU conversion needs matrix settings. +For more detail information, see below + + Renesas R-Car datasheet + - Sampling Rate Converter Unit (SCU) + - SCU Operation + - CMD Block + - Functional Blocks in CMD + + Renesas R-Car datasheet + - Sampling Rate Converter Unit (SCU) + - Register Description + - CTUn Scale Value exx Register (CTUn_SVxxR) + + ${LINUX}/sound/soc/sh/rcar/ctu.c + - comment of header + +You need to use "renesas,rsrc-card" sound card for it. +example) + + sound { + compatible = "renesas,rsrc-card"; + ... + /* + * CTU setting + * All input data will be converted to 2ch + * as output data + */ + convert-channels = <2>; + ... + cpu { + sound-dai = <&rcar_sound>; + }; + codec { + ... + }; + }; + +Ex) Exchange output channel + Input -> Output + 1ch -> 0ch + 0ch -> 1ch + + example of using matrix + output 0ch = (input 0ch x 0) + (input 1ch x 1) + output 1ch = (input 0ch x 1) + (input 1ch x 0) + + amixer set "CTU Reset" on + amixer set "CTU Pass" 9,10 + amixer set "CTU SV0" 0,4194304 + amixer set "CTU SV1" 4194304,0 + + example of changing connection + amixer set "CTU Reset" on + amixer set "CTU Pass" 2,1 + +============================================= +* MIX (Mixer) +============================================= + +MIX merges 2 sounds path. You can see 2 sound interface on system, +and these sounds will be merged by MIX. + + aplay -D plughw:0,0 xxxx.wav & + aplay -D plughw:0,1 yyyy.wav + +You need to use "renesas,rsrc-card" sound card for it. +Ex) + [MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0] + | + [MEM] -> [SRC2] -> [CTU03] -+ + + sound { + compatible = "renesas,rsrc-card"; + ... + cpu@0 { + sound-dai = <&rcar_sound 0>; + }; + cpu@1 { + sound-dai = <&rcar_sound 1>; + }; + codec { + ... + }; + }; + + &rcar_sound { + ... + rcar_sound,dai { + dai0 { + playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>; + }; + dai1 { + playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; + }; + }; + }; + +============================================= +* DVC (Digital Volume and Mute Function) +============================================= + +DVC controls Playback/Capture volume. + +Playback Volume + amixer set "DVC Out" 100% + +Capture Volume + amixer set "DVC In" 100% + +Playback Mute + amixer set "DVC Out Mute" on + +Capture Mute + amixer set "DVC In Mute" on + +Volume Ramp + amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" + amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" + amixer set "DVC Out Ramp" on + aplay xxx.wav & + amixer set "DVC Out" 80% // Volume Down + amixer set "DVC Out" 100% // Volume Up + +============================================= +* SSIU (Serial Sound Interface Unit) +============================================= + +There is no DT settings for SSIU, because SSIU will be automatically +selected via SSI. +SSIU can avoid some under/over run error, because it has some buffer. +But you can't use it if SSI was PIO mode. +In DMA mode, you can select not to use SSIU by using "no-busif" on DT. + + &ssi0 { + no-busif; + }; + +============================================= +* SSI (Serial Sound Interface) +============================================= + +** PIO mode + +You can use PIO mode which is for connection check by using. +Note: The system will drop non-SSI modules in PIO mode +even though if DT is selecting other modules. + + &ssi0 { + pio-transfer + }; + +** DMA mode without SSIU + +You can use DMA without SSIU. +Note: under/over run, or noise are likely to occur + + &ssi0 { + no-busif; + }; + +** PIN sharing + +Each SSI can share WS pin. It is based on platform. +This is example if SSI1 want to share WS pin with SSI0 + + &ssi1 { + shared-pin; + }; + +** Multi-SSI + +You can use Multi-SSI. +This is example of SSI0/SSI1/SSI2 (= for 6ch) + + &rcar_sound { + ... + rcar_sound,dai { + dai0 { + playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>; + }; + }; + }; + +** TDM-SSI + +You can use TDM with SSI. +This is example of TDM 6ch. +Driver can automatically switches TDM <-> stereo mode in this case. + + rsnd_tdm: sound { + compatible = "simple-audio-card"; + ... + simple-audio-card,cpu { + /* system can use TDM 6ch */ + dai-tdm-slot-num = <6>; + sound-dai = <&rcar_sound>; + }; + simple-audio-card,codec { + ... + }; + }; + + +============================================= Required properties: +============================================= + - compatible : "renesas,rcar_sound-", fallbacks "renesas,rcar_sound-gen1" if generation1, and "renesas,rcar_sound-gen2" if generation2 @@ -64,7 +395,10 @@ DAI subnode properties: - playback : list of playback modules - capture : list of capture modules + +============================================= Example: +============================================= rcar_sound: sound@ec500000 { #sound-dai-cells = <1>; @@ -250,7 +584,9 @@ rcar_sound: sound@ec500000 { }; }; +============================================= Example: simple sound card +============================================= rsnd_ak4643: sound { compatible = "simple-audio-card"; @@ -290,7 +626,9 @@ Example: simple sound card shared-pin; }; +============================================= Example: simple sound card for TDM +============================================= rsnd_tdm: sound { compatible = "simple-audio-card"; @@ -309,7 +647,9 @@ Example: simple sound card for TDM }; }; +============================================= Example: simple sound card for Multi channel +============================================= &rcar_sound { pinctrl-0 = <&sound_pins &sound_clk_pins>; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 93b11e1c5d7f..02d971f69eff 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -8,6 +8,29 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +/* + * Playback Volume + * amixer set "DVC Out" 100% + * + * Capture Volume + * amixer set "DVC In" 100% + * + * Playback Mute + * amixer set "DVC Out Mute" on + * + * Capture Mute + * amixer set "DVC In Mute" on + * + * Volume Ramp + * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" + * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" + * amixer set "DVC Out Ramp" on + * aplay xxx.wav & + * amixer set "DVC Out" 80% // Volume Down + * amixer set "DVC Out" 100% // Volume Up + */ + #include "rsnd.h" #define RSND_DVC_NAME_SIZE 16 -- cgit v1.2.3