162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Socionext UniPhier AIO Compress Audio driver. 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2017-2018 Socionext Inc. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/bitfield.h> 862306a36Sopenharmony_ci#include <linux/circ_buf.h> 962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <sound/core.h> 1462306a36Sopenharmony_ci#include <sound/pcm.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "aio.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int uniphier_aio_compr_prepare(struct snd_soc_component *component, 2062306a36Sopenharmony_ci struct snd_compr_stream *cstream); 2162306a36Sopenharmony_cistatic int uniphier_aio_compr_hw_free(struct snd_soc_component *component, 2262306a36Sopenharmony_ci struct snd_compr_stream *cstream); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int uniphier_aio_comprdma_new(struct snd_soc_pcm_runtime *rtd) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct snd_compr *compr = rtd->compr; 2762306a36Sopenharmony_ci struct device *dev = compr->card->dev; 2862306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 2962306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[compr->direction]; 3062306a36Sopenharmony_ci size_t size = AUD_RING_SIZE; 3162306a36Sopenharmony_ci int dma_dir = DMA_FROM_DEVICE, ret; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33)); 3462306a36Sopenharmony_ci if (ret) 3562306a36Sopenharmony_ci return ret; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci sub->compr_area = kzalloc(size, GFP_KERNEL); 3862306a36Sopenharmony_ci if (!sub->compr_area) 3962306a36Sopenharmony_ci return -ENOMEM; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (sub->swm->dir == PORT_DIR_OUTPUT) 4262306a36Sopenharmony_ci dma_dir = DMA_TO_DEVICE; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci sub->compr_addr = dma_map_single(dev, sub->compr_area, size, dma_dir); 4562306a36Sopenharmony_ci if (dma_mapping_error(dev, sub->compr_addr)) { 4662306a36Sopenharmony_ci kfree(sub->compr_area); 4762306a36Sopenharmony_ci sub->compr_area = NULL; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return -ENOMEM; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci sub->compr_bytes = size; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int uniphier_aio_comprdma_free(struct snd_soc_pcm_runtime *rtd) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct snd_compr *compr = rtd->compr; 6062306a36Sopenharmony_ci struct device *dev = compr->card->dev; 6162306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 6262306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[compr->direction]; 6362306a36Sopenharmony_ci int dma_dir = DMA_FROM_DEVICE; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (sub->swm->dir == PORT_DIR_OUTPUT) 6662306a36Sopenharmony_ci dma_dir = DMA_TO_DEVICE; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci dma_unmap_single(dev, sub->compr_addr, sub->compr_bytes, dma_dir); 6962306a36Sopenharmony_ci kfree(sub->compr_area); 7062306a36Sopenharmony_ci sub->compr_area = NULL; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int uniphier_aio_compr_open(struct snd_soc_component *component, 7662306a36Sopenharmony_ci struct snd_compr_stream *cstream) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 7962306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 8062306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 8162306a36Sopenharmony_ci int ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (sub->cstream) 8462306a36Sopenharmony_ci return -EBUSY; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci sub->cstream = cstream; 8762306a36Sopenharmony_ci sub->pass_through = 1; 8862306a36Sopenharmony_ci sub->use_mmap = false; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = uniphier_aio_comprdma_new(rtd); 9162306a36Sopenharmony_ci if (ret) 9262306a36Sopenharmony_ci return ret; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ret = aio_init(sub); 9562306a36Sopenharmony_ci if (ret) 9662306a36Sopenharmony_ci return ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int uniphier_aio_compr_free(struct snd_soc_component *component, 10262306a36Sopenharmony_ci struct snd_compr_stream *cstream) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 10562306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 10662306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 10762306a36Sopenharmony_ci int ret; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci ret = uniphier_aio_compr_hw_free(component, cstream); 11062306a36Sopenharmony_ci if (ret) 11162306a36Sopenharmony_ci return ret; 11262306a36Sopenharmony_ci ret = uniphier_aio_comprdma_free(rtd); 11362306a36Sopenharmony_ci if (ret) 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci sub->cstream = NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int uniphier_aio_compr_get_params(struct snd_soc_component *component, 12262306a36Sopenharmony_ci struct snd_compr_stream *cstream, 12362306a36Sopenharmony_ci struct snd_codec *params) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 12662306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 12762306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci *params = sub->cparams.codec; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int uniphier_aio_compr_set_params(struct snd_soc_component *component, 13562306a36Sopenharmony_ci struct snd_compr_stream *cstream, 13662306a36Sopenharmony_ci struct snd_compr_params *params) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 13962306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 14062306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 14162306a36Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (params->codec.id != SND_AUDIOCODEC_IEC61937) { 14462306a36Sopenharmony_ci dev_err(dev, "Codec ID is not supported(%d)\n", 14562306a36Sopenharmony_ci params->codec.id); 14662306a36Sopenharmony_ci return -EINVAL; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) { 14962306a36Sopenharmony_ci dev_err(dev, "Codec profile is not supported(%d)\n", 15062306a36Sopenharmony_ci params->codec.profile); 15162306a36Sopenharmony_ci return -EINVAL; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* IEC frame type will be changed after received valid data */ 15562306a36Sopenharmony_ci sub->iec_pc = IEC61937_PC_AAC; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci sub->cparams = *params; 15862306a36Sopenharmony_ci sub->setting = 1; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci aio_port_reset(sub); 16162306a36Sopenharmony_ci aio_src_reset(sub); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return uniphier_aio_compr_prepare(component, cstream); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int uniphier_aio_compr_hw_free(struct snd_soc_component *component, 16762306a36Sopenharmony_ci struct snd_compr_stream *cstream) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 17062306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 17162306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci sub->setting = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic int uniphier_aio_compr_prepare(struct snd_soc_component *component, 17962306a36Sopenharmony_ci struct snd_compr_stream *cstream) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 18262306a36Sopenharmony_ci struct snd_compr_runtime *runtime = cstream->runtime; 18362306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 18462306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 18562306a36Sopenharmony_ci int bytes = runtime->fragment_size; 18662306a36Sopenharmony_ci unsigned long flags; 18762306a36Sopenharmony_ci int ret; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci ret = aiodma_ch_set_param(sub); 19062306a36Sopenharmony_ci if (ret) 19162306a36Sopenharmony_ci return ret; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 19462306a36Sopenharmony_ci ret = aiodma_rb_set_buffer(sub, sub->compr_addr, 19562306a36Sopenharmony_ci sub->compr_addr + sub->compr_bytes, 19662306a36Sopenharmony_ci bytes); 19762306a36Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci ret = aio_port_set_param(sub, sub->pass_through, &sub->params); 20262306a36Sopenharmony_ci if (ret) 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci ret = aio_oport_set_stream_type(sub, sub->iec_pc); 20562306a36Sopenharmony_ci if (ret) 20662306a36Sopenharmony_ci return ret; 20762306a36Sopenharmony_ci aio_port_set_enable(sub, 1); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci ret = aio_if_set_param(sub, sub->pass_through); 21062306a36Sopenharmony_ci if (ret) 21162306a36Sopenharmony_ci return ret; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int uniphier_aio_compr_trigger(struct snd_soc_component *component, 21762306a36Sopenharmony_ci struct snd_compr_stream *cstream, 21862306a36Sopenharmony_ci int cmd) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 22162306a36Sopenharmony_ci struct snd_compr_runtime *runtime = cstream->runtime; 22262306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 22362306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 22462306a36Sopenharmony_ci struct device *dev = &aio->chip->pdev->dev; 22562306a36Sopenharmony_ci int bytes = runtime->fragment_size, ret = 0; 22662306a36Sopenharmony_ci unsigned long flags; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 22962306a36Sopenharmony_ci switch (cmd) { 23062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 23162306a36Sopenharmony_ci aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes); 23262306a36Sopenharmony_ci aiodma_ch_set_enable(sub, 1); 23362306a36Sopenharmony_ci sub->running = 1; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 23762306a36Sopenharmony_ci sub->running = 0; 23862306a36Sopenharmony_ci aiodma_ch_set_enable(sub, 0); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci default: 24262306a36Sopenharmony_ci dev_warn(dev, "Unknown trigger(%d)\n", cmd); 24362306a36Sopenharmony_ci ret = -EINVAL; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return ret; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int uniphier_aio_compr_pointer(struct snd_soc_component *component, 25162306a36Sopenharmony_ci struct snd_compr_stream *cstream, 25262306a36Sopenharmony_ci struct snd_compr_tstamp *tstamp) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 25562306a36Sopenharmony_ci struct snd_compr_runtime *runtime = cstream->runtime; 25662306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 25762306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 25862306a36Sopenharmony_ci int bytes = runtime->fragment_size; 25962306a36Sopenharmony_ci unsigned long flags; 26062306a36Sopenharmony_ci u32 pos; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (sub->swm->dir == PORT_DIR_OUTPUT) { 26762306a36Sopenharmony_ci pos = sub->rd_offs; 26862306a36Sopenharmony_ci /* Size of AIO output format is double of IEC61937 */ 26962306a36Sopenharmony_ci tstamp->copied_total = sub->rd_total / 2; 27062306a36Sopenharmony_ci } else { 27162306a36Sopenharmony_ci pos = sub->wr_offs; 27262306a36Sopenharmony_ci tstamp->copied_total = sub->rd_total; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci tstamp->byte_offset = pos; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int aio_compr_send_to_hw(struct uniphier_aio_sub *sub, 28262306a36Sopenharmony_ci char __user *buf, size_t dstsize) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci u32 __user *srcbuf = (u32 __user *)buf; 28562306a36Sopenharmony_ci u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs); 28662306a36Sopenharmony_ci int src = 0, dst = 0, ret; 28762306a36Sopenharmony_ci u32 frm, frm_a, frm_b; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci while (dstsize > 0) { 29062306a36Sopenharmony_ci ret = get_user(frm, srcbuf + src); 29162306a36Sopenharmony_ci if (ret) 29262306a36Sopenharmony_ci return ret; 29362306a36Sopenharmony_ci src++; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci frm_a = frm & 0xffff; 29662306a36Sopenharmony_ci frm_b = (frm >> 16) & 0xffff; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (frm == IEC61937_HEADER_SIGN) { 29962306a36Sopenharmony_ci frm_a |= 0x01000000; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Next data is Pc and Pd */ 30262306a36Sopenharmony_ci sub->iec_header = true; 30362306a36Sopenharmony_ci } else { 30462306a36Sopenharmony_ci u16 pc = be16_to_cpu((__be16)frm_a); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (sub->iec_header && sub->iec_pc != pc) { 30762306a36Sopenharmony_ci /* Force overwrite IEC frame type */ 30862306a36Sopenharmony_ci sub->iec_pc = pc; 30962306a36Sopenharmony_ci ret = aio_oport_set_stream_type(sub, pc); 31062306a36Sopenharmony_ci if (ret) 31162306a36Sopenharmony_ci return ret; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci sub->iec_header = false; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci dstbuf[dst++] = frm_a; 31662306a36Sopenharmony_ci dstbuf[dst++] = frm_b; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci dstsize -= sizeof(u32) * 2; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int uniphier_aio_compr_copy(struct snd_soc_component *component, 32562306a36Sopenharmony_ci struct snd_compr_stream *cstream, 32662306a36Sopenharmony_ci char __user *buf, size_t count) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = cstream->private_data; 32962306a36Sopenharmony_ci struct snd_compr_runtime *runtime = cstream->runtime; 33062306a36Sopenharmony_ci struct device *carddev = rtd->compr->card->dev; 33162306a36Sopenharmony_ci struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0)); 33262306a36Sopenharmony_ci struct uniphier_aio_sub *sub = &aio->sub[cstream->direction]; 33362306a36Sopenharmony_ci size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2); 33462306a36Sopenharmony_ci int bytes = runtime->fragment_size; 33562306a36Sopenharmony_ci unsigned long flags; 33662306a36Sopenharmony_ci size_t s; 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (cnt < sizeof(u32)) 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (sub->swm->dir == PORT_DIR_OUTPUT) { 34362306a36Sopenharmony_ci dma_addr_t dmapos = sub->compr_addr + sub->wr_offs; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* Size of AIO output format is double of IEC61937 */ 34662306a36Sopenharmony_ci s = cnt * 2; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE); 34962306a36Sopenharmony_ci ret = aio_compr_send_to_hw(sub, buf, s); 35062306a36Sopenharmony_ci dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE); 35162306a36Sopenharmony_ci } else { 35262306a36Sopenharmony_ci dma_addr_t dmapos = sub->compr_addr + sub->rd_offs; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci s = cnt; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE); 35762306a36Sopenharmony_ci ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s); 35862306a36Sopenharmony_ci dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci if (ret) 36162306a36Sopenharmony_ci return -EFAULT; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci sub->threshold = 2 * bytes; 36662306a36Sopenharmony_ci aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (sub->swm->dir == PORT_DIR_OUTPUT) { 36962306a36Sopenharmony_ci sub->wr_offs += s; 37062306a36Sopenharmony_ci if (sub->wr_offs >= sub->compr_bytes) 37162306a36Sopenharmony_ci sub->wr_offs -= sub->compr_bytes; 37262306a36Sopenharmony_ci } else { 37362306a36Sopenharmony_ci sub->rd_offs += s; 37462306a36Sopenharmony_ci if (sub->rd_offs >= sub->compr_bytes) 37562306a36Sopenharmony_ci sub->rd_offs -= sub->compr_bytes; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return cnt; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int uniphier_aio_compr_get_caps(struct snd_soc_component *component, 38562306a36Sopenharmony_ci struct snd_compr_stream *cstream, 38662306a36Sopenharmony_ci struct snd_compr_caps *caps) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci caps->num_codecs = 1; 38962306a36Sopenharmony_ci caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE; 39062306a36Sopenharmony_ci caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE; 39162306a36Sopenharmony_ci caps->min_fragments = AUD_MIN_FRAGMENT; 39262306a36Sopenharmony_ci caps->max_fragments = AUD_MAX_FRAGMENT; 39362306a36Sopenharmony_ci caps->codecs[0] = SND_AUDIOCODEC_IEC61937; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic const struct snd_compr_codec_caps caps_iec = { 39962306a36Sopenharmony_ci .num_descriptors = 1, 40062306a36Sopenharmony_ci .descriptor[0].max_ch = 8, 40162306a36Sopenharmony_ci .descriptor[0].num_sample_rates = 0, 40262306a36Sopenharmony_ci .descriptor[0].num_bitrates = 0, 40362306a36Sopenharmony_ci .descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF, 40462306a36Sopenharmony_ci .descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 | 40562306a36Sopenharmony_ci SND_AUDIOMODE_IEC_MPEG1 | 40662306a36Sopenharmony_ci SND_AUDIOMODE_IEC_MP3 | 40762306a36Sopenharmony_ci SND_AUDIOMODE_IEC_DTS, 40862306a36Sopenharmony_ci .descriptor[0].formats = 0, 40962306a36Sopenharmony_ci}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int uniphier_aio_compr_get_codec_caps(struct snd_soc_component *component, 41262306a36Sopenharmony_ci struct snd_compr_stream *stream, 41362306a36Sopenharmony_ci struct snd_compr_codec_caps *codec) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci if (codec->codec == SND_AUDIOCODEC_IEC61937) 41662306a36Sopenharmony_ci *codec = caps_iec; 41762306a36Sopenharmony_ci else 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ciconst struct snd_compress_ops uniphier_aio_compress_ops = { 42462306a36Sopenharmony_ci .open = uniphier_aio_compr_open, 42562306a36Sopenharmony_ci .free = uniphier_aio_compr_free, 42662306a36Sopenharmony_ci .get_params = uniphier_aio_compr_get_params, 42762306a36Sopenharmony_ci .set_params = uniphier_aio_compr_set_params, 42862306a36Sopenharmony_ci .trigger = uniphier_aio_compr_trigger, 42962306a36Sopenharmony_ci .pointer = uniphier_aio_compr_pointer, 43062306a36Sopenharmony_ci .copy = uniphier_aio_compr_copy, 43162306a36Sopenharmony_ci .get_caps = uniphier_aio_compr_get_caps, 43262306a36Sopenharmony_ci .get_codec_caps = uniphier_aio_compr_get_codec_caps, 43362306a36Sopenharmony_ci}; 434