mirror of
https://github.com/LineageOS/android_kernel_samsung_msm8226.git
synced 2026-10-02 00:00:41 +02:00
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:
@@ -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[] = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__); \
|
||||
|
||||
Reference in New Issue
Block a user