272 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * sst_mfld_platform.c - Intel MID Platform driver4 *5 * Copyright (C) 2010-2014 Intel Corp6 * Author: Vinod Koul <vinod.koul@intel.com>7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~8 *9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~10 */11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt12 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