linux/sound/soc/intel/atom/sst-mfld-platform-compress.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  sst_mfld_platform.c - Intel MID Platform driver
   4 *
   5 *  Copyright (C) 2010-2014 Intel Corp
   6 *  Author: Vinod Koul <vinod.koul@intel.com>
   7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10 */
  11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12
  13#include <linux/slab.h>
  14#include <linux/io.h>
  15#include <linux/module.h>
  16#include <sound/core.h>
  17#include <sound/pcm.h>
  18#include <sound/pcm_params.h>
  19#include <sound/soc.h>
  20#include <sound/compress_driver.h>
  21#include "sst-mfld-platform.h"
  22
  23/* compress stream operations */
  24static void sst_compr_fragment_elapsed(void *arg)
  25{
  26        struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
  27
  28        pr_debug("fragment elapsed by driver\n");
  29        if (cstream)
  30                snd_compr_fragment_elapsed(cstream);
  31}
  32
  33static void sst_drain_notify(void *arg)
  34{
  35        struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
  36
  37        pr_debug("drain notify by driver\n");
  38        if (cstream)
  39                snd_compr_drain_notify(cstream);
  40}
  41
  42static int sst_platform_compr_open(struct snd_soc_component *component,
  43                                   struct snd_compr_stream *cstream)
  44{
  45        int ret_val;
  46        struct snd_compr_runtime *runtime = cstream->runtime;
  47        struct sst_runtime_stream *stream;
  48
  49        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
  50        if (!stream)
  51                return -ENOMEM;
  52
  53        spin_lock_init(&stream->status_lock);
  54
  55        /* get the sst ops */
  56        if (!sst || !try_module_get(sst->dev->driver->owner)) {
  57                pr_err("no device available to run\n");
  58                ret_val = -ENODEV;
  59                goto out_ops;
  60        }
  61        stream->compr_ops = sst->compr_ops;
  62        stream->id = 0;
  63
  64        /* Turn on LPE */
  65        sst->compr_ops->power(sst->dev, true);
  66
  67        sst_set_stream_status(stream, SST_PLATFORM_INIT);
  68        runtime->private_data = stream;
  69        return 0;
  70out_ops:
  71        kfree(stream);
  72        return ret_val;
  73}
  74
  75static int sst_platform_compr_free(struct snd_soc_component *component,
  76                                   struct snd_compr_stream *cstream)
  77{
  78        struct sst_runtime_stream *stream;
  79        int ret_val = 0, str_id;
  80
  81        stream = cstream->runtime->private_data;
  82        /* Turn off LPE */
  83        sst->compr_ops->power(sst->dev, false);
  84
  85        /*need to check*/
  86        str_id = stream->id;
  87        if (str_id)
  88                ret_val = stream->compr_ops->close(sst->dev, str_id);
  89        module_put(sst->dev->driver->owner);
  90        kfree(stream);
  91        pr_debug("%s: %d\n", __func__, ret_val);
  92        return 0;
  93}
  94
  95static int sst_platform_compr_set_params(struct snd_soc_component *component,
  96                                         struct snd_compr_stream *cstream,
  97                                         struct snd_compr_params *params)
  98{
  99        struct sst_runtime_stream *stream;
 100        int retval;
 101        struct snd_sst_params str_params;
 102        struct sst_compress_cb cb;
 103        struct sst_data *ctx = snd_soc_component_get_drvdata(component);
 104
 105        stream = cstream->runtime->private_data;
 106        /* construct fw structure for this*/
 107        memset(&str_params, 0, sizeof(str_params));
 108
 109        /* fill the device type and stream id to pass to SST driver */
 110        retval = sst_fill_stream_params(cstream, ctx, &str_params, true);
 111        pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval);
 112        if (retval < 0)
 113                return retval;
 114
 115        switch (params->codec.id) {
 116        case SND_AUDIOCODEC_MP3: {
 117                str_params.codec = SST_CODEC_TYPE_MP3;
 118                str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
 119                str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
 120                break;
 121        }
 122
 123        case SND_AUDIOCODEC_AAC: {
 124                str_params.codec = SST_CODEC_TYPE_AAC;
 125                str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
 126                str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
 127                if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
 128                        str_params.sparams.uc.aac_params.bs_format =
 129                                                        AAC_BIT_STREAM_ADTS;
 130                else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
 131                        str_params.sparams.uc.aac_params.bs_format =
 132                                                        AAC_BIT_STREAM_RAW;
 133                else {
 134                        pr_err("Undefined format%d\n", params->codec.format);
 135                        return -EINVAL;
 136                }
 137                str_params.sparams.uc.aac_params.externalsr =
 138                                                params->codec.sample_rate;
 139                break;
 140        }
 141
 142        default:
 143                pr_err("codec not supported, id =%d\n", params->codec.id);
 144                return -EINVAL;
 145        }
 146
 147        str_params.aparams.ring_buf_info[0].addr  =
 148                                        virt_to_phys(cstream->runtime->buffer);
 149        str_params.aparams.ring_buf_info[0].size =
 150                                        cstream->runtime->buffer_size;
 151        str_params.aparams.sg_count = 1;
 152        str_params.aparams.frag_size = cstream->runtime->fragment_size;
 153
 154        cb.param = cstream;
 155        cb.compr_cb = sst_compr_fragment_elapsed;
 156        cb.drain_cb_param = cstream;
 157        cb.drain_notify = sst_drain_notify;
 158
 159        retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
 160        if (retval < 0) {
 161                pr_err("stream allocation failed %d\n", retval);
 162                return retval;
 163        }
 164
 165        stream->id = retval;
 166        return 0;
 167}
 168
 169static int sst_platform_compr_trigger(struct snd_soc_component *component,
 170                                      struct snd_compr_stream *cstream, int cmd)
 171{
 172        struct sst_runtime_stream *stream = cstream->runtime->private_data;
 173
 174        switch (cmd) {
 175        case SNDRV_PCM_TRIGGER_START:
 176                if (stream->compr_ops->stream_start)
 177                        return stream->compr_ops->stream_start(sst->dev, stream->id);
 178                break;
 179        case SNDRV_PCM_TRIGGER_STOP:
 180                if (stream->compr_ops->stream_drop)
 181                        return stream->compr_ops->stream_drop(sst->dev, stream->id);
 182                break;
 183        case SND_COMPR_TRIGGER_DRAIN:
 184                if (stream->compr_ops->stream_drain)
 185                        return stream->compr_ops->stream_drain(sst->dev, stream->id);
 186                break;
 187        case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
 188                if (stream->compr_ops->stream_partial_drain)
 189                        return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
 190                break;
 191        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 192                if (stream->compr_ops->stream_pause)
 193                        return stream->compr_ops->stream_pause(sst->dev, stream->id);
 194                break;
 195        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 196                if (stream->compr_ops->stream_pause_release)
 197                        return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
 198                break;
 199        }
 200        return -EINVAL;
 201}
 202
 203static int sst_platform_compr_pointer(struct snd_soc_component *component,
 204                                      struct snd_compr_stream *cstream,
 205                                      struct snd_compr_tstamp *tstamp)
 206{
 207        struct sst_runtime_stream *stream;
 208
 209        stream  = cstream->runtime->private_data;
 210        stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
 211        tstamp->byte_offset = tstamp->copied_total %
 212                                 (u32)cstream->runtime->buffer_size;
 213        pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
 214        return 0;
 215}
 216
 217static int sst_platform_compr_ack(struct snd_soc_component *component,
 218                                  struct snd_compr_stream *cstream,
 219                                  size_t bytes)
 220{
 221        struct sst_runtime_stream *stream;
 222
 223        stream  = cstream->runtime->private_data;
 224        stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
 225        stream->bytes_written += bytes;
 226
 227        return 0;
 228}
 229
 230static int sst_platform_compr_get_caps(struct snd_soc_component *component,
 231                                       struct snd_compr_stream *cstream,
 232                                       struct snd_compr_caps *caps)
 233{
 234        struct sst_runtime_stream *stream =
 235                cstream->runtime->private_data;
 236
 237        return stream->compr_ops->get_caps(caps);
 238}
 239
 240static int sst_platform_compr_get_codec_caps(struct snd_soc_component *component,
 241                                             struct snd_compr_stream *cstream,
 242                                             struct snd_compr_codec_caps *codec)
 243{
 244        struct sst_runtime_stream *stream =
 245                cstream->runtime->private_data;
 246
 247        return stream->compr_ops->get_codec_caps(codec);
 248}
 249
 250static int sst_platform_compr_set_metadata(struct snd_soc_component *component,
 251                                           struct snd_compr_stream *cstream,
 252                                           struct snd_compr_metadata *metadata)
 253{
 254        struct sst_runtime_stream *stream  =
 255                 cstream->runtime->private_data;
 256
 257        return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
 258}
 259
 260const struct snd_compress_ops sst_platform_compress_ops = {
 261
 262        .open = sst_platform_compr_open,
 263        .free = sst_platform_compr_free,
 264        .set_params = sst_platform_compr_set_params,
 265        .set_metadata = sst_platform_compr_set_metadata,
 266        .trigger = sst_platform_compr_trigger,
 267        .pointer = sst_platform_compr_pointer,
 268        .ack = sst_platform_compr_ack,
 269        .get_caps = sst_platform_compr_get_caps,
 270        .get_codec_caps = sst_platform_compr_get_codec_caps,
 271};
 272