diff --git a/asoc/codecs/wsa881x-temp-sensor.c b/asoc/codecs/wsa881x-temp-sensor.c index 5ab0ecfdc0..b2ed963b7e 100644 --- a/asoc/codecs/wsa881x-temp-sensor.c +++ b/asoc/codecs/wsa881x-temp-sensor.c @@ -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 * it under the terms of the GNU General Public License version 2 and @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -61,6 +62,20 @@ int wsa881x_get_temp(struct thermal_zone_device *thermal, pr_err("%s: pdata is NULL\n", __func__); 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: if (pdata->wsa_temp_reg_read) { ret = pdata->wsa_temp_reg_read(codec, ®); @@ -108,6 +123,8 @@ temp_retry: goto temp_retry; } } + pdata->curr_temp = temp_val; + if (temp) *temp = temp_val; 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, }; + +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) { struct thermal_zone_device *tz_dev; @@ -137,12 +171,23 @@ int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata) return -EINVAL; } 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; } EXPORT_SYMBOL(wsa881x_init_thermal); 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) thermal_zone_device_unregister(tz_dev); } diff --git a/asoc/codecs/wsa881x-temp-sensor.h b/asoc/codecs/wsa881x-temp-sensor.h index d6c1eb75e9..26828b716d 100644 --- a/asoc/codecs/wsa881x-temp-sensor.h +++ b/asoc/codecs/wsa881x-temp-sensor.h @@ -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 * 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; char name[80]; 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); diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c index 0755cdcab8..2ef9e0a604 100644 --- a/asoc/codecs/wsa881x.c +++ b/asoc/codecs/wsa881x.c @@ -200,12 +200,40 @@ static int wsa881x_set_mute(struct snd_kcontrol *kcontrol, 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[] = { SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum, wsa_pa_gain_get, wsa_pa_gain_put), SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0, 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)