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
20struct 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
29struct 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
36struct 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
46static 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
61static 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
78static 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
102static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)
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
131static 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
213static 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
222static 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
242static 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
254static 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
277static 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
286static 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
296static 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
303static 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 */
319static 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
351static 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
359static 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
368static 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
397static 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
406static 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
415static 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
470static 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
498static 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
546static 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
552static 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
589static 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
608	qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
609							"fsl,qmc-chan");
610	if (IS_ERR(qmc_dai->qmc_chan)) {
611		ret = PTR_ERR(qmc_dai->qmc_chan);
612		return dev_err_probe(qmc_audio->dev, ret,
613				     "dai %d get QMC channel failed\n", qmc_dai->id);
614	}
615
616	qmc_soc_dai_driver->id = qmc_dai->id;
617	qmc_soc_dai_driver->name = qmc_dai->name;
618
619	ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
620	if (ret) {
621		dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
622			qmc_dai->id, ret);
623		return ret;
624	}
625	dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
626		 qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
627
628	if (info.mode != QMC_TRANSPARENT) {
629		dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
630			qmc_dai->id, info.mode);
631		return -EINVAL;
632	}
633	qmc_dai->nb_tx_ts = info.nb_tx_ts;
634	qmc_dai->nb_rx_ts = info.nb_rx_ts;
635
636	qmc_soc_dai_driver->playback.channels_min = 0;
637	qmc_soc_dai_driver->playback.channels_max = 0;
638	if (qmc_dai->nb_tx_ts) {
639		qmc_soc_dai_driver->playback.channels_min = 1;
640		qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
641	}
642	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
643
644	qmc_soc_dai_driver->capture.channels_min = 0;
645	qmc_soc_dai_driver->capture.channels_max = 0;
646	if (qmc_dai->nb_rx_ts) {
647		qmc_soc_dai_driver->capture.channels_min = 1;
648		qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
649	}
650	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
651
652	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
653	qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
654	qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
655	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
656	qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
657	qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
658
659	qmc_soc_dai_driver->ops = &qmc_dai_ops;
660
661	return 0;
662}
663
664static int qmc_audio_probe(struct platform_device *pdev)
665{
666	struct device_node *np = pdev->dev.of_node;
667	struct qmc_audio *qmc_audio;
668	struct device_node *child;
669	unsigned int i;
670	int ret;
671
672	qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);
673	if (!qmc_audio)
674		return -ENOMEM;
675
676	qmc_audio->dev = &pdev->dev;
677
678	qmc_audio->num_dais = of_get_available_child_count(np);
679	if (qmc_audio->num_dais) {
680		qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
681					       sizeof(*qmc_audio->dais),
682					       GFP_KERNEL);
683		if (!qmc_audio->dais)
684			return -ENOMEM;
685
686		qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
687						      sizeof(*qmc_audio->dai_drivers),
688						      GFP_KERNEL);
689		if (!qmc_audio->dai_drivers)
690			return -ENOMEM;
691	}
692
693	i = 0;
694	for_each_available_child_of_node(np, child) {
695		ret = qmc_audio_dai_parse(qmc_audio, child,
696					  qmc_audio->dais + i,
697					  qmc_audio->dai_drivers + i);
698		if (ret) {
699			of_node_put(child);
700			return ret;
701		}
702		i++;
703	}
704
705
706	platform_set_drvdata(pdev, qmc_audio);
707
708	ret = devm_snd_soc_register_component(qmc_audio->dev,
709					      &qmc_audio_soc_platform,
710					      qmc_audio->dai_drivers,
711					      qmc_audio->num_dais);
712	if (ret)
713		return ret;
714
715	return 0;
716}
717
718static const struct of_device_id qmc_audio_id_table[] = {
719	{ .compatible = "fsl,qmc-audio" },
720	{} /* sentinel */
721};
722MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
723
724static struct platform_driver qmc_audio_driver = {
725	.driver = {
726		.name = "fsl-qmc-audio",
727		.of_match_table = of_match_ptr(qmc_audio_id_table),
728	},
729	.probe = qmc_audio_probe,
730};
731module_platform_driver(qmc_audio_driver);
732
733MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
734MODULE_DESCRIPTION("CPM/QE QMC audio driver");
735MODULE_LICENSE("GPL");
736