Loading drivers/misc/atmel-ssc.c +1 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading sound/soc/atmel/atmel_ssc_dai.c +18 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading sound/soc/bcm/bcm2835-i2s.c +64 −220 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/slab.h> #include <sound/core.h> Loading @@ -46,55 +47,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> /* 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 Loading Loading @@ -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; Loading @@ -170,20 +118,22 @@ struct bcm2835_i2s_dev { unsigned int bclk_ratio; struct regmap *i2s_regmap; struct regmap *clk_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; Loading @@ -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, Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 */ Loading Loading @@ -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; /* Loading @@ -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; Loading @@ -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; /* * 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. */ else /* otherwise calculate a fitting block ratio */ 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; Loading Loading @@ -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) Loading Loading @@ -750,18 +606,7 @@ 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[] = { { static const struct regmap_config bcm2835_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, Loading @@ -769,15 +614,6 @@ static const struct regmap_config bcm2835_regmap_config[] = { .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 snd_soc_component_driver bcm2835_i2s_component = { Loading @@ -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++) { struct resource *mem; 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]); } 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 = Loading sound/soc/codecs/cs42xx8.c +8 −2 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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; } Loading Loading
drivers/misc/atmel-ssc.c +1 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading
sound/soc/atmel/atmel_ssc_dai.c +18 −9 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading
sound/soc/bcm/bcm2835-i2s.c +64 −220 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/slab.h> #include <sound/core.h> Loading @@ -46,55 +47,6 @@ #include <sound/pcm_params.h> #include <sound/soc.h> /* 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 Loading Loading @@ -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; Loading @@ -170,20 +118,22 @@ struct bcm2835_i2s_dev { unsigned int bclk_ratio; struct regmap *i2s_regmap; struct regmap *clk_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; Loading @@ -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, Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 */ Loading Loading @@ -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; /* Loading @@ -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; Loading @@ -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; /* * 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. */ else /* otherwise calculate a fitting block ratio */ 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; Loading Loading @@ -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) Loading Loading @@ -750,18 +606,7 @@ 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[] = { { static const struct regmap_config bcm2835_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, Loading @@ -769,15 +614,6 @@ static const struct regmap_config bcm2835_regmap_config[] = { .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 snd_soc_component_driver bcm2835_i2s_component = { Loading @@ -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++) { struct resource *mem; 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]); } 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 = Loading
sound/soc/codecs/cs42xx8.c +8 −2 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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; } Loading