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_compr_stream *cstream)
  43{
  44
  45        int ret_val = 0;
  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_compr_stream *cstream)
  76{
  77        struct sst_runtime_stream *stream;
  78        int ret_val = 0, str_id;
  79
  80        stream = cstream->runtime->private_data;
  81        /* Turn off LPE */
  82        sst->compr_ops->power(sst->dev, false);
  83
  84        /*need to check*/
  85        str_id = stream->id;
  86        if (str_id)
  87                ret_val = stream->compr_ops->close(sst->dev, str_id);
  88        module_put(sst->dev->driver->owner);
  89        kfree(stream);
  90        pr_debug("%s: %d\n", __func__, ret_val);
  91        return 0;
  92}
  93
  94static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
  95                                        struct snd_compr_params *params)
  96{
  97        struct sst_runtime_stream *stream;
  98        int retval;
  99        struct snd_sst_params str_params;
 100        struct sst_compress_cb cb;
 101        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 102        struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
 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_compr_stream *cstream, int cmd)
 170{
 171        struct sst_runtime_stream *stream = cstream->runtime->private_data;
 172
 173        switch (cmd) {
 174        case SNDRV_PCM_TRIGGER_START:
 175                if (stream->compr_ops->stream_start)
 176                        return stream->compr_ops->stream_start(sst->dev, stream->id);
 177                break;
 178        case SNDRV_PCM_TRIGGER_STOP:
 179                if (stream->compr_ops->stream_drop)
 180                        return stream->compr_ops->stream_drop(sst->dev, stream->id);
 181                break;
 182        case SND_COMPR_TRIGGER_DRAIN:
 183                if (stream->compr_ops->stream_drain)
 184                        return stream->compr_ops->stream_drain(sst->dev, stream->id);
 185                break;
 186        case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
 187                if (stream->compr_ops->stream_partial_drain)
 188                        return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
 189                break;
 190        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 191                if (stream->compr_ops->stream_pause)
 192                        return stream->compr_ops->stream_pause(sst->dev, stream->id);
 193                break;
 194        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 195                if (stream->compr_ops->stream_pause_release)
 196                        return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
 197                break;
 198        }
 199        return -EINVAL;
 200}
 201
 202static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
 203                                        struct snd_compr_tstamp *tstamp)
 204{
 205        struct sst_runtime_stream *stream;
 206
 207        stream  = cstream->runtime->private_data;
 208        stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
 209        tstamp->byte_offset = tstamp->copied_total %
 210                                 (u32)cstream->runtime->buffer_size;
 211        pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
 212        return 0;
 213}
 214
 215static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
 216                                        size_t bytes)
 217{
 218        struct sst_runtime_stream *stream;
 219
 220        stream  = cstream->runtime->private_data;
 221        stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
 222        stream->bytes_written += bytes;
 223
 224        return 0;
 225}
 226
 227static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
 228                                        struct snd_compr_caps *caps)
 229{
 230        struct sst_runtime_stream *stream =
 231                cstream->runtime->private_data;
 232
 233        return stream->compr_ops->get_caps(caps);
 234}
 235
 236static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
 237                                        struct snd_compr_codec_caps *codec)
 238{
 239        struct sst_runtime_stream *stream =
 240                cstream->runtime->private_data;
 241
 242        return stream->compr_ops->get_codec_caps(codec);
 243}
 244
 245static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
 246                                        struct snd_compr_metadata *metadata)
 247{
 248        struct sst_runtime_stream *stream  =
 249                 cstream->runtime->private_data;
 250
 251        return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
 252}
 253
 254const struct snd_compr_ops sst_platform_compr_ops = {
 255
 256        .open = sst_platform_compr_open,
 257        .free = sst_platform_compr_free,
 258        .set_params = sst_platform_compr_set_params,
 259        .set_metadata = sst_platform_compr_set_metadata,
 260        .trigger = sst_platform_compr_trigger,
 261        .pointer = sst_platform_compr_pointer,
 262        .ack = sst_platform_compr_ack,
 263        .get_caps = sst_platform_compr_get_caps,
 264        .get_codec_caps = sst_platform_compr_get_codec_caps,
 265};
 266