linux/sound/soc/uniphier/aio-compress.c
<<
>>
Prefs
   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        int ret;
 143
 144        if (params->codec.id != SND_AUDIOCODEC_IEC61937) {
 145                dev_err(dev, "Codec ID is not supported(%d)\n",
 146                        params->codec.id);
 147                return -EINVAL;
 148        }
 149        if (params->codec.profile != SND_AUDIOPROFILE_IEC61937_SPDIF) {
 150                dev_err(dev, "Codec profile is not supported(%d)\n",
 151                        params->codec.profile);
 152                return -EINVAL;
 153        }
 154
 155        /* IEC frame type will be changed after received valid data */
 156        sub->iec_pc = IEC61937_PC_AAC;
 157
 158        sub->cparams = *params;
 159        sub->setting = 1;
 160
 161        aio_port_reset(sub);
 162        aio_src_reset(sub);
 163
 164        ret = uniphier_aio_compr_prepare(component, cstream);
 165        if (ret)
 166                return ret;
 167
 168        return 0;
 169}
 170
 171static int uniphier_aio_compr_hw_free(struct snd_soc_component *component,
 172                                      struct snd_compr_stream *cstream)
 173{
 174        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 175        struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 176        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 177
 178        sub->setting = 0;
 179
 180        return 0;
 181}
 182
 183static int uniphier_aio_compr_prepare(struct snd_soc_component *component,
 184                                      struct snd_compr_stream *cstream)
 185{
 186        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 187        struct snd_compr_runtime *runtime = cstream->runtime;
 188        struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 189        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 190        int bytes = runtime->fragment_size;
 191        unsigned long flags;
 192        int ret;
 193
 194        ret = aiodma_ch_set_param(sub);
 195        if (ret)
 196                return ret;
 197
 198        spin_lock_irqsave(&sub->lock, flags);
 199        ret = aiodma_rb_set_buffer(sub, sub->compr_addr,
 200                                   sub->compr_addr + sub->compr_bytes,
 201                                   bytes);
 202        spin_unlock_irqrestore(&sub->lock, flags);
 203        if (ret)
 204                return ret;
 205
 206        ret = aio_port_set_param(sub, sub->pass_through, &sub->params);
 207        if (ret)
 208                return ret;
 209        ret = aio_oport_set_stream_type(sub, sub->iec_pc);
 210        if (ret)
 211                return ret;
 212        aio_port_set_enable(sub, 1);
 213
 214        ret = aio_if_set_param(sub, sub->pass_through);
 215        if (ret)
 216                return ret;
 217
 218        return 0;
 219}
 220
 221static int uniphier_aio_compr_trigger(struct snd_soc_component *component,
 222                                      struct snd_compr_stream *cstream,
 223                                      int cmd)
 224{
 225        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 226        struct snd_compr_runtime *runtime = cstream->runtime;
 227        struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 228        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 229        struct device *dev = &aio->chip->pdev->dev;
 230        int bytes = runtime->fragment_size, ret = 0;
 231        unsigned long flags;
 232
 233        spin_lock_irqsave(&sub->lock, flags);
 234        switch (cmd) {
 235        case SNDRV_PCM_TRIGGER_START:
 236                aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 237                aiodma_ch_set_enable(sub, 1);
 238                sub->running = 1;
 239
 240                break;
 241        case SNDRV_PCM_TRIGGER_STOP:
 242                sub->running = 0;
 243                aiodma_ch_set_enable(sub, 0);
 244
 245                break;
 246        default:
 247                dev_warn(dev, "Unknown trigger(%d)\n", cmd);
 248                ret = -EINVAL;
 249        }
 250        spin_unlock_irqrestore(&sub->lock, flags);
 251
 252        return ret;
 253}
 254
 255static int uniphier_aio_compr_pointer(struct snd_soc_component *component,
 256                                      struct snd_compr_stream *cstream,
 257                                      struct snd_compr_tstamp *tstamp)
 258{
 259        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 260        struct snd_compr_runtime *runtime = cstream->runtime;
 261        struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 262        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 263        int bytes = runtime->fragment_size;
 264        unsigned long flags;
 265        u32 pos;
 266
 267        spin_lock_irqsave(&sub->lock, flags);
 268
 269        aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 270
 271        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 272                pos = sub->rd_offs;
 273                /* Size of AIO output format is double of IEC61937 */
 274                tstamp->copied_total = sub->rd_total / 2;
 275        } else {
 276                pos = sub->wr_offs;
 277                tstamp->copied_total = sub->rd_total;
 278        }
 279        tstamp->byte_offset = pos;
 280
 281        spin_unlock_irqrestore(&sub->lock, flags);
 282
 283        return 0;
 284}
 285
 286static int aio_compr_send_to_hw(struct uniphier_aio_sub *sub,
 287                                char __user *buf, size_t dstsize)
 288{
 289        u32 __user *srcbuf = (u32 __user *)buf;
 290        u32 *dstbuf = (u32 *)(sub->compr_area + sub->wr_offs);
 291        int src = 0, dst = 0, ret;
 292        u32 frm, frm_a, frm_b;
 293
 294        while (dstsize > 0) {
 295                ret = get_user(frm, srcbuf + src);
 296                if (ret)
 297                        return ret;
 298                src++;
 299
 300                frm_a = frm & 0xffff;
 301                frm_b = (frm >> 16) & 0xffff;
 302
 303                if (frm == IEC61937_HEADER_SIGN) {
 304                        frm_a |= 0x01000000;
 305
 306                        /* Next data is Pc and Pd */
 307                        sub->iec_header = true;
 308                } else {
 309                        u16 pc = be16_to_cpu((__be16)frm_a);
 310
 311                        if (sub->iec_header && sub->iec_pc != pc) {
 312                                /* Force overwrite IEC frame type */
 313                                sub->iec_pc = pc;
 314                                ret = aio_oport_set_stream_type(sub, pc);
 315                                if (ret)
 316                                        return ret;
 317                        }
 318                        sub->iec_header = false;
 319                }
 320                dstbuf[dst++] = frm_a;
 321                dstbuf[dst++] = frm_b;
 322
 323                dstsize -= sizeof(u32) * 2;
 324        }
 325
 326        return 0;
 327}
 328
 329static int uniphier_aio_compr_copy(struct snd_soc_component *component,
 330                                   struct snd_compr_stream *cstream,
 331                                   char __user *buf, size_t count)
 332{
 333        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 334        struct snd_compr_runtime *runtime = cstream->runtime;
 335        struct device *carddev = rtd->compr->card->dev;
 336        struct uniphier_aio *aio = uniphier_priv(asoc_rtd_to_cpu(rtd, 0));
 337        struct uniphier_aio_sub *sub = &aio->sub[cstream->direction];
 338        size_t cnt = min_t(size_t, count, aio_rb_space_to_end(sub) / 2);
 339        int bytes = runtime->fragment_size;
 340        unsigned long flags;
 341        size_t s;
 342        int ret;
 343
 344        if (cnt < sizeof(u32))
 345                return 0;
 346
 347        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 348                dma_addr_t dmapos = sub->compr_addr + sub->wr_offs;
 349
 350                /* Size of AIO output format is double of IEC61937 */
 351                s = cnt * 2;
 352
 353                dma_sync_single_for_cpu(carddev, dmapos, s, DMA_TO_DEVICE);
 354                ret = aio_compr_send_to_hw(sub, buf, s);
 355                dma_sync_single_for_device(carddev, dmapos, s, DMA_TO_DEVICE);
 356        } else {
 357                dma_addr_t dmapos = sub->compr_addr + sub->rd_offs;
 358
 359                s = cnt;
 360
 361                dma_sync_single_for_cpu(carddev, dmapos, s, DMA_FROM_DEVICE);
 362                ret = copy_to_user(buf, sub->compr_area + sub->rd_offs, s);
 363                dma_sync_single_for_device(carddev, dmapos, s, DMA_FROM_DEVICE);
 364        }
 365        if (ret)
 366                return -EFAULT;
 367
 368        spin_lock_irqsave(&sub->lock, flags);
 369
 370        sub->threshold = 2 * bytes;
 371        aiodma_rb_set_threshold(sub, sub->compr_bytes, 2 * bytes);
 372
 373        if (sub->swm->dir == PORT_DIR_OUTPUT) {
 374                sub->wr_offs += s;
 375                if (sub->wr_offs >= sub->compr_bytes)
 376                        sub->wr_offs -= sub->compr_bytes;
 377        } else {
 378                sub->rd_offs += s;
 379                if (sub->rd_offs >= sub->compr_bytes)
 380                        sub->rd_offs -= sub->compr_bytes;
 381        }
 382        aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 383
 384        spin_unlock_irqrestore(&sub->lock, flags);
 385
 386        return cnt;
 387}
 388
 389static int uniphier_aio_compr_get_caps(struct snd_soc_component *component,
 390                                       struct snd_compr_stream *cstream,
 391                                       struct snd_compr_caps *caps)
 392{
 393        caps->num_codecs = 1;
 394        caps->min_fragment_size = AUD_MIN_FRAGMENT_SIZE;
 395        caps->max_fragment_size = AUD_MAX_FRAGMENT_SIZE;
 396        caps->min_fragments = AUD_MIN_FRAGMENT;
 397        caps->max_fragments = AUD_MAX_FRAGMENT;
 398        caps->codecs[0] = SND_AUDIOCODEC_IEC61937;
 399
 400        return 0;
 401}
 402
 403static const struct snd_compr_codec_caps caps_iec = {
 404        .num_descriptors = 1,
 405        .descriptor[0].max_ch = 8,
 406        .descriptor[0].num_sample_rates = 0,
 407        .descriptor[0].num_bitrates = 0,
 408        .descriptor[0].profiles = SND_AUDIOPROFILE_IEC61937_SPDIF,
 409        .descriptor[0].modes = SND_AUDIOMODE_IEC_AC3 |
 410                                SND_AUDIOMODE_IEC_MPEG1 |
 411                                SND_AUDIOMODE_IEC_MP3 |
 412                                SND_AUDIOMODE_IEC_DTS,
 413        .descriptor[0].formats = 0,
 414};
 415
 416static int uniphier_aio_compr_get_codec_caps(struct snd_soc_component *component,
 417                                             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_compress_ops uniphier_aio_compress_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};
 439
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.