Path: blob/master/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
26488 views
// SPDX-License-Identifier: GPL-2.01/*2* MediaTek ALSA SoC Audio DAI eTDM Control3*4* Copyright (c) 2023 MediaTek Inc.5* Authors: Vic Wu <[email protected]>6* Maso Huang <[email protected]>7*/89#include <linux/bitfield.h>10#include <linux/bitops.h>11#include <linux/regmap.h>12#include <sound/pcm_params.h>13#include "mt7986-afe-common.h"14#include "mt7986-reg.h"1516#define HOPPING_CLK 017#define APLL_CLK 118#define MTK_DAI_ETDM_FORMAT_I2S 019#define MTK_DAI_ETDM_FORMAT_DSPA 420#define MTK_DAI_ETDM_FORMAT_DSPB 52122enum {23MTK_ETDM_RATE_8K = 0,24MTK_ETDM_RATE_12K = 1,25MTK_ETDM_RATE_16K = 2,26MTK_ETDM_RATE_24K = 3,27MTK_ETDM_RATE_32K = 4,28MTK_ETDM_RATE_48K = 5,29MTK_ETDM_RATE_96K = 7,30MTK_ETDM_RATE_192K = 9,31MTK_ETDM_RATE_11K = 16,32MTK_ETDM_RATE_22K = 17,33MTK_ETDM_RATE_44K = 18,34MTK_ETDM_RATE_88K = 19,35MTK_ETDM_RATE_176K = 20,36};3738struct mtk_dai_etdm_priv {39bool bck_inv;40bool lrck_inv;41bool slave_mode;42unsigned int format;43};4445static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate)46{47switch (rate) {48case 8000:49return MTK_ETDM_RATE_8K;50case 11025:51return MTK_ETDM_RATE_11K;52case 12000:53return MTK_ETDM_RATE_12K;54case 16000:55return MTK_ETDM_RATE_16K;56case 22050:57return MTK_ETDM_RATE_22K;58case 24000:59return MTK_ETDM_RATE_24K;60case 32000:61return MTK_ETDM_RATE_32K;62case 44100:63return MTK_ETDM_RATE_44K;64case 48000:65return MTK_ETDM_RATE_48K;66case 88200:67return MTK_ETDM_RATE_88K;68case 96000:69return MTK_ETDM_RATE_96K;70case 176400:71return MTK_ETDM_RATE_176K;72case 192000:73return MTK_ETDM_RATE_192K;74default:75dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",76__func__, rate, MTK_ETDM_RATE_48K);77return MTK_ETDM_RATE_48K;78}79}8081static int get_etdm_wlen(unsigned int bitwidth)82{83return bitwidth <= 16 ? 16 : 32;84}8586/* dai component */87/* interconnection */8889static const struct snd_kcontrol_new o124_mix[] = {90SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),91};9293static const struct snd_kcontrol_new o125_mix[] = {94SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),95};9697static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {9899/* DL */100SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),101SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),102/* UL */103SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)),104SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)),105};106107static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {108{"I150", NULL, "ETDM Capture"},109{"I151", NULL, "ETDM Capture"},110{"ETDM Playback", NULL, "O124"},111{"ETDM Playback", NULL, "O125"},112{"O124", "I032_Switch", "I032"},113{"O125", "I033_Switch", "I033"},114};115116/* dai ops */117static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,118struct snd_soc_dai *dai)119{120struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);121struct mt7986_afe_private *afe_priv = afe->platform_priv;122int ret;123124ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);125if (ret)126return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");127128regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);129regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);130131return 0;132}133134static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,135struct snd_soc_dai *dai)136{137struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);138struct mt7986_afe_private *afe_priv = afe->platform_priv;139140regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,141CLK_OUT5_PDN);142regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,143CLK_IN5_PDN);144145clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);146}147148static unsigned int get_etdm_ch_fixup(unsigned int channels)149{150if (channels > 16)151return 24;152else if (channels > 8)153return 16;154else if (channels > 4)155return 8;156else if (channels > 2)157return 4;158else159return 2;160}161162static int mtk_dai_etdm_config(struct mtk_base_afe *afe,163struct snd_pcm_hw_params *params,164struct snd_soc_dai *dai,165int stream)166{167struct mt7986_afe_private *afe_priv = afe->platform_priv;168struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];169unsigned int rate = params_rate(params);170unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate);171unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate);172unsigned int channels = params_channels(params);173unsigned int bit_width = params_width(params);174unsigned int wlen = get_etdm_wlen(bit_width);175unsigned int val = 0;176unsigned int mask = 0;177178dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",179__func__, stream, rate, bit_width);180181/* CON0 */182mask |= ETDM_BIT_LEN_MASK;183val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1);184mask |= ETDM_WRD_LEN_MASK;185val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1);186mask |= ETDM_FMT_MASK;187val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format);188mask |= ETDM_CH_NUM_MASK;189val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1);190mask |= RELATCH_SRC_MASK;191val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK);192193switch (stream) {194case SNDRV_PCM_STREAM_PLAYBACK:195/* set ETDM_OUT5_CON0 */196regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);197198/* set ETDM_OUT5_CON4 */199regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,200OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));201regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,202OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));203regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,204OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));205206/* set ETDM_OUT5_CON5 */207regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,208ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);209break;210case SNDRV_PCM_STREAM_CAPTURE:211/* set ETDM_IN5_CON0 */212regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);213regmap_update_bits(afe->regmap, ETDM_IN5_CON0,214ETDM_SYNC_MASK, ETDM_SYNC);215216/* set ETDM_IN5_CON2 */217regmap_update_bits(afe->regmap, ETDM_IN5_CON2,218IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));219220/* set ETDM_IN5_CON3 */221regmap_update_bits(afe->regmap, ETDM_IN5_CON3,222IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));223224/* set ETDM_IN5_CON4 */225regmap_update_bits(afe->regmap, ETDM_IN5_CON4,226IN_RELATCH_MASK, IN_RELATCH(afe_rate));227break;228default:229break;230}231232return 0;233}234235static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,236struct snd_pcm_hw_params *params,237struct snd_soc_dai *dai)238{239unsigned int rate = params_rate(params);240struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);241242switch (rate) {243case 8000:244case 12000:245case 16000:246case 24000:247case 32000:248case 48000:249case 96000:250case 192000:251mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);252mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);253return 0;254default:255dev_err(afe->dev,256"Sample rate %d invalid. Supported rates: 8/12/16/24/32/48/96/192 kHz\n",257rate);258return -EINVAL;259}260}261262static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,263struct snd_soc_dai *dai)264{265struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);266267dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);268switch (cmd) {269case SNDRV_PCM_TRIGGER_START:270case SNDRV_PCM_TRIGGER_RESUME:271regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,272ETDM_EN);273regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,274ETDM_EN);275break;276case SNDRV_PCM_TRIGGER_STOP:277case SNDRV_PCM_TRIGGER_SUSPEND:278regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,2790);280regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,2810);282break;283default:284break;285}286287return 0;288}289290static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)291{292struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);293struct mt7986_afe_private *afe_priv = afe->platform_priv;294struct mtk_dai_etdm_priv *etdm_data;295void *priv_data;296297switch (dai->id) {298case MT7986_DAI_ETDM:299break;300default:301dev_warn(afe->dev, "%s(), id %d not support\n",302__func__, dai->id);303return -EINVAL;304}305306priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),307GFP_KERNEL);308if (!priv_data)309return -ENOMEM;310311afe_priv->dai_priv[dai->id] = priv_data;312etdm_data = afe_priv->dai_priv[dai->id];313314switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {315case SND_SOC_DAIFMT_I2S:316etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;317break;318case SND_SOC_DAIFMT_DSP_A:319etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;320break;321case SND_SOC_DAIFMT_DSP_B:322etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;323break;324default:325return -EINVAL;326}327328switch (fmt & SND_SOC_DAIFMT_INV_MASK) {329case SND_SOC_DAIFMT_NB_NF:330etdm_data->bck_inv = false;331etdm_data->lrck_inv = false;332break;333case SND_SOC_DAIFMT_NB_IF:334etdm_data->bck_inv = false;335etdm_data->lrck_inv = true;336break;337case SND_SOC_DAIFMT_IB_NF:338etdm_data->bck_inv = true;339etdm_data->lrck_inv = false;340break;341case SND_SOC_DAIFMT_IB_IF:342etdm_data->bck_inv = true;343etdm_data->lrck_inv = true;344break;345default:346return -EINVAL;347}348349switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {350case SND_SOC_DAIFMT_CBP_CFP:351etdm_data->slave_mode = true;352break;353case SND_SOC_DAIFMT_CBC_CFC:354etdm_data->slave_mode = false;355break;356default:357return -EINVAL;358}359360return 0;361}362363static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {364.startup = mtk_dai_etdm_startup,365.shutdown = mtk_dai_etdm_shutdown,366.hw_params = mtk_dai_etdm_hw_params,367.trigger = mtk_dai_etdm_trigger,368.set_fmt = mtk_dai_etdm_set_fmt,369};370371/* dai driver */372#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\373SNDRV_PCM_RATE_88200 |\374SNDRV_PCM_RATE_96000 |\375SNDRV_PCM_RATE_176400 |\376SNDRV_PCM_RATE_192000)377378#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\379SNDRV_PCM_FMTBIT_S24_LE |\380SNDRV_PCM_FMTBIT_S32_LE)381382static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {383{384.name = "ETDM",385.id = MT7986_DAI_ETDM,386.capture = {387.stream_name = "ETDM Capture",388.channels_min = 1,389.channels_max = 2,390.rates = MTK_ETDM_RATES,391.formats = MTK_ETDM_FORMATS,392},393.playback = {394.stream_name = "ETDM Playback",395.channels_min = 1,396.channels_max = 2,397.rates = MTK_ETDM_RATES,398.formats = MTK_ETDM_FORMATS,399},400.ops = &mtk_dai_etdm_ops,401.symmetric_rate = 1,402.symmetric_sample_bits = 1,403},404};405406int mt7986_dai_etdm_register(struct mtk_base_afe *afe)407{408struct mtk_base_afe_dai *dai;409410dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);411if (!dai)412return -ENOMEM;413414list_add(&dai->list, &afe->sub_dais);415416dai->dai_drivers = mtk_dai_etdm_driver;417dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);418419dai->dapm_widgets = mtk_dai_etdm_widgets;420dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);421dai->dapm_routes = mtk_dai_etdm_routes;422dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);423424return 0;425}426427428