aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c111
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.h1
2 files changed, 108 insertions, 4 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 379ac2a6ab16..6b8e64899205 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
187 return IRQ_HANDLED; 187 return IRQ_HANDLED;
188} 188}
189 189
190/*
191 * When the bit clock is input, limit the maximum rate according to the
192 * Serial Clock Ratio Considerations section from the SSC documentation:
193 *
194 * The Transmitter and the Receiver can be programmed to operate
195 * with the clock signals provided on either the TK or RK pins.
196 * This allows the SSC to support many slave-mode data transfers.
197 * In this case, the maximum clock speed allowed on the RK pin is:
198 * - Peripheral clock divided by 2 if Receiver Frame Synchro is input
199 * - Peripheral clock divided by 3 if Receiver Frame Synchro is output
200 * In addition, the maximum clock speed allowed on the TK pin is:
201 * - Peripheral clock divided by 6 if Transmit Frame Synchro is input
202 * - Peripheral clock divided by 2 if Transmit Frame Synchro is output
203 *
204 * When the bit clock is output, limit the rate according to the
205 * SSC divider restrictions.
206 */
207static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
208 struct snd_pcm_hw_rule *rule)
209{
210 struct atmel_ssc_info *ssc_p = rule->private;
211 struct ssc_device *ssc = ssc_p->ssc;
212 struct snd_interval *i = hw_param_interval(params, rule->var);
213 struct snd_interval t;
214 struct snd_ratnum r = {
215 .den_min = 1,
216 .den_max = 4095,
217 .den_step = 1,
218 };
219 unsigned int num = 0, den = 0;
220 int frame_size;
221 int mck_div = 2;
222 int ret;
223
224 frame_size = snd_soc_params_to_frame_size(params);
225 if (frame_size < 0)
226 return frame_size;
227
228 switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
229 case SND_SOC_DAIFMT_CBM_CFS:
230 if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
231 && ssc->clk_from_rk_pin)
232 /* Receiver Frame Synchro (i.e. capture)
233 * is output (format is _CFS) and the RK pin
234 * is used for input (format is _CBM_).
235 */
236 mck_div = 3;
237 break;
238
239 case SND_SOC_DAIFMT_CBM_CFM:
240 if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
241 && !ssc->clk_from_rk_pin)
242 /* Transmit Frame Synchro (i.e. playback)
243 * is input (format is _CFM) and the TK pin
244 * is used for input (format _CBM_ but not
245 * using the RK pin).
246 */
247 mck_div = 6;
248 break;
249 }
250
251 switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
252 case SND_SOC_DAIFMT_CBS_CFS:
253 r.num = ssc_p->mck_rate / mck_div / frame_size;
254
255 ret = snd_interval_ratnum(i, 1, &r, &num, &den);
256 if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
257 params->rate_num = num;
258 params->rate_den = den;
259 }
260 break;
261
262 case SND_SOC_DAIFMT_CBM_CFS:
263 case SND_SOC_DAIFMT_CBM_CFM:
264 t.min = 8000;
265 t.max = ssc_p->mck_rate / mck_div / frame_size;
266 t.openmin = t.openmax = 0;
267 t.integer = 0;
268 ret = snd_interval_refine(i, &t);
269 break;
270
271 default:
272 ret = -EINVAL;
273 break;
274 }
275
276 return ret;
277}
190 278
191/*-------------------------------------------------------------------------*\ 279/*-------------------------------------------------------------------------*\
192 * DAI functions 280 * DAI functions
@@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
200 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; 288 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
201 struct atmel_pcm_dma_params *dma_params; 289 struct atmel_pcm_dma_params *dma_params;
202 int dir, dir_mask; 290 int dir, dir_mask;
291 int ret;
203 292
204 pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", 293 pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
205 ssc_readl(ssc_p->ssc->regs, SR)); 294 ssc_readl(ssc_p->ssc->regs, SR));
@@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
207 /* Enable PMC peripheral clock for this SSC */ 296 /* Enable PMC peripheral clock for this SSC */
208 pr_debug("atmel_ssc_dai: Starting clock\n"); 297 pr_debug("atmel_ssc_dai: Starting clock\n");
209 clk_enable(ssc_p->ssc->clk); 298 clk_enable(ssc_p->ssc->clk);
299 ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
210 300
211 /* Reset the SSC to keep it at a clean status */ 301 /* Reset the SSC to keep it at a clean status */
212 ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); 302 ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
@@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
219 dir_mask = SSC_DIR_MASK_CAPTURE; 309 dir_mask = SSC_DIR_MASK_CAPTURE;
220 } 310 }
221 311
312 ret = snd_pcm_hw_rule_add(substream->runtime, 0,
313 SNDRV_PCM_HW_PARAM_RATE,
314 atmel_ssc_hw_rule_rate,
315 ssc_p,
316 SNDRV_PCM_HW_PARAM_FRAME_BITS,
317 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
318 if (ret < 0) {
319 dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret);
320 return ret;
321 }
322
222 dma_params = &ssc_dma_params[dai->id][dir]; 323 dma_params = &ssc_dma_params[dai->id][dir];
223 dma_params->ssc = ssc_p->ssc; 324 dma_params->ssc = ssc_p->ssc;
224 dma_params->substream = substream; 325 dma_params->substream = substream;
@@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
783# define atmel_ssc_resume NULL 884# define atmel_ssc_resume NULL
784#endif /* CONFIG_PM */ 885#endif /* CONFIG_PM */
785 886
786#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
787
788#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ 887#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
789 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 888 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
790 889
@@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
804 .playback = { 903 .playback = {
805 .channels_min = 1, 904 .channels_min = 1,
806 .channels_max = 2, 905 .channels_max = 2,
807 .rates = ATMEL_SSC_RATES, 906 .rates = SNDRV_PCM_RATE_CONTINUOUS,
907 .rate_min = 8000,
908 .rate_max = 384000,
808 .formats = ATMEL_SSC_FORMATS,}, 909 .formats = ATMEL_SSC_FORMATS,},
809 .capture = { 910 .capture = {
810 .channels_min = 1, 911 .channels_min = 1,
811 .channels_max = 2, 912 .channels_max = 2,
812 .rates = ATMEL_SSC_RATES, 913 .rates = SNDRV_PCM_RATE_CONTINUOUS,
914 .rate_min = 8000,
915 .rate_max = 384000,
813 .formats = ATMEL_SSC_FORMATS,}, 916 .formats = ATMEL_SSC_FORMATS,},
814 .ops = &atmel_ssc_dai_ops, 917 .ops = &atmel_ssc_dai_ops,
815}; 918};
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index b1f08d511495..80b153857a88 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -115,6 +115,7 @@ struct atmel_ssc_info {
115 unsigned short rcmr_period; 115 unsigned short rcmr_period;
116 struct atmel_pcm_dma_params *dma_params[2]; 116 struct atmel_pcm_dma_params *dma_params[2];
117 struct atmel_ssc_state ssc_state; 117 struct atmel_ssc_state ssc_state;
118 unsigned long mck_rate;
118}; 119};
119 120
120int atmel_ssc_set_audio(int ssc_id); 121int atmel_ssc_set_audio(int ssc_id);