Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// Socionext UniPhier AIO Compress Audio driver.
  4//
  5// Copyright (c) 2017-2018 Socionext Inc.
 
 
 
 
 
 
 
 
 
 
 
 
 
  6
  7#include <linux/bitfield.h>
  8#include <linux/circ_buf.h>
  9#include <linux/dma-mapping.h>
 10#include <linux/errno.h>
 11#include <linux/kernel.h>
 12#include <linux/module.h>
 13#include <sound/core.h>
 14#include <sound/pcm.h>
 15#include <sound/soc.h>
 16
 17#include "aio.h"
 18
 19static int uniphier_aio_compr_prepare(struct snd_soc_component *component,
 20				      struct snd_compr_stream *cstream);
 21static int uniphier_aio_compr_hw_free(struct snd_soc_component *component,
 22				      struct snd_compr_stream *cstream);
 23
 24static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
 25{
 26	struct snd_compr *compr = rtd->compr;
 27	struct device *dev = compr->card->dev;
 28	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 29	struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
 30	size_t size = AUD_RING_SIZE;
 31	int dma_dir = DMA_FROM_DEVICE, ret;
 32
 33	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
 34	if (ret)
 35		return ret;
 36
 37	sub->compr_area = kzalloc(size, GFP_KERNEL);
 38	if (!sub->compr_area)
 39		return -ENOMEM;
 40
 41	if (sub->swm->dir == PORT_DIR_OUTPUT)
 42		dma_dir = DMA_TO_DEVICE;
 43
 44	sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir);
 45	if (dma_mapping_error(dev, sub->compr_addr)) {
 46		kfree(sub->compr_area);
 47		sub->compr_area = NULL;
 48
 49		return -ENOMEM;
 50	}
 51
 52	sub->compr_bytes = size;
 53
 54	return 0;
 55}
 56
 57static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
 58{
 59	struct snd_compr *compr = rtd->compr;
 60	struct device *dev = compr->card->dev;
 61	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 62	struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
 63	int dma_dir = DMA_FROM_DEVICE;
 64
 65	if (sub->swm->dir == PORT_DIR_OUTPUT)
 66		dma_dir = DMA_TO_DEVICE;
 67
 68	dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir);
 69	kfree(sub->compr_area);
 70	sub->compr_area = NULL;
 71
 72	return 0;
 73}
 74
 75static int uniphier_aio_compr_open(struct snd_soc_component *component,
 76				   struct snd_compr_stream *cstream)
 77{
 78	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 79	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 80	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 81	int ret;
 82
 83	if (sub->cstream)
 84		return -EBUSY;
 85
 86	sub->cstream = cstream;
 87	sub->pass_through = 1;
 88	sub->use_mmap = false;
 89
 90	ret = uniphier_aio_comprdma_new(rtd);
 91	if (ret)
 92		return ret;
 93
 94	ret = aio_init(sub);
 95	if (ret)
 96		return ret;
 97
 98	return 0;
 99}
100
101static int uniphier_aio_compr_free(struct snd_soc_component *component,
102				   struct snd_compr_stream *cstream)
103{
104	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
105	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
106	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
107	int ret;
108
109	ret = uniphier_aio_compr_hw_free(component, cstream);
110	if (ret)
111		return ret;
112	ret = uniphier_aio_comprdma_free(rtd);
113	if (ret)
114		return ret;
115
116	sub->cstream = NULL;
117
118	return 0;
119}
120
121static int uniphier_aio_compr_get_params(struct snd_soc_component *component,
122					 struct snd_compr_stream *cstream,
123					 struct snd_codec *params)
124{
125	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
126	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
127	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
128
129	*params = sub->cparams.codec;
130
131	return 0;
132}
133
134static int uniphier_aio_compr_set_params(struct snd_soc_component *component,
135					 struct snd_compr_stream *cstream,
136					 struct snd_compr_params *params)
137{
138	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
139	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
140	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
141	struct device *dev = &aio->chip->pdev->dev;
 
142
143	if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
144		dev_err(dev, "Codec ID is not supported(%d)\n",
145			params->codec.id);
146		return -EINVAL;
147	}
148	if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
149		dev_err(dev, "Codec profile is not supported(%d)\n",
150			params->codec.profile);
151		return -EINVAL;
152	}
153
154	/* IEC frame type will be changed after received valid data */
155	sub->iec_pc = IEC61937_PC_AAC;
156
157	sub->cparams = *params;
158	sub->setting = 1;
159
160	aio_port_reset(sub);
161	aio_src_reset(sub);
162
163	return uniphier_aio_compr_prepare(component, cstream);
 
 
 
 
164}
165
166static int uniphier_aio_compr_hw_free(struct snd_soc_component *component,
167				      struct snd_compr_stream *cstream)
168{
169	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
170	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
171	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
172
173	sub->setting = 0;
174
175	return 0;
176}
177
178static int uniphier_aio_compr_prepare(struct snd_soc_component *component,
179				      struct snd_compr_stream *cstream)
180{
181	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
182	struct snd_compr_runtime *runtime = cstream->runtime;
183	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
184	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
185	int bytes = runtime->fragment_size;
186	unsigned long flags;
187	int ret;
188
189	ret = aiodma_ch_set_param(sub);
190	if (ret)
191		return ret;
192
193	spin_lock_irqsave(&sub->lock, flags);
194	ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
195				   sub->compr_addr + sub->compr_bytes,
196				   bytes);
197	spin_unlock_irqrestore(&sub->lock, flags);
198	if (ret)
199		return ret;
200
201	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
202	if (ret)
203		return ret;
204	ret = aio_oport_set_stream_type(sub, sub->iec_pc);
205	if (ret)
206		return ret;
207	aio_port_set_enable(sub, 1);
208
209	ret = aio_if_set_param(sub, sub->pass_through);
210	if (ret)
211		return ret;
212
213	return 0;
214}
215
216static int uniphier_aio_compr_trigger(struct snd_soc_component *component,
217				      struct snd_compr_stream *cstream,
218				      int cmd)
219{
220	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
221	struct snd_compr_runtime *runtime = cstream->runtime;
222	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
223	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
224	struct device *dev = &aio->chip->pdev->dev;
225	int bytes = runtime->fragment_size, ret = 0;
226	unsigned long flags;
227
228	spin_lock_irqsave(&sub->lock, flags);
229	switch (cmd) {
230	case SNDRV_PCM_TRIGGER_START:
231		aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
232		aiodma_ch_set_enable(sub, 1);
233		sub->running = 1;
234
235		break;
236	case SNDRV_PCM_TRIGGER_STOP:
237		sub->running = 0;
238		aiodma_ch_set_enable(sub, 0);
239
240		break;
241	default:
242		dev_warn(dev, "Unknown trigger(%d)\n", cmd);
243		ret = -EINVAL;
244	}
245	spin_unlock_irqrestore(&sub->lock, flags);
246
247	return ret;
248}
249
250static int uniphier_aio_compr_pointer(struct snd_soc_component *component,
251				      struct snd_compr_stream *cstream,
252				      struct snd_compr_tstamp *tstamp)
253{
254	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
255	struct snd_compr_runtime *runtime = cstream->runtime;
256	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
257	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
258	int bytes = runtime->fragment_size;
259	unsigned long flags;
260	u32 pos;
261
262	spin_lock_irqsave(&sub->lock, flags);
263
264	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
265
266	if (sub->swm->dir == PORT_DIR_OUTPUT) {
267		pos = sub->rd_offs;
268		/* Size of AIO output format is double of IEC61937 */
269		tstamp->copied_total = sub->rd_total / 2;
270	} else {
271		pos = sub->wr_offs;
272		tstamp->copied_total = sub->rd_total;
273	}
274	tstamp->byte_offset = pos;
275
276	spin_unlock_irqrestore(&sub->lock, flags);
277
278	return 0;
279}
280
281static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
282				char __user *buf, size_t dstsize)
283{
284	u32 __user *srcbuf = (u32 __user *)buf;
285	u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
286	int src = 0, dst = 0, ret;
287	u32 frm, frm_a, frm_b;
288
289	while (dstsize > 0) {
290		ret = get_user(frm, srcbuf + src);
291		if (ret)
292			return ret;
293		src++;
294
295		frm_a = frm & 0xffff;
296		frm_b = (frm >> 16) & 0xffff;
297
298		if (frm == IEC61937_HEADER_SIGN) {
299			frm_a |= 0x01000000;
300
301			/* Next data is Pc and Pd */
302			sub->iec_header = true;
303		} else {
304			u16 pc = be16_to_cpu((__be16)frm_a);
305
306			if (sub->iec_header && sub->iec_pc != pc) {
307				/* Force overwrite IEC frame type */
308				sub->iec_pc = pc;
309				ret = aio_oport_set_stream_type(sub, pc);
310				if (ret)
311					return ret;
312			}
313			sub->iec_header = false;
314		}
315		dstbuf[dst++] = frm_a;
316		dstbuf[dst++] = frm_b;
317
318		dstsize -= sizeof(u32) * 2;
319	}
320
321	return 0;
322}
323
324static int uniphier_aio_compr_copy(struct snd_soc_component *component,
325				   struct snd_compr_stream *cstream,
326				   char __user *buf, size_t count)
327{
328	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
329	struct snd_compr_runtime *runtime = cstream->runtime;
330	struct device *carddev = rtd->compr->card->dev;
331	struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
332	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
333	size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
334	int bytes = runtime->fragment_size;
335	unsigned long flags;
336	size_t s;
337	int ret;
338
339	if (cnt < sizeof(u32))
340		return 0;
341
342	if (sub->swm->dir == PORT_DIR_OUTPUT) {
343		dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
344
345		/* Size of AIO output format is double of IEC61937 */
346		s = cnt * 2;
347
348		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
349		ret = aio_compr_send_to_hw(sub, buf, s);
350		dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
351	} else {
352		dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
353
354		s = cnt;
355
356		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
357		ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
358		dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
359	}
360	if (ret)
361		return -EFAULT;
362
363	spin_lock_irqsave(&sub->lock, flags);
364
365	sub->threshold = 2 * bytes;
366	aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
367
368	if (sub->swm->dir == PORT_DIR_OUTPUT) {
369		sub->wr_offs += s;
370		if (sub->wr_offs >= sub->compr_bytes)
371			sub->wr_offs -= sub->compr_bytes;
372	} else {
373		sub->rd_offs += s;
374		if (sub->rd_offs >= sub->compr_bytes)
375			sub->rd_offs -= sub->compr_bytes;
376	}
377	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
378
379	spin_unlock_irqrestore(&sub->lock, flags);
380
381	return cnt;
382}
383
384static int uniphier_aio_compr_get_caps(struct snd_soc_component *component,
385				       struct snd_compr_stream *cstream,
386				       struct snd_compr_caps *caps)
387{
388	caps->num_codecs = 1;
389	caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
390	caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
391	caps->min_fragments = AUD_MIN_FRAGMENT;
392	caps->max_fragments = AUD_MAX_FRAGMENT;
393	caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
394
395	return 0;
396}
397
398static const struct snd_compr_codec_caps caps_iec = {
399	.num_descriptors = 1,
400	.descriptor[0].max_ch = 8,
401	.descriptor[0].num_sample_rates = 0,
402	.descriptor[0].num_bitrates = 0,
403	.descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
404	.descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
405				SND_AUDIOMODE_IEC_MPEG1 |
406				SND_AUDIOMODE_IEC_MP3 |
407				SND_AUDIOMODE_IEC_DTS,
408	.descriptor[0].formats = 0,
409};
410
411static int uniphier_aio_compr_get_codec_caps(struct snd_soc_component *component,
412					     struct snd_compr_stream *stream,
413					     struct snd_compr_codec_caps *codec)
414{
415	if (codec->codec == SND_AUDIOCODEC_IEC61937)
416		*codec = caps_iec;
417	else
418		return -EINVAL;
419
420	return 0;
421}
422
423const struct snd_compress_ops uniphier_aio_compress_ops = {
424	.open           = uniphier_aio_compr_open,
425	.free           = uniphier_aio_compr_free,
426	.get_params     = uniphier_aio_compr_get_params,
427	.set_params     = uniphier_aio_compr_set_params,
428	.trigger        = uniphier_aio_compr_trigger,
429	.pointer        = uniphier_aio_compr_pointer,
430	.copy           = uniphier_aio_compr_copy,
431	.get_caps       = uniphier_aio_compr_get_caps,
432	.get_codec_caps = uniphier_aio_compr_get_codec_caps,
433};
v4.17
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// Socionext UniPhier AIO Compress Audio driver.
  4//
  5// Copyright (c) 2017-2018 Socionext Inc.
  6//
  7// This program is free software; you can redistribute it and/or
  8// modify it under the terms of the GNU General Public License
  9// as published by the Free Software Foundation; version 2
 10// of the License.
 11//
 12// This program is distributed in the hope that it will be useful,
 13// but WITHOUT ANY WARRANTY; without even the implied warranty of
 14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15// GNU General Public License for more details.
 16//
 17// You should have received a copy of the GNU General Public License
 18// along with this program; if not, see <http://www.gnu.org/licenses/>.
 19
 20#include <linux/bitfield.h>
 21#include <linux/circ_buf.h>
 22#include <linux/dma-mapping.h>
 23#include <linux/errno.h>
 24#include <linux/kernel.h>
 25#include <linux/module.h>
 26#include <sound/core.h>
 27#include <sound/pcm.h>
 28#include <sound/soc.h>
 29
 30#include "aio.h"
 31
 32static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream);
 33static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream);
 
 
 34
 35static int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd)
 36{
 37	struct snd_compr *compr = rtd->compr;
 38	struct device *dev = compr->card->dev;
 39	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 40	struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
 41	size_t size = AUD_RING_SIZE;
 42	int dma_dir = DMA_FROM_DEVICE, ret;
 43
 44	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
 45	if (ret)
 46		return ret;
 47
 48	sub->compr_area = kzalloc(size, GFP_KERNEL);
 49	if (!sub->compr_area)
 50		return -ENOMEM;
 51
 52	if (sub->swm->dir == PORT_DIR_OUTPUT)
 53		dma_dir = DMA_TO_DEVICE;
 54
 55	sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir);
 56	if (dma_mapping_error(dev, sub->compr_addr)) {
 57		kfree(sub->compr_area);
 58		sub->compr_area = NULL;
 59
 60		return -ENOMEM;
 61	}
 62
 63	sub->compr_bytes = size;
 64
 65	return 0;
 66}
 67
 68static int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd)
 69{
 70	struct snd_compr *compr = rtd->compr;
 71	struct device *dev = compr->card->dev;
 72	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 73	struct uniphier_aio_sub *sub = &aio->sub[compr->direction];
 74	int dma_dir = DMA_FROM_DEVICE;
 75
 76	if (sub->swm->dir == PORT_DIR_OUTPUT)
 77		dma_dir = DMA_TO_DEVICE;
 78
 79	dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir);
 80	kfree(sub->compr_area);
 81	sub->compr_area = NULL;
 82
 83	return 0;
 84}
 85
 86static int uniphier_aio_compr_open(struct snd_compr_stream *cstream)
 
 87{
 88	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 89	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
 90	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 91	int ret;
 92
 93	if (sub->cstream)
 94		return -EBUSY;
 95
 96	sub->cstream = cstream;
 97	sub->pass_through = 1;
 98	sub->use_mmap = false;
 99
100	ret = uniphier_aio_comprdma_new(rtd);
101	if (ret)
102		return ret;
103
104	ret = aio_init(sub);
105	if (ret)
106		return ret;
107
108	return 0;
109}
110
111static int uniphier_aio_compr_free(struct snd_compr_stream *cstream)
 
112{
113	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
114	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
115	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
116	int ret;
117
118	ret = uniphier_aio_compr_hw_free(cstream);
119	if (ret)
120		return ret;
121	ret = uniphier_aio_comprdma_free(rtd);
122	if (ret)
123		return ret;
124
125	sub->cstream = NULL;
126
127	return 0;
128}
129
130static int uniphier_aio_compr_get_params(struct snd_compr_stream *cstream,
 
131					 struct snd_codec *params)
132{
133	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
134	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
135	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
136
137	*params = sub->cparams.codec;
138
139	return 0;
140}
141
142static int uniphier_aio_compr_set_params(struct snd_compr_stream *cstream,
 
143					 struct snd_compr_params *params)
144{
145	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
146	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
147	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
148	struct device *dev = &aio->chip->pdev->dev;
149	int ret;
150
151	if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
152		dev_err(dev, "Codec ID is not supported(%d)\n",
153			params->codec.id);
154		return -EINVAL;
155	}
156	if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
157		dev_err(dev, "Codec profile is not supported(%d)\n",
158			params->codec.profile);
159		return -EINVAL;
160	}
161
162	/* IEC frame type will be changed after received valid data */
163	sub->iec_pc = IEC61937_PC_AAC;
164
165	sub->cparams = *params;
166	sub->setting = 1;
167
168	aio_port_reset(sub);
169	aio_src_reset(sub);
170
171	ret = uniphier_aio_compr_prepare(cstream);
172	if (ret)
173		return ret;
174
175	return 0;
176}
177
178static int uniphier_aio_compr_hw_free(struct snd_compr_stream *cstream)
 
179{
180	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
181	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
182	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
183
184	sub->setting = 0;
185
186	return 0;
187}
188
189static int uniphier_aio_compr_prepare(struct snd_compr_stream *cstream)
 
190{
191	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
192	struct snd_compr_runtime *runtime = cstream->runtime;
193	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
194	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
195	int bytes = runtime->fragment_size;
196	unsigned long flags;
197	int ret;
198
199	ret = aiodma_ch_set_param(sub);
200	if (ret)
201		return ret;
202
203	spin_lock_irqsave(&sub->lock, flags);
204	ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
205				   sub->compr_addr + sub->compr_bytes,
206				   bytes);
207	spin_unlock_irqrestore(&sub->lock, flags);
208	if (ret)
209		return ret;
210
211	ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
212	if (ret)
213		return ret;
214	ret = aio_oport_set_stream_type(sub, sub->iec_pc);
215	if (ret)
216		return ret;
217	aio_port_set_enable(sub, 1);
218
219	ret = aio_if_set_param(sub, sub->pass_through);
220	if (ret)
221		return ret;
222
223	return 0;
224}
225
226static int uniphier_aio_compr_trigger(struct snd_compr_stream *cstream,
 
227				      int cmd)
228{
229	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
230	struct snd_compr_runtime *runtime = cstream->runtime;
231	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
232	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
233	struct device *dev = &aio->chip->pdev->dev;
234	int bytes = runtime->fragment_size, ret = 0;
235	unsigned long flags;
236
237	spin_lock_irqsave(&sub->lock, flags);
238	switch (cmd) {
239	case SNDRV_PCM_TRIGGER_START:
240		aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
241		aiodma_ch_set_enable(sub, 1);
242		sub->running = 1;
243
244		break;
245	case SNDRV_PCM_TRIGGER_STOP:
246		sub->running = 0;
247		aiodma_ch_set_enable(sub, 0);
248
249		break;
250	default:
251		dev_warn(dev, "Unknown trigger(%d)\n", cmd);
252		ret = -EINVAL;
253	}
254	spin_unlock_irqrestore(&sub->lock, flags);
255
256	return ret;
257}
258
259static int uniphier_aio_compr_pointer(struct snd_compr_stream *cstream,
 
260				      struct snd_compr_tstamp *tstamp)
261{
262	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
263	struct snd_compr_runtime *runtime = cstream->runtime;
264	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
265	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
266	int bytes = runtime->fragment_size;
267	unsigned long flags;
268	u32 pos;
269
270	spin_lock_irqsave(&sub->lock, flags);
271
272	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
273
274	if (sub->swm->dir == PORT_DIR_OUTPUT) {
275		pos = sub->rd_offs;
276		/* Size of AIO output format is double of IEC61937 */
277		tstamp->copied_total = sub->rd_total / 2;
278	} else {
279		pos = sub->wr_offs;
280		tstamp->copied_total = sub->rd_total;
281	}
282	tstamp->byte_offset = pos;
283
284	spin_unlock_irqrestore(&sub->lock, flags);
285
286	return 0;
287}
288
289static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
290				char __user *buf, size_t dstsize)
291{
292	u32 __user *srcbuf = (u32 __user *)buf;
293	u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
294	int src = 0, dst = 0, ret;
295	u32 frm, frm_a, frm_b;
296
297	while (dstsize > 0) {
298		ret = get_user(frm, srcbuf + src);
299		if (ret)
300			return ret;
301		src++;
302
303		frm_a = frm & 0xffff;
304		frm_b = (frm >> 16) & 0xffff;
305
306		if (frm == IEC61937_HEADER_SIGN) {
307			frm_a |= 0x01000000;
308
309			/* Next data is Pc and Pd */
310			sub->iec_header = true;
311		} else {
312			u16 pc = be16_to_cpu((__be16)frm_a);
313
314			if (sub->iec_header && sub->iec_pc != pc) {
315				/* Force overwrite IEC frame type */
316				sub->iec_pc = pc;
317				ret = aio_oport_set_stream_type(sub, pc);
318				if (ret)
319					return ret;
320			}
321			sub->iec_header = false;
322		}
323		dstbuf[dst++] = frm_a;
324		dstbuf[dst++] = frm_b;
325
326		dstsize -= sizeof(u32) * 2;
327	}
328
329	return 0;
330}
331
332static int uniphier_aio_compr_copy(struct snd_compr_stream *cstream,
 
333				   char __user *buf, size_t count)
334{
335	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
336	struct snd_compr_runtime *runtime = cstream->runtime;
337	struct device *carddev = rtd->compr->card->dev;
338	struct uniphier_aio *aio = uniphier_priv(rtd->cpu_dai);
339	struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
340	size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
341	int bytes = runtime->fragment_size;
342	unsigned long flags;
343	size_t s;
344	int ret;
345
346	if (cnt < sizeof(u32))
347		return 0;
348
349	if (sub->swm->dir == PORT_DIR_OUTPUT) {
350		dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
351
352		/* Size of AIO output format is double of IEC61937 */
353		s = cnt * 2;
354
355		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
356		ret = aio_compr_send_to_hw(sub, buf, s);
357		dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
358	} else {
359		dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
360
361		s = cnt;
362
363		dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
364		ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
365		dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
366	}
367	if (ret)
368		return -EFAULT;
369
370	spin_lock_irqsave(&sub->lock, flags);
371
372	sub->threshold = 2 * bytes;
373	aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
374
375	if (sub->swm->dir == PORT_DIR_OUTPUT) {
376		sub->wr_offs += s;
377		if (sub->wr_offs >= sub->compr_bytes)
378			sub->wr_offs -= sub->compr_bytes;
379	} else {
380		sub->rd_offs += s;
381		if (sub->rd_offs >= sub->compr_bytes)
382			sub->rd_offs -= sub->compr_bytes;
383	}
384	aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
385
386	spin_unlock_irqrestore(&sub->lock, flags);
387
388	return cnt;
389}
390
391static int uniphier_aio_compr_get_caps(struct snd_compr_stream *cstream,
 
392				       struct snd_compr_caps *caps)
393{
394	caps->num_codecs = 1;
395	caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
396	caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
397	caps->min_fragments = AUD_MIN_FRAGMENT;
398	caps->max_fragments = AUD_MAX_FRAGMENT;
399	caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
400
401	return 0;
402}
403
404static const struct snd_compr_codec_caps caps_iec = {
405	.num_descriptors = 1,
406	.descriptor[0].max_ch = 8,
407	.descriptor[0].num_sample_rates = 0,
408	.descriptor[0].num_bitrates = 0,
409	.descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
410	.descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
411				SND_AUDIOMODE_IEC_MPEG1 |
412				SND_AUDIOMODE_IEC_MP3 |
413				SND_AUDIOMODE_IEC_DTS,
414	.descriptor[0].formats = 0,
415};
416
417static int uniphier_aio_compr_get_codec_caps(struct snd_compr_stream *stream,
 
418					     struct snd_compr_codec_caps *codec)
419{
420	if (codec->codec == SND_AUDIOCODEC_IEC61937)
421		*codec = caps_iec;
422	else
423		return -EINVAL;
424
425	return 0;
426}
427
428const struct snd_compr_ops uniphier_aio_compr_ops = {
429	.open           = uniphier_aio_compr_open,
430	.free           = uniphier_aio_compr_free,
431	.get_params     = uniphier_aio_compr_get_params,
432	.set_params     = uniphier_aio_compr_set_params,
433	.trigger        = uniphier_aio_compr_trigger,
434	.pointer        = uniphier_aio_compr_pointer,
435	.copy           = uniphier_aio_compr_copy,
436	.get_caps       = uniphier_aio_compr_get_caps,
437	.get_codec_caps = uniphier_aio_compr_get_codec_caps,
438};