Prechádzať zdrojové kódy

ASoC: wsa883x: Add support for VBAT monitor

Add support for VBAT monitor on WSA883x speaker amplifier
for signal profiling.

Change-Id: I1544b601ac9ee4e8ed6da3839cc46914bbae5d93
Signed-off-by: Sudheer Papothi <[email protected]>
Sudheer Papothi 5 rokov pred
rodič
commit
eecf60dcb5

+ 2 - 1
asoc/codecs/wsa883x/internal.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef WSA883X_INTERNAL_H
@@ -118,6 +118,7 @@ struct wsa883x_priv {
 	void *handle;
 	int (*register_notifier)(void *handle,
 				struct notifier_block *nblock, bool enable);
+	struct delayed_work vbat_work;
 };
 
 static int32_t wsa883x_resource_acquire(struct snd_soc_component *component,

+ 57 - 6
asoc/codecs/wsa883x/wsa883x.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -35,6 +35,11 @@
 #define HIGH_TEMP_THRESHOLD 45
 #define TEMP_INVALID	0xFFFF
 #define WSA883X_TEMP_RETRY 3
+#define WSA883X_VBAT_TIMER_SEC    2
+
+static int wsa883x_vbat_timer_sec = WSA883X_VBAT_TIMER_SEC;
+module_param(wsa883x_vbat_timer_sec, int, 0664);
+MODULE_PARM_DESC(wsa883x_vbat_timer_sec, "timer for VBAT monitor polling");
 
 #define DRV_NAME "wsa-codec"
 
@@ -883,17 +888,29 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
 
 	dev_dbg(component->dev, "%s: %s %d\n", __func__, w->name, event);
 	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
+	case SND_SOC_DAPM_POST_PMU:
 		snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL,
 				0x01, 0x01);
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
 		/* Force remove group */
 		swr_remove_from_group(wsa883x->swr_slave,
 				      wsa883x->swr_slave->dev_num);
+		snd_soc_component_update_bits(component,
+				WSA883X_VBAT_ADC_FLT_CTL,
+				0x0E, 0x06);
+		snd_soc_component_update_bits(component,
+				WSA883X_VBAT_ADC_FLT_CTL,
+				0x01, 0x01);
+		schedule_delayed_work(&wsa883x->vbat_work,
+			msecs_to_jiffies(wsa883x_vbat_timer_sec * 1000));
 		break;
-	case SND_SOC_DAPM_POST_PMD:
+	case SND_SOC_DAPM_PRE_PMD:
+		cancel_delayed_work_sync(&wsa883x->vbat_work);
+		snd_soc_component_update_bits(component,
+				WSA883X_VBAT_ADC_FLT_CTL,
+				0x01, 0x00);
+		snd_soc_component_update_bits(component,
+				WSA883X_VBAT_ADC_FLT_CTL,
+				0x0E, 0x00);
 		snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL,
 				0x01, 0x00);
 		break;
@@ -1061,6 +1078,37 @@ static int wsa883x_get_temperature(struct snd_soc_component *component,
 	return ret;
 }
 
+static void wsa883x_vbat_monitor_work(struct work_struct *work)
+{
+	struct wsa883x_priv *wsa883x;
+	struct delayed_work *dwork;
+	struct snd_soc_component *component;
+	u16 val = 0, vbat_code = 0;
+	int vbat_val = 0;
+
+	dwork = to_delayed_work(work);
+	wsa883x = container_of(dwork, struct wsa883x_priv, vbat_work);
+	component = wsa883x->component;
+
+	val = snd_soc_component_read32(component, WSA883X_VBAT_DIN_MSB);
+	vbat_code = (val << 2);
+	val = (snd_soc_component_read32(component, WSA883X_VBAT_DIN_LSB)
+		& 0xC0);
+	vbat_code |= (val >> 6);
+	vbat_val = ((vbat_code * 5) / 1023);
+	dev_dbg(component->dev, "%s: instant vbat code = %d val = %d\n",
+		__func__, vbat_code, vbat_val);
+
+	val = snd_soc_component_read32(component, WSA883X_VBAT_DOUT);
+	vbat_val = ((val * 5) / 255);
+
+	dev_dbg(component->dev, "%s: low pass vbat code = %d val = %d\n",
+		__func__, val, vbat_val);
+
+	schedule_delayed_work(&wsa883x->vbat_work,
+			msecs_to_jiffies(wsa883x_vbat_timer_sec * 1000));
+}
+
 static int wsa883x_codec_probe(struct snd_soc_component *component)
 {
 	struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
@@ -1074,6 +1122,7 @@ static int wsa883x_codec_probe(struct snd_soc_component *component)
 	wsa883x->component = component;
 	wsa883x_codec_init(component);
 	wsa883x->global_pa_cnt = 0;
+	INIT_DELAYED_WORK(&wsa883x->vbat_work, wsa883x_vbat_monitor_work);
 
 	return 0;
 }
@@ -1132,6 +1181,8 @@ static int wsa883x_event_notify(struct notifier_block *nb,
 
 	switch (event) {
 	case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
+		if (delayed_work_pending(&wsa883x->vbat_work))
+			cancel_delayed_work_sync(&wsa883x->vbat_work);
 		snd_soc_component_update_bits(wsa883x->component,
 					WSA883X_PA_FSM_CTL,
 					0x01, 0x00);