diff options
-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 da38efba721..ef30dbdd7ae 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 | ||