diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h index 14bc375720..5b532c563f 100644 --- a/asoc/codecs/wsa883x/internal.h +++ b/asoc/codecs/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; }; #endif /* WSA883X_INTERNAL_H */ diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c index 171abc6761..9c0c2de3f1 100644 --- a/asoc/codecs/wsa883x/wsa883x.c +++ b/asoc/codecs/wsa883x/wsa883x.c @@ -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" @@ -875,17 +880,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; @@ -1053,6 +1070,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); @@ -1066,6 +1114,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; } @@ -1124,6 +1173,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);