162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCM1681 ASoC codec driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) StreamUnlimited GmbH 2013
662306a36Sopenharmony_ci *	Marek Belisko <marek.belisko@streamunlimited.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/gpio.h>
1362306a36Sopenharmony_ci#include <linux/i2c.h>
1462306a36Sopenharmony_ci#include <linux/regmap.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/of_device.h>
1762306a36Sopenharmony_ci#include <linux/of_gpio.h>
1862306a36Sopenharmony_ci#include <sound/pcm.h>
1962306a36Sopenharmony_ci#include <sound/pcm_params.h>
2062306a36Sopenharmony_ci#include <sound/soc.h>
2162306a36Sopenharmony_ci#include <sound/tlv.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |		\
2462306a36Sopenharmony_ci			     SNDRV_PCM_FMTBIT_S24_LE)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define PCM1681_PCM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
2762306a36Sopenharmony_ci			     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
2862306a36Sopenharmony_ci			     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
2962306a36Sopenharmony_ci			     SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define PCM1681_SOFT_MUTE_ALL		0xff
3262306a36Sopenharmony_ci#define PCM1681_DEEMPH_RATE_MASK	0x18
3362306a36Sopenharmony_ci#define PCM1681_DEEMPH_MASK		0x01
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define PCM1681_ATT_CONTROL(X)	(X <= 6 ? X : X + 9) /* Attenuation level */
3662306a36Sopenharmony_ci#define PCM1681_SOFT_MUTE	0x07	/* Soft mute control register */
3762306a36Sopenharmony_ci#define PCM1681_DAC_CONTROL	0x08	/* DAC operation control */
3862306a36Sopenharmony_ci#define PCM1681_FMT_CONTROL	0x09	/* Audio interface data format */
3962306a36Sopenharmony_ci#define PCM1681_DEEMPH_CONTROL	0x0a	/* De-emphasis control */
4062306a36Sopenharmony_ci#define PCM1681_ZERO_DETECT_STATUS	0x0e	/* Zero detect status reg */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const struct reg_default pcm1681_reg_defaults[] = {
4362306a36Sopenharmony_ci	{ 0x01,	0xff },
4462306a36Sopenharmony_ci	{ 0x02,	0xff },
4562306a36Sopenharmony_ci	{ 0x03,	0xff },
4662306a36Sopenharmony_ci	{ 0x04,	0xff },
4762306a36Sopenharmony_ci	{ 0x05,	0xff },
4862306a36Sopenharmony_ci	{ 0x06,	0xff },
4962306a36Sopenharmony_ci	{ 0x07,	0x00 },
5062306a36Sopenharmony_ci	{ 0x08,	0x00 },
5162306a36Sopenharmony_ci	{ 0x09,	0x06 },
5262306a36Sopenharmony_ci	{ 0x0A,	0x00 },
5362306a36Sopenharmony_ci	{ 0x0B,	0xff },
5462306a36Sopenharmony_ci	{ 0x0C,	0x0f },
5562306a36Sopenharmony_ci	{ 0x0D,	0x00 },
5662306a36Sopenharmony_ci	{ 0x10,	0xff },
5762306a36Sopenharmony_ci	{ 0x11,	0xff },
5862306a36Sopenharmony_ci	{ 0x12,	0x00 },
5962306a36Sopenharmony_ci	{ 0x13,	0x00 },
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic bool pcm1681_accessible_reg(struct device *dev, unsigned int reg)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	return !((reg == 0x00) || (reg == 0x0f));
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic bool pcm1681_writeable_reg(struct device *dev, unsigned int reg)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	return pcm1681_accessible_reg(dev, reg) &&
7062306a36Sopenharmony_ci		(reg != PCM1681_ZERO_DETECT_STATUS);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct pcm1681_private {
7462306a36Sopenharmony_ci	struct regmap *regmap;
7562306a36Sopenharmony_ci	unsigned int format;
7662306a36Sopenharmony_ci	/* Current deemphasis status */
7762306a36Sopenharmony_ci	unsigned int deemph;
7862306a36Sopenharmony_ci	/* Current rate for deemphasis control */
7962306a36Sopenharmony_ci	unsigned int rate;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic const int pcm1681_deemph[] = { 44100, 48000, 32000 };
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int pcm1681_set_deemph(struct snd_soc_component *component)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
8762306a36Sopenharmony_ci	int i, val = -1, enable = 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (priv->deemph) {
9062306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) {
9162306a36Sopenharmony_ci			if (pcm1681_deemph[i] == priv->rate) {
9262306a36Sopenharmony_ci				val = i;
9362306a36Sopenharmony_ci				break;
9462306a36Sopenharmony_ci			}
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (val != -1) {
9962306a36Sopenharmony_ci		regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
10062306a36Sopenharmony_ci				   PCM1681_DEEMPH_RATE_MASK, val << 3);
10162306a36Sopenharmony_ci		enable = 1;
10262306a36Sopenharmony_ci	} else {
10362306a36Sopenharmony_ci		enable = 0;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* enable/disable deemphasis functionality */
10762306a36Sopenharmony_ci	return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
10862306a36Sopenharmony_ci					PCM1681_DEEMPH_MASK, enable);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
11262306a36Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
11562306a36Sopenharmony_ci	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = priv->deemph;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
12362306a36Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
12662306a36Sopenharmony_ci	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	priv->deemph = ucontrol->value.integer.value[0];
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return pcm1681_set_deemph(component);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
13462306a36Sopenharmony_ci			      unsigned int format)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
13762306a36Sopenharmony_ci	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* The PCM1681 can only be consumer to all clocks */
14062306a36Sopenharmony_ci	if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
14162306a36Sopenharmony_ci		dev_err(component->dev, "Invalid clocking mode\n");
14262306a36Sopenharmony_ci		return -EINVAL;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	priv->format = format;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int pcm1681_mute(struct snd_soc_dai *dai, int mute, int direction)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
15362306a36Sopenharmony_ci	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
15462306a36Sopenharmony_ci	int val;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (mute)
15762306a36Sopenharmony_ci		val = PCM1681_SOFT_MUTE_ALL;
15862306a36Sopenharmony_ci	else
15962306a36Sopenharmony_ci		val = 0;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic int pcm1681_hw_params(struct snd_pcm_substream *substream,
16562306a36Sopenharmony_ci			     struct snd_pcm_hw_params *params,
16662306a36Sopenharmony_ci			     struct snd_soc_dai *dai)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
16962306a36Sopenharmony_ci	struct pcm1681_private *priv = snd_soc_component_get_drvdata(component);
17062306a36Sopenharmony_ci	int val = 0, ret;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	priv->rate = params_rate(params);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
17562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
17662306a36Sopenharmony_ci		switch (params_width(params)) {
17762306a36Sopenharmony_ci		case 24:
17862306a36Sopenharmony_ci			val = 0;
17962306a36Sopenharmony_ci			break;
18062306a36Sopenharmony_ci		case 16:
18162306a36Sopenharmony_ci			val = 3;
18262306a36Sopenharmony_ci			break;
18362306a36Sopenharmony_ci		default:
18462306a36Sopenharmony_ci			return -EINVAL;
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
18862306a36Sopenharmony_ci		val = 0x04;
18962306a36Sopenharmony_ci		break;
19062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
19162306a36Sopenharmony_ci		val = 0x05;
19262306a36Sopenharmony_ci		break;
19362306a36Sopenharmony_ci	default:
19462306a36Sopenharmony_ci		dev_err(component->dev, "Invalid DAI format\n");
19562306a36Sopenharmony_ci		return -EINVAL;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val);
19962306a36Sopenharmony_ci	if (ret < 0)
20062306a36Sopenharmony_ci		return ret;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return pcm1681_set_deemph(component);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pcm1681_dai_ops = {
20662306a36Sopenharmony_ci	.set_fmt	= pcm1681_set_dai_fmt,
20762306a36Sopenharmony_ci	.hw_params	= pcm1681_hw_params,
20862306a36Sopenharmony_ci	.mute_stream	= pcm1681_mute,
20962306a36Sopenharmony_ci	.no_capture_mute = 1,
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget pcm1681_dapm_widgets[] = {
21362306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT1"),
21462306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT2"),
21562306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT3"),
21662306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT4"),
21762306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT5"),
21862306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT6"),
21962306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT7"),
22062306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("VOUT8"),
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic const struct snd_soc_dapm_route pcm1681_dapm_routes[] = {
22462306a36Sopenharmony_ci	{ "VOUT1", NULL, "Playback" },
22562306a36Sopenharmony_ci	{ "VOUT2", NULL, "Playback" },
22662306a36Sopenharmony_ci	{ "VOUT3", NULL, "Playback" },
22762306a36Sopenharmony_ci	{ "VOUT4", NULL, "Playback" },
22862306a36Sopenharmony_ci	{ "VOUT5", NULL, "Playback" },
22962306a36Sopenharmony_ci	{ "VOUT6", NULL, "Playback" },
23062306a36Sopenharmony_ci	{ "VOUT7", NULL, "Playback" },
23162306a36Sopenharmony_ci	{ "VOUT8", NULL, "Playback" },
23262306a36Sopenharmony_ci};
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic const struct snd_kcontrol_new pcm1681_controls[] = {
23762306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
23862306a36Sopenharmony_ci			PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0,
23962306a36Sopenharmony_ci			0x7f, 0, pcm1681_dac_tlv),
24062306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
24162306a36Sopenharmony_ci			PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0,
24262306a36Sopenharmony_ci			0x7f, 0, pcm1681_dac_tlv),
24362306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
24462306a36Sopenharmony_ci			PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0,
24562306a36Sopenharmony_ci			0x7f, 0, pcm1681_dac_tlv),
24662306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume",
24762306a36Sopenharmony_ci			PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0,
24862306a36Sopenharmony_ci			0x7f, 0, pcm1681_dac_tlv),
24962306a36Sopenharmony_ci	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
25062306a36Sopenharmony_ci			    pcm1681_get_deemph, pcm1681_put_deemph),
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic struct snd_soc_dai_driver pcm1681_dai = {
25462306a36Sopenharmony_ci	.name = "pcm1681-hifi",
25562306a36Sopenharmony_ci	.playback = {
25662306a36Sopenharmony_ci		.stream_name = "Playback",
25762306a36Sopenharmony_ci		.channels_min = 2,
25862306a36Sopenharmony_ci		.channels_max = 8,
25962306a36Sopenharmony_ci		.rates = PCM1681_PCM_RATES,
26062306a36Sopenharmony_ci		.formats = PCM1681_PCM_FORMATS,
26162306a36Sopenharmony_ci	},
26262306a36Sopenharmony_ci	.ops = &pcm1681_dai_ops,
26362306a36Sopenharmony_ci};
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#ifdef CONFIG_OF
26662306a36Sopenharmony_cistatic const struct of_device_id pcm1681_dt_ids[] = {
26762306a36Sopenharmony_ci	{ .compatible = "ti,pcm1681", },
26862306a36Sopenharmony_ci	{ }
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
27162306a36Sopenharmony_ci#endif
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic const struct regmap_config pcm1681_regmap = {
27462306a36Sopenharmony_ci	.reg_bits		= 8,
27562306a36Sopenharmony_ci	.val_bits		= 8,
27662306a36Sopenharmony_ci	.max_register		= 0x13,
27762306a36Sopenharmony_ci	.reg_defaults		= pcm1681_reg_defaults,
27862306a36Sopenharmony_ci	.num_reg_defaults	= ARRAY_SIZE(pcm1681_reg_defaults),
27962306a36Sopenharmony_ci	.writeable_reg		= pcm1681_writeable_reg,
28062306a36Sopenharmony_ci	.readable_reg		= pcm1681_accessible_reg,
28162306a36Sopenharmony_ci};
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_pcm1681 = {
28462306a36Sopenharmony_ci	.controls		= pcm1681_controls,
28562306a36Sopenharmony_ci	.num_controls		= ARRAY_SIZE(pcm1681_controls),
28662306a36Sopenharmony_ci	.dapm_widgets		= pcm1681_dapm_widgets,
28762306a36Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
28862306a36Sopenharmony_ci	.dapm_routes		= pcm1681_dapm_routes,
28962306a36Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
29062306a36Sopenharmony_ci	.idle_bias_on		= 1,
29162306a36Sopenharmony_ci	.use_pmdown_time	= 1,
29262306a36Sopenharmony_ci	.endianness		= 1,
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic const struct i2c_device_id pcm1681_i2c_id[] = {
29662306a36Sopenharmony_ci	{"pcm1681", 0},
29762306a36Sopenharmony_ci	{}
29862306a36Sopenharmony_ci};
29962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int pcm1681_i2c_probe(struct i2c_client *client)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	int ret;
30462306a36Sopenharmony_ci	struct pcm1681_private *priv;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
30762306a36Sopenharmony_ci	if (!priv)
30862306a36Sopenharmony_ci		return -ENOMEM;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap);
31162306a36Sopenharmony_ci	if (IS_ERR(priv->regmap)) {
31262306a36Sopenharmony_ci		ret = PTR_ERR(priv->regmap);
31362306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
31462306a36Sopenharmony_ci		return ret;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	i2c_set_clientdata(client, priv);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return devm_snd_soc_register_component(&client->dev,
32062306a36Sopenharmony_ci		&soc_component_dev_pcm1681,
32162306a36Sopenharmony_ci		&pcm1681_dai, 1);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic struct i2c_driver pcm1681_i2c_driver = {
32562306a36Sopenharmony_ci	.driver = {
32662306a36Sopenharmony_ci		.name	= "pcm1681",
32762306a36Sopenharmony_ci		.of_match_table = of_match_ptr(pcm1681_dt_ids),
32862306a36Sopenharmony_ci	},
32962306a36Sopenharmony_ci	.id_table	= pcm1681_i2c_id,
33062306a36Sopenharmony_ci	.probe		= pcm1681_i2c_probe,
33162306a36Sopenharmony_ci};
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cimodule_i2c_driver(pcm1681_i2c_driver);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver");
33662306a36Sopenharmony_ciMODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>");
33762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
338