// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <linux/spinlock.h>
#include <sound/compress_driver.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <sound/pcm_params.h>
#include "q6asm.h"
#include "q6routing.h"
#include "q6dsp-errno.h"
#define DRV_NAME "q6asm-fe-dai"
#define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 65536
#define PLAYBACK_MIN_PERIOD_SIZE 128
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
#define CAPTURE_MAX_PERIOD_SIZE 4096
#define CAPTURE_MIN_PERIOD_SIZE 320
#define SID_MASK_DEFAULT 0xF
/* Default values used if user space does not set */
#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
#define Q6ASM_DAI_TX_RX 0
#define Q6ASM_DAI_TX 1
#define Q6ASM_DAI_RX 2
enum stream_state {
Q6ASM_STREAM_IDLE = 0,
Q6ASM_STREAM_STOPPED,
Q6ASM_STREAM_RUNNING,
};
struct q6asm_dai_rtd {
struct snd_pcm_substream *substream;
struct snd_compr_stream *cstream;
struct snd_compr_params codec_param;
struct snd_dma_buffer dma_buffer;
spinlock_t lock;
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
unsigned int pcm_irq_pos; /* IRQ position */
unsigned int periods;
unsigned int bytes_sent;
unsigned int bytes_received;
unsigned int copied_total;
uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
uint16_t session_id;
enum stream_state state;
};
struct q6asm_dai_data {
long long int sid;
};
static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE),
.rates = SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 4,
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS *
CAPTURE_MAX_PERIOD_SIZE,
.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
.periods_min = CAPTURE_MIN_NUM_PERIODS,
.periods_max = CAPTURE_MAX_NUM_PERIODS,
.fifo_size = 0,
};
static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE),
.rates = SNDRV_PCM_RATE_8000_192000,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
.channels_max = 8,
.buffer_bytes_max = (PLAYBACK_MAX_NUM_PERIODS *
PLAYBACK_MAX_PERIOD_SIZE),
.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
.periods_min = PLAYBACK_MIN_NUM_PERIODS,
.periods_max = PLAYBACK_MAX_NUM_PERIODS,
.fifo_size = 0,
};
#define Q6ASM_FEDAI_DRIVER(num) { \
.playback = { \
.stream_name = "MultiMedia"#num" Playback", \
.rates = (SNDRV_PCM_RATE_8000_192000| \
SNDRV_PCM_RATE_KNOT), \
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE), \
.channels_min = 1, \
.channels_max = 8, \
.rate_min = 8000, \
.rate_max = 192000, \
}, \
.capture = { \
.stream_name = "MultiMedia"#num" Capture", \
.rates = (SNDRV_PCM_RATE_8000_48000| \
SNDRV_PCM_RATE_KNOT), \
.formats = (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE), \
.channels_min = 1, \
.channels_max = 4, \
.rate_min = 8000, \
.rate_max = 48000, \
}, \
.name = "MultiMedia"#num, \
.id = MSM_FRONTEND_DAI_MULTIMEDIA##num, \
}
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
88200, 96000, 176400, 192000
};
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.count = ARRAY_SIZE(supported_sample_rates),
.list = supported_sample_rates,
.mask = 0,
};
static const struct snd_compr_codec_caps q6asm_compr_caps = {
.num_descriptors = 1,
.descriptor[0].max_ch = 2,
.descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 88200,
96000, 176400, 192000 },
.descriptor[0].num_sample_rates = 13,
.descriptor[0].bit_rate[0] = 320,
.descriptor[0].bit_rate[1] = 128,
.descriptor[0