ASoC: wsa881x: Avoid query temp during suspend

Runtime suspend in slimbus driver makes QMI call which takes
wakelock and result in first system suspend to fail. As a result
of first suspend fail, POST_PM_SUSPEND event is dispatched to
thermal core which registered to pm notifier. WSA being one
of registered thermal zone gets query for temperature, and makes
slimbus reads/writes which will result in runtime resume of
slimbus driver to happen. System suspend fails again continuously
in this endless loop as slimbus runtime suspend will make QMI call
again.
Update wsa temp sensor to handle suspend event by registering to
pm notifier and ignore the temperature request from thermal core
at resume. This will avoid slimbus reads/writes during suspend in
progress and allow XO shutdown to happen.

Change-Id: Id13a9701cffb1231ef7d563cbc30756fd71d5868
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
This commit is contained in:
Sudheer Papothi 2018-04-06 00:51:48 +05:30 committed by Gerrit - the friendly Code Review server
parent 29dfffc4b2
commit c9dd3be3c3
3 changed files with 79 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -12,6 +12,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/suspend.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/thermal.h> #include <linux/thermal.h>
@ -61,6 +62,20 @@ int wsa881x_get_temp(struct thermal_zone_device *thermal,
pr_err("%s: pdata is NULL\n", __func__); pr_err("%s: pdata is NULL\n", __func__);
return -EINVAL; return -EINVAL;
} }
if (atomic_cmpxchg(&pdata->is_suspend_spk, 1, 0)) {
/*
* get_temp query happens as part of POST_PM_SUSPEND
* from thermal core. To avoid calls to slimbus
* as part of this thermal query, return default temp
* and reset the suspend flag.
*/
if (!pdata->t0_init) {
if (temp)
*temp = pdata->curr_temp;
return 0;
}
}
temp_retry: temp_retry:
if (pdata->wsa_temp_reg_read) { if (pdata->wsa_temp_reg_read) {
ret = pdata->wsa_temp_reg_read(codec, &reg); ret = pdata->wsa_temp_reg_read(codec, &reg);
@ -108,6 +123,8 @@ temp_retry:
goto temp_retry; goto temp_retry;
} }
} }
pdata->curr_temp = temp_val;
if (temp) if (temp)
*temp = temp_val; *temp = temp_val;
pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n", pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
@ -120,6 +137,23 @@ static struct thermal_zone_device_ops wsa881x_thermal_ops = {
.get_temp = wsa881x_get_temp, .get_temp = wsa881x_get_temp,
}; };
static int wsa881x_pm_notify(struct notifier_block *nb,
unsigned long mode, void *_unused)
{
struct wsa881x_tz_priv *pdata =
container_of(nb, struct wsa881x_tz_priv, pm_nb);
switch (mode) {
case PM_SUSPEND_PREPARE:
atomic_set(&pdata->is_suspend_spk, 1);
break;
default:
break;
}
return 0;
}
int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata) int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata)
{ {
struct thermal_zone_device *tz_dev; struct thermal_zone_device *tz_dev;
@ -137,12 +171,23 @@ int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata)
return -EINVAL; return -EINVAL;
} }
tz_pdata->tz_dev = tz_dev; tz_pdata->tz_dev = tz_dev;
tz_pdata->pm_nb.notifier_call = wsa881x_pm_notify;
register_pm_notifier(&tz_pdata->pm_nb);
atomic_set(&tz_pdata->is_suspend_spk, 0);
return 0; return 0;
} }
EXPORT_SYMBOL(wsa881x_init_thermal); EXPORT_SYMBOL(wsa881x_init_thermal);
void wsa881x_deinit_thermal(struct thermal_zone_device *tz_dev) void wsa881x_deinit_thermal(struct thermal_zone_device *tz_dev)
{ {
struct wsa881x_tz_priv *pdata;
if (tz_dev && tz_dev->devdata) {
pdata = tz_dev->devdata;
if (pdata)
unregister_pm_notifier(&pdata->pm_nb);
}
if (tz_dev) if (tz_dev)
thermal_zone_device_unregister(tz_dev); thermal_zone_device_unregister(tz_dev);
} }

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -31,6 +31,10 @@ struct wsa881x_tz_priv {
struct wsa_temp_register *wsa_temp_reg; struct wsa_temp_register *wsa_temp_reg;
char name[80]; char name[80];
wsa_temp_register_read wsa_temp_reg_read; wsa_temp_register_read wsa_temp_reg_read;
struct notifier_block pm_nb;
atomic_t is_suspend_spk;
int t0_init;
int curr_temp;
}; };
int wsa881x_get_temp(struct thermal_zone_device *tz_dev, int *temp); int wsa881x_get_temp(struct thermal_zone_device *tz_dev, int *temp);

View File

@ -200,12 +200,40 @@ static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
static int wsa881x_get_t0_init(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
ucontrol->value.integer.value[0] = pdata->t0_init;
dev_dbg(codec->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
return 0;
}
static int wsa881x_set_t0_init(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
pdata->t0_init = ucontrol->value.integer.value[0];
dev_dbg(codec->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
return 0;
}
static const struct snd_kcontrol_new wsa_snd_controls[] = { static const struct snd_kcontrol_new wsa_snd_controls[] = {
SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum, SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
wsa_pa_gain_get, wsa_pa_gain_put), wsa_pa_gain_get, wsa_pa_gain_put),
SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0, SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
wsa881x_get_mute, wsa881x_set_mute), wsa881x_get_mute, wsa881x_set_mute),
SOC_SINGLE_EXT("WSA T0 Init", SND_SOC_NOPM, 0, 1, 0,
wsa881x_get_t0_init, wsa881x_set_t0_init),
}; };
static int codec_debug_open(struct inode *inode, struct file *file) static int codec_debug_open(struct inode *inode, struct file *file)