xref: /openbmc/linux/sound/soc/fsl/fsl_qmc_audio.c (revision b4205dfc)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ALSA SoC using the QUICC Multichannel Controller (QMC)
4  *
5  * Copyright 2022 CS GROUP France
6  *
7  * Author: Herve Codina <herve.codina@bootlin.com>
8  */
9 
10 #include <linux/dma-mapping.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/of_platform.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <soc/fsl/qe/qmc.h>
17 #include <sound/pcm_params.h>
18 #include <sound/soc.h>
19 
20 struct qmc_dai {
21 	char *name;
22 	int id;
23 	struct device *dev;
24 	struct qmc_chan *qmc_chan;
25 	unsigned int nb_tx_ts;
26 	unsigned int nb_rx_ts;
27 };
28 
29 struct qmc_audio {
30 	struct device *dev;
31 	unsigned int num_dais;
32 	struct qmc_dai *dais;
33 	struct snd_soc_dai_driver *dai_drivers;
34 };
35 
36 struct qmc_dai_prtd {
37 	struct qmc_dai *qmc_dai;
38 	dma_addr_t dma_buffer_start;
39 	dma_addr_t period_ptr_submitted;
40 	dma_addr_t period_ptr_ended;
41 	dma_addr_t dma_buffer_end;
42 	size_t period_size;
43 	struct snd_pcm_substream *substream;
44 };
45 
qmc_audio_pcm_construct(struct snd_soc_component * component,struct snd_soc_pcm_runtime * rtd)46 static int qmc_audio_pcm_construct(struct snd_soc_component *component,
47 				   struct snd_soc_pcm_runtime *rtd)
48 {
49 	struct snd_card *card = rtd->card->snd_card;
50 	int ret;
51 
52 	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
53 	if (ret)
54 		return ret;
55 
56 	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
57 				       64*1024, 64*1024);
58 	return 0;
59 }
60 
qmc_audio_pcm_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)61 static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
62 				   struct snd_pcm_substream *substream,
63 				   struct snd_pcm_hw_params *params)
64 {
65 	struct snd_pcm_runtime *runtime = substream->runtime;
66 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
67 
68 	prtd->dma_buffer_start = runtime->dma_addr;
69 	prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params);
70 	prtd->period_size = params_period_bytes(params);
71 	prtd->period_ptr_submitted = prtd->dma_buffer_start;
72 	prtd->period_ptr_ended = prtd->dma_buffer_start;
73 	prtd->substream = substream;
74 
75 	return 0;
76 }
77 
qmc_audio_pcm_write_complete(void * context)78 static void qmc_audio_pcm_write_complete(void *context)
79 {
80 	struct qmc_dai_prtd *prtd = context;
81 	int ret;
82 
83 	prtd->period_ptr_ended += prtd->period_size;
84 	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
85 		prtd->period_ptr_ended = prtd->dma_buffer_start;
86 
87 	prtd->period_ptr_submitted += prtd->period_size;
88 	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
89 		prtd->period_ptr_submitted = prtd->dma_buffer_start;
90 
91 	ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
92 		prtd->period_ptr_submitted, prtd->period_size,
93 		qmc_audio_pcm_write_complete, prtd);
94 	if (ret) {
95 		dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n",
96 			ret);
97 	}
98 
99 	snd_pcm_period_elapsed(prtd->substream);
100 }
101 
qmc_audio_pcm_read_complete(void * context,size_t length)102 static void qmc_audio_pcm_read_complete(void *context, size_t length)
103 {
104 	struct qmc_dai_prtd *prtd = context;
105 	int ret;
106 
107 	if (length != prtd->period_size) {
108 		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
109 			length, prtd->period_size);
110 	}
111 
112 	prtd->period_ptr_ended += prtd->period_size;
113 	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
114 		prtd->period_ptr_ended = prtd->dma_buffer_start;
115 
116 	prtd->period_ptr_submitted += prtd->period_size;
117 	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
118 		prtd->period_ptr_submitted = prtd->dma_buffer_start;
119 
120 	ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
121 		prtd->period_ptr_submitted, prtd->period_size,
122 		qmc_audio_pcm_read_complete, prtd);
123 	if (ret) {
124 		dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n",
125 			ret);
126 	}
127 
128 	snd_pcm_period_elapsed(prtd->substream);
129 }
130 
qmc_audio_pcm_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)131 static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
132 				 struct snd_pcm_substream *substream, int cmd)
133 {
134 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
135 	int ret;
136 
137 	if (!prtd->qmc_dai) {
138 		dev_err(component->dev, "qmc_dai is not set\n");
139 		return -EINVAL;
140 	}
141 
142 	switch (cmd) {
143 	case SNDRV_PCM_TRIGGER_START:
144 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
145 			/* Submit first chunk ... */
146 			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
147 				prtd->period_ptr_submitted, prtd->period_size,
148 				qmc_audio_pcm_write_complete, prtd);
149 			if (ret) {
150 				dev_err(component->dev, "write_submit failed %d\n",
151 					ret);
152 				return ret;
153 			}
154 
155 			/* ... prepare next one ... */
156 			prtd->period_ptr_submitted += prtd->period_size;
157 			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
158 				prtd->period_ptr_submitted = prtd->dma_buffer_start;
159 
160 			/* ... and send it */
161 			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
162 				prtd->period_ptr_submitted, prtd->period_size,
163 				qmc_audio_pcm_write_complete, prtd);
164 			if (ret) {
165 				dev_err(component->dev, "write_submit failed %d\n",
166 					ret);
167 				return ret;
168 			}
169 		} else {
170 			/* Submit first chunk ... */
171 			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
172 				prtd->period_ptr_submitted, prtd->period_size,
173 				qmc_audio_pcm_read_complete, prtd);
174 			if (ret) {
175 				dev_err(component->dev, "read_submit failed %d\n",
176 					ret);
177 				return ret;
178 			}
179 
180 			/* ... prepare next one ... */
181 			prtd->period_ptr_submitted += prtd->period_size;
182 			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
183 				prtd->period_ptr_submitted = prtd->dma_buffer_start;
184 
185 			/* ... and send it */
186 			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
187 				prtd->period_ptr_submitted, prtd->period_size,
188 				qmc_audio_pcm_read_complete, prtd);
189 			if (ret) {
190 				dev_err(component->dev, "write_submit failed %d\n",
191 					ret);
192 				return ret;
193 			}
194 		}
195 		break;
196 
197 	case SNDRV_PCM_TRIGGER_RESUME:
198 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
199 		break;
200 
201 	case SNDRV_PCM_TRIGGER_STOP:
202 	case SNDRV_PCM_TRIGGER_SUSPEND:
203 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
204 		break;
205 
206 	default:
207 		return -EINVAL;
208 	}
209 
210 	return 0;
211 }
212 
qmc_audio_pcm_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)213 static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,
214 					       struct snd_pcm_substream *substream)
215 {
216 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
217 
218 	return bytes_to_frames(substream->runtime,
219 			       prtd->period_ptr_ended - prtd->dma_buffer_start);
220 }
221 
qmc_audio_of_xlate_dai_name(struct snd_soc_component * component,const struct of_phandle_args * args,const char ** dai_name)222 static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
223 					const struct of_phandle_args *args,
224 					const char **dai_name)
225 {
226 	struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
227 	struct snd_soc_dai_driver *dai_driver;
228 	int id = args->args[0];
229 	int i;
230 
231 	for (i = 0; i  < qmc_audio->num_dais; i++) {
232 		dai_driver = qmc_audio->dai_drivers + i;
233 		if (dai_driver->id == id) {
234 			*dai_name = dai_driver->name;
235 			return 0;
236 		}
237 	}
238 
239 	return -EINVAL;
240 }
241 
242 static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
243 	.info			= SNDRV_PCM_INFO_MMAP |
244 				  SNDRV_PCM_INFO_MMAP_VALID |
245 				  SNDRV_PCM_INFO_INTERLEAVED |
246 				  SNDRV_PCM_INFO_PAUSE,
247 	.period_bytes_min	= 32,
248 	.period_bytes_max	= 64*1024,
249 	.periods_min		= 2,
250 	.periods_max		= 2*1024,
251 	.buffer_bytes_max	= 64*1024,
252 };
253 
qmc_audio_pcm_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)254 static int qmc_audio_pcm_open(struct snd_soc_component *component,
255 			      struct snd_pcm_substream *substream)
256 {
257 	struct snd_pcm_runtime *runtime = substream->runtime;
258 	struct qmc_dai_prtd *prtd;
259 	int ret;
260 
261 	snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);
262 
263 	/* ensure that buffer size is a multiple of period size */
264 	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
265 	if (ret < 0)
266 		return ret;
267 
268 	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
269 	if (prtd == NULL)
270 		return -ENOMEM;
271 
272 	runtime->private_data = prtd;
273 
274 	return 0;
275 }
276 
qmc_audio_pcm_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)277 static int qmc_audio_pcm_close(struct snd_soc_component *component,
278 			       struct snd_pcm_substream *substream)
279 {
280 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
281 
282 	kfree(prtd);
283 	return 0;
284 }
285 
286 static const struct snd_soc_component_driver qmc_audio_soc_platform = {
287 	.open			= qmc_audio_pcm_open,
288 	.close			= qmc_audio_pcm_close,
289 	.hw_params		= qmc_audio_pcm_hw_params,
290 	.trigger		= qmc_audio_pcm_trigger,
291 	.pointer		= qmc_audio_pcm_pointer,
292 	.pcm_construct		= qmc_audio_pcm_construct,
293 	.of_xlate_dai_name	= qmc_audio_of_xlate_dai_name,
294 };
295 
qmc_dai_get_index(struct snd_soc_dai * dai)296 static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)
297 {
298 	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
299 
300 	return dai->driver - qmc_audio->dai_drivers;
301 }
302 
qmc_dai_get_data(struct snd_soc_dai * dai)303 static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)
304 {
305 	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
306 	unsigned int index;
307 
308 	index = qmc_dai_get_index(dai);
309 	if (index > qmc_audio->num_dais)
310 		return NULL;
311 
312 	return qmc_audio->dais + index;
313 }
314 
315 /*
316  * The constraints for format/channel is to match with the number of 8bit
317  * time-slots available.
318  */
qmc_dai_hw_rule_channels_by_format(struct qmc_dai * qmc_dai,struct snd_pcm_hw_params * params,unsigned int nb_ts)319 static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai,
320 					      struct snd_pcm_hw_params *params,
321 					      unsigned int nb_ts)
322 {
323 	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
324 	snd_pcm_format_t format = params_format(params);
325 	struct snd_interval ch = {0};
326 
327 	switch (snd_pcm_format_physical_width(format)) {
328 	case 8:
329 		ch.max = nb_ts;
330 		break;
331 	case 16:
332 		ch.max = nb_ts/2;
333 		break;
334 	case 32:
335 		ch.max = nb_ts/4;
336 		break;
337 	case 64:
338 		ch.max = nb_ts/8;
339 		break;
340 	default:
341 		dev_err(qmc_dai->dev, "format physical width %u not supported\n",
342 			snd_pcm_format_physical_width(format));
343 		return -EINVAL;
344 	}
345 
346 	ch.min = ch.max ? 1 : 0;
347 
348 	return snd_interval_refine(c, &ch);
349 }
350 
qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)351 static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
352 						       struct snd_pcm_hw_rule *rule)
353 {
354 	struct qmc_dai *qmc_dai = rule->private;
355 
356 	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
357 }
358 
qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)359 static int qmc_dai_hw_rule_capture_channels_by_format(
360 			struct snd_pcm_hw_params *params,
361 			struct snd_pcm_hw_rule *rule)
362 {
363 	struct qmc_dai *qmc_dai = rule->private;
364 
365 	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);
366 }
367 
qmc_dai_hw_rule_format_by_channels(struct qmc_dai * qmc_dai,struct snd_pcm_hw_params * params,unsigned int nb_ts)368 static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
369 					      struct snd_pcm_hw_params *params,
370 					      unsigned int nb_ts)
371 {
372 	struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
373 	unsigned int channels = params_channels(params);
374 	unsigned int slot_width;
375 	snd_pcm_format_t format;
376 	struct snd_mask f_new;
377 
378 	if (!channels || channels > nb_ts) {
379 		dev_err(qmc_dai->dev, "channels %u not supported\n",
380 			nb_ts);
381 		return -EINVAL;
382 	}
383 
384 	slot_width = (nb_ts / channels) * 8;
385 
386 	snd_mask_none(&f_new);
387 	pcm_for_each_format(format) {
388 		if (snd_mask_test_format(f_old, format)) {
389 			if (snd_pcm_format_physical_width(format) <= slot_width)
390 				snd_mask_set_format(&f_new, format);
391 		}
392 	}
393 
394 	return snd_mask_refine(f_old, &f_new);
395 }
396 
qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)397 static int qmc_dai_hw_rule_playback_format_by_channels(
398 			struct snd_pcm_hw_params *params,
399 			struct snd_pcm_hw_rule *rule)
400 {
401 	struct qmc_dai *qmc_dai = rule->private;
402 
403 	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
404 }
405 
qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)406 static int qmc_dai_hw_rule_capture_format_by_channels(
407 			struct snd_pcm_hw_params *params,
408 			struct snd_pcm_hw_rule *rule)
409 {
410 	struct qmc_dai *qmc_dai = rule->private;
411 
412 	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
413 }
414 
qmc_dai_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)415 static int qmc_dai_startup(struct snd_pcm_substream *substream,
416 			     struct snd_soc_dai *dai)
417 {
418 	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
419 	snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
420 	snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
421 	struct qmc_dai *qmc_dai;
422 	unsigned int frame_bits;
423 	int ret;
424 
425 	qmc_dai = qmc_dai_get_data(dai);
426 	if (!qmc_dai) {
427 		dev_err(dai->dev, "Invalid dai\n");
428 		return -EINVAL;
429 	}
430 
431 	prtd->qmc_dai = qmc_dai;
432 
433 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
434 		hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
435 		hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
436 		frame_bits = qmc_dai->nb_rx_ts * 8;
437 	} else {
438 		hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;
439 		hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;
440 		frame_bits = qmc_dai->nb_tx_ts * 8;
441 	}
442 
443 	ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
444 				  hw_rule_channels_by_format, qmc_dai,
445 				  SNDRV_PCM_HW_PARAM_FORMAT, -1);
446 	if (ret) {
447 		dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret);
448 		return ret;
449 	}
450 
451 	ret = snd_pcm_hw_rule_add(substream->runtime, 0,  SNDRV_PCM_HW_PARAM_FORMAT,
452 				  hw_rule_format_by_channels, qmc_dai,
453 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
454 	if (ret) {
455 		dev_err(dai->dev, "Failed to add format rule (%d)\n", ret);
456 		return ret;
457 	}
458 
459 	ret = snd_pcm_hw_constraint_single(substream->runtime,
460 					   SNDRV_PCM_HW_PARAM_FRAME_BITS,
461 					   frame_bits);
462 	if (ret < 0) {
463 		dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);
464 		return ret;
465 	}
466 
467 	return 0;
468 }
469 
qmc_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)470 static int qmc_dai_hw_params(struct snd_pcm_substream *substream,
471 			     struct snd_pcm_hw_params *params,
472 			     struct snd_soc_dai *dai)
473 {
474 	struct qmc_chan_param chan_param = {0};
475 	struct qmc_dai *qmc_dai;
476 	int ret;
477 
478 	qmc_dai = qmc_dai_get_data(dai);
479 	if (!qmc_dai) {
480 		dev_err(dai->dev, "Invalid dai\n");
481 		return -EINVAL;
482 	}
483 
484 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
485 		chan_param.mode = QMC_TRANSPARENT;
486 		chan_param.transp.max_rx_buf_size = params_period_bytes(params);
487 		ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param);
488 		if (ret) {
489 			dev_err(dai->dev, "set param failed %d\n",
490 				ret);
491 			return ret;
492 		}
493 	}
494 
495 	return 0;
496 }
497 
qmc_dai_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)498 static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
499 			   struct snd_soc_dai *dai)
500 {
501 	struct qmc_dai *qmc_dai;
502 	int direction;
503 	int ret;
504 
505 	qmc_dai = qmc_dai_get_data(dai);
506 	if (!qmc_dai) {
507 		dev_err(dai->dev, "Invalid dai\n");
508 		return -EINVAL;
509 	}
510 
511 	direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
512 		    QMC_CHAN_WRITE : QMC_CHAN_READ;
513 
514 	switch (cmd) {
515 	case SNDRV_PCM_TRIGGER_START:
516 	case SNDRV_PCM_TRIGGER_RESUME:
517 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
518 		ret = qmc_chan_start(qmc_dai->qmc_chan, direction);
519 		if (ret)
520 			return ret;
521 		break;
522 
523 	case SNDRV_PCM_TRIGGER_STOP:
524 		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
525 		if (ret)
526 			return ret;
527 		ret = qmc_chan_reset(qmc_dai->qmc_chan, direction);
528 		if (ret)
529 			return ret;
530 		break;
531 
532 	case SNDRV_PCM_TRIGGER_SUSPEND:
533 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
534 		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
535 		if (ret)
536 			return ret;
537 		break;
538 
539 	default:
540 		return -EINVAL;
541 	}
542 
543 	return 0;
544 }
545 
546 static const struct snd_soc_dai_ops qmc_dai_ops = {
547 	.startup	= qmc_dai_startup,
548 	.trigger	= qmc_dai_trigger,
549 	.hw_params	= qmc_dai_hw_params,
550 };
551 
qmc_audio_formats(u8 nb_ts)552 static u64 qmc_audio_formats(u8 nb_ts)
553 {
554 	unsigned int format_width;
555 	unsigned int chan_width;
556 	snd_pcm_format_t format;
557 	u64 formats_mask;
558 
559 	if (!nb_ts)
560 		return 0;
561 
562 	formats_mask = 0;
563 	chan_width = nb_ts * 8;
564 	pcm_for_each_format(format) {
565 		/*
566 		 * Support format other than little-endian (ie big-endian or
567 		 * without endianness such as 8bit formats)
568 		 */
569 		if (snd_pcm_format_little_endian(format) == 1)
570 			continue;
571 
572 		/* Support physical width multiple of 8bit */
573 		format_width = snd_pcm_format_physical_width(format);
574 		if (format_width == 0 || format_width % 8)
575 			continue;
576 
577 		/*
578 		 * And support physical width that can fit N times in the
579 		 * channel
580 		 */
581 		if (format_width > chan_width || chan_width % format_width)
582 			continue;
583 
584 		formats_mask |= pcm_format_to_bits(format);
585 	}
586 	return formats_mask;
587 }
588 
qmc_audio_dai_parse(struct qmc_audio * qmc_audio,struct device_node * np,struct qmc_dai * qmc_dai,struct snd_soc_dai_driver * qmc_soc_dai_driver)589 static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
590 	struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver)
591 {
592 	struct qmc_chan_info info;
593 	u32 val;
594 	int ret;
595 
596 	qmc_dai->dev = qmc_audio->dev;
597 
598 	ret = of_property_read_u32(np, "reg", &val);
599 	if (ret) {
600 		dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);
601 		return ret;
602 	}
603 	qmc_dai->id = val;
604 
605 	qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
606 				       np->parent->name, qmc_dai->id);
607 	if (!qmc_dai->name)
608 		return -ENOMEM;
609 
610 	qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
611 							"fsl,qmc-chan");
612 	if (IS_ERR(qmc_dai->qmc_chan)) {
613 		ret = PTR_ERR(qmc_dai->qmc_chan);
614 		return dev_err_probe(qmc_audio->dev, ret,
615 				     "dai %d get QMC channel failed\n", qmc_dai->id);
616 	}
617 
618 	qmc_soc_dai_driver->id = qmc_dai->id;
619 	qmc_soc_dai_driver->name = qmc_dai->name;
620 
621 	ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
622 	if (ret) {
623 		dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
624 			qmc_dai->id, ret);
625 		return ret;
626 	}
627 	dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
628 		 qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
629 
630 	if (info.mode != QMC_TRANSPARENT) {
631 		dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
632 			qmc_dai->id, info.mode);
633 		return -EINVAL;
634 	}
635 	qmc_dai->nb_tx_ts = info.nb_tx_ts;
636 	qmc_dai->nb_rx_ts = info.nb_rx_ts;
637 
638 	qmc_soc_dai_driver->playback.channels_min = 0;
639 	qmc_soc_dai_driver->playback.channels_max = 0;
640 	if (qmc_dai->nb_tx_ts) {
641 		qmc_soc_dai_driver->playback.channels_min = 1;
642 		qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
643 	}
644 	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
645 
646 	qmc_soc_dai_driver->capture.channels_min = 0;
647 	qmc_soc_dai_driver->capture.channels_max = 0;
648 	if (qmc_dai->nb_rx_ts) {
649 		qmc_soc_dai_driver->capture.channels_min = 1;
650 		qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
651 	}
652 	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
653 
654 	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
655 	qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
656 	qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
657 	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
658 	qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
659 	qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
660 
661 	qmc_soc_dai_driver->ops = &qmc_dai_ops;
662 
663 	return 0;
664 }
665 
qmc_audio_probe(struct platform_device * pdev)666 static int qmc_audio_probe(struct platform_device *pdev)
667 {
668 	struct device_node *np = pdev->dev.of_node;
669 	struct qmc_audio *qmc_audio;
670 	struct device_node *child;
671 	unsigned int i;
672 	int ret;
673 
674 	qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);
675 	if (!qmc_audio)
676 		return -ENOMEM;
677 
678 	qmc_audio->dev = &pdev->dev;
679 
680 	qmc_audio->num_dais = of_get_available_child_count(np);
681 	if (qmc_audio->num_dais) {
682 		qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
683 					       sizeof(*qmc_audio->dais),
684 					       GFP_KERNEL);
685 		if (!qmc_audio->dais)
686 			return -ENOMEM;
687 
688 		qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
689 						      sizeof(*qmc_audio->dai_drivers),
690 						      GFP_KERNEL);
691 		if (!qmc_audio->dai_drivers)
692 			return -ENOMEM;
693 	}
694 
695 	i = 0;
696 	for_each_available_child_of_node(np, child) {
697 		ret = qmc_audio_dai_parse(qmc_audio, child,
698 					  qmc_audio->dais + i,
699 					  qmc_audio->dai_drivers + i);
700 		if (ret) {
701 			of_node_put(child);
702 			return ret;
703 		}
704 		i++;
705 	}
706 
707 
708 	platform_set_drvdata(pdev, qmc_audio);
709 
710 	ret = devm_snd_soc_register_component(qmc_audio->dev,
711 					      &qmc_audio_soc_platform,
712 					      qmc_audio->dai_drivers,
713 					      qmc_audio->num_dais);
714 	if (ret)
715 		return ret;
716 
717 	return 0;
718 }
719 
720 static const struct of_device_id qmc_audio_id_table[] = {
721 	{ .compatible = "fsl,qmc-audio" },
722 	{} /* sentinel */
723 };
724 MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
725 
726 static struct platform_driver qmc_audio_driver = {
727 	.driver = {
728 		.name = "fsl-qmc-audio",
729 		.of_match_table = of_match_ptr(qmc_audio_id_table),
730 	},
731 	.probe = qmc_audio_probe,
732 };
733 module_platform_driver(qmc_audio_driver);
734 
735 MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
736 MODULE_DESCRIPTION("CPM/QE QMC audio driver");
737 MODULE_LICENSE("GPL");
738