brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · f85ec07 Raw
294 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * MediaTek 8365 ALSA SoC Audio DAI PCM Control4 *5 * Copyright (c) 2024 MediaTek Inc.6 * Authors: Jia Zeng <jia.zeng@mediatek.com>7 *          Alexandre Mergnat <amergnat@baylibre.com>8 */9 10#include <linux/bitops.h>11#include <linux/regmap.h>12#include <sound/pcm_params.h>13#include "mt8365-afe-clk.h"14#include "mt8365-afe-common.h"15 16struct mt8365_pcm_intf_data {17	bool slave_mode;18	bool lrck_inv;19	bool bck_inv;20	unsigned int format;21};22 23/* DAI Drivers */24 25static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)26{27	regmap_update_bits(afe->regmap, PCM_INTF_CON1,28			   PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);29}30 31static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)32{33	regmap_update_bits(afe->regmap, PCM_INTF_CON1,34			   PCM_INTF_CON1_EN, 0x0);35}36 37static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,38				     struct snd_soc_dai *dai)39{40	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);41	struct mt8365_afe_private *afe_priv = afe->platform_priv;42	struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];43	bool slave_mode = pcm_priv->slave_mode;44	bool lrck_inv = pcm_priv->lrck_inv;45	bool bck_inv = pcm_priv->bck_inv;46	unsigned int fmt = pcm_priv->format;47	unsigned int bit_width = dai->sample_bits;48	unsigned int val = 0;49 50	if (!slave_mode) {51		val |= PCM_INTF_CON1_MASTER_MODE |52		       PCM_INTF_CON1_BYPASS_ASRC;53 54		if (lrck_inv)55			val |= PCM_INTF_CON1_SYNC_OUT_INV;56		if (bck_inv)57			val |= PCM_INTF_CON1_BCLK_OUT_INV;58	} else {59		val |= PCM_INTF_CON1_SLAVE_MODE;60 61		if (lrck_inv)62			val |= PCM_INTF_CON1_SYNC_IN_INV;63		if (bck_inv)64			val |= PCM_INTF_CON1_BCLK_IN_INV;65 66		/* TODO: add asrc setting */67	}68 69	val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);70 71	if (fmt == MT8365_PCM_FORMAT_PCMA ||72	    fmt == MT8365_PCM_FORMAT_PCMB)73		val |= PCM_INTF_CON1_SYNC_LEN(1);74	else75		val |= PCM_INTF_CON1_SYNC_LEN(bit_width);76 77	switch (substream->runtime->rate) {78	case 48000:79		val |= PCM_INTF_CON1_FS_48K;80		break;81	case 32000:82		val |= PCM_INTF_CON1_FS_32K;83		break;84	case 16000:85		val |= PCM_INTF_CON1_FS_16K;86		break;87	case 8000:88		val |= PCM_INTF_CON1_FS_8K;89		break;90	default:91		return -EINVAL;92	}93 94	if (bit_width > 16)95		val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;96	else97		val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;98 99	val |= PCM_INTF_CON1_EXT_MODEM;100 101	regmap_update_bits(afe->regmap, PCM_INTF_CON1,102			   PCM_INTF_CON1_CONFIG_MASK, val);103 104	return 0;105}106 107static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,108				   struct snd_soc_dai *dai)109{110	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);111 112	if (snd_soc_dai_active(dai))113		return 0;114 115	mt8365_afe_enable_main_clk(afe);116 117	return 0;118}119 120static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,121				     struct snd_soc_dai *dai)122{123	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);124 125	if (snd_soc_dai_active(dai))126		return;127 128	mt8365_dai_disable_pcm1(afe);129	mt8365_afe_disable_main_clk(afe);130}131 132static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,133				   struct snd_soc_dai *dai)134{135	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);136	int ret;137 138	if ((snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) +139	    snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) > 1) {140		dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",141			 __func__, snd_pcm_stream_str(substream),142			 snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK),143			 snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE));144		return 0;145	}146 147	ret = mt8365_dai_configure_pcm1(substream, dai);148	if (ret)149		return ret;150 151	mt8365_dai_enable_pcm1(afe);152 153	return 0;154}155 156static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)157{158	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);159	struct mt8365_afe_private *afe_priv = afe->platform_priv;160	struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];161 162	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {163	case SND_SOC_DAIFMT_I2S:164		pcm_priv->format = MT8365_PCM_FORMAT_I2S;165		break;166	default:167		return -EINVAL;168	}169 170	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {171	case SND_SOC_DAIFMT_NB_NF:172		pcm_priv->bck_inv = false;173		pcm_priv->lrck_inv = false;174		break;175	case SND_SOC_DAIFMT_NB_IF:176		pcm_priv->bck_inv = false;177		pcm_priv->lrck_inv = true;178		break;179	case SND_SOC_DAIFMT_IB_NF:180		pcm_priv->bck_inv = true;181		pcm_priv->lrck_inv = false;182		break;183	case SND_SOC_DAIFMT_IB_IF:184		pcm_priv->bck_inv = true;185		pcm_priv->lrck_inv = true;186		break;187	default:188		return -EINVAL;189	}190 191	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {192	case SND_SOC_DAIFMT_CBM_CFM:193		pcm_priv->slave_mode = true;194		break;195	case SND_SOC_DAIFMT_CBS_CFS:196		pcm_priv->slave_mode = false;197		break;198	default:199		return -EINVAL;200	}201 202	return 0;203}204 205static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {206	.startup	= mt8365_dai_pcm1_startup,207	.shutdown	= mt8365_dai_pcm1_shutdown,208	.prepare	= mt8365_dai_pcm1_prepare,209	.set_fmt	= mt8365_dai_pcm1_set_fmt,210};211 212static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {213	{214		.name = "PCM1",215		.id = MT8365_AFE_IO_PCM1,216		.playback = {217			.stream_name = "PCM1 Playback",218			.channels_min = 1,219			.channels_max = 2,220			.rates = SNDRV_PCM_RATE_8000 |221				 SNDRV_PCM_RATE_16000 |222				 SNDRV_PCM_RATE_32000 |223				 SNDRV_PCM_RATE_48000,224			.formats = SNDRV_PCM_FMTBIT_S16_LE |225				   SNDRV_PCM_FMTBIT_S32_LE,226		},227		.capture = {228			.stream_name = "PCM1 Capture",229			.channels_min = 1,230			.channels_max = 2,231			.rates = SNDRV_PCM_RATE_8000 |232				 SNDRV_PCM_RATE_16000 |233				 SNDRV_PCM_RATE_32000 |234				 SNDRV_PCM_RATE_48000,235			.formats = SNDRV_PCM_FMTBIT_S16_LE |236				   SNDRV_PCM_FMTBIT_S32_LE,237		},238		.ops = &mt8365_dai_pcm1_ops,239		.symmetric_rate = 1,240		.symmetric_sample_bits = 1,241	}242};243 244/* DAI widget */245 246static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {247	SND_SOC_DAPM_OUTPUT("PCM1 Out"),248	SND_SOC_DAPM_INPUT("PCM1 In"),249};250 251/* DAI route */252 253static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {254	{"PCM1 Playback", NULL, "O07"},255	{"PCM1 Playback", NULL, "O08"},256	{"PCM1 Out", NULL, "PCM1 Playback"},257 258	{"I09", NULL, "PCM1 Capture"},259	{"I22", NULL, "PCM1 Capture"},260	{"PCM1 Capture", NULL, "PCM1 In"},261};262 263static int init_pcmif_priv_data(struct mtk_base_afe *afe)264{265	struct mt8365_afe_private *afe_priv = afe->platform_priv;266	struct mt8365_pcm_intf_data *pcmif_priv;267 268	pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),269				  GFP_KERNEL);270	if (!pcmif_priv)271		return -ENOMEM;272 273	afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;274	return 0;275}276 277int mt8365_dai_pcm_register(struct mtk_base_afe *afe)278{279	struct mtk_base_afe_dai *dai;280 281	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);282	if (!dai)283		return -ENOMEM;284 285	list_add(&dai->list, &afe->sub_dais);286	dai->dai_drivers = mtk_dai_pcm_driver;287	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);288	dai->dapm_widgets = mtk_dai_pcm_widgets;289	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);290	dai->dapm_routes = mtk_dai_pcm_routes;291	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);292	return init_pcmif_priv_data(afe);293}294