Path: blob/master/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
26488 views
// SPDX-License-Identifier: GPL-2.01/*2* MediaTek ALSA SoC Audio DAI PCM I/F Control3*4* Copyright (c) 2020 MediaTek Inc.5* Author: Bicycle Tsai <[email protected]>6* Trevor Wu <[email protected]>7*/89#include <linux/regmap.h>10#include <sound/pcm_params.h>11#include "mt8195-afe-clk.h"12#include "mt8195-afe-common.h"13#include "mt8195-reg.h"1415enum {16MTK_DAI_PCM_FMT_I2S,17MTK_DAI_PCM_FMT_EIAJ,18MTK_DAI_PCM_FMT_MODEA,19MTK_DAI_PCM_FMT_MODEB,20};2122enum {23MTK_DAI_PCM_CLK_A1SYS,24MTK_DAI_PCM_CLK_A2SYS,25MTK_DAI_PCM_CLK_26M_48K,26MTK_DAI_PCM_CLK_26M_441K,27};2829struct mtk_dai_pcm_rate {30unsigned int rate;31unsigned int reg_value;32};3334struct mtk_dai_pcmif_priv {35unsigned int slave_mode;36unsigned int lrck_inv;37unsigned int bck_inv;38unsigned int format;39};4041static const struct mtk_dai_pcm_rate mtk_dai_pcm_rates[] = {42{ .rate = 8000, .reg_value = 0, },43{ .rate = 16000, .reg_value = 1, },44{ .rate = 32000, .reg_value = 2, },45{ .rate = 48000, .reg_value = 3, },46{ .rate = 11025, .reg_value = 1, },47{ .rate = 22050, .reg_value = 2, },48{ .rate = 44100, .reg_value = 3, },49};5051static int mtk_dai_pcm_mode(unsigned int rate)52{53int i;5455for (i = 0; i < ARRAY_SIZE(mtk_dai_pcm_rates); i++)56if (mtk_dai_pcm_rates[i].rate == rate)57return mtk_dai_pcm_rates[i].reg_value;5859return -EINVAL;60}6162static const struct snd_kcontrol_new mtk_dai_pcm_o000_mix[] = {63SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN0, 0, 1, 0),64SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN0_2, 6, 1, 0),65};6667static const struct snd_kcontrol_new mtk_dai_pcm_o001_mix[] = {68SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN1, 1, 1, 0),69SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN1_2, 7, 1, 0),70};7172static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {73SND_SOC_DAPM_MIXER("I002", SND_SOC_NOPM, 0, 0, NULL, 0),74SND_SOC_DAPM_MIXER("I003", SND_SOC_NOPM, 0, 0, NULL, 0),75SND_SOC_DAPM_MIXER("O000", SND_SOC_NOPM, 0, 0,76mtk_dai_pcm_o000_mix,77ARRAY_SIZE(mtk_dai_pcm_o000_mix)),78SND_SOC_DAPM_MIXER("O001", SND_SOC_NOPM, 0, 0,79mtk_dai_pcm_o001_mix,80ARRAY_SIZE(mtk_dai_pcm_o001_mix)),8182SND_SOC_DAPM_SUPPLY("PCM_EN", PCM_INTF_CON1,83PCM_INTF_CON1_PCM_EN_SHIFT, 0, NULL, 0),8485SND_SOC_DAPM_INPUT("PCM1_INPUT"),86SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"),8788SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc11"),89SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc12"),90SND_SOC_DAPM_CLOCK_SUPPLY("aud_pcmif"),91};9293static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {94{"I002", NULL, "PCM1 Capture"},95{"I003", NULL, "PCM1 Capture"},9697{"O000", "I000 Switch", "I000"},98{"O001", "I001 Switch", "I001"},99100{"O000", "I070 Switch", "I070"},101{"O001", "I071 Switch", "I071"},102103{"PCM1 Playback", NULL, "O000"},104{"PCM1 Playback", NULL, "O001"},105106{"PCM1 Playback", NULL, "PCM_EN"},107{"PCM1 Playback", NULL, "aud_asrc12"},108{"PCM1 Playback", NULL, "aud_pcmif"},109110{"PCM1 Capture", NULL, "PCM_EN"},111{"PCM1 Capture", NULL, "aud_asrc11"},112{"PCM1 Capture", NULL, "aud_pcmif"},113114{"PCM1_OUTPUT", NULL, "PCM1 Playback"},115{"PCM1 Capture", NULL, "PCM1_INPUT"},116};117118static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,119struct snd_soc_dai *dai)120{121struct snd_pcm_runtime * const runtime = substream->runtime;122struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);123struct mt8195_afe_private *afe_priv = afe->platform_priv;124struct mtk_dai_pcmif_priv *pcmif_priv;125unsigned int slave_mode;126unsigned int lrck_inv;127unsigned int bck_inv;128unsigned int fmt;129unsigned int bit_width = dai->symmetric_sample_bits;130unsigned int val = 0;131unsigned int mask = 0;132int fs = 0;133int mode = 0;134135if (dai->id != MT8195_AFE_IO_PCM)136return -EINVAL;137138pcmif_priv = afe_priv->dai_priv[dai->id];139slave_mode = pcmif_priv->slave_mode;140lrck_inv = pcmif_priv->lrck_inv;141bck_inv = pcmif_priv->bck_inv;142fmt = pcmif_priv->format;143144/* sync freq mode */145fs = mt8195_afe_fs_timing(runtime->rate);146if (fs < 0)147return -EINVAL;148val |= PCM_INTF_CON2_SYNC_FREQ_MODE(fs);149mask |= PCM_INTF_CON2_SYNC_FREQ_MODE_MASK;150151/* clk domain sel */152if (runtime->rate % 8000)153val |= PCM_INTF_CON2_CLK_DOMAIN_SEL(MTK_DAI_PCM_CLK_26M_441K);154else155val |= PCM_INTF_CON2_CLK_DOMAIN_SEL(MTK_DAI_PCM_CLK_26M_48K);156mask |= PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK;157158regmap_update_bits(afe->regmap, PCM_INTF_CON2, mask, val);159160val = 0;161mask = 0;162163/* pcm mode */164mode = mtk_dai_pcm_mode(runtime->rate);165if (mode < 0)166return -EINVAL;167val |= PCM_INTF_CON1_PCM_MODE(mode);168mask |= PCM_INTF_CON1_PCM_MODE_MASK;169170/* pcm format */171val |= PCM_INTF_CON1_PCM_FMT(fmt);172mask |= PCM_INTF_CON1_PCM_FMT_MASK;173174/* pcm sync length */175if (fmt == MTK_DAI_PCM_FMT_MODEA ||176fmt == MTK_DAI_PCM_FMT_MODEB)177val |= PCM_INTF_CON1_SYNC_LENGTH(1);178else179val |= PCM_INTF_CON1_SYNC_LENGTH(bit_width);180mask |= PCM_INTF_CON1_SYNC_LENGTH_MASK;181182/* pcm bits, word length */183if (bit_width > 16) {184val |= PCM_INTF_CON1_PCM_24BIT;185val |= PCM_INTF_CON1_PCM_WLEN_64BCK;186} else {187val |= PCM_INTF_CON1_PCM_16BIT;188val |= PCM_INTF_CON1_PCM_WLEN_32BCK;189}190mask |= PCM_INTF_CON1_PCM_BIT_MASK;191mask |= PCM_INTF_CON1_PCM_WLEN_MASK;192193/* master/slave */194if (!slave_mode) {195val |= PCM_INTF_CON1_PCM_MASTER;196197if (lrck_inv)198val |= PCM_INTF_CON1_SYNC_OUT_INV;199if (bck_inv)200val |= PCM_INTF_CON1_BCLK_OUT_INV;201mask |= PCM_INTF_CON1_CLK_OUT_INV_MASK;202} else {203val |= PCM_INTF_CON1_PCM_SLAVE;204205if (lrck_inv)206val |= PCM_INTF_CON1_SYNC_IN_INV;207if (bck_inv)208val |= PCM_INTF_CON1_BCLK_IN_INV;209mask |= PCM_INTF_CON1_CLK_IN_INV_MASK;210211/* TODO: add asrc setting for slave mode */212}213mask |= PCM_INTF_CON1_PCM_M_S_MASK;214215regmap_update_bits(afe->regmap, PCM_INTF_CON1, mask, val);216217return 0;218}219220/* dai ops */221static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream,222struct snd_soc_dai *dai)223{224struct snd_soc_dapm_widget *p = snd_soc_dai_get_widget_playback(dai);225struct snd_soc_dapm_widget *c = snd_soc_dai_get_widget_capture(dai);226227dev_dbg(dai->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n",228__func__, dai->id, substream->stream,229p->active, c->active);230231if (p->active || c->active)232return 0;233234return mtk_dai_pcm_configure(substream, dai);235}236237static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)238{239struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);240struct mt8195_afe_private *afe_priv = afe->platform_priv;241struct mtk_dai_pcmif_priv *pcmif_priv;242243dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt);244245if (dai->id != MT8195_AFE_IO_PCM)246return -EINVAL;247248pcmif_priv = afe_priv->dai_priv[dai->id];249250switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {251case SND_SOC_DAIFMT_I2S:252pcmif_priv->format = MTK_DAI_PCM_FMT_I2S;253break;254case SND_SOC_DAIFMT_DSP_A:255pcmif_priv->format = MTK_DAI_PCM_FMT_MODEA;256break;257case SND_SOC_DAIFMT_DSP_B:258pcmif_priv->format = MTK_DAI_PCM_FMT_MODEB;259break;260default:261return -EINVAL;262}263264switch (fmt & SND_SOC_DAIFMT_INV_MASK) {265case SND_SOC_DAIFMT_NB_NF:266pcmif_priv->bck_inv = 0;267pcmif_priv->lrck_inv = 0;268break;269case SND_SOC_DAIFMT_NB_IF:270pcmif_priv->bck_inv = 0;271pcmif_priv->lrck_inv = 1;272break;273case SND_SOC_DAIFMT_IB_NF:274pcmif_priv->bck_inv = 1;275pcmif_priv->lrck_inv = 0;276break;277case SND_SOC_DAIFMT_IB_IF:278pcmif_priv->bck_inv = 1;279pcmif_priv->lrck_inv = 1;280break;281default:282return -EINVAL;283}284285switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {286case SND_SOC_DAIFMT_BC_FC:287pcmif_priv->slave_mode = 1;288break;289case SND_SOC_DAIFMT_BP_FP:290pcmif_priv->slave_mode = 0;291break;292default:293return -EINVAL;294}295296return 0;297}298299static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {300.prepare = mtk_dai_pcm_prepare,301.set_fmt = mtk_dai_pcm_set_fmt,302};303304/* dai driver */305#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000)306307#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\308SNDRV_PCM_FMTBIT_S24_LE |\309SNDRV_PCM_FMTBIT_S32_LE)310311static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {312{313.name = "PCM1",314.id = MT8195_AFE_IO_PCM,315.playback = {316.stream_name = "PCM1 Playback",317.channels_min = 1,318.channels_max = 2,319.rates = MTK_PCM_RATES,320.formats = MTK_PCM_FORMATS,321},322.capture = {323.stream_name = "PCM1 Capture",324.channels_min = 1,325.channels_max = 2,326.rates = MTK_PCM_RATES,327.formats = MTK_PCM_FORMATS,328},329.ops = &mtk_dai_pcm_ops,330.symmetric_rate = 1,331.symmetric_sample_bits = 1,332},333};334335static int init_pcmif_priv_data(struct mtk_base_afe *afe)336{337struct mt8195_afe_private *afe_priv = afe->platform_priv;338struct mtk_dai_pcmif_priv *pcmif_priv;339340pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_pcmif_priv),341GFP_KERNEL);342if (!pcmif_priv)343return -ENOMEM;344345afe_priv->dai_priv[MT8195_AFE_IO_PCM] = pcmif_priv;346return 0;347}348349int mt8195_dai_pcm_register(struct mtk_base_afe *afe)350{351struct mtk_base_afe_dai *dai;352353dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);354if (!dai)355return -ENOMEM;356357list_add(&dai->list, &afe->sub_dais);358359dai->dai_drivers = mtk_dai_pcm_driver;360dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);361362dai->dapm_widgets = mtk_dai_pcm_widgets;363dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);364dai->dapm_routes = mtk_dai_pcm_routes;365dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);366367return init_pcmif_priv_data(afe);368}369370371