diff options
author | Angela Stegmaier | 2013-07-12 15:17:34 -0500 |
---|---|---|
committer | Misael Lopez Cruz | 2013-07-22 15:04:18 -0500 |
commit | c46ee17381911655894b2f1d78f2e187f3db2c1e (patch) | |
tree | c70d616f006fa501640bdaaf58bde6876a3fa4f4 | |
parent | 13b25a428ba2656d0d6ae2bd242a772e88850aba (diff) | |
download | kernel-audio-c46ee17381911655894b2f1d78f2e187f3db2c1e.tar.gz kernel-audio-c46ee17381911655894b2f1d78f2e187f3db2c1e.tar.xz kernel-audio-c46ee17381911655894b2f1d78f2e187f3db2c1e.zip |
ASoC: davinci-mcasp: Add hw_rule for buffer_size when using AFIFO
The AFIFO threshold imposes a limiation on the buffer size.
When the AFIFO is used, the buffer size (in samples) needs to be
an integer multiple of the AFIFO threshold value (wnumevt, rnumevt).
This patch adds a hw_rule to the McASP driver for version 4
of the McASP to account for the limitation on the buffer size.
Change-Id: I3bd320130b10a55d3d84defd99572526ad6469fb
Signed-off-by: Angela Stegmaier <angelabaker@ti.com>
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index da38efba7213..ef30dbdd7aee 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
26 | #include <linux/of_platform.h> | 26 | #include <linux/of_platform.h> |
27 | #include <linux/of_device.h> | 27 | #include <linux/of_device.h> |
28 | #include <linux/lcm.h> | ||
28 | 29 | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
@@ -1042,14 +1043,92 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, | |||
1042 | return ret; | 1043 | return ret; |
1043 | } | 1044 | } |
1044 | 1045 | ||
1046 | static int davinci_mcasp_hwrule_buffersize(struct snd_pcm_hw_params *params, | ||
1047 | struct snd_pcm_hw_rule *rule, | ||
1048 | int stream) | ||
1049 | { | ||
1050 | struct snd_interval *buffer_size = hw_param_interval(params, | ||
1051 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE); | ||
1052 | int channels = params_channels(params); | ||
1053 | int periods = params_periods(params); | ||
1054 | struct davinci_audio_dev *dev = rule->private; | ||
1055 | int i; | ||
1056 | u8 slots = dev->tdm_slots; | ||
1057 | u8 max_active_serializers = (channels + slots - 1) / slots; | ||
1058 | u8 num_ser = 0; | ||
1059 | u8 num_evt = 0; | ||
1060 | unsigned long step = 1; | ||
1061 | |||
1062 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1063 | for (i = 0; i < dev->num_serializer; i++) { | ||
1064 | if (dev->serial_dir[i] == TX_MODE && | ||
1065 | num_ser < max_active_serializers) | ||
1066 | num_ser++; | ||
1067 | } | ||
1068 | num_evt = dev->txnumevt * num_ser; | ||
1069 | } else { | ||
1070 | for (i = 0; i < dev->num_serializer; i++) { | ||
1071 | if (dev->serial_dir[i] == RX_MODE && | ||
1072 | num_ser < max_active_serializers) | ||
1073 | num_ser++; | ||
1074 | } | ||
1075 | num_evt = dev->rxnumevt * num_ser; | ||
1076 | } | ||
1077 | |||
1078 | /* | ||
1079 | * The buffersize (in samples), must be a multiple of num_evt. The | ||
1080 | * buffersize (in frames) is the product of the period_size and the | ||
1081 | * number of periods. Therefore, the buffersize should be a multiple | ||
1082 | * of the number of periods. The below finds the least common | ||
1083 | * multiple of num_evt and channels (since the number of samples | ||
1084 | * per frame is equal to the number of channels). It also makes sure | ||
1085 | * that the resulting step value (LCM / channels) is a multiple of the | ||
1086 | * number of periods. | ||
1087 | */ | ||
1088 | step = lcm((lcm(num_evt, channels) / channels), periods); | ||
1089 | |||
1090 | return snd_interval_step(buffer_size, 0, step); | ||
1091 | } | ||
1092 | |||
1093 | static int davinci_mcasp_hwrule_txbuffersize(struct snd_pcm_hw_params *params, | ||
1094 | struct snd_pcm_hw_rule *rule) | ||
1095 | { | ||
1096 | return davinci_mcasp_hwrule_buffersize(params, rule, | ||
1097 | SNDRV_PCM_STREAM_PLAYBACK); | ||
1098 | } | ||
1099 | |||
1100 | static int davinci_mcasp_hwrule_rxbuffersize(struct snd_pcm_hw_params *params, | ||
1101 | struct snd_pcm_hw_rule *rule) | ||
1102 | { | ||
1103 | return davinci_mcasp_hwrule_buffersize(params, rule, | ||
1104 | SNDRV_PCM_STREAM_CAPTURE); | ||
1105 | } | ||
1106 | |||
1045 | static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | 1107 | static int davinci_mcasp_startup(struct snd_pcm_substream *substream, |
1046 | struct snd_soc_dai *dai) | 1108 | struct snd_soc_dai *dai) |
1047 | { | 1109 | { |
1048 | struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); | 1110 | struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); |
1049 | 1111 | ||
1050 | if (dev->version == MCASP_VERSION_4) | 1112 | |
1113 | if (dev->version == MCASP_VERSION_4) { | ||
1051 | snd_soc_dai_set_dma_data(dai, substream, | 1114 | snd_soc_dai_set_dma_data(dai, substream, |
1052 | dev->dma_params[substream->stream]); | 1115 | dev->dma_params[substream->stream]); |
1116 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1117 | if (dev->txnumevt) | ||
1118 | snd_pcm_hw_rule_add(substream->runtime, 0, | ||
1119 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1120 | davinci_mcasp_hwrule_txbuffersize, | ||
1121 | dev, | ||
1122 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); | ||
1123 | } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
1124 | if (dev->rxnumevt) | ||
1125 | snd_pcm_hw_rule_add(substream->runtime, 0, | ||
1126 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1127 | davinci_mcasp_hwrule_rxbuffersize, | ||
1128 | dev, | ||
1129 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); | ||
1130 | } | ||
1131 | } | ||
1053 | else | 1132 | else |
1054 | snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); | 1133 | snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); |
1055 | 1134 | ||