Loading include/sound/pcm_params.h +7 −0 Original line number Diff line number Diff line Loading @@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p) return snd_pcm_format_physical_width(params_format(p)); } static inline void params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) { snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), (__force int)fmt); } #endif /* __SOUND_PCM_PARAMS_H */ include/sound/soc.h +3 −0 Original line number Diff line number Diff line Loading @@ -954,6 +954,9 @@ struct snd_soc_dai_link { unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* Mark this pcm with non atomic ops */ bool nonatomic; /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; Loading sound/soc/atmel/atmel_ssc_dai.c +107 −4 Original line number Diff line number Diff line Loading @@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } /* * When the bit clock is input, limit the maximum rate according to the * Serial Clock Ratio Considerations section from the SSC documentation: * * The Transmitter and the Receiver can be programmed to operate * with the clock signals provided on either the TK or RK pins. * This allows the SSC to support many slave-mode data transfers. * In this case, the maximum clock speed allowed on the RK pin is: * - Peripheral clock divided by 2 if Receiver Frame Synchro is input * - Peripheral clock divided by 3 if Receiver Frame Synchro is output * In addition, the maximum clock speed allowed on the TK pin is: * - Peripheral clock divided by 6 if Transmit Frame Synchro is input * - Peripheral clock divided by 2 if Transmit Frame Synchro is output * * When the bit clock is output, limit the rate according to the * SSC divider restrictions. */ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct atmel_ssc_info *ssc_p = rule->private; struct ssc_device *ssc = ssc_p->ssc; struct snd_interval *i = hw_param_interval(params, rule->var); struct snd_interval t; struct snd_ratnum r = { .den_min = 1, .den_max = 4095, .den_step = 1, }; unsigned int num = 0, den = 0; int frame_size; int mck_div = 2; int ret; frame_size = snd_soc_params_to_frame_size(params); if (frame_size < 0) return frame_size; switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) && ssc->clk_from_rk_pin) /* Receiver Frame Synchro (i.e. capture) * is output (format is _CFS) and the RK pin * is used for input (format is _CBM_). */ mck_div = 3; break; case SND_SOC_DAIFMT_CBM_CFM: if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) && !ssc->clk_from_rk_pin) /* Transmit Frame Synchro (i.e. playback) * is input (format is _CFM) and the TK pin * is used for input (format _CBM_ but not * using the RK pin). */ mck_div = 6; break; } switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: r.num = ssc_p->mck_rate / mck_div / frame_size; ret = snd_interval_ratnum(i, 1, &r, &num, &den); if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { params->rate_num = num; params->rate_den = den; } break; case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBM_CFM: t.min = 8000; t.max = ssc_p->mck_rate / mck_div / frame_size; t.openmin = t.openmax = 0; t.integer = 0; ret = snd_interval_refine(i, &t); break; default: ret = -EINVAL; break; } return ret; } /*-------------------------------------------------------------------------*\ * DAI functions Loading @@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; int ret; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); Loading @@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); clk_enable(ssc_p->ssc->clk); ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); /* Reset the SSC to keep it at a clean status */ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); Loading @@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, dir_mask = SSC_DIR_MASK_CAPTURE; } ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, atmel_ssc_hw_rule_rate, ssc_p, SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (ret < 0) { dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret); return ret; } dma_params = &ssc_dma_params[dai->id][dir]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream; Loading Loading @@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) Loading @@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { .channels_min = 1, .channels_max = 2, .rates = ATMEL_SSC_RATES, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { .channels_min = 1, .channels_max = 2, .rates = ATMEL_SSC_RATES, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, }; Loading sound/soc/atmel/atmel_ssc_dai.h +1 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,7 @@ struct atmel_ssc_info { unsigned short rcmr_period; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; unsigned long mck_rate; }; int atmel_ssc_set_audio(int ssc_id); Loading sound/soc/codecs/adau1977.c +5 −12 Original line number Diff line number Diff line Loading @@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, adau1977->dvdd_reg = NULL; } adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); if (IS_ERR(adau1977->reset_gpio)) { ret = PTR_ERR(adau1977->reset_gpio); if (ret != -ENOENT && ret != -ENOSYS) adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(adau1977->reset_gpio)) return PTR_ERR(adau1977->reset_gpio); adau1977->reset_gpio = NULL; } dev_set_drvdata(dev, adau1977); if (adau1977->reset_gpio) { ret = gpiod_direction_output(adau1977->reset_gpio, 0); if (ret) return ret; if (adau1977->reset_gpio) ndelay(100); } ret = adau1977_power_enable(adau1977); if (ret) Loading Loading
include/sound/pcm_params.h +7 −0 Original line number Diff line number Diff line Loading @@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p) return snd_pcm_format_physical_width(params_format(p)); } static inline void params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) { snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), (__force int)fmt); } #endif /* __SOUND_PCM_PARAMS_H */
include/sound/soc.h +3 −0 Original line number Diff line number Diff line Loading @@ -954,6 +954,9 @@ struct snd_soc_dai_link { unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* Mark this pcm with non atomic ops */ bool nonatomic; /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; Loading
sound/soc/atmel/atmel_ssc_dai.c +107 −4 Original line number Diff line number Diff line Loading @@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } /* * When the bit clock is input, limit the maximum rate according to the * Serial Clock Ratio Considerations section from the SSC documentation: * * The Transmitter and the Receiver can be programmed to operate * with the clock signals provided on either the TK or RK pins. * This allows the SSC to support many slave-mode data transfers. * In this case, the maximum clock speed allowed on the RK pin is: * - Peripheral clock divided by 2 if Receiver Frame Synchro is input * - Peripheral clock divided by 3 if Receiver Frame Synchro is output * In addition, the maximum clock speed allowed on the TK pin is: * - Peripheral clock divided by 6 if Transmit Frame Synchro is input * - Peripheral clock divided by 2 if Transmit Frame Synchro is output * * When the bit clock is output, limit the rate according to the * SSC divider restrictions. */ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct atmel_ssc_info *ssc_p = rule->private; struct ssc_device *ssc = ssc_p->ssc; struct snd_interval *i = hw_param_interval(params, rule->var); struct snd_interval t; struct snd_ratnum r = { .den_min = 1, .den_max = 4095, .den_step = 1, }; unsigned int num = 0, den = 0; int frame_size; int mck_div = 2; int ret; frame_size = snd_soc_params_to_frame_size(params); if (frame_size < 0) return frame_size; switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE) && ssc->clk_from_rk_pin) /* Receiver Frame Synchro (i.e. capture) * is output (format is _CFS) and the RK pin * is used for input (format is _CBM_). */ mck_div = 3; break; case SND_SOC_DAIFMT_CBM_CFM: if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK) && !ssc->clk_from_rk_pin) /* Transmit Frame Synchro (i.e. playback) * is input (format is _CFM) and the TK pin * is used for input (format _CBM_ but not * using the RK pin). */ mck_div = 6; break; } switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: r.num = ssc_p->mck_rate / mck_div / frame_size; ret = snd_interval_ratnum(i, 1, &r, &num, &den); if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) { params->rate_num = num; params->rate_den = den; } break; case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBM_CFM: t.min = 8000; t.max = ssc_p->mck_rate / mck_div / frame_size; t.openmin = t.openmax = 0; t.integer = 0; ret = snd_interval_refine(i, &t); break; default: ret = -EINVAL; break; } return ret; } /*-------------------------------------------------------------------------*\ * DAI functions Loading @@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; struct atmel_pcm_dma_params *dma_params; int dir, dir_mask; int ret; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); Loading @@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); clk_enable(ssc_p->ssc->clk); ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); /* Reset the SSC to keep it at a clean status */ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); Loading @@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, dir_mask = SSC_DIR_MASK_CAPTURE; } ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, atmel_ssc_hw_rule_rate, ssc_p, SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (ret < 0) { dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret); return ret; } dma_params = &ssc_dma_params[dai->id][dir]; dma_params->ssc = ssc_p->ssc; dma_params->substream = substream; Loading Loading @@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) Loading @@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { .channels_min = 1, .channels_max = 2, .rates = ATMEL_SSC_RATES, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { .channels_min = 1, .channels_max = 2, .rates = ATMEL_SSC_RATES, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .ops = &atmel_ssc_dai_ops, }; Loading
sound/soc/atmel/atmel_ssc_dai.h +1 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,7 @@ struct atmel_ssc_info { unsigned short rcmr_period; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; unsigned long mck_rate; }; int atmel_ssc_set_audio(int ssc_id); Loading
sound/soc/codecs/adau1977.c +5 −12 Original line number Diff line number Diff line Loading @@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap, adau1977->dvdd_reg = NULL; } adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); if (IS_ERR(adau1977->reset_gpio)) { ret = PTR_ERR(adau1977->reset_gpio); if (ret != -ENOENT && ret != -ENOSYS) adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(adau1977->reset_gpio)) return PTR_ERR(adau1977->reset_gpio); adau1977->reset_gpio = NULL; } dev_set_drvdata(dev, adau1977); if (adau1977->reset_gpio) { ret = gpiod_direction_output(adau1977->reset_gpio, 0); if (ret) return ret; if (adau1977->reset_gpio) ndelay(100); } ret = adau1977_power_enable(adau1977); if (ret) Loading