brintos

brintos / linux-shallow public Read only

0
0
Text · 26.0 KiB · 8668abd Raw
991 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ALSA SoC using the QUICC Multichannel Controller (QMC)4 *5 * Copyright 2022 CS GROUP France6 *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_chan {21	struct qmc_dai_prtd *prtd_tx;22	struct qmc_dai_prtd *prtd_rx;23	struct qmc_chan *qmc_chan;24};25 26struct qmc_dai {27	char *name;28	int id;29	struct device *dev;30	unsigned int nb_tx_ts;31	unsigned int nb_rx_ts;32 33	unsigned int nb_chans_avail;34	unsigned int nb_chans_used_tx;35	unsigned int nb_chans_used_rx;36	struct qmc_dai_chan *chans;37};38 39struct qmc_audio {40	struct device *dev;41	unsigned int num_dais;42	struct qmc_dai *dais;43	struct snd_soc_dai_driver *dai_drivers;44};45 46struct qmc_dai_prtd {47	struct qmc_dai *qmc_dai;48 49	snd_pcm_uframes_t buffer_ended;50	snd_pcm_uframes_t buffer_size;51	snd_pcm_uframes_t period_size;52 53	dma_addr_t ch_dma_addr_start;54	dma_addr_t ch_dma_addr_current;55	dma_addr_t ch_dma_addr_end;56	size_t ch_dma_size;57	size_t ch_dma_offset;58 59	unsigned int channels;60	DECLARE_BITMAP(chans_pending, 64);61	struct snd_pcm_substream *substream;62};63 64static int qmc_audio_pcm_construct(struct snd_soc_component *component,65				   struct snd_soc_pcm_runtime *rtd)66{67	struct snd_card *card = rtd->card->snd_card;68	int ret;69 70	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));71	if (ret)72		return ret;73 74	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,75				       64 * 1024, 64 * 1024);76	return 0;77}78 79static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access)80{81	switch (access) {82	case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:83	case SNDRV_PCM_ACCESS_RW_INTERLEAVED:84		return true;85	default:86		break;87	}88	return false;89}90 91static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,92				   struct snd_pcm_substream *substream,93				   struct snd_pcm_hw_params *params)94{95	struct snd_pcm_runtime *runtime = substream->runtime;96	struct qmc_dai_prtd *prtd = substream->runtime->private_data;97 98	/*99	 * In interleaved mode, the driver uses one QMC channel for all audio100	 * channels whereas in non-interleaved mode, it uses one QMC channel per101	 * audio channel.102	 */103	prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ?104				1 : params_channels(params);105 106	prtd->substream = substream;107 108	prtd->buffer_ended = 0;109	prtd->buffer_size = params_buffer_size(params);110	prtd->period_size = params_period_size(params);111 112	prtd->ch_dma_addr_start = runtime->dma_addr;113	prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels;114	prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset;115	prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;116	prtd->ch_dma_size = params_period_bytes(params) / prtd->channels;117 118	return 0;119}120 121static void qmc_audio_pcm_write_complete(void *context);122 123static int qmc_audio_pcm_write_submit(struct qmc_dai_prtd *prtd)124{125	unsigned int i;126	int ret;127 128	for (i = 0; i < prtd->channels; i++) {129		bitmap_set(prtd->chans_pending, i, 1);130 131		ret = qmc_chan_write_submit(prtd->qmc_dai->chans[i].qmc_chan,132					    prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,133					    prtd->ch_dma_size,134					    qmc_audio_pcm_write_complete,135					    &prtd->qmc_dai->chans[i]);136		if (ret) {137			dev_err(prtd->qmc_dai->dev, "write_submit %u failed %d\n",138				i, ret);139			bitmap_clear(prtd->chans_pending, i, 1);140			return ret;141		}142	}143 144	return 0;145}146 147static void qmc_audio_pcm_write_complete(void *context)148{149	struct qmc_dai_chan *chan = context;150	struct qmc_dai_prtd *prtd;151 152	prtd = chan->prtd_tx;153 154	/* Mark the current channel as completed */155	bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);156 157	/*158	 * All QMC channels involved must have completed their transfer before159	 * submitting a new one.160	 */161	if (!bitmap_empty(prtd->chans_pending, 64))162		return;163 164	prtd->buffer_ended += prtd->period_size;165	if (prtd->buffer_ended >= prtd->buffer_size)166		prtd->buffer_ended = 0;167 168	prtd->ch_dma_addr_current += prtd->ch_dma_size;169	if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)170		prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;171 172	qmc_audio_pcm_write_submit(prtd);173 174	snd_pcm_period_elapsed(prtd->substream);175}176 177static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags);178 179static int qmc_audio_pcm_read_submit(struct qmc_dai_prtd *prtd)180{181	unsigned int i;182	int ret;183 184	for (i = 0; i < prtd->channels; i++) {185		bitmap_set(prtd->chans_pending, i, 1);186 187		ret = qmc_chan_read_submit(prtd->qmc_dai->chans[i].qmc_chan,188					   prtd->ch_dma_addr_current + i * prtd->ch_dma_offset,189					   prtd->ch_dma_size,190					   qmc_audio_pcm_read_complete,191					   &prtd->qmc_dai->chans[i]);192		if (ret) {193			dev_err(prtd->qmc_dai->dev, "read_submit %u failed %d\n",194				i, ret);195			bitmap_clear(prtd->chans_pending, i, 1);196			return ret;197		}198	}199 200	return 0;201}202 203static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags)204{205	struct qmc_dai_chan *chan = context;206	struct qmc_dai_prtd *prtd;207 208	prtd = chan->prtd_rx;209 210	/* Mark the current channel as completed */211	bitmap_clear(prtd->chans_pending, chan - prtd->qmc_dai->chans, 1);212 213	if (length != prtd->ch_dma_size) {214		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",215			length, prtd->ch_dma_size);216	}217 218	/*219	 * All QMC channels involved must have completed their transfer before220	 * submitting a new one.221	 */222	if (!bitmap_empty(prtd->chans_pending, 64))223		return;224 225	prtd->buffer_ended += prtd->period_size;226	if (prtd->buffer_ended >= prtd->buffer_size)227		prtd->buffer_ended = 0;228 229	prtd->ch_dma_addr_current += prtd->ch_dma_size;230	if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)231		prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;232 233	qmc_audio_pcm_read_submit(prtd);234 235	snd_pcm_period_elapsed(prtd->substream);236}237 238static int qmc_audio_pcm_trigger(struct snd_soc_component *component,239				 struct snd_pcm_substream *substream, int cmd)240{241	struct qmc_dai_prtd *prtd = substream->runtime->private_data;242	unsigned int i;243	int ret;244 245	if (!prtd->qmc_dai) {246		dev_err(component->dev, "qmc_dai is not set\n");247		return -EINVAL;248	}249 250	switch (cmd) {251	case SNDRV_PCM_TRIGGER_START:252		bitmap_zero(prtd->chans_pending, 64);253		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {254			for (i = 0; i < prtd->channels; i++)255				prtd->qmc_dai->chans[i].prtd_tx = prtd;256 257			/* Submit first chunk ... */258			ret = qmc_audio_pcm_write_submit(prtd);259			if (ret)260				return ret;261 262			/* ... prepare next one ... */263			prtd->ch_dma_addr_current += prtd->ch_dma_size;264			if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)265				prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;266 267			/* ... and send it */268			ret = qmc_audio_pcm_write_submit(prtd);269			if (ret)270				return ret;271		} else {272			for (i = 0; i < prtd->channels; i++)273				prtd->qmc_dai->chans[i].prtd_rx = prtd;274 275			/* Submit first chunk ... */276			ret = qmc_audio_pcm_read_submit(prtd);277			if (ret)278				return ret;279 280			/* ... prepare next one ... */281			prtd->ch_dma_addr_current += prtd->ch_dma_size;282			if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end)283				prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;284 285			/* ... and send it */286			ret = qmc_audio_pcm_read_submit(prtd);287			if (ret)288				return ret;289		}290		break;291 292	case SNDRV_PCM_TRIGGER_RESUME:293	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:294		break;295 296	case SNDRV_PCM_TRIGGER_STOP:297	case SNDRV_PCM_TRIGGER_SUSPEND:298	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:299		break;300 301	default:302		return -EINVAL;303	}304 305	return 0;306}307 308static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,309					       struct snd_pcm_substream *substream)310{311	struct qmc_dai_prtd *prtd = substream->runtime->private_data;312 313	return prtd->buffer_ended;314}315 316static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,317				       const struct of_phandle_args *args,318				       const char **dai_name)319{320	struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);321	struct snd_soc_dai_driver *dai_driver;322	int id = args->args[0];323	int i;324 325	for (i = 0; i  < qmc_audio->num_dais; i++) {326		dai_driver = qmc_audio->dai_drivers + i;327		if (dai_driver->id == id) {328			*dai_name = dai_driver->name;329			return 0;330		}331	}332 333	return -EINVAL;334}335 336static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {337	.info			= SNDRV_PCM_INFO_MMAP |338				  SNDRV_PCM_INFO_MMAP_VALID |339				  SNDRV_PCM_INFO_INTERLEAVED |340				  SNDRV_PCM_INFO_NONINTERLEAVED |341				  SNDRV_PCM_INFO_PAUSE,342	.period_bytes_min	= 32,343	.period_bytes_max	= 64 * 1024,344	.periods_min		= 2,345	.periods_max		= 2 * 1024,346	.buffer_bytes_max	= 64 * 1024,347};348 349static int qmc_audio_pcm_open(struct snd_soc_component *component,350			      struct snd_pcm_substream *substream)351{352	struct snd_pcm_runtime *runtime = substream->runtime;353	struct qmc_dai_prtd *prtd;354	int ret;355 356	snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);357 358	/* ensure that buffer size is a multiple of period size */359	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);360	if (ret < 0)361		return ret;362 363	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);364	if (!prtd)365		return -ENOMEM;366 367	runtime->private_data = prtd;368 369	return 0;370}371 372static int qmc_audio_pcm_close(struct snd_soc_component *component,373			       struct snd_pcm_substream *substream)374{375	struct qmc_dai_prtd *prtd = substream->runtime->private_data;376 377	kfree(prtd);378	return 0;379}380 381static const struct snd_soc_component_driver qmc_audio_soc_platform = {382	.open			= qmc_audio_pcm_open,383	.close			= qmc_audio_pcm_close,384	.hw_params		= qmc_audio_pcm_hw_params,385	.trigger		= qmc_audio_pcm_trigger,386	.pointer		= qmc_audio_pcm_pointer,387	.pcm_construct		= qmc_audio_pcm_construct,388	.of_xlate_dai_name	= qmc_audio_of_xlate_dai_name,389};390 391static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)392{393	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);394 395	return dai->driver - qmc_audio->dai_drivers;396}397 398static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)399{400	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);401	unsigned int index;402 403	index = qmc_dai_get_index(dai);404	if (index > qmc_audio->num_dais)405		return NULL;406 407	return qmc_audio->dais + index;408}409 410/*411 * The constraints for format/channel is to match with the number of 8bit412 * time-slots available.413 */414static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_dai,415					      struct snd_pcm_hw_params *params,416					      unsigned int nb_ts)417{418	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);419	snd_pcm_format_t format = params_format(params);420	struct snd_interval ch = {0};421 422	switch (snd_pcm_format_physical_width(format)) {423	case 8:424		ch.max = nb_ts;425		break;426	case 16:427		ch.max = nb_ts / 2;428		break;429	case 32:430		ch.max = nb_ts / 4;431		break;432	case 64:433		ch.max = nb_ts / 8;434		break;435	default:436		dev_err(qmc_dai->dev, "format physical width %u not supported\n",437			snd_pcm_format_physical_width(format));438		return -EINVAL;439	}440 441	ch.min = ch.max ? 1 : 0;442 443	return snd_interval_refine(c, &ch);444}445 446static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,447						       struct snd_pcm_hw_rule *rule)448{449	struct qmc_dai *qmc_dai = rule->private;450 451	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);452}453 454static int qmc_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,455						      struct snd_pcm_hw_rule *rule)456{457	struct qmc_dai *qmc_dai = rule->private;458 459	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);460}461 462static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,463					      struct snd_pcm_hw_params *params,464					      unsigned int nb_ts)465{466	struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);467	unsigned int channels = params_channels(params);468	unsigned int slot_width;469	snd_pcm_format_t format;470	struct snd_mask f_new;471 472	if (!channels || channels > nb_ts) {473		dev_err(qmc_dai->dev, "channels %u not supported\n",474			nb_ts);475		return -EINVAL;476	}477 478	slot_width = (nb_ts / channels) * 8;479 480	snd_mask_none(&f_new);481	pcm_for_each_format(format) {482		if (snd_mask_test_format(f_old, format)) {483			if (snd_pcm_format_physical_width(format) <= slot_width)484				snd_mask_set_format(&f_new, format);485		}486	}487 488	return snd_mask_refine(f_old, &f_new);489}490 491static int qmc_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,492						       struct snd_pcm_hw_rule *rule)493{494	struct qmc_dai *qmc_dai = rule->private;495 496	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);497}498 499static int qmc_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,500						      struct snd_pcm_hw_rule *rule)501{502	struct qmc_dai *qmc_dai = rule->private;503 504	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);505}506 507static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,508					   struct qmc_dai *qmc_dai)509{510	snd_pcm_hw_rule_func_t hw_rule_channels_by_format;511	snd_pcm_hw_rule_func_t hw_rule_format_by_channels;512	unsigned int frame_bits;513	u64 access;514	int ret;515 516	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {517		hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;518		hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;519		frame_bits = qmc_dai->nb_rx_ts * 8;520	} else {521		hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;522		hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;523		frame_bits = qmc_dai->nb_tx_ts * 8;524	}525 526	ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,527				  hw_rule_channels_by_format, qmc_dai,528				  SNDRV_PCM_HW_PARAM_FORMAT, -1);529	if (ret) {530		dev_err(qmc_dai->dev, "Failed to add channels rule (%d)\n", ret);531		return ret;532	}533 534	ret = snd_pcm_hw_rule_add(substream->runtime, 0,  SNDRV_PCM_HW_PARAM_FORMAT,535				  hw_rule_format_by_channels, qmc_dai,536				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);537	if (ret) {538		dev_err(qmc_dai->dev, "Failed to add format rule (%d)\n", ret);539		return ret;540	}541 542	ret = snd_pcm_hw_constraint_single(substream->runtime,543					   SNDRV_PCM_HW_PARAM_FRAME_BITS,544					   frame_bits);545	if (ret < 0) {546		dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);547		return ret;548	}549 550	access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |551		 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;552	ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,553					   access);554	if (ret) {555		dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);556		return ret;557	}558 559	return 0;560}561 562static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substream,563					      struct qmc_dai *qmc_dai)564{565	unsigned int frame_bits;566	u64 access;567	int ret;568 569	frame_bits = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ?570			qmc_dai->nb_rx_ts * 8 : qmc_dai->nb_tx_ts * 8;571	ret = snd_pcm_hw_constraint_single(substream->runtime,572					   SNDRV_PCM_HW_PARAM_FRAME_BITS,573					   frame_bits);574	if (ret < 0) {575		dev_err(qmc_dai->dev, "Failed to add frame_bits constraint (%d)\n", ret);576		return ret;577	}578 579	access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |580		 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;581	ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,582					   access);583	if (ret) {584		dev_err(qmc_dai->dev, "Failed to add hw_param_access constraint (%d)\n", ret);585		return ret;586	}587 588	return 0;589}590 591static int qmc_dai_startup(struct snd_pcm_substream *substream,592			   struct snd_soc_dai *dai)593{594	struct qmc_dai_prtd *prtd = substream->runtime->private_data;595	struct qmc_dai *qmc_dai;596 597	qmc_dai = qmc_dai_get_data(dai);598	if (!qmc_dai) {599		dev_err(dai->dev, "Invalid dai\n");600		return -EINVAL;601	}602 603	prtd->qmc_dai = qmc_dai;604 605	return qmc_dai->nb_chans_avail > 1 ?606		qmc_dai_constraints_noninterleaved(substream, qmc_dai) :607		qmc_dai_constraints_interleaved(substream, qmc_dai);608}609 610static int qmc_dai_hw_params(struct snd_pcm_substream *substream,611			     struct snd_pcm_hw_params *params,612			     struct snd_soc_dai *dai)613{614	struct qmc_chan_param chan_param = {0};615	unsigned int nb_chans_used;616	struct qmc_dai *qmc_dai;617	unsigned int i;618	int ret;619 620	qmc_dai = qmc_dai_get_data(dai);621	if (!qmc_dai) {622		dev_err(dai->dev, "Invalid dai\n");623		return -EINVAL;624	}625 626	/*627	 * In interleaved mode, the driver uses one QMC channel for all audio628	 * channels whereas in non-interleaved mode, it uses one QMC channel per629	 * audio channel.630	 */631	nb_chans_used = qmc_audio_access_is_interleaved(params_access(params)) ?632				1 : params_channels(params);633 634	if (nb_chans_used > qmc_dai->nb_chans_avail) {635		dev_err(dai->dev, "Not enough qmc_chans. Need %u, avail %u\n",636			nb_chans_used, qmc_dai->nb_chans_avail);637		return -EINVAL;638	}639 640	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {641		chan_param.mode = QMC_TRANSPARENT;642		chan_param.transp.max_rx_buf_size = params_period_bytes(params) / nb_chans_used;643		for (i = 0; i < nb_chans_used; i++) {644			ret = qmc_chan_set_param(qmc_dai->chans[i].qmc_chan, &chan_param);645			if (ret) {646				dev_err(dai->dev, "chans[%u], set param failed %d\n",647					i, ret);648				return ret;649			}650		}651		qmc_dai->nb_chans_used_rx = nb_chans_used;652	} else {653		qmc_dai->nb_chans_used_tx = nb_chans_used;654	}655 656	return 0;657}658 659static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,660			   struct snd_soc_dai *dai)661{662	unsigned int nb_chans_used;663	struct qmc_dai *qmc_dai;664	unsigned int i;665	int direction;666	int ret = 0;667	int ret_tmp;668 669	qmc_dai = qmc_dai_get_data(dai);670	if (!qmc_dai) {671		dev_err(dai->dev, "Invalid dai\n");672		return -EINVAL;673	}674 675	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {676		direction = QMC_CHAN_WRITE;677		nb_chans_used = qmc_dai->nb_chans_used_tx;678	} else {679		direction = QMC_CHAN_READ;680		nb_chans_used = qmc_dai->nb_chans_used_rx;681	}682 683	switch (cmd) {684	case SNDRV_PCM_TRIGGER_START:685	case SNDRV_PCM_TRIGGER_RESUME:686	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:687		for (i = 0; i < nb_chans_used; i++) {688			ret = qmc_chan_start(qmc_dai->chans[i].qmc_chan, direction);689			if (ret)690				goto err_stop;691		}692		break;693 694	case SNDRV_PCM_TRIGGER_STOP:695		/* Stop and reset all QMC channels and return the first error encountered */696		for (i = 0; i < nb_chans_used; i++) {697			ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);698			if (!ret)699				ret = ret_tmp;700			if (ret_tmp)701				continue;702 703			ret_tmp = qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);704			if (!ret)705				ret = ret_tmp;706		}707		if (ret)708			return ret;709		break;710 711	case SNDRV_PCM_TRIGGER_SUSPEND:712	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:713		/* Stop all QMC channels and return the first error encountered */714		for (i = 0; i < nb_chans_used; i++) {715			ret_tmp = qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);716			if (!ret)717				ret = ret_tmp;718		}719		if (ret)720			return ret;721		break;722 723	default:724		return -EINVAL;725	}726 727	return 0;728 729err_stop:730	while (i--) {731		qmc_chan_stop(qmc_dai->chans[i].qmc_chan, direction);732		qmc_chan_reset(qmc_dai->chans[i].qmc_chan, direction);733	}734	return ret;735}736 737static const struct snd_soc_dai_ops qmc_dai_ops = {738	.startup	= qmc_dai_startup,739	.trigger	= qmc_dai_trigger,740	.hw_params	= qmc_dai_hw_params,741};742 743static u64 qmc_audio_formats(u8 nb_ts, bool is_noninterleaved)744{745	unsigned int format_width;746	unsigned int chan_width;747	snd_pcm_format_t format;748	u64 formats_mask;749 750	if (!nb_ts)751		return 0;752 753	formats_mask = 0;754	chan_width = nb_ts * 8;755	pcm_for_each_format(format) {756		/*757		 * Support format other than little-endian (ie big-endian or758		 * without endianness such as 8bit formats)759		 */760		if (snd_pcm_format_little_endian(format) == 1)761			continue;762 763		/* Support physical width multiple of 8bit */764		format_width = snd_pcm_format_physical_width(format);765		if (format_width == 0 || format_width % 8)766			continue;767 768		/*769		 * And support physical width that can fit N times in the770		 * channel771		 */772		if (format_width > chan_width || chan_width % format_width)773			continue;774 775		/*776		 * In non interleaved mode, we can only support formats that777		 * can fit only 1 time in the channel778		 */779		if (is_noninterleaved && format_width != chan_width)780			continue;781 782		formats_mask |= pcm_format_to_bits(format);783	}784	return formats_mask;785}786 787static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,788			       struct qmc_dai *qmc_dai,789			       struct snd_soc_dai_driver *qmc_soc_dai_driver)790{791	struct qmc_chan_info info;792	unsigned long rx_fs_rate;793	unsigned long tx_fs_rate;794	unsigned int nb_tx_ts;795	unsigned int nb_rx_ts;796	unsigned int i;797	int count;798	u32 val;799	int ret;800 801	qmc_dai->dev = qmc_audio->dev;802 803	ret = of_property_read_u32(np, "reg", &val);804	if (ret) {805		dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);806		return ret;807	}808	qmc_dai->id = val;809 810	qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",811				       np->parent->name, qmc_dai->id);812	if (!qmc_dai->name)813		return -ENOMEM;814 815	count = qmc_chan_count_phandles(np, "fsl,qmc-chan");816	if (count < 0)817		return dev_err_probe(qmc_audio->dev, count,818				     "dai %d get number of QMC channel failed\n", qmc_dai->id);819	if (!count)820		return dev_err_probe(qmc_audio->dev, -EINVAL,821				     "dai %d no QMC channel defined\n", qmc_dai->id);822 823	qmc_dai->chans = devm_kcalloc(qmc_audio->dev, count, sizeof(*qmc_dai->chans), GFP_KERNEL);824	if (!qmc_dai->chans)825		return -ENOMEM;826 827	for (i = 0; i < count; i++) {828		qmc_dai->chans[i].qmc_chan = devm_qmc_chan_get_byphandles_index(qmc_audio->dev, np,829										"fsl,qmc-chan", i);830		if (IS_ERR(qmc_dai->chans[i].qmc_chan)) {831			return dev_err_probe(qmc_audio->dev, PTR_ERR(qmc_dai->chans[i].qmc_chan),832					     "dai %d get QMC channel %d failed\n", qmc_dai->id, i);833		}834 835		ret = qmc_chan_get_info(qmc_dai->chans[i].qmc_chan, &info);836		if (ret) {837			dev_err(qmc_audio->dev, "dai %d get QMC %d channel info failed %d\n",838				qmc_dai->id, i, ret);839			return ret;840		}841		dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n",842			 qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts);843 844		if (info.mode != QMC_TRANSPARENT) {845			dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n",846				qmc_dai->id, i, info.mode);847			return -EINVAL;848		}849 850		/*851		 * All channels must have the same number of Tx slots and the852		 * same numbers of Rx slots.853		 */854		if (i == 0) {855			nb_tx_ts = info.nb_tx_ts;856			nb_rx_ts = info.nb_rx_ts;857			tx_fs_rate = info.tx_fs_rate;858			rx_fs_rate = info.rx_fs_rate;859		} else {860			if (nb_tx_ts != info.nb_tx_ts) {861				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Tx timeslots (%u instead of %u)\n",862					qmc_dai->id, i, info.nb_tx_ts, nb_tx_ts);863				return -EINVAL;864			}865			if (nb_rx_ts != info.nb_rx_ts) {866				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent number of Rx timeslots (%u instead of %u)\n",867					qmc_dai->id, i, info.nb_rx_ts, nb_rx_ts);868				return -EINVAL;869			}870			if (tx_fs_rate != info.tx_fs_rate) {871				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Tx frame sample rate (%lu instead of %lu)\n",872					qmc_dai->id, i, info.tx_fs_rate, tx_fs_rate);873				return -EINVAL;874			}875			if (rx_fs_rate != info.rx_fs_rate) {876				dev_err(qmc_audio->dev, "dai %d QMC chan %d inconsistent Rx frame sample rate (%lu instead of %lu)\n",877					qmc_dai->id, i, info.rx_fs_rate, rx_fs_rate);878				return -EINVAL;879			}880		}881	}882 883	qmc_dai->nb_chans_avail = count;884	qmc_dai->nb_tx_ts = nb_tx_ts * count;885	qmc_dai->nb_rx_ts = nb_rx_ts * count;886 887	qmc_soc_dai_driver->id = qmc_dai->id;888	qmc_soc_dai_driver->name = qmc_dai->name;889 890	qmc_soc_dai_driver->playback.channels_min = 0;891	qmc_soc_dai_driver->playback.channels_max = 0;892	if (nb_tx_ts) {893		qmc_soc_dai_driver->playback.channels_min = 1;894		qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;895	}896	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,897								 count > 1 ? true : false);898 899	qmc_soc_dai_driver->capture.channels_min = 0;900	qmc_soc_dai_driver->capture.channels_max = 0;901	if (nb_rx_ts) {902		qmc_soc_dai_driver->capture.channels_min = 1;903		qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;904	}905	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,906								count > 1 ? true : false);907 908	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate);909	qmc_soc_dai_driver->playback.rate_min = tx_fs_rate;910	qmc_soc_dai_driver->playback.rate_max = tx_fs_rate;911	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(rx_fs_rate);912	qmc_soc_dai_driver->capture.rate_min = rx_fs_rate;913	qmc_soc_dai_driver->capture.rate_max = rx_fs_rate;914 915	qmc_soc_dai_driver->ops = &qmc_dai_ops;916 917	return 0;918}919 920static int qmc_audio_probe(struct platform_device *pdev)921{922	struct device_node *np = pdev->dev.of_node;923	struct qmc_audio *qmc_audio;924	struct device_node *child;925	unsigned int i;926	int ret;927 928	qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);929	if (!qmc_audio)930		return -ENOMEM;931 932	qmc_audio->dev = &pdev->dev;933 934	qmc_audio->num_dais = of_get_available_child_count(np);935	if (qmc_audio->num_dais) {936		qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,937					       sizeof(*qmc_audio->dais),938					       GFP_KERNEL);939		if (!qmc_audio->dais)940			return -ENOMEM;941 942		qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,943						      sizeof(*qmc_audio->dai_drivers),944						      GFP_KERNEL);945		if (!qmc_audio->dai_drivers)946			return -ENOMEM;947	}948 949	i = 0;950	for_each_available_child_of_node(np, child) {951		ret = qmc_audio_dai_parse(qmc_audio, child,952					  qmc_audio->dais + i,953					  qmc_audio->dai_drivers + i);954		if (ret) {955			of_node_put(child);956			return ret;957		}958		i++;959	}960 961	platform_set_drvdata(pdev, qmc_audio);962 963	ret = devm_snd_soc_register_component(qmc_audio->dev,964					      &qmc_audio_soc_platform,965					      qmc_audio->dai_drivers,966					      qmc_audio->num_dais);967	if (ret)968		return ret;969 970	return 0;971}972 973static const struct of_device_id qmc_audio_id_table[] = {974	{ .compatible = "fsl,qmc-audio" },975	{} /* sentinel */976};977MODULE_DEVICE_TABLE(of, qmc_audio_id_table);978 979static struct platform_driver qmc_audio_driver = {980	.driver = {981		.name = "fsl-qmc-audio",982		.of_match_table = of_match_ptr(qmc_audio_id_table),983	},984	.probe = qmc_audio_probe,985};986module_platform_driver(qmc_audio_driver);987 988MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");989MODULE_DESCRIPTION("CPM/QE QMC audio driver");990MODULE_LICENSE("GPL");991