All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] Asoc: tas2764 : new tas27xx driver to support either tas2764 or tas2780
@ 2022-03-15  5:28 Xu, Yang
  2022-03-15  9:12 ` Takashi Iwai
  0 siblings, 1 reply; 2+ messages in thread
From: Xu, Yang @ 2022-03-15  5:28 UTC (permalink / raw)
  To: broonie@kernel.org, tiwai@suse.com
  Cc: alsa-devel@alsa-project.org, Ding, Shenghao

[-- Attachment #1: Type: text/plain, Size: 368 bytes --]

Hi Mark and Takashi Iwai,

This is Raphael Xu who is from Low Power Audio team,Texas Instrument.
Could you help to review the attached patch and upstream them to the kernel?
Thanks.

Change log:
Path:  sound/soc/codecs

  1.  This patch to support either TAS2764 or TAS2780 device from TI
  2.  Fixed "no sound" issue on some platforms.

Regards
Raphael

[-- Attachment #2: tas27xx.c.patch --]
[-- Type: application/octet-stream, Size: 28010 bytes --]

--- kernel-5-16-13/tas2764.c	2022-03-09 13:21:36.425208700 +0800
+++ kernel-5-16-13-modified/tas27xx.c	2022-03-11 14:06:20.233656800 +0800
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 //
-// Driver for the Texas Instruments TAS2764 CODEC
-// Copyright (C) 2020 Texas Instruments Inc.
+// Driver for the Texas Instruments TAS2764/TAS2780 Mono Audio amplifier
+// Copyright (C) 2022 Texas Instruments Inc.
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -12,118 +12,142 @@
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
-#include <linux/regulator/consumer.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
-#include <linux/slab.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
+#include <linux/version.h>
 
-#include "tas2764.h"
+#include "tas27xx.h"
 
-struct tas2764_priv {
+struct tas27xx_priv {
 	struct snd_soc_component *component;
 	struct gpio_desc *reset_gpio;
 	struct gpio_desc *sdz_gpio;
 	struct regmap *regmap;
 	struct device *dev;
-	
+	struct mutex codec_lock;
 	int v_sense_slot;
 	int i_sense_slot;
+	int device_id;
+	bool mbPowerUp;
 };
 
-static void tas2764_reset(struct tas2764_priv *tas2764)
+static void tas27xx_reset(struct tas27xx_priv *tas27xx)
 {
-	if (tas2764->reset_gpio) {
-		gpiod_set_value_cansleep(tas2764->reset_gpio, 0);
+	if (tas27xx->reset_gpio) {
+		gpiod_set_value_cansleep(tas27xx->reset_gpio, 0);
 		msleep(20);
-		gpiod_set_value_cansleep(tas2764->reset_gpio, 1);
+		gpiod_set_value_cansleep(tas27xx->reset_gpio, 1);
 	}
 
-	snd_soc_component_write(tas2764->component, TAS2764_SW_RST,
+	snd_soc_component_write(tas27xx->component, TAS2764_SW_RST,
 				TAS2764_RST);
 }
 
-static int tas2764_set_bias_level(struct snd_soc_component *component,
+static int tas27xx_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+	mutex_lock(&tas27xx->codec_lock);
 	switch (level) {
-	case SND_SOC_BIAS_ON:
-		snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
-					      TAS2764_PWR_CTRL_MASK,
-					      TAS2764_PWR_CTRL_ACTIVE);
-		break;
-	case SND_SOC_BIAS_STANDBY:
-	case SND_SOC_BIAS_PREPARE:
-		snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
-					      TAS2764_PWR_CTRL_MASK,
-					      TAS2764_PWR_CTRL_MUTE);
-		break;
-	case SND_SOC_BIAS_OFF:
-		snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
-					      TAS2764_PWR_CTRL_MASK,
-					      TAS2764_PWR_CTRL_SHUTDOWN);
-		break;
-
-	default:
-		dev_err(tas2764->dev,
-				"wrong power level setting %d\n", level);
-		return -EINVAL;
-	}
-
-	return 0;
+		case SND_SOC_BIAS_ON:
+			ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+						      TAS2764_PWR_CTRL_MASK,
+						      TAS2764_PWR_CTRL_ACTIVE);
+			if(ret >= 0) {
+				tas27xx->mbPowerUp = true;
+				ret = 0;
+			}
+			break;
+		case SND_SOC_BIAS_STANDBY:
+		case SND_SOC_BIAS_PREPARE:
+			ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+						      TAS2764_PWR_CTRL_MASK,
+						      TAS2764_PWR_CTRL_MUTE);
+			if(ret >= 0) {
+				tas27xx->mbPowerUp = true;
+				ret = 0;
+			}
+			break;
+		case SND_SOC_BIAS_OFF:
+			ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+						      TAS2764_PWR_CTRL_MASK,
+						      TAS2764_PWR_CTRL_SHUTDOWN);
+			if(ret >= 0) {
+				tas27xx->mbPowerUp = false;
+				ret = 0;
+			}
+			break;
+		default:
+			dev_err(tas27xx->dev,
+					"wrong power level setting %d\n", level);
+			ret = -EINVAL;
+	}
+	if (ret < 0)
+		pr_err("%s:%u:errCode:0x%0x:set BIAS error\n",
+			__func__, __LINE__, ret);
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
 #ifdef CONFIG_PM
-static int tas2764_codec_suspend(struct snd_soc_component *component)
+static int tas27xx_codec_suspend(struct snd_soc_component *component)
 {
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-	int ret;
-
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+	mutex_lock(&tas27xx->codec_lock);
 	ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
 					    TAS2764_PWR_CTRL_MASK,
 					    TAS2764_PWR_CTRL_SHUTDOWN);
 
-	if (ret < 0)
-		return ret;
-
-	if (tas2764->sdz_gpio)
-		gpiod_set_value_cansleep(tas2764->sdz_gpio, 0);
-
-	regcache_cache_only(tas2764->regmap, true);
-	regcache_mark_dirty(tas2764->regmap);
-
-	return 0;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%0x:power down error\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
+	ret = 0;
+	tas27xx->mbPowerUp = false;
+	if (tas27xx->sdz_gpio)
+		gpiod_set_value_cansleep(tas27xx->sdz_gpio, 0);
+
+	regcache_cache_only(tas27xx->regmap, true);
+	regcache_mark_dirty(tas27xx->regmap);
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
-static int tas2764_codec_resume(struct snd_soc_component *component)
+static int tas27xx_codec_resume(struct snd_soc_component *component)
 {
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-	int ret;
-
-	if (tas2764->sdz_gpio)
-		gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+	mutex_lock(&tas27xx->codec_lock);
+	if (tas27xx->sdz_gpio)
+		gpiod_set_value_cansleep(tas27xx->sdz_gpio, 1);
 
 	ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
 					    TAS2764_PWR_CTRL_MASK,
 					    TAS2764_PWR_CTRL_ACTIVE);
 
-	if (ret < 0)
-		return ret;
-
-	regcache_cache_only(tas2764->regmap, false);
-
-	return regcache_sync(tas2764->regmap);
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%0x:power down error\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
+	ret = 0;
+	tas27xx->mbPowerUp = false;
+	regcache_cache_only(tas27xx->regmap, false);
+	ret = regcache_sync(tas27xx->regmap);
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
-#else
-#define tas2764_codec_suspend NULL
-#define tas2764_codec_resume NULL
 #endif
 
 static const char * const tas2764_ASI1_src[] = {
@@ -136,33 +160,36 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new tas2764_asi1_mux =
 	SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
 
-static int tas2764_dac_event(struct snd_soc_dapm_widget *w,
+static int tas27xx_dac_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-	int ret;
-
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+	mutex_lock(&tas27xx->codec_lock);
 	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
-						    TAS2764_PWR_CTRL_MASK,
-						    TAS2764_PWR_CTRL_MUTE);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
-						    TAS2764_PWR_CTRL_MASK,
-						    TAS2764_PWR_CTRL_SHUTDOWN);
-		break;
-	default:
-		dev_err(tas2764->dev, "Unsupported event\n");
-		return -EINVAL;
+		case SND_SOC_DAPM_POST_PMU:
+			ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+							    TAS2764_PWR_CTRL_MASK,
+							    TAS2764_PWR_CTRL_MUTE);
+			break;
+		case SND_SOC_DAPM_PRE_PMD:
+			ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+							    TAS2764_PWR_CTRL_MASK,
+							    TAS2764_PWR_CTRL_SHUTDOWN);
+			break;
+		default:
+			dev_err(tas27xx->dev, "Unsupported event\n");
+			ret = -EINVAL;
+	}
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%0x:PWR_CTRL error\n",
+			__func__, __LINE__, ret);
+	} else {
+		ret = 0;
 	}
-
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
 static const struct snd_kcontrol_new isense_switch =
@@ -177,7 +204,7 @@ static const struct snd_soc_dapm_widget
 			    1, &isense_switch),
 	SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN,
 			    1, &vsense_switch),
-	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event,
+	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas27xx_dac_event,
 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 	SND_SOC_DAPM_OUTPUT("OUT"),
 	SND_SOC_DAPM_SIGGEN("VMON"),
@@ -195,87 +222,134 @@ static const struct snd_soc_dapm_route t
 	{"VSENSE", "Switch", "VMON"},
 };
 
-static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
+static int tas27xx_mute(struct snd_soc_dai *dai, int mute, int direction)
 {
 	struct snd_soc_component *component = dai->component;
-	int ret;
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
+	mutex_lock(&tas27xx->codec_lock);
 
+	if(mute == 0) {
+		ret = snd_soc_component_update_bits(component, TAS27XX_CLK_CFG,
+						    TAS27XX_CLK_CFG_MASK, TAS27XX_CLK_CFG_ENABLE);
+		if (ret < 0) {
+			dev_err(tas27xx->dev, "%s:%u: Failed to CLK_CFG_ENABLE\n",
+				__func__, __LINE__);
+			goto EXIT;
+		}
+		usleep_range(2000, 2000);
+	}
 	ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
 					    TAS2764_PWR_CTRL_MASK,
 					    mute ? TAS2764_PWR_CTRL_MUTE : 0);
+	if(ret >=0) {
+		tas27xx->mbPowerUp = mute?false:true;
+		ret = 0;
+	}
 
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	if (ret < 0) {
+		pr_err("%s:%u: Failed to set powercontrol\n", __func__, __LINE__);
+	}
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
-static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
+static int tas27xx_set_bitwidth(struct tas27xx_priv *tas27xx, int bitwidth)
 {
-	struct snd_soc_component *component = tas2764->component;
+	struct snd_soc_component *component = tas27xx->component;
 	int sense_en;
 	int val;
 	int ret;
-
+    int slot_size;
+	mutex_lock(&tas27xx->codec_lock);
 	switch (bitwidth) {
-	case SNDRV_PCM_FORMAT_S16_LE:
-		ret = snd_soc_component_update_bits(component,
-						    TAS2764_TDM_CFG2,
-						    TAS2764_TDM_CFG2_RXW_MASK,
-						    TAS2764_TDM_CFG2_RXW_16BITS);
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		ret = snd_soc_component_update_bits(component,
-						    TAS2764_TDM_CFG2,
-						    TAS2764_TDM_CFG2_RXW_MASK,
-						    TAS2764_TDM_CFG2_RXW_24BITS);
-		break;
-	case SNDRV_PCM_FORMAT_S32_LE:
-		ret = snd_soc_component_update_bits(component,
-						    TAS2764_TDM_CFG2,
-						    TAS2764_TDM_CFG2_RXW_MASK,
-						    TAS2764_TDM_CFG2_RXW_32BITS);
-		break;
-
-	default:
-		return -EINVAL;
+		case SNDRV_PCM_FORMAT_S16_LE:
+			ret = snd_soc_component_update_bits(component,
+							    TAS2764_TDM_CFG2,
+							    TAS2764_TDM_CFG2_RXW_MASK,
+							    TAS2764_TDM_CFG2_RXW_16BITS);
+	        slot_size = TAS2764_TDM_CFG2_RXS_16BITS;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+			ret = snd_soc_component_update_bits(component,
+							    TAS2764_TDM_CFG2,
+							    TAS2764_TDM_CFG2_RXW_MASK,
+							    TAS2764_TDM_CFG2_RXW_24BITS);
+			slot_size = TAS2764_TDM_CFG2_RXS_24BITS;
+			break;
+		case SNDRV_PCM_FORMAT_S32_LE:
+			ret = snd_soc_component_update_bits(component,
+							    TAS2764_TDM_CFG2,
+							    TAS2764_TDM_CFG2_RXW_MASK,
+							    TAS2764_TDM_CFG2_RXW_32BITS);
+			slot_size = TAS2764_TDM_CFG2_RXS_32BITS;
+			break;
+		default:
+			ret = -EINVAL;
+	}
+
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x set bitwidth error\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
 	}
 
-	if (ret < 0)
-		return ret;
-
-	val = snd_soc_component_read(tas2764->component, TAS2764_PWR_CTRL);
-	if (val < 0)
-		return val;
+	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
+					    TAS2764_TDM_CFG2_RXS_MASK,
+					    slot_size);
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x set RX slot size error\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
+#if KERNEL_VERSION(4, 19, 94) >= LINUX_VERSION_CODE
+	snd_soc_component_read(tas27xx->component, TAS2764_PWR_CTRL, &val);
+#else
+	val = snd_soc_component_read(tas27xx->component, TAS2764_PWR_CTRL);
+#endif
+	if (val < 0) {
+		pr_err("%s:%u:errCode:0x%x read PWR_CTRL error\n",
+			__func__, __LINE__, val);
+		ret = val;
+		goto EXIT;
+	}
 
 	if (val & (1 << TAS2764_VSENSE_POWER_EN))
 		sense_en = 0;
 	else
 		sense_en = TAS2764_TDM_CFG5_VSNS_ENABLE;
 
-	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
+	ret = snd_soc_component_update_bits(tas27xx->component, TAS2764_TDM_CFG5,
 					    TAS2764_TDM_CFG5_VSNS_ENABLE,
 					    sense_en);
-	if (ret < 0)
-		return ret;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x enable vSNS error\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
 
 	if (val & (1 << TAS2764_ISENSE_POWER_EN))
 		sense_en = 0;
 	else
 		sense_en = TAS2764_TDM_CFG6_ISNS_ENABLE;
 
-	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
+	ret = snd_soc_component_update_bits(tas27xx->component, TAS2764_TDM_CFG6,
 					    TAS2764_TDM_CFG6_ISNS_ENABLE,
 					    sense_en);
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x enable iSNS error\n",
+			__func__, __LINE__, ret);
+	}
+	ret = 0;
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
-static int tas2764_set_samplerate(struct tas2764_priv *tas2764, int samplerate)
+static int tas27xx_set_samplerate(struct tas27xx_priv *tas27xx, int samplerate)
 {
-	struct snd_soc_component *component = tas2764->component;
+	struct snd_soc_component *component = tas27xx->component;
 	int ramp_rate_val;
 	int ret;
 
@@ -299,39 +373,44 @@ static int tas2764_set_samplerate(struct
 	default:
 		return -EINVAL;
 	}
-
+	mutex_lock(&tas27xx->codec_lock);
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
 					    TAS2764_TDM_CFG0_SMP_MASK |
 					    TAS2764_TDM_CFG0_MASK,
 					    ramp_rate_val);
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set ramp_rate_val\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
+	ret = 0;
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
-static int tas2764_hw_params(struct snd_pcm_substream *substream,
+static int tas27xx_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
 {
 	struct snd_soc_component *component = dai->component;
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
 	int ret;
 
-	ret = tas2764_set_bitwidth(tas2764, params_format(params));
+	ret = tas27xx_set_bitwidth(tas27xx, params_format(params));
 	if (ret < 0)
 		return ret;
 
-	return tas2764_set_samplerate(tas2764, params_rate(params));
+	return tas27xx_set_samplerate(tas27xx, params_rate(params));
 }
 
-static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+static int tas27xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_component *component = dai->component;
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
 	u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
 	int iface;
-	int ret;
+	int ret = 0;
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
 	case SND_SOC_DAIFMT_NB_NF:
@@ -341,58 +420,70 @@ static int tas2764_set_fmt(struct snd_so
 		asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
 		break;
 	default:
-		dev_err(tas2764->dev, "ASI format Inverse is not found\n");
+		dev_err(tas27xx->dev, "ASI format Inverse is not found\n");
 		return -EINVAL;
 	}
-
+	mutex_lock(&tas27xx->codec_lock);
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
 					    TAS2764_TDM_CFG1_RX_MASK,
 					    asi_cfg_1);
-	if (ret < 0)
-		return ret;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set asi_cfg_1\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-	case SND_SOC_DAIFMT_DSP_A:
-		iface = TAS2764_TDM_CFG2_SCFG_I2S;
-		tdm_rx_start_slot = 1;
-		break;
-	case SND_SOC_DAIFMT_DSP_B:
-	case SND_SOC_DAIFMT_LEFT_J:
-		iface = TAS2764_TDM_CFG2_SCFG_LEFT_J;
-		tdm_rx_start_slot = 0;
-		break;
-	default:
-		dev_err(tas2764->dev,
-			"DAI Format is not found, fmt=0x%x\n", fmt);
-		return -EINVAL;
+		case SND_SOC_DAIFMT_I2S:
+		case SND_SOC_DAIFMT_DSP_A:
+			iface = TAS2764_TDM_CFG2_SCFG_I2S;
+			tdm_rx_start_slot = 1;
+			break;
+		case SND_SOC_DAIFMT_DSP_B:
+		case SND_SOC_DAIFMT_LEFT_J:
+			iface = TAS2764_TDM_CFG2_SCFG_LEFT_J;
+			tdm_rx_start_slot = 0;
+			break;
+		default:
+			pr_err("%s:%u:DAI Format is not found, fmt=0x%x\n",
+				__func__, __LINE__, fmt);
+			ret = -EINVAL;
+			goto EXIT;
 	}
 
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
 					    TAS2764_TDM_CFG1_MASK,
 					    (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
-	if (ret < 0)
-		return ret;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set tdm_rx_start_slot\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
 
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
 					    TAS2764_TDM_CFG2_SCFG_MASK, iface);
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set iface\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
+	ret = 0;
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
-static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
+static int tas27xx_set_dai_tdm_slot(struct snd_soc_dai *dai,
 				unsigned int tx_mask,
 				unsigned int rx_mask,
 				int slots, int slot_width)
 {
 	struct snd_soc_component *component = dai->component;
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
 	int left_slot, right_slot;
 	int slots_cfg;
 	int slot_size;
-	int ret;
+	int ret = 0;
 
 	if (tx_mask == 0 || rx_mask != 0)
 		return -EINVAL;
@@ -417,10 +508,13 @@ static int tas2764_set_dai_tdm_slot(stru
 		return -EINVAL;
 
 	slots_cfg = (right_slot << TAS2764_TDM_CFG3_RXS_SHIFT) | left_slot;
-
+	mutex_lock(&tas27xx->codec_lock);
 	ret = snd_soc_component_write(component, TAS2764_TDM_CFG3, slots_cfg);
-	if (ret)
-		return ret;
+	if (ret) {
+		pr_err("%s:%u:errCode:0x%x Failed to set slots_cfg\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
 
 	switch (slot_width) {
 	case 16:
@@ -433,36 +527,50 @@ static int tas2764_set_dai_tdm_slot(stru
 		slot_size = TAS2764_TDM_CFG2_RXS_32BITS;
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		goto EXIT;
 	}
 
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
 					    TAS2764_TDM_CFG2_RXS_MASK,
 					    slot_size);
-	if (ret < 0)
-		return ret;
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set slot_size\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
 
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG5,
 					    TAS2764_TDM_CFG5_50_MASK,
-					    tas2764->v_sense_slot);
-	if (ret < 0)
-		return ret;
+					    tas27xx->v_sense_slot);
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set v_sense_slot\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
 
 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG6,
 					    TAS2764_TDM_CFG6_50_MASK,
-					    tas2764->i_sense_slot);
-	if (ret < 0)
-		return ret;
-
-	return 0;
+					    tas27xx->i_sense_slot);
+	if (ret < 0) {
+		pr_err("%s:%u:errCode:0x%x Failed to set i_sense_slot\n",
+			__func__, __LINE__, ret);
+		goto EXIT;
+	}
+	ret = 0;
+EXIT:
+	mutex_unlock(&tas27xx->codec_lock);
+	return ret;
 }
 
 static const struct snd_soc_dai_ops tas2764_dai_ops = {
-	.mute_stream = tas2764_mute,
-	.hw_params  = tas2764_hw_params,
-	.set_fmt    = tas2764_set_fmt,
-	.set_tdm_slot = tas2764_set_dai_tdm_slot,
+	.mute_stream = tas27xx_mute,
+	.hw_params  = tas27xx_hw_params,
+	.set_fmt    = tas27xx_set_fmt,
+	.set_tdm_slot = tas27xx_set_dai_tdm_slot,
+#if KERNEL_VERSION(4, 19, 94) < LINUX_VERSION_CODE
 	.no_capture_mute = 1,
+#endif
 };
 
 #define TAS2764_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
@@ -484,45 +592,63 @@ static struct snd_soc_dai_driver tas2764
 		},
 		.capture = {
 			.stream_name    = "ASI1 Capture",
-			.channels_min   = 0,
+			.channels_min   = 1,
 			.channels_max   = 2,
 			.rates = TAS2764_RATES,
 			.formats = TAS2764_FORMATS,
 		},
 		.ops = &tas2764_dai_ops,
-		.symmetric_rate = 1,
+#if KERNEL_VERSION(4, 19, 94) < LINUX_VERSION_CODE
+		.symmetric_rates = 1,
+#endif
 	},
 };
 
-static int tas2764_codec_probe(struct snd_soc_component *component)
+static int tas27xx_codec_probe(struct snd_soc_component *component)
 {
-	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-	int ret;
+	struct tas27xx_priv *tas27xx = snd_soc_component_get_drvdata(component);
+	int ret = 0;
 
-	tas2764->component = component;
+	tas27xx->component = component;
 
-	if (tas2764->sdz_gpio)
-		gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+	if (tas27xx->sdz_gpio)
+		gpiod_set_value_cansleep(tas27xx->sdz_gpio, 1);
 
-	tas2764_reset(tas2764);
+	tas27xx_reset(tas27xx);
 
-	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
+	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG5,
 					    TAS2764_TDM_CFG5_VSNS_ENABLE, 0);
-	if (ret < 0)
-		return ret;
-
-	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
+	if (ret < 0) {
+		dev_err(tas27xx->dev, "%s:%u: Failed to enable vSNS\n",
+			__func__, __LINE__);
+		goto EXIT;
+	}
+	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG6,
 					    TAS2764_TDM_CFG6_ISNS_ENABLE, 0);
-	if (ret < 0)
-		return ret;
-
+	if (ret < 0) {
+		dev_err(tas27xx->dev, "%s:%u: Failed to enable iSNS\n",
+			__func__, __LINE__);
+		goto EXIT;
+	}
 	ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
 					    TAS2764_PWR_CTRL_MASK,
 					    TAS2764_PWR_CTRL_MUTE);
-	if (ret < 0)
-		return ret;
-
-	return 0;
+	if (ret < 0) {
+		dev_err(tas27xx->dev, "%s:%u: Failed to PWR_CTRL_MUTE\n",
+			__func__, __LINE__);
+		goto EXIT;
+	}
+
+	ret = snd_soc_component_write(component, TAS2764_PWR_CTRL, 0x02);
+
+	if (ret < 0) {
+		dev_err(tas27xx->dev, "%s:%u: Failed to initial active\n",
+			__func__, __LINE__);
+		goto EXIT;
+	}
+	ret = 0;
+EXIT:
+	return ret;
 }
 
 static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
@@ -536,10 +662,12 @@ static const struct snd_kcontrol_new tas
 };
 
 static const struct snd_soc_component_driver soc_component_driver_tas2764 = {
-	.probe			= tas2764_codec_probe,
-	.suspend		= tas2764_codec_suspend,
-	.resume			= tas2764_codec_resume,
-	.set_bias_level		= tas2764_set_bias_level,
+	.probe			= tas27xx_codec_probe,
+#ifdef CONFIG_PM		
+	.suspend		= tas27xx_codec_suspend,
+	.resume			= tas27xx_codec_resume,
+#endif	
+	.set_bias_level		= tas27xx_set_bias_level,
 	.controls		= tas2764_snd_controls,
 	.num_controls		= ARRAY_SIZE(tas2764_snd_controls),
 	.dapm_widgets		= tas2764_dapm_widgets,
@@ -576,6 +704,11 @@ static const struct regmap_range_cfg tas
 	},
 };
 
+static bool tas27xx_volatile(struct device *dev, unsigned int reg)
+{
+		return true;
+}
+
 static const struct regmap_config tas2764_i2c_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
@@ -585,82 +718,87 @@ static const struct regmap_config tas276
 	.ranges = tas2764_regmap_ranges,
 	.num_ranges = ARRAY_SIZE(tas2764_regmap_ranges),
 	.max_register = 1 * 128,
+	.volatile_reg = tas27xx_volatile,
 };
 
-static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764)
+static int tas27xx_parse_dt(struct device *dev, struct tas27xx_priv *tas27xx)
 {
 	int ret = 0;
 
-	tas2764->reset_gpio = devm_gpiod_get_optional(tas2764->dev, "reset",
+	tas27xx->reset_gpio = devm_gpiod_get_optional(tas27xx->dev, "reset",
 						      GPIOD_OUT_HIGH);
-	if (IS_ERR(tas2764->reset_gpio)) {
-		if (PTR_ERR(tas2764->reset_gpio) == -EPROBE_DEFER) {
-			tas2764->reset_gpio = NULL;
+	if (IS_ERR(tas27xx->reset_gpio)) {
+		if (PTR_ERR(tas27xx->reset_gpio) == -EPROBE_DEFER) {
+			tas27xx->reset_gpio = NULL;
 			return -EPROBE_DEFER;
 		}
 	}
 
-	tas2764->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
-	if (IS_ERR(tas2764->sdz_gpio)) {
-		if (PTR_ERR(tas2764->sdz_gpio) == -EPROBE_DEFER)
+	tas27xx->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
+	if (IS_ERR(tas27xx->sdz_gpio)) {
+		if (PTR_ERR(tas27xx->sdz_gpio) == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
 
-		tas2764->sdz_gpio = NULL;
+		tas27xx->sdz_gpio = NULL;
 	}
 
 	ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
-				       &tas2764->i_sense_slot);
+				       &tas27xx->i_sense_slot);
 	if (ret)
-		tas2764->i_sense_slot = 0;
+		tas27xx->i_sense_slot = 0;
 
 	ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
-				       &tas2764->v_sense_slot);
+				       &tas27xx->v_sense_slot);
 	if (ret)
-		tas2764->v_sense_slot = 2;
+		tas27xx->v_sense_slot = 2;
 
 	return 0;
 }
 
-static int tas2764_i2c_probe(struct i2c_client *client,
+static int tas27xx_i2c_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	struct tas2764_priv *tas2764;
+	struct tas27xx_priv *tas27xx;
 	int result;
 
-	tas2764 = devm_kzalloc(&client->dev, sizeof(struct tas2764_priv),
+	tas27xx = devm_kzalloc(&client->dev, sizeof(struct tas27xx_priv),
 			       GFP_KERNEL);
-	if (!tas2764)
+	if (!tas27xx)
 		return -ENOMEM;
-
-	tas2764->dev = &client->dev;
-	i2c_set_clientdata(client, tas2764);
-	dev_set_drvdata(&client->dev, tas2764);
-
-	tas2764->regmap = devm_regmap_init_i2c(client, &tas2764_i2c_regmap);
-	if (IS_ERR(tas2764->regmap)) {
-		result = PTR_ERR(tas2764->regmap);
+	mutex_init(&tas27xx->codec_lock);
+	tas27xx->dev = &client->dev;
+	i2c_set_clientdata(client, tas27xx);
+	dev_set_drvdata(&client->dev, tas27xx);
+
+	tas27xx->regmap = devm_regmap_init_i2c(client, &tas2764_i2c_regmap);
+	if (IS_ERR(tas27xx->regmap)) {
+		result = PTR_ERR(tas27xx->regmap);
 		dev_err(&client->dev, "Failed to allocate register map: %d\n",
 					result);
 		return result;
 	}
 
 	if (client->dev.of_node) {
-		result = tas2764_parse_dt(&client->dev, tas2764);
+		result = tas27xx_parse_dt(&client->dev, tas27xx);
 		if (result) {
-			dev_err(tas2764->dev, "%s: Failed to parse devicetree\n",
+			dev_err(tas27xx->dev, "%s: Failed to parse devicetree\n",
 				__func__);
 			return result;
 		}
 	}
 
-	return devm_snd_soc_register_component(tas2764->dev,
+	tas27xx->device_id = id->driver_data;
+	dev_info(tas27xx->dev, "chip_id: %u\n", tas27xx->device_id);
+	
+	return devm_snd_soc_register_component(tas27xx->dev,
 					       &soc_component_driver_tas2764,
 					       tas2764_dai_driver,
 					       ARRAY_SIZE(tas2764_dai_driver));
 }
 
 static const struct i2c_device_id tas2764_i2c_id[] = {
-	{ "tas2764", 0},
+	{ "tas2764", TAS2764},
+	{ "tas2780", TAS2780},
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id);
@@ -668,6 +806,7 @@ MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id)
 #if defined(CONFIG_OF)
 static const struct of_device_id tas2764_of_match[] = {
 	{ .compatible = "ti,tas2764" },
+	{ .compatible = "ti,tas2780" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, tas2764_of_match);
@@ -675,14 +814,14 @@ MODULE_DEVICE_TABLE(of, tas2764_of_match
 
 static struct i2c_driver tas2764_i2c_driver = {
 	.driver = {
-		.name   = "tas2764",
+		.name   = "tas27xx",
 		.of_match_table = of_match_ptr(tas2764_of_match),
 	},
-	.probe      = tas2764_i2c_probe,
+	.probe      = tas27xx_i2c_probe,
 	.id_table   = tas2764_i2c_id,
 };
 module_i2c_driver(tas2764_i2c_driver);
 
-MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
-MODULE_DESCRIPTION("TAS2764 I2C Smart Amplifier driver");
+MODULE_AUTHOR("Raphael Xu <raphael-xu@ti.com>");
+MODULE_DESCRIPTION("TAS2764/TAS2780 I2C Smart Amplifier driver");
 MODULE_LICENSE("GPL v2");

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH 1/4] Asoc: tas2764 : new tas27xx driver to support either tas2764 or tas2780
  2022-03-15  5:28 [PATCH 1/4] Asoc: tas2764 : new tas27xx driver to support either tas2764 or tas2780 Xu, Yang
@ 2022-03-15  9:12 ` Takashi Iwai
  0 siblings, 0 replies; 2+ messages in thread
From: Takashi Iwai @ 2022-03-15  9:12 UTC (permalink / raw)
  To: Xu, Yang
  Cc: alsa-devel@alsa-project.org, broonie@kernel.org, tiwai@suse.com,
	Ding, Shenghao

On Tue, 15 Mar 2022 06:28:05 +0100,
Xu, Yang wrote:
> 
> Hi Mark and Takashi Iwai,
> 
> This is Raphael Xu who is from Low Power Audio team,Texas Instrument.
> 
> Could you help to review the attached patch and upstream them to the kernel?

Thanks for the patches, but could you prepare the proper patches and
submit in a better way?  The details about how to submit patches are
found in Documentation/process/submitting-patches.rst.

It seems that you sent a diff from each file, but it's no proper
patch.  I guess it'll be a single patch containing all files in your
case.

Also, above all, describe why and what you added / modified the code
concisely but well understandably in the patch description (commit
log).

Drop the kernel version check with #if LINUX_VERSION.  This must not
be in the upstream code.

Last but not least, don't forget to put your Signed-off-by tag.  It's
a legal requirement.  Again, see the document above for details.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-03-15  9:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-15  5:28 [PATCH 1/4] Asoc: tas2764 : new tas27xx driver to support either tas2764 or tas2780 Xu, Yang
2022-03-15  9:12 ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.