blob: 232b0b2f2be280df92d54ba4002dfb642bfa62bb [file] [log] [blame]
/*
* Mediatek ALSA SoC AFE platform driver
*
* Copyright (c) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include "mt8167-afe-common.h"
#include "mt8167-afe-regs.h"
#include "mt8167-afe-util.h"
#include "mt8167-afe-controls.h"
#include "mt8167-afe-debug.h"
#define MT8167_I2S0_MCLK_MULTIPLIER 256
#define MT8167_I2S1_MCLK_MULTIPLIER 256
#define MT8167_I2S2_MCLK_MULTIPLIER 256
#define MT8167_I2S3_MCLK_MULTIPLIER 256
#define MT8167_HDMI_OUT_MCLK_MULTIPLIER 64
#define MT8167_TDM_OUT_MCLK_MULTIPLIER 256
#define MT8167_TDM_IN_MCLK_MULTIPLIER 256
#define LRCK_CYCLE_INVALID ((unsigned int)-1)
#define AFE_PCM_NAME "mtk-afe-pcm"
static const unsigned int mt8167_afe_backup_list[] = {
AUDIO_TOP_CON0,
AUDIO_TOP_CON3,
AFE_CONN0,
AFE_CONN1,
AFE_CONN2,
AFE_CONN3,
AFE_CONN5,
AFE_CONN_24BIT,
AFE_APLL1_TUNER_CFG,
AFE_APLL2_TUNER_CFG,
AFE_I2S_CON,
AFE_I2S_CON1,
AFE_I2S_CON2,
AFE_I2S_CON3,
AFE_ADDA_PREDIS_CON0,
AFE_ADDA_PREDIS_CON1,
AFE_ADDA_DL_SRC2_CON0,
AFE_ADDA_DL_SRC2_CON1,
AFE_ADDA_UL_SRC_CON0,
AFE_ADDA_UL_SRC_CON0,
AFE_ADDA_NEWIF_CFG1,
AFE_ADDA_TOP_CON0,
AFE_ADDA_UL_DL_CON0,
AFE_GAIN1_CON0,
AFE_GAIN1_CON1,
AFE_GAIN1_CUR,
AFE_MEMIF_PBUF_SIZE,
AFE_MEMIF_PBUF2_SIZE,
AFE_DAC_CON0,
AFE_DAC_CON1,
AFE_DL1_BASE,
AFE_DL1_END,
AFE_DL2_BASE,
AFE_DL2_END,
AFE_VUL_BASE,
AFE_VUL_END,
AFE_AWB_BASE,
AFE_AWB_END,
AFE_DAI_BASE,
AFE_DAI_END,
AFE_HDMI_OUT_BASE,
AFE_HDMI_OUT_END,
AFE_HDMI_IN_2CH_BASE,
AFE_HDMI_IN_2CH_END,
AFE_TDM_CON1,
AFE_TDM_CON2,
AFE_HDMI_OUT_CON0,
AFE_TDM_IN_CON1,
};
static const struct snd_pcm_hardware mt8167_afe_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID,
.buffer_bytes_max = 1024 * 1024,
.period_bytes_min = 256,
.period_bytes_max = 512 * 1024,
.periods_min = 2,
.periods_max = 256,
.fifo_size = 0,
};
static unsigned int channels_2_4_6_8[] = {
2, 4, 6, 8
};
static unsigned int rate_2nd_i2s_slave[] = {
8000, 11025, 16000, 22050,32000, 44100, 48000
};
static struct snd_pcm_hw_constraint_list constraints_rate_2nd_i2s_slave = {
.count = ARRAY_SIZE(rate_2nd_i2s_slave),
.list = rate_2nd_i2s_slave,
.mask = 0,
};
static struct snd_pcm_hw_constraint_list constraints_channels_tdm_in = {
.count = ARRAY_SIZE(channels_2_4_6_8),
.list = channels_2_4_6_8,
.mask = 0,
};
static unsigned int mt8167_afe_tdm_ch_fixup(unsigned int channels)
{
if (channels > 4)
return 8;
else if (channels > 2)
return 4;
else
return 2;
}
static unsigned int mt8167_afe_tdm_out_ch_per_sdata(unsigned int mode,
unsigned int channels)
{
if (mode == MT8167_AFE_TDM_OUT_TDM)
return mt8167_afe_tdm_ch_fixup(channels);
else
return 2;
}
static int mt8167_afe_tdm_out_bitwidth_fixup(unsigned int mode,
int bitwidth)
{
if (mode == MT8167_AFE_TDM_OUT_HDMI ||
mode == MT8167_AFE_TDM_OUT_I2S_32BITS ||
bitwidth == 24)
return 32;
else
return bitwidth;
}
static snd_pcm_uframes_t mt8167_afe_pcm_pointer
(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_afe *afe = snd_soc_component_get_drvdata(component);
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
unsigned int hw_ptr;
int ret;
ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr);
if (ret || hw_ptr == 0) {
dev_err(afe->dev, "%s hw_ptr err ret = %d\n", __func__, ret);
hw_ptr = memif->phys_buf_addr;
} else if (memif->use_sram) {
/* enforce natural alignment to 8 bytes */
hw_ptr &= ~7;
}
return bytes_to_frames(substream->runtime,
hw_ptr - memif->phys_buf_addr);
}
static const struct snd_pcm_ops mt8167_afe_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl,
.pointer = mt8167_afe_pcm_pointer,
};
static int mt8167_afe_pcm_probe(struct snd_soc_component *component)
{
return mt8167_afe_add_controls(component);
}
static int mt8167_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_afe *afe = snd_soc_component_get_drvdata(component);
size_t size = afe->memif[rtd->cpu_dai->id].data->prealloc_size;
struct snd_pcm_substream *substream;
int stream;
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
if (substream) {
struct snd_dma_buffer *buf = &substream->dma_buffer;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = card->dev;
buf->private_data = NULL;
}
}
if (size > 0)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, size, size);
return 0;
}
static void mt8167_afe_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static const struct snd_soc_component_driver mt8167_afe_pcm_platform = {
.name = AFE_PCM_NAME,
.probe = mt8167_afe_pcm_probe,
.pcm_new = mt8167_afe_pcm_new,
.pcm_free = mt8167_afe_pcm_free,
.ops = &mt8167_afe_pcm_ops,
};
struct mt8167_afe_rate {
unsigned int rate;
unsigned int regvalue;
};
static const struct mt8167_afe_rate mt8167_afe_i2s_rates[] = {
{ .rate = 8000, .regvalue = 0 },
{ .rate = 11025, .regvalue = 1 },
{ .rate = 12000, .regvalue = 2 },
{ .rate = 16000, .regvalue = 4 },
{ .rate = 22050, .regvalue = 5 },
{ .rate = 24000, .regvalue = 6 },
{ .rate = 32000, .regvalue = 8 },
{ .rate = 44100, .regvalue = 9 },
{ .rate = 48000, .regvalue = 10 },
{ .rate = 88000, .regvalue = 11 },
{ .rate = 96000, .regvalue = 12 },
{ .rate = 176400, .regvalue = 13 },
{ .rate = 192000, .regvalue = 14 },
};
struct mt8167_afe_asrc_info {
unsigned int rate_in;
unsigned int rate_out;
unsigned int freq_in;
unsigned int freq_out;
unsigned int fc_rstth_high;
unsigned int fc_rstth_low;
unsigned int fc_demtr;
};
static const struct mt8167_afe_asrc_info mt8167_afe_asrc_settings[] = {
/* 8Khz => 8Khz */
{ .rate_in = 8000, .rate_out = 8000,
.freq_in = 0x50000, .freq_out = 0x50000,
.fc_rstth_high = 0x37dc0, .fc_rstth_low = 0x2db40,
.fc_demtr = 0x1fbd },
/* 11.025Khz => 11.025Khz */
{ .rate_in = 11025, .rate_out = 11025,
.freq_in = 0x6e400, .freq_out = 0x6e400,
.fc_rstth_high = 0x28886, .fc_rstth_low = 0x2129c,
.fc_demtr = 0x1fbd },
/* 16Khz =>16Khz */
{ .rate_in = 16000, .rate_out = 16000,
.freq_in = 0xa0000, .freq_out = 0xa0000,
.fc_rstth_high = 0x1bee0, .fc_rstth_low = 0x16da0,
.fc_demtr = 0x1fbd },
/* 22.05Khz =>22.05Khz */
{ .rate_in = 22050, .rate_out = 22050,
.freq_in = 0xdc800, .freq_out = 0xdc800,
.fc_rstth_high = 0x14443, .fc_rstth_low = 0x1094e,
.fc_demtr = 0x1fbd },
/* 32Khz => 32Khz */
{ .rate_in = 32000, .rate_out = 32000,
.freq_in = 0x140000, .freq_out = 0x140000,
.fc_rstth_high = 0xd800, .fc_rstth_low = 0xbd00,
.fc_demtr = 0x1fbd },
/* 44.1Khz => 44.1Khz */
{ .rate_in = 44100, .rate_out = 44100,
.freq_in = 0x1b9000, .freq_out = 0x1b9000,
.fc_rstth_high = 0x9c00, .fc_rstth_low = 0x8b00,
.fc_demtr = 0x1fbd },
/* 48Khz =>48Khz */
{ .rate_in = 48000, .rate_out = 48000,
.freq_in = 0x1e0000, .freq_out = 0x1e0000,
.fc_rstth_high = 0x8f00, .fc_rstth_low = 0x7f00,
.fc_demtr = 0x1fbd },
};
static int mt8167_afe_asrc_fs(unsigned int rate_in, unsigned int rate_out)
{
int i;
for (i = 0; i < ARRAY_SIZE(mt8167_afe_asrc_settings); i++)
if ((mt8167_afe_asrc_settings[i].rate_in == rate_in) &&
(mt8167_afe_asrc_settings[i].rate_out == rate_out))
return i;
return -EINVAL;
}
static int mt8167_afe_i2s_fs(unsigned int sample_rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(mt8167_afe_i2s_rates); i++)
if (mt8167_afe_i2s_rates[i].rate == sample_rate)
return mt8167_afe_i2s_rates[i].regvalue;
return -EINVAL;
}
static int mt8167_afe_set_i2s_out(struct mtk_afe *afe, unsigned int rate,
int bit_width)
{
unsigned int val;
int fs = mt8167_afe_i2s_fs(rate);
if (fs < 0)
return -EINVAL;
val = AFE_I2S_CON1_I2S2_TO_PAD |
AFE_I2S_CON1_LOW_JITTER_CLK |
AFE_I2S_CON1_RATE(fs) |
AFE_I2S_CON1_FORMAT_I2S;
if (bit_width > 16)
val |= AFE_I2S_CON1_WLEN_32BIT;
regmap_update_bits(afe->regmap, AFE_I2S_CON1, ~(u32)AFE_I2S_CON1_EN, val);
return 0;
}
static int mt8167_afe_set_2nd_i2s_out(struct mtk_afe *afe, unsigned int rate,
int bit_width)
{
unsigned int val;
int fs = mt8167_afe_i2s_fs(rate);
if (fs < 0)
return -EINVAL;
val = AFE_I2S_CON3_LOW_JITTER_CLK |
AFE_I2S_CON3_RATE(fs) |
AFE_I2S_CON3_FORMAT_I2S;
if (bit_width > 16)
val |= AFE_I2S_CON3_WLEN_32BIT;
regmap_update_bits(afe->regmap, AFE_I2S_CON3, ~(u32)AFE_I2S_CON3_EN, val);
return 0;
}
static int mt8167_afe_set_i2s_in(struct mtk_afe *afe, unsigned int rate,
int bit_width)
{
unsigned int val;
int fs = mt8167_afe_i2s_fs(rate);
if (fs < 0)
return -EINVAL;
val = AFE_I2S_CON2_LOW_JITTER_CLK |
AFE_I2S_CON2_RATE(fs) |
AFE_I2S_CON2_FORMAT_I2S;
if (bit_width > 16)
val |= AFE_I2S_CON2_WLEN_32BIT;
regmap_update_bits(afe->regmap, AFE_I2S_CON2, ~(u32)AFE_I2S_CON2_EN, val);
regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1);
return 0;
}
static int mt8167_afe_set_2nd_i2s_asrc(struct mtk_afe *afe, unsigned int rate_in,
unsigned int rate_out, unsigned int width, unsigned int mono)
{
int id = 0;
unsigned int val = 0;
unsigned int mask = 0;
id = mt8167_afe_asrc_fs(rate_in, rate_out);
if (id < 0)
return -EINVAL;
if (width == 16)
val |= AFE_ASRC_CON13_16BIT;
if (mono)
val |= AFE_ASRC_CON13_MONO;
regmap_update_bits(afe->regmap, AFE_ASRC_CON13,
AFE_ASRC_CON13_16BIT | AFE_ASRC_CON13_MONO,
val);
regmap_write(afe->regmap,
AFE_ASRC_CON14,
mt8167_afe_asrc_settings[id].freq_out);
regmap_write(afe->regmap,
AFE_ASRC_CON15,
mt8167_afe_asrc_settings[id].freq_in);
val = AFE_ASRC_CON16_FC2_CYCLE(64) |
AFE_ASRC_CON16_FC2_AUTO_RST |
AFE_ASRC_CON16_TUNE_FREQ5 |
AFE_ASRC_CON16_COMP_FREQ_EN |
AFE_ASRC_CON16_FC2_I2S_IN |
AFE_ASRC_CON16_FC2_DGL_BYPASS |
AFE_ASRC_CON16_FC2_AUTO_RESTART |
AFE_ASRC_CON16_FC2_FREQ |
AFE_ASRC_CON16_FC2_EN;
mask = AFE_ASRC_CON16_FC2_CYCLE_MASK |
AFE_ASRC_CON16_FC2_AUTO_RST |
AFE_ASRC_CON16_TUNE_FREQ5 |
AFE_ASRC_CON16_COMP_FREQ_EN |
AFE_ASRC_CON16_FC2_SEL |
AFE_ASRC_CON16_FC2_DGL_BYPASS |
AFE_ASRC_CON16_FC2_AUTO_RESTART |
AFE_ASRC_CON16_FC2_FREQ |
AFE_ASRC_CON16_FC2_EN;
regmap_update_bits(afe->regmap, AFE_ASRC_CON16,
mask, val);
regmap_write(afe->regmap,
AFE_ASRC_CON17,
mt8167_afe_asrc_settings[id].fc_demtr);
regmap_write(afe->regmap,
AFE_ASRC_CON20,
mt8167_afe_asrc_settings[id].fc_rstth_high);
regmap_write(afe->regmap,
AFE_ASRC_CON21,
mt8167_afe_asrc_settings[id].fc_rstth_low);
val = AFE_ASRC_CON0_CLR_TX |
AFE_ASRC_CON0_CLR_RX |
AFE_ASRC_CON0_CLR_I2S;
regmap_update_bits(afe->regmap, AFE_ASRC_CON0,
AFE_ASRC_CON0_STR_CLR_MASK, val);
return 0;
}
static int mt8167_afe_set_2nd_i2s_asrc_enable(struct mtk_afe *afe, bool enable)
{
if (enable)
regmap_update_bits(afe->regmap, AFE_ASRC_CON0,
AFE_ASRC_CON0_ASM_ON, AFE_ASRC_CON0_ASM_ON);
else
regmap_update_bits(afe->regmap, AFE_ASRC_CON0,
AFE_ASRC_CON0_ASM_ON, 0);
return 0;
}
static int mt8167_afe_set_2nd_i2s_in(struct mtk_afe *afe, unsigned int rate,
int bit_width)
{
unsigned int val;
int fs = mt8167_afe_i2s_fs(rate);
struct mt8167_afe_be_dai_data *be = &afe->be_data[MT8167_AFE_IO_2ND_I2S - MT8167_AFE_BACKEND_BASE];
if (fs < 0)
return -EINVAL;
regmap_update_bits(afe->regmap, AFE_DAC_CON1, 0xf << 8, fs << 8);
val = AFE_I2S_CON_PHASE_SHIFT_FIX |
AFE_I2S_CON_FROM_IO_MUX |
AFE_I2S_CON_LOW_JITTER_CLK;
if ((be->fmt_mode & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
val |= AFE_I2S_CON_FORMAT_I2S;
switch (be->fmt_mode & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
val |= AFE_I2S_CON_LRCK_INV;
val |= AFE_I2S_CON_BCK_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
val |= AFE_I2S_CON_LRCK_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
val |= AFE_I2S_CON_BCK_INV;
break;
default:
break;
}
if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
val |= AFE_I2S_CON_SRC_SLAVE;
if (bit_width > 16)
val |= AFE_I2S_CON_WLEN_32BIT;
regmap_update_bits(afe->regmap, AFE_I2S_CON, ~(u32)AFE_I2S_CON_EN, val);
return 0;
}
static void mt8167_afe_set_i2s_out_enable(struct mtk_afe *afe, bool enable)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
if (enable) {
afe->i2s_out_on_ref_cnt++;
if (afe->i2s_out_on_ref_cnt == 1)
regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable);
} else {
afe->i2s_out_on_ref_cnt--;
if (afe->i2s_out_on_ref_cnt == 0)
regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable);
else if (afe->i2s_out_on_ref_cnt < 0)
afe->i2s_out_on_ref_cnt = 0;
}
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
}
static void mt8167_afe_set_2nd_i2s_out_enable(struct mtk_afe *afe, bool enable)
{
regmap_update_bits(afe->regmap, AFE_I2S_CON3, 0x1, enable);
}
static void mt8167_afe_set_i2s_in_enable(struct mtk_afe *afe, bool enable)
{
regmap_update_bits(afe->regmap, AFE_I2S_CON2, 0x1, enable);
}
static void mt8167_afe_set_2nd_i2s_in_enable(struct mtk_afe *afe, bool enable)
{
regmap_update_bits(afe->regmap, AFE_I2S_CON, 0x1, enable);
}
static int mt8167_afe_enable_adda_on(struct mtk_afe *afe)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->adda_afe_on_ref_cnt++;
if (afe->adda_afe_on_ref_cnt == 1)
regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0, 0x1, 0x1);
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
}
static int mt8167_afe_disable_adda_on(struct mtk_afe *afe)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->adda_afe_on_ref_cnt--;
if (afe->adda_afe_on_ref_cnt == 0)
regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0, 0x1, 0x0);
else if (afe->adda_afe_on_ref_cnt < 0)
afe->adda_afe_on_ref_cnt = 0;
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
}
static int mt8167_afe_set_adda_out(struct mtk_afe *afe, unsigned int rate)
{
unsigned int val = 0;
switch (rate) {
case 8000:
val |= (0 << 28) | AFE_ADDA_DL_VOICE_DATA;
break;
case 11025:
val |= 1 << 28;
break;
case 12000:
val |= 2 << 28;
break;
case 16000:
val |= (3 << 28) | AFE_ADDA_DL_VOICE_DATA;
break;
case 22050:
val |= 4 << 28;
break;
case 24000:
val |= 5 << 28;
break;
case 32000:
val |= 6 << 28;
break;
case 44100:
val |= 7 << 28;
break;
case 48000:
val |= 8 << 28;
break;
default:
return -EINVAL;
}
val |= AFE_ADDA_DL_8X_UPSAMPLE |
AFE_ADDA_DL_MUTE_OFF |
AFE_ADDA_DL_DEGRADE_GAIN;
regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);
regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);
regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);
regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1, 0xffffffff, 0xf74f0000);
return 0;
}
static int mt8167_afe_set_adda_in(struct mtk_afe *afe, unsigned int rate)
{
unsigned int val = 0;
unsigned int val2 = 0;
switch (rate) {
case 8000:
val |= (0 << 17) | (0 << 19);
val2 |= 1 << 10;
break;
case 16000:
val |= (1 << 17) | (1 << 19);
val2 |= 1 << 10;
break;
case 32000:
val |= (2 << 17) | (2 << 19);
val2 |= 1 << 10;
break;
case 48000:
val |= (3 << 17) | (3 << 19);
val2 |= 3 << 10;
break;
default:
return -EINVAL;
}
regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x001e0000, val);
regmap_update_bits(afe->regmap, AFE_ADDA_NEWIF_CFG1, 0xc00, val2);
regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);
return 0;
}
static void mt8167_afe_set_adda_out_enable(struct mtk_afe *afe, bool enable)
{
regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);
if (enable)
mt8167_afe_enable_adda_on(afe);
else
mt8167_afe_disable_adda_on(afe);
}
static void mt8167_afe_set_adda_in_enable(struct mtk_afe *afe, bool enable)
{
regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, enable);
if (enable)
mt8167_afe_enable_adda_on(afe);
else
mt8167_afe_disable_adda_on(afe);
}
static int mt8167_afe_set_mrg(struct mtk_afe *afe, unsigned int rate)
{
unsigned int val = 0;
switch (rate) {
case 8000:
val |= 0 << 9;
break;
case 16000:
val |= 1 << 9;
break;
default:
return -EINVAL;
}
val |= AFE_DAIBT_CON0_USE_MRG_INPUT |
AFE_DAIBT_CON0_DATA_DRY;
regmap_update_bits(afe->regmap, AFE_MRGIF_CON, 0xf00000, 9 << 20);
regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, 0x1208, val);
return 0;
}
static void mt8167_afe_enable_mrg(struct mtk_afe *afe)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->daibt_on_ref_cnt++;
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
if (afe->daibt_on_ref_cnt != 1)
return;
regmap_update_bits(afe->regmap, AFE_MRGIF_CON, 1 << 16, 1 << 16);
regmap_update_bits(afe->regmap, AFE_MRGIF_CON, 0x1, 0x1);
udelay(100);
regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, 0x3, 0x3);
}
static void mt8167_afe_disable_mrg(struct mtk_afe *afe)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->daibt_on_ref_cnt--;
if (afe->daibt_on_ref_cnt < 0)
afe->daibt_on_ref_cnt = 0;
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
if (afe->daibt_on_ref_cnt != 0)
return;
regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, 0x3, 0x0);
udelay(100);
regmap_update_bits(afe->regmap, AFE_MRGIF_CON, 1 << 16, 0x0);
regmap_update_bits(afe->regmap, AFE_MRGIF_CON, 0x1, 0x0);
}
static int mt8167_afe_set_pcm0(struct mtk_afe *afe, unsigned int rate)
{
unsigned int val = 0;
switch (rate) {
case 8000:
val |= 0 << 9;
break;
case 16000:
val |= 1 << 9;
break;
default:
return -EINVAL;
}
val |= AFE_DAIBT_CON0_DATA_DRY;
regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, 0x1208, val);
return 0;
}
static void mt8167_afe_enable_pcm0(struct mtk_afe *afe)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->daibt_on_ref_cnt++;
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
if (afe->daibt_on_ref_cnt != 1)
return;
regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, 0x3, 0x3);
}
static void mt8167_afe_disable_pcm0(struct mtk_afe *afe)
{
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->daibt_on_ref_cnt--;
if (afe->daibt_on_ref_cnt < 0)
afe->daibt_on_ref_cnt = 0;
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
if (afe->daibt_on_ref_cnt != 0)
return;
regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, 0x3, 0x0);
}
static int mt8167_afe_enable_irq(struct mtk_afe *afe, struct mt8167_afe_memif *memif)
{
int irq_mode = memif->data->irq_mode;
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->irq_mode_ref_cnt[irq_mode]++;
if (afe->irq_mode_ref_cnt[irq_mode] > 1) {
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
}
switch (irq_mode) {
case MT8167_AFE_IRQ_1:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, 1 << 0, 1 << 0);
break;
case MT8167_AFE_IRQ_2:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, 1 << 1, 1 << 1);
break;
case MT8167_AFE_IRQ_5:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON2, 1 << 3, 1 << 3);
break;
case MT8167_AFE_IRQ_7:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, 1 << 14, 1 << 14);
break;
case MT8167_AFE_IRQ_10:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON2, 1 << 4, 1 << 4);
break;
case MT8167_AFE_IRQ_13:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON2, 1 << 7, 1 << 7);
break;
default:
break;
}
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
}
static int mt8167_afe_disable_irq(struct mtk_afe *afe, struct mt8167_afe_memif *memif)
{
int irq_mode = memif->data->irq_mode;
unsigned long flags;
spin_lock_irqsave(&afe->afe_ctrl_lock, flags);
afe->irq_mode_ref_cnt[irq_mode]--;
if (afe->irq_mode_ref_cnt[irq_mode] > 0) {
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
} else if (afe->irq_mode_ref_cnt[irq_mode] < 0) {
afe->irq_mode_ref_cnt[irq_mode] = 0;
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
}
switch (irq_mode) {
case MT8167_AFE_IRQ_1:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, 1 << 0, 0 << 0);
regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << 0);
break;
case MT8167_AFE_IRQ_2:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, 1 << 1, 0 << 1);
regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << 1);
break;
case MT8167_AFE_IRQ_5:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON2, 1 << 3, 0 << 3);
regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << 4);
break;
case MT8167_AFE_IRQ_7:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, 1 << 14, 0 << 14);
regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << 6);
break;
case MT8167_AFE_IRQ_10:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON2, 1 << 4, 0 << 4);
regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << 9);
break;
case MT8167_AFE_IRQ_13:
regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON2, 1 << 7, 0 << 7);
break;
default:
break;
}
spin_unlock_irqrestore(&afe->afe_ctrl_lock, flags);
return 0;
}
static int mt8167_afe_dais_enable_clks(struct mtk_afe *afe,
struct clk *m_ck, struct clk *b_ck)
{
#ifdef COMMON_CLOCK_FRAMEWORK_API
int ret;
if (m_ck) {
ret = clk_prepare_enable(m_ck);
if (ret) {
dev_err(afe->dev, "Failed to enable m_ck\n");
return ret;
}
}
if (b_ck) {
ret = clk_prepare_enable(b_ck);
if (ret) {
dev_err(afe->dev, "Failed to enable b_ck\n");
return ret;
}
}
#endif
return 0;
}
static int mt8167_afe_dais_set_clks(struct mtk_afe *afe,
struct clk *m_ck, unsigned int mck_rate,
struct clk *b_ck, unsigned int bck_rate)
{
#ifdef COMMON_CLOCK_FRAMEWORK_API
int ret;
if (m_ck) {
ret = clk_set_rate(m_ck, mck_rate);
if (ret) {
dev_err(afe->dev, "Failed to set m_ck rate\n");
return ret;
}
}
if (b_ck) {
ret = clk_set_rate(b_ck, bck_rate);
if (ret) {
dev_err(afe->dev, "Failed to set b_ck rate\n");
return ret;
}
}
#endif
return 0;
}
static void mt8167_afe_dais_disable_clks(struct mtk_afe *afe,
struct clk *m_ck, struct clk *b_ck)
{
#ifdef COMMON_CLOCK_FRAMEWORK_API
if (m_ck)
clk_disable_unprepare(m_ck);
if (b_ck)
clk_disable_unprepare(b_ck);
#endif
}
static int mt8167_afe_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
const unsigned int clk_mode = afe->i2s_clk_modes[MT8167_AFE_1ST_I2S];
dev_dbg(afe->dev, "%s '%s'\n",
__func__, snd_pcm_stream_str(substream));
if (clk_mode == MT8167_AFE_I2S_SHARED_CLOCK && dai->active)
return 0;
mt8167_afe_enable_main_clk(afe);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
clk_mode == MT8167_AFE_I2S_SHARED_CLOCK)
mt8167_afe_dais_enable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV1], NULL);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE ||
clk_mode == MT8167_AFE_I2S_SHARED_CLOCK)
mt8167_afe_dais_enable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV2], NULL);
return 0;
}
static void mt8167_afe_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const unsigned int stream = substream->stream;
const unsigned int clk_mode = afe->i2s_clk_modes[MT8167_AFE_1ST_I2S];
const bool reset_i2s_out_change = (stream == SNDRV_PCM_STREAM_PLAYBACK) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
const bool reset_i2s_in_change = (stream == SNDRV_PCM_STREAM_CAPTURE) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
dev_dbg(afe->dev, "%s '%s'\n",
__func__, snd_pcm_stream_str(substream));
if (clk_mode == MT8167_AFE_I2S_SHARED_CLOCK && dai->active)
return;
if (be->prepared[stream]) {
if (reset_i2s_out_change)
mt8167_afe_set_i2s_out_enable(afe, false);
if (reset_i2s_in_change)
mt8167_afe_set_i2s_in_enable(afe, false);
if (rate % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
if (reset_i2s_out_change)
be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = false;
if (reset_i2s_in_change)
be->prepared[SNDRV_PCM_STREAM_CAPTURE] = false;
}
if (reset_i2s_out_change)
mt8167_afe_dais_disable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV1], NULL);
if (reset_i2s_in_change)
mt8167_afe_dais_disable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV2], NULL);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
unsigned int width_val = params_width(params) > 16 ?
(AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04) : 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04, width_val);
return 0;
}
static int mt8167_afe_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const int bit_width = snd_pcm_format_width(substream->runtime->format);
const unsigned int stream = substream->stream;
const unsigned int clk_mode = afe->i2s_clk_modes[MT8167_AFE_1ST_I2S];
const bool apply_i2s_out_change = (stream == SNDRV_PCM_STREAM_PLAYBACK) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
const bool apply_i2s_in_change = (stream == SNDRV_PCM_STREAM_CAPTURE) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
int ret;
if ((clk_mode == MT8167_AFE_I2S_SHARED_CLOCK) &&
(dai->playback_widget->power || dai->capture_widget->power)) {
dev_dbg(afe->dev, "%s '%s' widget powered(%u-%u) already\n",
__func__, snd_pcm_stream_str(substream),
dai->playback_widget->power,
dai->capture_widget->power);
return 0;
}
if (be->prepared[stream] &&
(be->cached_rate[stream] == rate) &&
(be->cached_format[stream] == substream->runtime->format)) {
dev_info(afe->dev, "%s '%s' prepared already\n",
__func__, snd_pcm_stream_str(substream));
return 0;
}
if (be->prepared[stream]) {
if (apply_i2s_out_change)
mt8167_afe_set_i2s_out_enable(afe, false);
if (apply_i2s_in_change)
mt8167_afe_set_i2s_in_enable(afe, false);
if (be->cached_rate[stream] % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
}
if (apply_i2s_out_change) {
ret = mt8167_afe_set_i2s_out(afe, rate, bit_width);
if (ret)
return ret;
}
if (apply_i2s_in_change) {
ret = mt8167_afe_set_i2s_in(afe, rate, bit_width);
if (ret)
return ret;
}
if (rate % 8000)
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
if (apply_i2s_out_change) {
clk_set_parent(afe->clocks[MT8167_CLK_I2S1_M_SEL], (rate % 8000) ?
afe->clocks[MT8167_CLK_AUD1] : afe->clocks[MT8167_CLK_AUD2]);
mt8167_afe_dais_set_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV1],
rate * MT8167_I2S1_MCLK_MULTIPLIER, NULL, 0);
mt8167_afe_set_i2s_out_enable(afe, true);
be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = true;
be->cached_rate[SNDRV_PCM_STREAM_PLAYBACK] = rate;
be->cached_format[SNDRV_PCM_STREAM_PLAYBACK] = substream->runtime->format;
}
if (apply_i2s_in_change) {
clk_set_parent(afe->clocks[MT8167_CLK_I2S2_M_SEL], (rate % 8000) ?
afe->clocks[MT8167_CLK_AUD1] : afe->clocks[MT8167_CLK_AUD2]);
mt8167_afe_dais_set_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV2],
rate * MT8167_I2S2_MCLK_MULTIPLIER, NULL, 0);
mt8167_afe_set_i2s_in_enable(afe, true);
be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true;
be->cached_rate[SNDRV_PCM_STREAM_CAPTURE] = rate;
be->cached_format[SNDRV_PCM_STREAM_CAPTURE] = substream->runtime->format;
}
return 0;
}
static int mt8167_afe_2nd_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
const unsigned int stream = substream->stream;
struct snd_pcm_runtime * const runtime = substream->runtime;
const unsigned int clk_mode = afe->i2s_clk_modes[MT8167_AFE_2ND_I2S];
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const bool i2s_in_slave = (stream == SNDRV_PCM_STREAM_CAPTURE) &&
((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM);
dev_dbg(afe->dev, "%s '%s'\n",
__func__, snd_pcm_stream_str(substream));
if (clk_mode == MT8167_AFE_I2S_SHARED_CLOCK && dai->active)
return 0;
if (i2s_in_slave)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rate_2nd_i2s_slave);
mt8167_afe_enable_main_clk(afe);
if (stream == SNDRV_PCM_STREAM_PLAYBACK ||
clk_mode == MT8167_AFE_I2S_SHARED_CLOCK)
mt8167_afe_dais_enable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV3], NULL);
if ((stream == SNDRV_PCM_STREAM_CAPTURE ||
clk_mode == MT8167_AFE_I2S_SHARED_CLOCK) && !i2s_in_slave)
mt8167_afe_dais_enable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV0], NULL);
if (i2s_in_slave)
mt8167_afe_enable_top_cg(afe, MT8167_AFE_CG_I2S);
return 0;
}
static void mt8167_afe_2nd_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const unsigned int stream = substream->stream;
const unsigned int clk_mode = afe->i2s_clk_modes[MT8167_AFE_2ND_I2S];
const bool reset_i2s_out_change = (stream == SNDRV_PCM_STREAM_PLAYBACK) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
const bool reset_i2s_in_change = (stream == SNDRV_PCM_STREAM_CAPTURE) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
const bool i2s_in_slave = (stream == SNDRV_PCM_STREAM_CAPTURE) &&
((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM);
dev_dbg(afe->dev, "%s '%s'\n",
__func__, snd_pcm_stream_str(substream));
if (clk_mode == MT8167_AFE_I2S_SHARED_CLOCK && dai->active)
return;
if (be->prepared[stream]) {
if (reset_i2s_out_change)
mt8167_afe_set_2nd_i2s_out_enable(afe, false);
if (reset_i2s_in_change) {
if (i2s_in_slave)
mt8167_afe_set_2nd_i2s_asrc_enable(afe, false);
mt8167_afe_set_2nd_i2s_in_enable(afe, false);
}
if (rate % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
if (reset_i2s_out_change)
be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = false;
if (reset_i2s_in_change)
be->prepared[SNDRV_PCM_STREAM_CAPTURE] = false;
}
if (reset_i2s_out_change)
mt8167_afe_dais_disable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV3], NULL);
if (reset_i2s_in_change && !i2s_in_slave)
mt8167_afe_dais_disable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV0], NULL);
if (i2s_in_slave)
mt8167_afe_disable_top_cg(afe, MT8167_AFE_CG_I2S);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_2nd_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
unsigned int width_val = params_width(params) > 16 ?
(AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01) : 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01, width_val);
return 0;
}
static int mt8167_afe_2nd_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const int bit_width = snd_pcm_format_width(substream->runtime->format);
const unsigned int stream = substream->stream;
const unsigned int clk_mode = afe->i2s_clk_modes[MT8167_AFE_2ND_I2S];
const bool apply_i2s_out_change = (stream == SNDRV_PCM_STREAM_PLAYBACK) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
const bool apply_i2s_in_change = (stream == SNDRV_PCM_STREAM_CAPTURE) ||
(clk_mode == MT8167_AFE_I2S_SHARED_CLOCK);
const bool i2s_in_slave = (stream == SNDRV_PCM_STREAM_CAPTURE) &&
((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM);
int ret;
if ((clk_mode == MT8167_AFE_I2S_SHARED_CLOCK) &&
(dai->playback_widget->power || dai->capture_widget->power)) {
dev_dbg(afe->dev, "%s '%s' widget powered(%u-%u) already\n",
__func__, snd_pcm_stream_str(substream),
dai->playback_widget->power,
dai->capture_widget->power);
return 0;
}
if (be->prepared[stream] &&
(be->cached_rate[stream] == rate) &&
(be->cached_format[stream] == substream->runtime->format)) {
dev_info(afe->dev, "%s '%s' prepared already\n",
__func__, snd_pcm_stream_str(substream));
return 0;
}
if (be->prepared[stream]) {
if (apply_i2s_out_change)
mt8167_afe_set_2nd_i2s_out_enable(afe, false);
if (apply_i2s_in_change) {
if (i2s_in_slave)
mt8167_afe_set_2nd_i2s_asrc_enable(afe, false);
mt8167_afe_set_2nd_i2s_in_enable(afe, false);
}
if (be->cached_rate[stream] % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
}
if (apply_i2s_out_change) {
ret = mt8167_afe_set_2nd_i2s_out(afe, rate, bit_width);
if (ret)
return ret;
}
if (apply_i2s_in_change) {
if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) {
ret = mt8167_afe_set_2nd_i2s_asrc(afe, rate, rate,
(unsigned int)bit_width, 0);
if (ret < 0)
return ret;
}
ret = mt8167_afe_set_2nd_i2s_in(afe, rate, bit_width);
if (ret)
return ret;
}
if (rate % 8000)
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
if (apply_i2s_out_change) {
clk_set_parent(afe->clocks[MT8167_CLK_I2S3_M_SEL], (rate % 8000) ?
afe->clocks[MT8167_CLK_AUD1] : afe->clocks[MT8167_CLK_AUD2]);
mt8167_afe_dais_set_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV3],
rate * MT8167_I2S3_MCLK_MULTIPLIER, NULL, 0);
mt8167_afe_set_2nd_i2s_out_enable(afe, true);
be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = true;
be->cached_rate[SNDRV_PCM_STREAM_PLAYBACK] = rate;
be->cached_format[SNDRV_PCM_STREAM_PLAYBACK] = substream->runtime->format;
}
if (apply_i2s_in_change) {
clk_set_parent(afe->clocks[MT8167_CLK_I2S0_M_SEL], (rate % 8000) ?
afe->clocks[MT8167_CLK_AUD1] : afe->clocks[MT8167_CLK_AUD2]);
mt8167_afe_dais_set_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV0],
rate * MT8167_I2S0_MCLK_MULTIPLIER, NULL, 0);
mt8167_afe_set_2nd_i2s_in_enable(afe, true);
if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
mt8167_afe_set_2nd_i2s_asrc_enable(afe, true);
be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true;
be->cached_rate[SNDRV_PCM_STREAM_CAPTURE] = rate;
be->cached_format[SNDRV_PCM_STREAM_CAPTURE] = substream->runtime->format;
}
return 0;
}
static int mt8167_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
be->fmt_mode = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
be->fmt_mode |= SND_SOC_DAIFMT_I2S;
break;
case SND_SOC_DAIFMT_LEFT_J:
be->fmt_mode |= SND_SOC_DAIFMT_LEFT_J;
break;
default:
dev_err(afe->dev, "invalid audio format for 2nd i2s!\n");
return -EINVAL;
}
if (((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) &&
((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_IF) &&
((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_NF) &&
((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_IF)) {
dev_err(afe->dev, "invalid audio format for 2nd i2s!\n");
return -EINVAL;
}
be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK);
if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) &&
(afe->i2s_clk_modes[MT8167_AFE_2ND_I2S] == MT8167_AFE_I2S_SEPARATE_CLOCK))
be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK);
return 0;
}
static int mt8167_afe_int_adda_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_enable_main_clk(afe);
mt8167_afe_enable_afe_on(afe);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mt8167_afe_enable_top_cg(afe, MT8167_AFE_CG_DAC);
mt8167_afe_enable_top_cg(afe, MT8167_AFE_CG_DAC_PREDIS);
} else {
mt8167_afe_enable_top_cg(afe, MT8167_AFE_CG_ADC);
}
udelay(100);
return 0;
}
static void mt8167_afe_int_adda_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int stream = substream->stream;
dev_dbg(afe->dev, "%s '%s'\n", __func__,
snd_pcm_stream_str(substream));
if (be->prepared[stream]) {
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
mt8167_afe_set_adda_out_enable(afe, false);
mt8167_afe_set_i2s_out_enable(afe, false);
} else {
mt8167_afe_set_adda_in_enable(afe, false);
}
be->prepared[stream] = false;
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
mt8167_afe_disable_top_cg(afe, MT8167_AFE_CG_DAC);
mt8167_afe_disable_top_cg(afe, MT8167_AFE_CG_DAC_PREDIS);
} else {
mt8167_afe_disable_top_cg(afe, MT8167_AFE_CG_ADC);
}
mt8167_afe_disable_afe_on(afe);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_int_adda_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
unsigned int width_val = params_width(params) > 16 ?
(AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04) : 0;
dev_dbg(afe->dev, "%s '%s'\n", __func__, snd_pcm_stream_str(substream));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
AFE_CONN_24BIT_O03 | AFE_CONN_24BIT_O04, width_val);
return 0;
}
static int mt8167_afe_int_adda_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const unsigned int stream = substream->stream;
const int bit_width = snd_pcm_format_width(substream->runtime->format);
int ret;
dev_dbg(afe->dev, "%s '%s' rate = %u\n", __func__,
snd_pcm_stream_str(substream), rate);
if (be->prepared[stream] &&
(be->cached_rate[stream] == rate) &&
(be->cached_format[stream] == substream->runtime->format)) {
dev_info(afe->dev, "%s '%s' prepared already\n",
__func__, snd_pcm_stream_str(substream));
return 0;
}
if (be->prepared[stream]) {
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
mt8167_afe_set_adda_out_enable(afe, false);
mt8167_afe_set_i2s_out_enable(afe, false);
} else {
mt8167_afe_set_adda_in_enable(afe, false);
}
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = mt8167_afe_set_adda_out(afe, rate);
if (ret)
return ret;
ret = mt8167_afe_set_i2s_out(afe, rate, bit_width);
if (ret)
return ret;
mt8167_afe_set_adda_out_enable(afe, true);
mt8167_afe_set_i2s_out_enable(afe, true);
} else {
ret = mt8167_afe_set_adda_in(afe, rate);
if (ret)
return ret;
mt8167_afe_set_adda_in_enable(afe, true);
}
be->prepared[stream] = true;
be->cached_rate[stream] = rate;
be->cached_format[stream] = substream->runtime->format;
return 0;
}
static int mt8167_afe_mrg_bt_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_enable_main_clk(afe);
return 0;
}
static void mt8167_afe_mrg_bt_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_mrg_bt_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
int ret;
dev_dbg(afe->dev, "%s '%s' rate = %u\n", __func__,
snd_pcm_stream_str(substream), params_rate(params));
ret = mt8167_afe_set_mrg(afe, params_rate(params));
if (ret)
return ret;
return 0;
}
static int mt8167_afe_mrg_bt_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
dev_info(afe->dev, "%s %s '%s' cmd = %d\n", __func__,
dai->name, snd_pcm_stream_str(substream), cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
mt8167_afe_enable_mrg(afe);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
mt8167_afe_disable_mrg(afe);
return 0;
default:
return -EINVAL;
}
}
static int mt8167_afe_pcm0_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_enable_main_clk(afe);
return 0;
}
static void mt8167_afe_pcm0_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_pcm0_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
int ret;
dev_dbg(afe->dev, "%s '%s' rate = %u\n", __func__,
snd_pcm_stream_str(substream), params_rate(params));
ret = mt8167_afe_set_pcm0(afe, params_rate(params));
if (ret)
return ret;
return 0;
}
static int mt8167_afe_pcm0_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
dev_info(afe->dev, "%s %s '%s' cmd = %d\n", __func__,
dai->name, snd_pcm_stream_str(substream), cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
mt8167_afe_enable_pcm0(afe);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
mt8167_afe_disable_pcm0(afe);
return 0;
default:
return -EINVAL;
}
}
static int mt8167_afe_hdmi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_enable_main_clk(afe);
mt8167_afe_dais_enable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV4],
afe->clocks[MT8167_CLK_APLL12_DIV4B]);
return 0;
}
static void mt8167_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const unsigned int stream = substream->stream;
if (be->prepared[stream]) {
/* disable tdm */
regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0);
mt8167_afe_disable_top_cg(afe, MT8167_AFE_CG_HDMI);
if (rate % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
be->prepared[stream] = false;
}
mt8167_afe_dais_disable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV4],
afe->clocks[MT8167_CLK_APLL12_DIV4B]);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_hdmi_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int tdm_out_mode = afe->tdm_out_mode;
const unsigned int rate = runtime->rate;
const unsigned int channels = runtime->channels;
const unsigned int out_channels_per_sdata =
mt8167_afe_tdm_out_ch_per_sdata(tdm_out_mode, runtime->channels);
const int bit_width = snd_pcm_format_width(runtime->format);
const int out_bit_width = mt8167_afe_tdm_out_bitwidth_fixup(tdm_out_mode, bit_width);
const unsigned int stream = substream->stream;
unsigned int val;
unsigned int bck_inverse = 0;
if (be->prepared[stream] &&
(be->cached_rate[stream] == rate) &&
(be->cached_format[stream] == runtime->format) &&
(be->cached_channels[stream] == channels)) {
dev_info(afe->dev, "%s prepared already\n", __func__);
return 0;
}
if (be->prepared[stream]) {
/* disable tdm */
regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0);
mt8167_afe_disable_top_cg(afe, MT8167_AFE_CG_HDMI);
if (be->cached_rate[stream] % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
}
if (rate % 8000) {
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
clk_set_parent(afe->clocks[MT8167_CLK_I2S4_M_SEL], afe->clocks[MT8167_CLK_AUD1]);
} else {
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
clk_set_parent(afe->clocks[MT8167_CLK_I2S4_M_SEL], afe->clocks[MT8167_CLK_AUD2]);
}
mt8167_afe_dais_set_clks(afe,
afe->clocks[MT8167_CLK_APLL12_DIV4],
rate * MT8167_TDM_OUT_MCLK_MULTIPLIER,
afe->clocks[MT8167_CLK_APLL12_DIV4B],
rate * out_channels_per_sdata * out_bit_width);
val = AFE_TDM_CON1_MSB_ALIGNED;
if ((tdm_out_mode == MT8167_AFE_TDM_OUT_I2S ||
tdm_out_mode == MT8167_AFE_TDM_OUT_I2S_32BITS) &&
(be->fmt_mode & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) {
val |= AFE_TDM_CON1_1_BCK_DELAY |
AFE_TDM_CON1_LRCK_INV;
bck_inverse = AUD_TCON3_HDMI_BCK_INV;
} else if (tdm_out_mode == MT8167_AFE_TDM_OUT_HDMI) {
val |= AFE_TDM_CON1_1_BCK_DELAY |
AFE_TDM_CON1_LRCK_INV;
} else if (tdm_out_mode == MT8167_AFE_TDM_OUT_TDM) {
val |= AFE_TDM_CON1_1_BCK_DELAY;
bck_inverse = AUD_TCON3_HDMI_BCK_INV;
}
/* bit width related */
if (out_bit_width > 16) {
val |= AFE_TDM_CON1_WLEN_32BIT |
AFE_TDM_CON1_32_BCK_CYCLES |
AFE_TDM_CON1_LRCK_WIDTH(32);
} else {
val |= AFE_TDM_CON1_WLEN_16BIT |
AFE_TDM_CON1_16_BCK_CYCLES |
AFE_TDM_CON1_LRCK_WIDTH(16);
}
/* channel per sdata */
if (out_channels_per_sdata > 4)
val |= AFE_TDM_CON1_8CH_PER_SDATA;
else if (out_channels_per_sdata > 2)
val |= AFE_TDM_CON1_4CH_PER_SDATA;
else
val |= AFE_TDM_CON1_2CH_PER_SDATA;
regmap_update_bits(afe->regmap, AFE_TDM_CON1, ~(u32)AFE_TDM_CON1_EN, val);
/* set tdm2 config */
if (out_channels_per_sdata == 2) {
switch (channels) {
case 1:
case 2:
val = AFE_TDM_CH_START_O28_O29;
val |= (AFE_TDM_CH_ZERO << 4);
val |= (AFE_TDM_CH_ZERO << 8);
val |= (AFE_TDM_CH_ZERO << 12);
break;
case 3:
case 4:
val = AFE_TDM_CH_START_O28_O29;
val |= (AFE_TDM_CH_START_O30_O31 << 4);
val |= (AFE_TDM_CH_ZERO << 8);
val |= (AFE_TDM_CH_ZERO << 12);
break;
case 5:
case 6:
val = AFE_TDM_CH_START_O28_O29;
val |= (AFE_TDM_CH_START_O30_O31 << 4);
val |= (AFE_TDM_CH_START_O32_O33 << 8);
val |= (AFE_TDM_CH_ZERO << 12);
break;
case 7:
case 8:
val = AFE_TDM_CH_START_O28_O29;
val |= (AFE_TDM_CH_START_O30_O31 << 4);
val |= (AFE_TDM_CH_START_O32_O33 << 8);
val |= (AFE_TDM_CH_START_O34_O35 << 12);
break;
default:
val = 0;
}
} else {
val = AFE_TDM_CH_START_O28_O29;
val |= (AFE_TDM_CH_ZERO << 4);
val |= (AFE_TDM_CH_ZERO << 8);
val |= (AFE_TDM_CH_ZERO << 12);
}
regmap_update_bits(afe->regmap, AFE_TDM_CON2,
AFE_TDM_CON2_SOUT_MASK, val);
regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
AUD_TCON3_HDMI_BCK_INV, bck_inverse);
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
AFE_HDMI_OUT_CON0_CH_MASK, channels << 4);
if (tdm_out_mode != MT8167_AFE_TDM_OUT_HDMI)
regmap_update_bits(afe->regmap, AFE_I2S_CON1,
AFE_I2S_CON1_TDMOUT_MUX_MASK, AFE_I2S_CON1_TDMOUT_TO_PAD);
mt8167_afe_enable_top_cg(afe, MT8167_AFE_CG_HDMI);
/* enable tdm */
regmap_update_bits(afe->regmap, AFE_TDM_CON1, 0x1, 0x1);
be->prepared[stream] = true;
be->cached_rate[stream] = rate;
be->cached_format[stream] = runtime->format;
be->cached_channels[stream] = channels;
return 0;
}
static int mt8167_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
dev_dbg(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
/* align the connection logic with HDMI Tx */
/* set connections: O28~O35: L/R/LFE/C/LS/RS/CH7/CH8 */
if (afe->tdm_out_mode == MT8167_AFE_TDM_OUT_HDMI)
regmap_write(afe->regmap, AFE_HDMI_CONN0,
AFE_HDMI_CONN0_O28_I28 | AFE_HDMI_CONN0_O29_I29 |
AFE_HDMI_CONN0_O30_I31 | AFE_HDMI_CONN0_O31_I30 |
AFE_HDMI_CONN0_O32_I32 | AFE_HDMI_CONN0_O33_I33 |
AFE_HDMI_CONN0_O34_I34 | AFE_HDMI_CONN0_O35_I35);
else
regmap_write(afe->regmap, AFE_HDMI_CONN0,
AFE_HDMI_CONN0_O28_I28 | AFE_HDMI_CONN0_O29_I29 |
AFE_HDMI_CONN0_O30_I30 | AFE_HDMI_CONN0_O31_I31 |
AFE_HDMI_CONN0_O32_I32 | AFE_HDMI_CONN0_O33_I33 |
AFE_HDMI_CONN0_O34_I34 | AFE_HDMI_CONN0_O35_I35);
/* enable Out control */
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
/* disable Out control */
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0);
return 0;
default:
return -EINVAL;
}
}
static int mt8167_afe_hdmi_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
be->fmt_mode = 0;
/* set DAI format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
be->fmt_mode |= fmt & SND_SOC_DAIFMT_FORMAT_MASK;
break;
default:
dev_err(afe->dev, "invalid dai format %u\n", fmt);
return -EINVAL;
}
return 0;
}
static int mt8167_afe_tdm_in_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels_tdm_in);
mt8167_afe_enable_main_clk(afe);
mt8167_afe_dais_enable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV5],
afe->clocks[MT8167_CLK_APLL12_DIV5B]);
return 0;
}
static void mt8167_afe_tdm_in_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = substream->runtime->rate;
const unsigned int stream = substream->stream;
if (be->prepared[stream]) {
if (rate % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
be->prepared[stream] = false;
}
mt8167_afe_dais_disable_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV5],
afe->clocks[MT8167_CLK_APLL12_DIV5B]);
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_tdm_in_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = runtime->rate;
const unsigned int channels = runtime->channels;
int bit_width = snd_pcm_format_width(runtime->format);
const unsigned int stream = substream->stream;
unsigned int val,val2;
unsigned int bck;
dev_info(afe->dev, "%s bit_width = %d\n", __func__,bit_width);
/*support S24_LE*/
if (bit_width > 16)
bit_width = 32;
if (be->prepared[stream] &&
(be->cached_rate[stream] == rate) &&
(be->cached_format[stream] == runtime->format) &&
(be->cached_channels[stream] == channels)) {
dev_info(afe->dev, "%s prepared already\n", __func__);
return 0;
}
if (be->prepared[stream]) {
if (be->cached_rate[stream] % 8000)
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
else
mt8167_afe_disable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
}
dev_dbg(afe->dev, "afe->tdm_in_lrck_cycle= %u\n", afe->tdm_in_lrck_cycle);
if (rate % 8000) {
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL1);
clk_set_parent(afe->clocks[MT8167_CLK_I2S5_M_SEL], afe->clocks[MT8167_CLK_AUD1]);
} else {
mt8167_afe_enable_apll_associated_cfg(afe, MT8167_AFE_APLL2);
clk_set_parent(afe->clocks[MT8167_CLK_I2S5_M_SEL], afe->clocks[MT8167_CLK_AUD2]);
}
bck = ((channels == 6 || channels == 4)
? 8 : channels) * rate * bit_width;
mt8167_afe_dais_set_clks(afe, afe->clocks[MT8167_CLK_APLL12_DIV5],
rate * MT8167_TDM_IN_MCLK_MULTIPLIER,
afe->clocks[MT8167_CLK_APLL12_DIV5B], bck);
val = 0;
if ((be->fmt_mode & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
val |= AFE_TDM_IN_CON1_I2S;
/* bck&lrck phase */
switch (be->fmt_mode & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
val |= AFE_TDM_IN_CON1_LRCK_INV |
AFE_TDM_IN_CON1_BCK_INV;
break;
case SND_SOC_DAIFMT_NB_IF:
val |= AFE_TDM_IN_CON1_LRCK_INV;
break;
case SND_SOC_DAIFMT_IB_NF:
val |= AFE_TDM_IN_CON1_BCK_INV;
break;
default:
break;
}
/* bit width related */
if (bit_width > 16)
val |= AFE_TDM_IN_CON1_WLEN_32BIT |
AFE_TDM_IN_CON1_FAST_LRCK_CYCLE_32BCK;
else
val |= AFE_TDM_IN_CON1_WLEN_16BIT |
AFE_TDM_IN_CON1_FAST_LRCK_CYCLE_16BCK;
if (LRCK_CYCLE_INVALID == afe->tdm_in_lrck_cycle) {
val2 = bit_width > 16 ? 32 : 16;
val |= AFE_TDM_IN_CON1_LRCK_WIDTH(val2);
}
else
val |= AFE_TDM_IN_CON1_LRCK_WIDTH(afe->tdm_in_lrck_cycle);
switch (channels) {
case 2:
val |= AFE_TDM_IN_CON1_4CH_PER_SDATA;
val |= AFE_TDM_IN_CON1_DISABLE_CH23;
break;
case 4:
val |= AFE_TDM_IN_CON1_8CH_PER_SDATA;
val |= AFE_TDM_IN_CON1_DISABLE_CH67;
val |= AFE_TDM_IN_CON1_DISABLE_CH45;
break;
case 6:
val |= AFE_TDM_IN_CON1_8CH_PER_SDATA;
val |= AFE_TDM_IN_CON1_DISABLE_CH67;
break;
case 8:
val |= AFE_TDM_IN_CON1_8CH_PER_SDATA;
break;
default:
break;
}
regmap_update_bits(afe->regmap, AFE_TDM_IN_CON1,
~(u32)AFE_TDM_IN_CON1_EN, val);
be->prepared[stream] = true;
be->cached_rate[stream] = rate;
be->cached_format[stream] = runtime->format;
be->cached_channels[stream] = channels;
return 0;
}
static int mt8167_afe_tdm_in_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
be->fmt_mode = 0;
/* set DAI format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
be->fmt_mode |= fmt & SND_SOC_DAIFMT_FORMAT_MASK;
break;
default:
dev_err(afe->dev, "invalid dai format %u\n", fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
case SND_SOC_DAIFMT_NB_IF:
case SND_SOC_DAIFMT_IB_NF:
case SND_SOC_DAIFMT_IB_IF:
be->fmt_mode |= fmt & SND_SOC_DAIFMT_INV_MASK;
break;
default:
dev_err(afe->dev, "invalid dai format %u\n", fmt);
return -EINVAL;
}
return 0;
}
static int mt8167_afe_tdm_in_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
unsigned int val;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
regmap_update_bits(afe->regmap, AFE_CONN_TDMIN_CON,
AFE_CONN_TDMIN_CON0_MASK,
AFE_CONN_TDMIN_O40_I40 | AFE_CONN_TDMIN_O41_I41);
regmap_update_bits(afe->regmap, AFE_HDMI_IN_2CH_CON0, 0x1, 0x1);
/* enable tdm in */
regmap_update_bits(afe->regmap, AFE_TDM_IN_CON1, 0x1, 0x1);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
#ifdef MT8167_AFE_E1_ONLY
do {
regmap_read(afe->regmap, AFE_TDM_IN_MON2, &val);
} while (val & AFE_TDM_IN_MON2_FAST_LRCK);
#endif
/* disable tdm in */
regmap_update_bits(afe->regmap, AFE_TDM_IN_CON1, 0x1, 0);
regmap_update_bits(afe->regmap, AFE_HDMI_IN_2CH_CON0, 0x1, 0);
return 0;
default:
return -EINVAL;
}
return 0;
}
static int mt8167_afe_dais_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct snd_pcm_runtime *runtime = substream->runtime;
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
int ret;
dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, memif->data->buffer_align_bytes);
snd_soc_set_runtime_hwparams(substream, &mt8167_afe_hardware);
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
return ret;
}
memif->substream = substream;
mt8167_afe_enable_main_clk(afe);
return 0;
}
static void mt8167_afe_dais_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);
if (memif->prepared) {
mt8167_afe_disable_afe_on(afe);
memif->prepared = false;
}
memif->substream = NULL;
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_dais_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
const struct mt8167_afe_memif_data *data = memif->data;
const size_t request_size = params_buffer_bytes(params);
int ret;
dev_dbg(afe->dev,
"%s %s period = %u rate = %u channels = %u size = %zu\n",
__func__, data->name, params_period_size(params),
params_rate(params), params_channels(params), request_size);
if (request_size > data->max_sram_size) {
ret = snd_pcm_lib_malloc_pages(substream, request_size);
if (ret < 0) {
dev_err(afe->dev,
"%s %s malloc pages %zu bytes failed %d\n",
__func__, data->name, request_size, ret);
return ret;
}
memif->use_sram = false;
mt8167_afe_emi_clk_on(afe);
} else {
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
dma_buf->dev.dev = substream->pcm->card->dev;
dma_buf->area = ((unsigned char *)afe->sram_address) +
data->sram_offset;
dma_buf->addr = afe->sram_phy_address + data->sram_offset;
dma_buf->bytes = request_size;
snd_pcm_set_runtime_buffer(substream, dma_buf);
memif->use_sram = true;
}
memif->phys_buf_addr = substream->runtime->dma_addr;
memif->buffer_size = substream->runtime->dma_bytes;
/* start */
regmap_write(afe->regmap, data->reg_ofs_base,
memif->phys_buf_addr);
/* end */
regmap_write(afe->regmap, data->reg_ofs_end,
memif->phys_buf_addr + memif->buffer_size - 1);
{
/* set channel */
unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
if (data->mono_shift >= 0) {
regmap_update_bits(afe->regmap, AFE_DAC_CON1,
1 << data->mono_shift,
mono << data->mono_shift);
}
/* set spdif in channel bit[1]: 0stereo/1mono*/
if (data->id == MT8167_AFE_MEMIF_MULTILINE_IN) {
regmap_update_bits(afe->regmap, SPDIFIN_MEMIF_CON0, 1 << 1, mono << 1);
if (mono == 1)/*0L,1R channel*/
regmap_update_bits(afe->regmap, SPDIFIN_MEMIF_CON0, 1 << 2, 1 << 2);
/*set spdif in intr_period*/
regmap_update_bits(afe->regmap, SPDIFIN_MEMIF_CON0, MULTI_INT_PERIOD_MASK, MULTI_INT_PERIOD_64);
}
}
/* set format */
if (data->format_shift >= 0) {
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
regmap_update_bits(afe->regmap, data->format_reg,
3 << data->format_shift,
0 << data->format_shift);
break;
case SNDRV_PCM_FORMAT_S32_LE:
regmap_update_bits(afe->regmap, data->format_reg,
3 << data->format_shift,
3 << data->format_shift);
break;
case SNDRV_PCM_FORMAT_S24_LE:
regmap_update_bits(afe->regmap, data->format_reg,
3 << data->format_shift,
1 << data->format_shift);
if (data->id == MT8167_AFE_MEMIF_MULTILINE_IN) {
regmap_update_bits(afe->regmap, data->format_reg,
3 << data->format_shift,
3 << data->format_shift);
}
break;
default:
return -EINVAL;
}
}
if (data->conn_format_mask > 0) {
if (params_width(params) > 16)
regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
data->conn_format_mask,
data->conn_format_mask);
else
regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
data->conn_format_mask,
0);
}
/* set rate */
if (data->fs_shift < 0)
return 0;
if (data->id == MT8167_AFE_MEMIF_DAI ||
data->id == MT8167_AFE_MEMIF_MOD_DAI) {
unsigned int val;
switch (params_rate(params)) {
case 8000:
val = 0;
break;
case 16000:
val = 1;
break;
case 32000:
val = 2;
break;
default:
dev_err(afe->dev, "%s %s rate %u not supported\n",
__func__, data->name, params_rate(params));
return -EINVAL;
}
if (data->id == MT8167_AFE_MEMIF_DAI)
regmap_update_bits(afe->regmap, AFE_DAC_CON0,
0x3 << data->fs_shift,
val << data->fs_shift);
else
regmap_update_bits(afe->regmap, AFE_DAC_CON1,
0x3 << data->fs_shift,
val << data->fs_shift);
} else {
int fs = mt8167_afe_i2s_fs(params_rate(params));
if (fs < 0)
return -EINVAL;
regmap_update_bits(afe->regmap, AFE_DAC_CON1,
0xf << data->fs_shift,
fs << data->fs_shift);
}
return 0;
}
static int mt8167_afe_dais_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
int ret = 0;
dev_dbg(afe->dev, "%s %s\n", __func__, memif->data->name);
if (memif->use_sram) {
snd_pcm_set_runtime_buffer(substream, NULL);
} else {
ret = snd_pcm_lib_free_pages(substream);
mt8167_afe_emi_clk_off(afe);
}
return ret;
}
static int mt8167_afe_dais_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
if (!memif->prepared) {
mt8167_afe_enable_afe_on(afe);
memif->prepared = true;
}
return 0;
}
static int mt8167_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
unsigned int counter = runtime->period_size;
dev_info(afe->dev, "%s %s cmd = %d\n", __func__,
memif->data->name, cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
if (memif->data->enable_shift >= 0)
regmap_update_bits(afe->regmap, AFE_DAC_CON0,
1 << memif->data->enable_shift,
1 << memif->data->enable_shift);
/*enable spdif in memif input
*enable update for spdifin sample, enable type detection and periodic interrupt generation
*/
if (memif->data->id == MT8167_AFE_MEMIF_MULTILINE_IN) {
regmap_update_bits(afe->regmap, SPDIFIN_MEMIF_CON0, SPDIFIN_IN_MEMIF_EN_MASK, SPDIFIN_IN_MEMIF_EN);
regmap_update_bits(afe->regmap, MPHONE_MULTI_CON0, MULTI_HW_EN_MASK, MULTI_HW_EN);
regmap_update_bits(afe->regmap, memif->data->irq_reg_cnt, 1 <<31, 1 <<31);
}
/* set irq counter */
regmap_update_bits(afe->regmap,
memif->data->irq_reg_cnt,
0x3ffff << memif->data->irq_cnt_shift,
counter << memif->data->irq_cnt_shift);
/* set irq fs */
if (memif->data->irq_fs_shift >= 0) {
int fs = mt8167_afe_i2s_fs(runtime->rate);
if (fs < 0)
return -EINVAL;
regmap_update_bits(afe->regmap,
memif->data->irq_fs_reg,
0xf << memif->data->irq_fs_shift,
fs << memif->data->irq_fs_shift);
}
mt8167_afe_enable_irq(afe, memif);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
if (memif->data->enable_shift >= 0)
regmap_update_bits(afe->regmap, AFE_DAC_CON0,
1 << memif->data->enable_shift, 0);
/*disable spdif in memif input */
if (memif->data->id == MT8167_AFE_MEMIF_MULTILINE_IN) {
regmap_update_bits(afe->regmap, SPDIFIN_MEMIF_CON0, SPDIFIN_IN_MEMIF_EN_MASK, SPDIFIN_IN_MEMIF_DIS);
regmap_update_bits(afe->regmap, MPHONE_MULTI_CON0, MULTI_HW_EN_MASK, MULTI_HW_DIS);
}
mt8167_afe_disable_irq(afe, memif);
return 0;
default:
return -EINVAL;
}
}
static int mt8167_afe_hw_gain1_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
mt8167_afe_enable_main_clk(afe);
return 0;
}
static void mt8167_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int stream = substream->stream;
if (be->prepared[stream]) {
regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_EN_MASK, 0);
be->prepared[stream] = false;
}
mt8167_afe_disable_main_clk(afe);
}
static int mt8167_afe_hw_gain1_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_pcm_runtime * const runtime = substream->runtime;
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8167_afe_be_dai_data *be = &afe->be_data[dai->id - MT8167_AFE_BACKEND_BASE];
const unsigned int rate = runtime->rate;
const unsigned int stream = substream->stream;
int fs;
unsigned int val1, val2;
if (be->prepared[stream] &&
(be->cached_rate[stream] == rate)) {
dev_info(afe->dev, "%s prepared already\n", __func__);
return 0;
}
if (be->prepared[stream])
regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_EN_MASK, 0);
fs = mt8167_afe_i2s_fs(rate);
regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs<<4);
regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1);
regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2);
if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK))
regmap_update_bits(afe->regmap, AFE_GAIN1_CUR, AFE_GAIN1_CUR_MASK, val1);
regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_EN_MASK, 1);
be->prepared[stream] = true;
be->cached_rate[stream] = rate;
return 0;
}
/* FE DAIs */
static const struct snd_soc_dai_ops mt8167_afe_dai_ops = {
.startup = mt8167_afe_dais_startup,
.shutdown = mt8167_afe_dais_shutdown,
.hw_params = mt8167_afe_dais_hw_params,
.hw_free = mt8167_afe_dais_hw_free,
.prepare = mt8167_afe_dais_prepare,
.trigger = mt8167_afe_dais_trigger,
};
/* BE DAIs */
static const struct snd_soc_dai_ops mt8167_afe_i2s_ops = {
.startup = mt8167_afe_i2s_startup,
.shutdown = mt8167_afe_i2s_shutdown,
.hw_params = mt8167_afe_i2s_hw_params,
.prepare = mt8167_afe_i2s_prepare,
};
static const struct snd_soc_dai_ops mt8167_afe_2nd_i2s_ops = {
.startup = mt8167_afe_2nd_i2s_startup,
.shutdown = mt8167_afe_2nd_i2s_shutdown,
.hw_params = mt8167_afe_2nd_i2s_hw_params,
.prepare = mt8167_afe_2nd_i2s_prepare,
.set_fmt = mt8167_afe_2nd_i2s_set_fmt,
};
static const struct snd_soc_dai_ops mt8167_afe_int_adda_ops = {
.startup = mt8167_afe_int_adda_startup,
.shutdown = mt8167_afe_int_adda_shutdown,
.hw_params = mt8167_afe_int_adda_hw_params,
.prepare = mt8167_afe_int_adda_prepare,
};
static const struct snd_soc_dai_ops mt8167_afe_mrg_bt_ops = {
.startup = mt8167_afe_mrg_bt_startup,
.shutdown = mt8167_afe_mrg_bt_shutdown,
.hw_params = mt8167_afe_mrg_bt_hw_params,
.trigger = mt8167_afe_mrg_bt_trigger,
};
static const struct snd_soc_dai_ops mt8167_afe_pcm0_ops = {
.startup = mt8167_afe_pcm0_startup,
.shutdown = mt8167_afe_pcm0_shutdown,
.hw_params = mt8167_afe_pcm0_hw_params,
.trigger = mt8167_afe_pcm0_trigger,
};
static const struct snd_soc_dai_ops mt8167_afe_hdmi_ops = {
.startup = mt8167_afe_hdmi_startup,
.shutdown = mt8167_afe_hdmi_shutdown,
.prepare = mt8167_afe_hdmi_prepare,
.trigger = mt8167_afe_hdmi_trigger,
.set_fmt = mt8167_afe_hdmi_set_fmt,
};
static const struct snd_soc_dai_ops mt8167_afe_tdm_in_ops = {
.startup = mt8167_afe_tdm_in_startup,
.shutdown = mt8167_afe_tdm_in_shutdown,
.prepare = mt8167_afe_tdm_in_prepare,
.trigger = mt8167_afe_tdm_in_trigger,
.set_fmt = mt8167_afe_tdm_in_set_fmt,
};
static const struct snd_soc_dai_ops mt8167_afe_hw_gain1_ops = {
.startup = mt8167_afe_hw_gain1_startup,
.shutdown = mt8167_afe_hw_gain1_shutdown,
.prepare = mt8167_afe_hw_gain1_prepare,
};
static int mt8167_afe_suspend(struct device *dev);
static int mt8167_afe_resume(struct device *dev);
static int mt8167_afe_dai_suspend(struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
dev_dbg(afe->dev, "%s id %d suspended %d\n",
__func__, dai->id, afe->suspended);
if (afe->suspended)
return 0;
return mt8167_afe_suspend(afe->dev);
}
static int mt8167_afe_dai_resume(struct snd_soc_dai *dai)
{
struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai);
dev_dbg(afe->dev, "%s id %d suspended %d\n",
__func__, dai->id, afe->suspended);
if (!afe->suspended)
return 0;
mt8167_afe_resume(afe->dev);
return 0;
}
static struct snd_soc_dai_driver mt8167_afe_pcm_dais[] = {
/* FE DAIs: memory intefaces to CPU */
{
.name = "DL1",
.id = MT8167_AFE_MEMIF_DL1,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.playback = {
.stream_name = "DL1",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "VUL",
.id = MT8167_AFE_MEMIF_VUL,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.capture = {
.stream_name = "VUL",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "DL2",
.id = MT8167_AFE_MEMIF_DL2,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.playback = {
.stream_name = "DL2",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "AWB",
.id = MT8167_AFE_MEMIF_AWB,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.capture = {
.stream_name = "AWB",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "DAI",
.id = MT8167_AFE_MEMIF_DAI,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.capture = {
.stream_name = "DAI",
.channels_min = 1,
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_32000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "HDMI",
.id = MT8167_AFE_MEMIF_HDMI,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.playback = {
.stream_name = "HDMI",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "TDM_IN",
.id = MT8167_AFE_MEMIF_TDM_IN,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.capture = {
.stream_name = "TDM_IN",
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
.name = "ULM",
.id = MT8167_AFE_MEMIF_MULTILINE_IN,
.suspend = mt8167_afe_dai_suspend,
.resume = mt8167_afe_dai_resume,
.capture = {
.stream_name = "MULTILINE_IN",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200
| SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_176400
| SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_dai_ops,
}, {
/* BE DAIs */
.name = "I2S",
.id = MT8167_AFE_IO_I2S,
.playback = {
.stream_name = "I2S Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "I2S Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_i2s_ops,
}, {
.name = "2ND I2S",
.id = MT8167_AFE_IO_2ND_I2S,
.playback = {
.stream_name = "2ND I2S Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "2ND I2S Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_2nd_i2s_ops,
}, {
/* BE DAIs */
.name = "INT ADDA",
.id = MT8167_AFE_IO_INT_ADDA,
.playback = {
.stream_name = "INT ADDA Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE,
},
.capture = {
.stream_name = "INT ADDA Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &mt8167_afe_int_adda_ops,
}, {
/* BE DAIs */
.name = "MRG BT",
.id = MT8167_AFE_IO_MRG_BT,
.playback = {
.stream_name = "MRG BT Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "MRG BT Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &mt8167_afe_mrg_bt_ops,
.symmetric_rates = 1,
}, {
/* BE DAIs */
.name = "PCM0",
.id = MT8167_AFE_IO_PCM_BT,
.playback = {
.stream_name = "PCM0 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "PCM0 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &mt8167_afe_pcm0_ops,
.symmetric_rates = 1,
}, {
/* BE DAIs */
.name = "DL Input",
.id = MT8167_AFE_IO_DL_BE,
.capture = {
.stream_name = "DL Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
}, {
/* BE DAIs */
.name = "HDMIO",
.id = MT8167_AFE_IO_HDMI,
.playback = {
.stream_name = "HDMIO Playback",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_hdmi_ops,
}, {
/* BE DAIs */
.name = "TDM_IN_IO",
.id = MT8167_AFE_IO_TDM_IN,
.capture = {
.stream_name = "TDM IN Capture",
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_tdm_in_ops,
}, {
.name = "INTDIR_IO",
.id = MT8167_AFE_IO_INTDIR_BE,
.capture = {
.stream_name = "INTDIR Capture",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200
| SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_176400
| SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S32_LE,
},
}, {
/* BE DAIs */
.name = "HW_GAIN1",
.id = MT8167_AFE_IO_HW_GAIN1,
.capture = {
.stream_name = "HW GAIN1 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &mt8167_afe_hw_gain1_ops,
},
};
static struct snd_soc_dai_driver *mt8167_afe_get_dai_drv_by_id(unsigned int id)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(mt8167_afe_pcm_dais); i++) {
if (id == mt8167_afe_pcm_dais[i].id)
return &mt8167_afe_pcm_dais[i];
}
return NULL;
}
static int mt8167_afe_set_memif_irq_by_mode(struct mt8167_afe_memif_data *data,
unsigned int mode)
{
int ret = 0;
if (data == NULL)
return -EINVAL;
switch (mode) {
case MT8167_AFE_IRQ_1:
data->irq_reg_cnt = AFE_IRQ_CNT1;
data->irq_cnt_shift = 0;
data->irq_mode = MT8167_AFE_IRQ_1;
data->irq_fs_reg = AFE_IRQ_MCU_CON;
data->irq_fs_shift = 4;
data->irq_clr_shift = 0;
break;
case MT8167_AFE_IRQ_2:
data->irq_reg_cnt = AFE_IRQ_CNT2;
data->irq_cnt_shift = 0;
data->irq_mode = MT8167_AFE_IRQ_2;
data->irq_fs_reg = AFE_IRQ_MCU_CON;
data->irq_fs_shift = 8;
data->irq_clr_shift = 1;
break