diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c index bc129dad2c8..cc021c01f4d 100644 --- a/drivers/mfd/wcd9xxx-core.c +++ b/drivers/mfd/wcd9xxx-core.c @@ -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[] = { diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index 4b2ad66ce36..1402fd0a600 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -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; diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c index 1546b9e4ee7..ad1546dbff1 100644 --- a/sound/soc/codecs/wcd9320.c +++ b/sound/soc/codecs/wcd9320.c @@ -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); diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c index d744cb92829..0ab650eb044 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr.c +++ b/sound/soc/codecs/wcd9xxx-resmgr.c @@ -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 diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h index 2d04102fc0e..6c30eebeba0 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr.h +++ b/sound/soc/codecs/wcd9xxx-resmgr.h @@ -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__); \