From eecf60dcb58fbb2dc75acc834ff8d5edd519c4fa Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Sat, 4 Jan 2020 01:52:53 +0530 Subject: [PATCH] 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 --- asoc/codecs/wsa883x/internal.h | 3 +- asoc/codecs/wsa883x/wsa883x.c | 63 ++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h index 2fd3589c53..5469003e8b 100644 --- a/asoc/codecs/wsa883x/internal.h +++ b/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, diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c index 6cc7eaf5cb..c8a12e4385 100644 --- a/asoc/codecs/wsa883x/wsa883x.c +++ b/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 @@ -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);