ASoC: wcd9xxx: Handle ADSP Subsystem Restart

Exercise codec reset as part of ADSP subsystem restart handling
and also update codec and ASoC cache registers to defaults. This
is required to clean up codec state post ADSP restart. Add flag
to avoid codec reset during device bootup.

If the software workaround to prevent leakage on the spkdrv is
enabled, handle the workaround post subsystem restart by turning
on PA and bandgap again.

Change-Id: Ieb7f9892b45bc01f0e2ea38485c4f63298f83999
Signed-off-by: Ravishankar Sarawadi <crsaraw@codeaurora.org>
This commit is contained in:
Ravishankar Sarawadi
2013-01-10 17:01:33 -08:00
parent 887a9bbbb0
commit 839fcf3283
5 changed files with 98 additions and 6 deletions
+29 -3
View File
@@ -1,4 +1,4 @@
/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2011-2013, 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
@@ -334,7 +334,7 @@ static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
{
int ret;
if (wcd9xxx->reset_gpio) {
if (wcd9xxx->reset_gpio && wcd9xxx->slim_device_bootup) {
ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
if (ret) {
pr_err("%s: Failed to request gpio %d\n", __func__,
@@ -342,7 +342,8 @@ static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
wcd9xxx->reset_gpio = 0;
return ret;
}
}
if (wcd9xxx->reset_gpio) {
gpio_direction_output(wcd9xxx->reset_gpio, 0);
msleep(20);
gpio_direction_output(wcd9xxx->reset_gpio, 1);
@@ -1259,6 +1260,7 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
wcd9xxx->reset_gpio = pdata->reset_gpio;
wcd9xxx->dev = &slim->dev;
wcd9xxx->mclk_rate = pdata->mclk_rate;
wcd9xxx->slim_device_bootup = true;
ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret)
@@ -1378,6 +1380,29 @@ static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
return ret;
}
static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
if (wcd9xxx->slim_device_bootup) {
wcd9xxx->slim_device_bootup = false;
return 0;
}
ret = wcd9xxx_reset(wcd9xxx);
if (ret)
pr_err("%s: Resetting Codec failed\n", __func__);
wcd9xxx_bring_up(wcd9xxx);
wcd9xxx->post_reset(wcd9xxx);
return ret;
}
static int wcd9xxx_slim_device_up(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
return wcd9xxx_device_up(wcd9xxx);
}
static int wcd9xxx_slim_resume(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
@@ -1533,6 +1558,7 @@ static struct slim_driver taiko_slim_driver = {
.id_table = taiko_slimtest_id,
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
.device_up = wcd9xxx_slim_device_up,
};
static const struct slim_device_id tapan_slimtest_id[] = {
+5 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2011-2013, 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
@@ -156,6 +156,10 @@ struct wcd9xxx {
int bytes, void *dest, bool interface_reg);
int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg);
int (*post_reset)(struct wcd9xxx *wcd9xxx);
void *ssr_priv;
bool slim_device_bootup;
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
+44 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2012-2013, 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
@@ -4892,12 +4892,53 @@ int taiko_hs_detect(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
struct snd_soc_codec *codec;
struct taiko_priv *taiko;
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
taiko = snd_soc_codec_get_drvdata(codec);
mutex_lock(&codec->mutex);
WCD9XXX_BCL_LOCK(&taiko->resmgr);
if (spkr_drv_wrnd == 1) {
wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
}
WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
if (codec->reg_def_copy) {
pr_debug("%s: Update ASOC cache", __func__);
kfree(codec->reg_cache);
codec->reg_cache = kmemdup(codec->reg_def_copy,
codec->reg_size, GFP_KERNEL);
}
taiko_update_reg_defaults(codec);
taiko_codec_init_reg(codec);
ret = taiko_handle_pdata(taiko);
if (IS_ERR_VALUE(ret))
pr_err("%s: bad pdata\n", __func__);
mutex_unlock(&codec->mutex);
return ret;
}
static struct wcd9xxx_reg_address taiko_reg_address = {
.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
.micb_4_int_rbias = TAIKO_A_MICB_4_INT_RBIAS,
.micb_4_ctl = TAIKO_A_MICB_4_CTL,
};
static int wcd9xxx_ssr_register(struct wcd9xxx *control,
int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
{
control->post_reset = post_reset_cb;
control->ssr_priv = priv;
return 0;
}
static int taiko_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -4912,6 +4953,8 @@ static int taiko_codec_probe(struct snd_soc_codec *codec)
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
wcd9xxx_ssr_register(control, taiko_post_reset_cb, (void *)codec);
dev_info(codec->dev, "%s()\n", __func__);
taiko = kzalloc(sizeof(struct taiko_priv), GFP_KERNEL);
+18
View File
@@ -195,6 +195,24 @@ static void wcd9xxx_disable_clock_block(struct wcd9xxx_resmgr *resmgr)
pr_debug("%s: leave\n", __func__);
}
void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
{
int old_bg_audio_users, old_bg_mbhc_users;
WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
old_bg_audio_users = resmgr->bg_audio_users;
resmgr->bg_audio_users = 0;
old_bg_mbhc_users = resmgr->bg_mbhc_users;
resmgr->bg_mbhc_users = 0;
while (old_bg_audio_users && --old_bg_audio_users)
wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
while (old_bg_mbhc_users && --old_bg_mbhc_users)
wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
}
/*
* wcd9xxx_resmgr_get_bandgap : Vote for bandgap ref
* choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
+2 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2013, 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
@@ -158,6 +158,7 @@ void wcd9xxx_resmgr_cfilt_put(struct wcd9xxx_resmgr *resmgr,
enum wcd9xxx_cfilt_sel cfilt_sel);
void wcd9xxx_resmgr_bcl_lock(struct wcd9xxx_resmgr *resmgr);
void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr);
#define WCD9XXX_BCL_LOCK(resmgr) \
{ \
pr_debug("%s: Acquiring BCL\n", __func__); \