summaryrefslogtreecommitdiff
path: root/sound/soc/davinci/davinci-mcasp.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 13:41:32 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 13:41:32 -0700
commitf4c80d5a16eb4b08a0d9ade154af1ebdc63f5752 (patch)
tree5334acabf48210285333bc80d4a3e326efb36750 /sound/soc/davinci/davinci-mcasp.c
parent7afd16f882887c9adc69cd1794f5e57777723217 (diff)
parent17e1717c11a34f9b0956e33e0c4a4e4ae8c51a57 (diff)
Merge tag 'sound-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "This time was again a relatively calm development cycle; most of updates are about drivers, and no radical changes are seen in any core code. Here are some highlights: ALSA core: - Continued hardening of ALSA hrtimer - A few leak fixes in timer interface - Fix poll error handling in PCM and compress - Add error propagation in compress API - Removal of dead rtctimer driver HD-audio: - Native ELD notify support for i915 HDMI - Realtek ALC234 & co support - Code refactoring to standardize chmap support - Continued development for SKL HDMI core support Firewire: - Apply delayed card registration to all drivers - Improved / stabilized the handling of PCM stream start / stop - Add tracepoints to dump a part of isochronous packet data - Fixed incoming/outgoing packet parameter usages - Add support for M-Audio profire series USB-audio: - Fixes for UAC2 clock source - SS+ support - Workaround for oft-seen repeated sample rate read errors ASoC: - Further slow progress on the topology code - Substantial updates and improvements for the da7219, es8328, fsl-ssi, Intel and rcar drivers. - Compress error handling in WM ADSP driver" * tag 'sound-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (177 commits) ALSA: firewire-lib: change a member of event structure to suppress sparse wanings to bool type sound: oss: Use setup_timer and mod_timer. ASoC: hdac_hdmi: Remove the unused 'timeout' variable ASoC: fsl_ssi: Fix channel slipping on capture (or playback) restart in full duplex. ASoC: fsl_ssi: Fix channel slipping in Playback at startup ASoC: fsl_ssi: Fix samples being dropped at Playback startup ASoC: fsl_ssi: Save a dev reference for dev_err() purpose. ASoC: fsl_ssi: The IPG/5 limitation concerns the bitclk, not the sysclk. ASoC: fsl_ssi: Real hardware channels max number is 32 ASoC: pcm5102a: Add support for PCM5102A codec ASoC: hdac_hdmi: add link management ASoC: Intel: Skylake: add link management ALSA: hdac: add link pm and ref counting ALSA: au88x0: Fix zero clear of stream->resources ASoC: rt298: Add DMI match for Broxton-P reference platform ASoC: rt298: fix null deref on acpi driver data ASoC: dapm: deprecate MICBIAS widget type ALSA: firewire-lib: drop skip argument from helper functions to queue a packet ALSA: firewire-lib: add context information to tracepoints ALSA: firewire-lib: permit to flush queued packets only in process context for better PCM period granularity ...
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
-rw-r--r--sound/soc/davinci/davinci-mcasp.c92
1 files changed, 59 insertions, 33 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index e1324989bd6b..0f66fda2c772 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -489,7 +489,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
- ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ ACLKX | AFSX | ACLKR | AHCLKR | AFSR);
mcasp->bclk_master = 0;
break;
default:
@@ -540,21 +540,19 @@ out:
return ret;
}
-static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id,
int div, bool explicit)
{
- struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
pm_runtime_get_sync(mcasp->dev);
switch (div_id) {
- case 0: /* MCLK divider */
+ case MCASP_CLKDIV_AUXCLK: /* MCLK divider */
mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
break;
- case 1: /* BCLK divider */
+ case MCASP_CLKDIV_BCLK: /* BCLK divider */
mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
ACLKXDIV(div - 1), ACLKXDIV_MASK);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
@@ -563,7 +561,8 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
mcasp->bclk_div = div;
break;
- case 2: /*
+ case MCASP_CLKDIV_BCLK_FS_RATIO:
+ /*
* BCLK/LRCLK ratio descries how many bit-clock cycles
* fit into one frame. The clock ratio is given for a
* full period of data (for I2S format both left and
@@ -591,7 +590,9 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
int div)
{
- return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+ return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1);
}
static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -999,27 +1000,53 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
}
static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp,
- unsigned int bclk_freq,
- int *error_ppm)
+ unsigned int bclk_freq, bool set)
{
- int div = mcasp->sysclk_freq / bclk_freq;
- int rem = mcasp->sysclk_freq % bclk_freq;
+ int error_ppm;
+ unsigned int sysclk_freq = mcasp->sysclk_freq;
+ u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG);
+ int div = sysclk_freq / bclk_freq;
+ int rem = sysclk_freq % bclk_freq;
+ int aux_div = 1;
+
+ if (div > (ACLKXDIV_MASK + 1)) {
+ if (reg & AHCLKXE) {
+ aux_div = div / (ACLKXDIV_MASK + 1);
+ if (div % (ACLKXDIV_MASK + 1))
+ aux_div++;
+
+ sysclk_freq /= aux_div;
+ div = sysclk_freq / bclk_freq;
+ rem = sysclk_freq % bclk_freq;
+ } else if (set) {
+ dev_warn(mcasp->dev, "Too fast reference clock (%u)\n",
+ sysclk_freq);
+ }
+ }
if (rem != 0) {
if (div == 0 ||
- ((mcasp->sysclk_freq / div) - bclk_freq) >
- (bclk_freq - (mcasp->sysclk_freq / (div+1)))) {
+ ((sysclk_freq / div) - bclk_freq) >
+ (bclk_freq - (sysclk_freq / (div+1)))) {
div++;
rem = rem - bclk_freq;
}
}
- if (error_ppm)
- *error_ppm =
- (div*1000000 + (int)div64_long(1000000LL*rem,
- (int)bclk_freq))
- /div - 1000000;
+ error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem,
+ (int)bclk_freq)) / div - 1000000;
+
+ if (set) {
+ if (error_ppm)
+ dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
+ error_ppm);
+
+ __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0);
+ if (reg & AHCLKXE)
+ __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK,
+ aux_div, 0);
+ }
- return div;
+ return error_ppm;
}
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
@@ -1044,18 +1071,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
int slots = mcasp->tdm_slots;
int rate = params_rate(params);
int sbits = params_width(params);
- int ppm, div;
if (mcasp->slot_width)
sbits = mcasp->slot_width;
- div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots,
- &ppm);
- if (ppm)
- dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n",
- ppm);
-
- __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);
+ davinci_mcasp_calc_clk_div(mcasp, rate * sbits * slots, true);
}
ret = mcasp_common_hw_param(mcasp, substream->stream,
@@ -1166,7 +1186,8 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params,
davinci_mcasp_dai_rates[i];
int ppm;
- davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm);
+ ppm = davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq,
+ false);
if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
if (range.empty) {
range.min = davinci_mcasp_dai_rates[i];
@@ -1205,8 +1226,9 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params,
if (rd->mcasp->slot_width)
sbits = rd->mcasp->slot_width;
- davinci_mcasp_calc_clk_div(rd->mcasp, sbits*slots*rate,
- &ppm);
+ ppm = davinci_mcasp_calc_clk_div(rd->mcasp,
+ sbits * slots * rate,
+ false);
if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) {
snd_mask_set(&nfmt, i);
count++;
@@ -1230,11 +1252,15 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
int i, dir;
int tdm_slots = mcasp->tdm_slots;
- if (mcasp->tdm_mask[substream->stream])
- tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
+ /* Do not allow more then one stream per direction */
+ if (mcasp->substreams[substream->stream])
+ return -EBUSY;
mcasp->substreams[substream->stream] = substream;
+ if (mcasp->tdm_mask[substream->stream])
+ tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]);
+
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
return 0;