Parcourir la source

Merge "asoc: lpass-cdc: reduce WSA digital gain when cooling is enabled"

qctecmdr il y a 3 ans
Parent
commit
984e5cd1f7

+ 112 - 14
asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c

@@ -193,6 +193,18 @@ struct lpass_cdc_wsa_macro_swr_ctrl_data {
 	struct platform_device *wsa_swr_pdev;
 };
 
+#define LPASS_CDC_WSA_MACRO_SET_VOLUME_TLV(xname, xreg, xmin, xmax, tlv_array) \
+{	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p  = (tlv_array), \
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+	.put = lpass_cdc_wsa_macro_set_digital_volume, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+	{.reg = xreg, .rreg = xreg,  \
+	.min = xmin, .max = xmax, .platform_max = xmax, \
+	.sign_bit = 7,} }
+
 struct lpass_cdc_wsa_macro_swr_ctrl_platform_data {
 	void *handle; /* holds codec private data */
 	int (*read)(void *handle, int reg);
@@ -276,9 +288,11 @@ struct lpass_cdc_wsa_macro_priv {
 	u16 default_clk_id;
 	u32 pcm_rate_vi;
 	int wsa_digital_mute_status[LPASS_CDC_WSA_MACRO_RX_MAX];
+	u8 original_gain;
 	struct thermal_cooling_device *tcdev;
 	uint32_t thermal_cur_state;
 	uint32_t thermal_max_state;
+	struct work_struct lpass_cdc_wsa_macro_cooling_work;
 };
 
 static struct snd_soc_dai_driver lpass_cdc_wsa_macro_dai[];
@@ -1891,6 +1905,44 @@ static int lpass_cdc_wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
+static int lpass_cdc_wsa_macro_set_digital_volume(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct device *wsa_dev = NULL;
+	struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL;
+	struct soc_mixer_control *mc =
+			(struct soc_mixer_control *)kcontrol->private_value;
+	u8 gain = 0;
+	int ret = 0;
+
+	if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
+		return -EINVAL;
+
+	if (!wsa_priv) {
+		pr_err("%s: priv is null for macro!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	wsa_priv->original_gain = (u8)snd_soc_component_read(wsa_priv->component,
+						mc->reg);
+
+	if (wsa_priv->thermal_cur_state > 0) {
+		gain = (u8)(wsa_priv->original_gain - wsa_priv->thermal_cur_state);
+		snd_soc_component_update_bits(wsa_priv->component,
+			mc->reg, 0xFF, gain);
+		dev_dbg(wsa_priv->dev,
+			"%s: Current thermal state: %d, adjusted gain: %x\n",
+			__func__, wsa_priv->thermal_cur_state, gain);
+	}
+
+	return ret;
+}
+
 static int lpass_cdc_wsa_macro_get_compander(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -2158,12 +2210,12 @@ static const struct snd_kcontrol_new lpass_cdc_wsa_macro_snd_controls[] = {
 			LPASS_CDC_WSA_MACRO_SOFTCLIP1, 1, 0,
 			lpass_cdc_wsa_macro_soft_clip_enable_get,
 			lpass_cdc_wsa_macro_soft_clip_enable_put),
-	SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume",
-			  LPASS_CDC_WSA_RX0_RX_VOL_CTL,
-			  -84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume",
-			  LPASS_CDC_WSA_RX1_RX_VOL_CTL,
-			  -84, 40, digital_gain),
+	LPASS_CDC_WSA_MACRO_SET_VOLUME_TLV("WSA_RX0 Digital Volume",
+					   LPASS_CDC_WSA_RX0_RX_VOL_CTL,
+					   -84, 40, digital_gain),
+	LPASS_CDC_WSA_MACRO_SET_VOLUME_TLV("WSA_RX1 Digital Volume",
+					   LPASS_CDC_WSA_RX1_RX_VOL_CTL,
+					   -84, 40, digital_gain),
 	SOC_SINGLE_EXT("WSA_RX0 Digital Mute", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_RX0, 1,
 			0, lpass_cdc_wsa_macro_get_rx_mute_status,
 			lpass_cdc_wsa_macro_set_rx_mute_status),
@@ -2747,7 +2799,6 @@ static int lpass_cdc_wsa_macro_set_cur_state(
 					unsigned long state)
 {
 	struct lpass_cdc_wsa_macro_priv *wsa_priv = cdev->devdata;
-	u8 gain = 0;
 
 	if (!wsa_priv) {
 		pr_err("%s: cdev->devdata is NULL\n", __func__);
@@ -2759,15 +2810,11 @@ static int lpass_cdc_wsa_macro_set_cur_state(
 	else
 		wsa_priv->thermal_cur_state = wsa_priv->thermal_max_state;
 
-	gain = (u8)(gain - wsa_priv->thermal_cur_state);
 	dev_dbg(wsa_priv->dev,
-		"%s: requested state:%d, actual state: %d, gain: %#x\n",
-		__func__, state, wsa_priv->thermal_cur_state, gain);
+		"%s: requested state:%d, actual state: %d\n",
+		__func__, state, wsa_priv->thermal_cur_state);
 
-	snd_soc_component_update_bits(wsa_priv->component,
-		LPASS_CDC_WSA_RX0_RX_VOL_CTL, 0xFF, gain);
-	snd_soc_component_update_bits(wsa_priv->component,
-		LPASS_CDC_WSA_RX1_RX_VOL_CTL, 0xFF, gain);
+	schedule_work(&wsa_priv->lpass_cdc_wsa_macro_cooling_work);
 
 	return 0;
 }
@@ -2958,6 +3005,55 @@ err:
 	return;
 }
 
+static void lpass_cdc_wsa_macro_cooling_adjust_gain(struct work_struct *work)
+{
+	struct lpass_cdc_wsa_macro_priv *wsa_priv;
+	struct snd_soc_dapm_context *dapm;
+	u8 gain = 0;
+	u32 ctl_reg;
+
+	wsa_priv = container_of(work, struct lpass_cdc_wsa_macro_priv,
+			     lpass_cdc_wsa_macro_cooling_work);
+	if (!wsa_priv) {
+		pr_err("%s: priv is null for macro!\n",
+			__func__);
+		return;
+	}
+	if (!wsa_priv->dev || !wsa_priv->dev->of_node) {
+		dev_err(wsa_priv->dev,
+			"%s: DT node for wsa_priv does not exist\n", __func__);
+		return;
+	}
+
+	dapm = snd_soc_component_get_dapm(wsa_priv->component);
+
+	/* Only adjust the volume when WSA clock is enabled */
+	ctl_reg = snd_soc_component_read(wsa_priv->component,
+			LPASS_CDC_WSA_RX0_RX_PATH_CTL);
+	if (ctl_reg & 0x20) {
+		gain = (u8)(wsa_priv->original_gain - wsa_priv->thermal_cur_state);
+		snd_soc_component_update_bits(wsa_priv->component,
+			LPASS_CDC_WSA_RX0_RX_VOL_CTL, 0xFF, gain);
+		dev_dbg(wsa_priv->dev,
+			"%s: RX0 current thermal state: %d, adjusted gain: %#x\n",
+			__func__, wsa_priv->thermal_cur_state, gain);
+	}
+
+	/* Only adjust the volume when WSA clock is enabled */
+	ctl_reg = snd_soc_component_read(wsa_priv->component,
+			LPASS_CDC_WSA_RX1_RX_PATH_CTL);
+	if (ctl_reg & 0x20) {
+		gain = (u8)(wsa_priv->original_gain - wsa_priv->thermal_cur_state);
+		snd_soc_component_update_bits(wsa_priv->component,
+			LPASS_CDC_WSA_RX1_RX_VOL_CTL, 0xFF, gain);
+		dev_dbg(wsa_priv->dev,
+			"%s: RX1 current thermal state: %d, adjusted gain: %#x\n",
+			__func__, wsa_priv->thermal_cur_state, gain);
+	}
+
+	return;
+}
+
 static void lpass_cdc_wsa_macro_init_ops(struct macro_ops *ops,
 			       char __iomem *wsa_io_base)
 {
@@ -3037,6 +3133,8 @@ static int lpass_cdc_wsa_macro_probe(struct platform_device *pdev)
 	wsa_priv->reset_swr = true;
 	INIT_WORK(&wsa_priv->lpass_cdc_wsa_macro_add_child_devices_work,
 		  lpass_cdc_wsa_macro_add_child_devices);
+	INIT_WORK(&wsa_priv->lpass_cdc_wsa_macro_cooling_work,
+		  lpass_cdc_wsa_macro_cooling_adjust_gain);
 	wsa_priv->swr_plat_data.handle = (void *) wsa_priv;
 	wsa_priv->swr_plat_data.read = NULL;
 	wsa_priv->swr_plat_data.write = NULL;

+ 112 - 14
asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c

@@ -193,6 +193,18 @@ struct lpass_cdc_wsa2_macro_swr_ctrl_data {
 	struct platform_device *wsa2_swr_pdev;
 };
 
+#define LPASS_CDC_WSA2_MACRO_SET_VOLUME_TLV(xname, xreg, xmin, xmax, tlv_array) \
+{	.iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p  = (tlv_array), \
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+	.put = lpass_cdc_wsa2_macro_set_digital_volume, \
+	.private_value = (unsigned long)&(struct soc_mixer_control) \
+	{.reg = xreg, .rreg = xreg,  \
+	.min = xmin, .max = xmax, .platform_max = xmax, \
+	.sign_bit = 7,} }
+
 struct lpass_cdc_wsa2_macro_swr_ctrl_platform_data {
 	void *handle; /* holds codec private data */
 	int (*read)(void *handle, int reg);
@@ -273,9 +285,11 @@ struct lpass_cdc_wsa2_macro_priv {
 	u16 default_clk_id;
 	u32 pcm_rate_vi;
 	int wsa2_digital_mute_status[LPASS_CDC_WSA2_MACRO_RX_MAX];
+	u8 original_gain;
 	struct thermal_cooling_device *tcdev;
 	uint32_t thermal_cur_state;
 	uint32_t thermal_max_state;
+	struct work_struct lpass_cdc_wsa2_macro_cooling_work;
 };
 
 static struct snd_soc_dai_driver lpass_cdc_wsa2_macro_dai[];
@@ -1890,6 +1904,44 @@ static int lpass_cdc_wsa2_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol
 	return ret;
 }
 
+static int lpass_cdc_wsa2_macro_set_digital_volume(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+				snd_soc_kcontrol_component(kcontrol);
+	struct device *wsa2_dev = NULL;
+	struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL;
+	struct soc_mixer_control *mc =
+			(struct soc_mixer_control *)kcontrol->private_value;
+	u8 gain = 0;
+	int ret = 0;
+
+	if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__))
+		return -EINVAL;
+
+	if (!wsa2_priv) {
+		pr_err("%s: priv is null for macro!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+	wsa2_priv->original_gain = (u8)snd_soc_component_read(wsa2_priv->component,
+						mc->reg);
+
+	if (wsa2_priv->thermal_cur_state > 0) {
+		gain = (u8)(wsa2_priv->original_gain - wsa2_priv->thermal_cur_state);
+		snd_soc_component_update_bits(wsa2_priv->component,
+			mc->reg, 0xFF, gain);
+		dev_dbg(wsa2_priv->dev,
+			"%s: Current thermal state: %d, adjusted gain: %x\n",
+			__func__, wsa2_priv->thermal_cur_state, gain);
+	}
+
+	return ret;
+}
+
 static int lpass_cdc_wsa2_macro_get_compander(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
@@ -2157,12 +2209,12 @@ static const struct snd_kcontrol_new lpass_cdc_wsa2_macro_snd_controls[] = {
 			LPASS_CDC_WSA2_MACRO_SOFTCLIP1, 1, 0,
 			lpass_cdc_wsa2_macro_soft_clip_enable_get,
 			lpass_cdc_wsa2_macro_soft_clip_enable_put),
-	SOC_SINGLE_S8_TLV("WSA2_RX0 Digital Volume",
-			  LPASS_CDC_WSA2_RX0_RX_VOL_CTL,
-			  -84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("WSA2_RX1 Digital Volume",
-			  LPASS_CDC_WSA2_RX1_RX_VOL_CTL,
-			  -84, 40, digital_gain),
+	LPASS_CDC_WSA2_MACRO_SET_VOLUME_TLV("WSA2_RX0 Digital Volume",
+					   LPASS_CDC_WSA2_RX0_RX_VOL_CTL,
+					   -84, 40, digital_gain),
+	LPASS_CDC_WSA2_MACRO_SET_VOLUME_TLV("WSA2_RX1 Digital Volume",
+					   LPASS_CDC_WSA2_RX1_RX_VOL_CTL,
+					   -84, 40, digital_gain),
 	SOC_SINGLE_EXT("WSA2_RX0 Digital Mute", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX0, 1,
 			0, lpass_cdc_wsa2_macro_get_rx_mute_status,
 			lpass_cdc_wsa2_macro_set_rx_mute_status),
@@ -2745,7 +2797,6 @@ static int lpass_cdc_wsa2_macro_set_cur_state(
 					unsigned long state)
 {
 	struct lpass_cdc_wsa2_macro_priv *wsa2_priv = cdev->devdata;
-	u8 gain = 0;
 
 	if (!wsa2_priv) {
 		pr_err("%s: cdev->devdata is NULL\n", __func__);
@@ -2757,15 +2808,11 @@ static int lpass_cdc_wsa2_macro_set_cur_state(
 	else
 		wsa2_priv->thermal_cur_state = wsa2_priv->thermal_max_state;
 
-	gain = (u8)(gain - wsa2_priv->thermal_cur_state);
 	dev_dbg(wsa2_priv->dev,
-		"%s: requested state:%d, actual state: %d, gain: %#x\n",
-		__func__, state, wsa2_priv->thermal_cur_state, gain);
+		"%s: requested state:%d, actual state: %d\n",
+		__func__, state, wsa2_priv->thermal_cur_state);
 
-	snd_soc_component_update_bits(wsa2_priv->component,
-		LPASS_CDC_WSA2_RX0_RX_VOL_CTL, 0xFF, gain);
-	snd_soc_component_update_bits(wsa2_priv->component,
-		LPASS_CDC_WSA2_RX1_RX_VOL_CTL, 0xFF, gain);
+	schedule_work(&wsa2_priv->lpass_cdc_wsa2_macro_cooling_work);
 
 	return 0;
 }
@@ -2957,6 +3004,55 @@ err:
 	return;
 }
 
+static void lpass_cdc_wsa2_macro_cooling_adjust_gain(struct work_struct *work)
+{
+	struct lpass_cdc_wsa2_macro_priv *wsa2_priv;
+	struct snd_soc_dapm_context *dapm;
+	u8 gain = 0;
+	u32 ctl_reg;
+
+	wsa2_priv = container_of(work, struct lpass_cdc_wsa2_macro_priv,
+			     lpass_cdc_wsa2_macro_cooling_work);
+	if (!wsa2_priv) {
+		pr_err("%s: priv is null for macro!\n",
+			__func__);
+		return;
+	}
+	if (!wsa2_priv->dev || !wsa2_priv->dev->of_node) {
+		dev_err(wsa2_priv->dev,
+			"%s: DT node for wsa2_priv does not exist\n", __func__);
+		return;
+	}
+
+	dapm = snd_soc_component_get_dapm(wsa2_priv->component);
+
+	/* Only adjust the volume when WSA2 clock is enabled */
+	ctl_reg = snd_soc_component_read(wsa2_priv->component,
+			LPASS_CDC_WSA2_RX0_RX_PATH_CTL);
+	if (ctl_reg & 0x20) {
+		gain = (u8)(wsa2_priv->original_gain - wsa2_priv->thermal_cur_state);
+		snd_soc_component_update_bits(wsa2_priv->component,
+			LPASS_CDC_WSA2_RX0_RX_VOL_CTL, 0xFF, gain);
+		dev_dbg(wsa2_priv->dev,
+			"%s: RX0 current thermal state: %d, adjusted gain: %#x\n",
+			__func__, wsa2_priv->thermal_cur_state, gain);
+	}
+
+	/* Only adjust the volume when WSA2 clock is enabled */
+	ctl_reg = snd_soc_component_read(wsa2_priv->component,
+			LPASS_CDC_WSA2_RX1_RX_PATH_CTL);
+	if (ctl_reg & 0x20) {
+		gain = (u8)(wsa2_priv->original_gain - wsa2_priv->thermal_cur_state);
+		snd_soc_component_update_bits(wsa2_priv->component,
+			LPASS_CDC_WSA2_RX1_RX_VOL_CTL, 0xFF, gain);
+		dev_dbg(wsa2_priv->dev,
+			"%s: RX1 current thermal state: %d, adjusted gain: %#x\n",
+			__func__, wsa2_priv->thermal_cur_state, gain);
+	}
+
+	return;
+}
+
 static void lpass_cdc_wsa2_macro_init_ops(struct macro_ops *ops,
 			       char __iomem *wsa2_io_base)
 {
@@ -3038,6 +3134,8 @@ static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev)
 	wsa2_priv->reset_swr = true;
 	INIT_WORK(&wsa2_priv->lpass_cdc_wsa2_macro_add_child_devices_work,
 		  lpass_cdc_wsa2_macro_add_child_devices);
+	INIT_WORK(&wsa2_priv->lpass_cdc_wsa2_macro_cooling_work,
+		  lpass_cdc_wsa2_macro_cooling_adjust_gain);
 	wsa2_priv->swr_plat_data.handle = (void *) wsa2_priv;
 	wsa2_priv->swr_plat_data.read = NULL;
 	wsa2_priv->swr_plat_data.write = NULL;