From fb0d683b3788f25782949b25bae8a294c12e3b37 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Sat, 22 Sep 2018 01:49:52 +0530 Subject: [PATCH] asoc: bolero: add SSR changes support on bolero codec Add changes for audio SSR and PDR on bolero codec and respective macro drivers. Change-Id: I146de15022cebb788ccb52ed6b8ab85b7cba2ba0 Signed-off-by: Vaishnavi Kommaraju Signed-off-by: Rohit kumar Signed-off-by: Laxminath Kasam --- asoc/codecs/bolero/bolero-cdc.c | 79 ++++++++++++++++++++++++++++++++- asoc/codecs/bolero/bolero-cdc.h | 3 ++ asoc/codecs/bolero/internal.h | 4 ++ asoc/codecs/bolero/rx-macro.c | 13 ++++++ asoc/codecs/bolero/tx-macro.c | 29 ++++++++++++ asoc/codecs/bolero/va-macro.c | 44 ++++++++++++++++-- asoc/codecs/bolero/wsa-macro.c | 28 ++++++++++++ 7 files changed, 195 insertions(+), 5 deletions(-) diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index e9ccee430a56..5001b7f26be3 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -18,7 +18,7 @@ #include #include #include - +#include #include "bolero-cdc.h" #include "internal.h" @@ -62,6 +62,11 @@ static int __bolero_reg_read(struct bolero_priv *priv, u16 current_mclk_mux_macro; mutex_lock(&priv->clk_lock); + if (!priv->dev_up) { + dev_dbg_ratelimited(priv->dev, + "%s: SSR in progress, exit\n", __func__); + goto err; + } current_mclk_mux_macro = priv->current_mclk_mux_macro[macro_id]; if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) { @@ -94,6 +99,11 @@ static int __bolero_reg_write(struct bolero_priv *priv, u16 current_mclk_mux_macro; mutex_lock(&priv->clk_lock); + if (!priv->dev_up) { + dev_dbg_ratelimited(priv->dev, + "%s: SSR in progress, exit\n", __func__); + goto err; + } current_mclk_mux_macro = priv->current_mclk_mux_macro[macro_id]; if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) { @@ -529,10 +539,64 @@ static ssize_t bolero_version_read(struct snd_info_entry *entry, return simple_read_from_buffer(buf, count, &pos, buffer, len); } +static int bolero_ssr_enable(struct device *dev, void *data) +{ + struct bolero_priv *priv = data; + int macro_idx; + + if (priv->initial_boot) { + priv->initial_boot = false; + return 0; + } + + if (priv->macro_params[VA_MACRO].event_handler) + priv->macro_params[VA_MACRO].event_handler(priv->codec, + BOLERO_MACRO_EVT_WAIT_VA_CLK_RESET, 0x0); + + regcache_cache_only(priv->regmap, false); + /* call ssr event for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler(priv->codec, + BOLERO_MACRO_EVT_SSR_UP, 0x0); + } + mutex_lock(&priv->clk_lock); + priv->dev_up = true; + mutex_unlock(&priv->clk_lock); + bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_SSR_UP); + return 0; +} + +static void bolero_ssr_disable(struct device *dev, void *data) +{ + struct bolero_priv *priv = data; + int macro_idx; + + regcache_cache_only(priv->regmap, true); + + mutex_lock(&priv->clk_lock); + priv->dev_up = false; + mutex_unlock(&priv->clk_lock); + /* call ssr event for supported macros */ + for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) { + if (!priv->macro_params[macro_idx].event_handler) + continue; + priv->macro_params[macro_idx].event_handler(priv->codec, + BOLERO_MACRO_EVT_SSR_DOWN, 0x0); + } + bolero_cdc_notifier_call(priv, BOLERO_WCD_EVT_SSR_DOWN); +} + static struct snd_info_entry_ops bolero_info_ops = { .read = bolero_version_read, }; +static const struct snd_event_ops bolero_ssr_ops = { + .enable = bolero_ssr_enable, + .disable = bolero_ssr_disable, +}; + /* * bolero_info_create_codec_entry - creates bolero module * @codec_root: The parent directory @@ -623,6 +687,16 @@ static int bolero_soc_codec_probe(struct snd_soc_codec *codec) else if (priv->num_macros_registered > 2) priv->version = BOLERO_VERSION_1_2; + ret = snd_event_client_register(priv->dev, &bolero_ssr_ops, priv); + if (!ret) { + snd_event_notify(priv->dev, SND_EVENT_UP); + } else { + dev_err(codec->dev, + "%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + goto err; + } + dev_dbg(codec->dev, "%s: bolero soc codec probe success\n", __func__); err: return ret; @@ -633,6 +707,7 @@ static int bolero_soc_codec_remove(struct snd_soc_codec *codec) struct bolero_priv *priv = dev_get_drvdata(codec->dev); int macro_idx; + snd_event_client_deregister(priv->dev); /* call exit for supported macros */ for (macro_idx = START_MACRO; macro_idx < MAX_MACRO; macro_idx++) if (priv->macro_params[macro_idx].exit) @@ -756,6 +831,8 @@ static int bolero_probe(struct platform_device *pdev) bolero_reg_access[VA_MACRO] = bolero_va_top_reg_access; priv->dev = &pdev->dev; + priv->dev_up = true; + priv->initial_boot = true; priv->regmap = bolero_regmap_init(priv->dev, &bolero_regmap_config); if (IS_ERR_OR_NULL((void *)(priv->regmap))) { diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h index 3e8197d58ee2..aa524918e64f 100644 --- a/asoc/codecs/bolero/bolero-cdc.h +++ b/asoc/codecs/bolero/bolero-cdc.h @@ -43,6 +43,9 @@ enum { BOLERO_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */ BOLERO_MACRO_EVT_IMPED_TRUE, /* for imped true */ BOLERO_MACRO_EVT_IMPED_FALSE, /* for imped false */ + BOLERO_MACRO_EVT_SSR_DOWN, + BOLERO_MACRO_EVT_SSR_UP, + BOLERO_MACRO_EVT_WAIT_VA_CLK_RESET }; struct macro_ops { diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h index 9e8a74c5e34f..0129c395f1b9 100644 --- a/asoc/codecs/bolero/internal.h +++ b/asoc/codecs/bolero/internal.h @@ -20,6 +20,8 @@ /* from bolero to WCD events */ enum { BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR = 1, + BOLERO_WCD_EVT_SSR_DOWN, + BOLERO_WCD_EVT_SSR_UP, }; enum { @@ -52,6 +54,8 @@ struct bolero_priv { struct mutex clk_lock; bool va_without_decimation; bool macros_supported[MAX_MACRO]; + bool dev_up; + bool initial_boot; struct macro_ops macro_params[MAX_MACRO]; struct snd_soc_dai_driver *bolero_dais; u16 num_dais; diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index a0e189b5d5df..6c936cbc014c 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -1130,6 +1130,19 @@ static int rx_macro_event_handler(struct snd_soc_codec *codec, u16 event, case BOLERO_MACRO_EVT_IMPED_FALSE: rx_macro_wcd_clsh_imped_config(codec, data, false); break; + case BOLERO_MACRO_EVT_SSR_DOWN: + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_DOWN, NULL); + break; + case BOLERO_MACRO_EVT_SSR_UP: + swrm_wcd_notify( + rx_priv->swr_ctrl_data[0].rx_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; } return 0; } diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 9cfd94d6b6d6..44826de51f54 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "bolero-cdc.h" #include "bolero-cdc-registers.h" #include "../msm-cdc-pinctrl.h" @@ -303,6 +304,33 @@ exit: return ret; } +static int tx_macro_event_handler(struct snd_soc_codec *codec, u16 event, + u32 data) +{ + struct device *tx_dev = NULL; + struct tx_macro_priv *tx_priv = NULL; + + if (!tx_macro_get_data(codec, &tx_dev, &tx_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_SSR_DOWN: + swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_DEVICE_DOWN, NULL); + break; + case BOLERO_MACRO_EVT_SSR_UP: + swrm_wcd_notify( + tx_priv->swr_ctrl_data[0].tx_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + } + return 0; +} + static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) { struct delayed_work *hpf_delayed_work = NULL; @@ -1640,6 +1668,7 @@ static void tx_macro_init_ops(struct macro_ops *ops, ops->dai_ptr = tx_macro_dai; ops->num_dais = ARRAY_SIZE(tx_macro_dai); ops->mclk_fn = tx_macro_mclk_ctrl; + ops->event_handler = tx_macro_event_handler; } static int tx_macro_probe(struct platform_device *pdev) diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index eb069fa0c324..1d28e411fa1a 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -46,6 +46,7 @@ #define VA_MACRO_TX_DMIC_CLK_DIV_SHFT 0x01 #define BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS 40 +#define MAX_RETRY_ATTEMPTS 50 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static int va_tx_unmute_delay = BOLERO_CDC_VA_TX_UNMUTE_DELAY_MS; @@ -178,8 +179,7 @@ static int va_macro_mclk_enable(struct va_macro_priv *va_priv, 0x02, 0x02); } } else { - va_priv->va_mclk_users--; - if (va_priv->va_mclk_users == 0) { + if (va_priv->va_mclk_users == 1) { regmap_update_bits(regmap, BOLERO_CDC_VA_TOP_CSR_TOP_CFG0, 0x02, 0x00); @@ -192,12 +192,47 @@ static int va_macro_mclk_enable(struct va_macro_priv *va_priv, bolero_request_clock(va_priv->dev, VA_MACRO, MCLK_MUX0, false); } + va_priv->va_mclk_users--; } exit: mutex_unlock(&va_priv->mclk_lock); return ret; } +static int va_macro_event_handler(struct snd_soc_codec *codec, u16 event, + u32 data) +{ + struct device *va_dev = NULL; + struct va_macro_priv *va_priv = NULL; + int retry_cnt = MAX_RETRY_ATTEMPTS; + + if (!va_macro_get_data(codec, &va_dev, &va_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_WAIT_VA_CLK_RESET: + while ((va_priv->va_mclk_users != 0) && (retry_cnt != 0)) { + dev_dbg(va_dev, "%s:retry_cnt: %d\n", + __func__, retry_cnt); + /* + * loop and check every 20ms for va_mclk user count + * to get reset to 0 which ensures userspace teardown + * is done and SSR powerup seq can proceed. + */ + msleep(20); + retry_cnt--; + } + if (retry_cnt == 0) + dev_err(va_dev, + "%s: va_mclk_users is non-zero still, audio SSR fail!!\n", + __func__); + break; + default: + break; + } + return 0; +} + static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1054,13 +1089,13 @@ static const struct snd_soc_dapm_widget va_macro_dapm_widgets[] = { SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY_S("VA_MCLK", 0, SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, va_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_widget va_macro_wod_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY_S("VA_MCLK", 0, SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY_S("VA_MCLK", -1, SND_SOC_NOPM, 0, 0, va_macro_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; @@ -1465,6 +1500,7 @@ static void va_macro_init_ops(struct macro_ops *ops, ops->exit = va_macro_deinit; ops->io_base = va_io_base; ops->mclk_fn = va_macro_mclk_ctrl; + ops->event_handler = va_macro_event_handler; } static int va_macro_probe(struct platform_device *pdev) diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index 3fe637e9a3b2..d5271865b2f5 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -859,6 +859,33 @@ exit: return ret; } +static int wsa_macro_event_handler(struct snd_soc_codec *codec, u16 event, + u32 data) +{ + struct device *wsa_dev = NULL; + struct wsa_macro_priv *wsa_priv = NULL; + + if (!wsa_macro_get_data(codec, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + switch (event) { + case BOLERO_MACRO_EVT_SSR_DOWN: + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_SSR_DOWN, NULL); + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_DOWN, NULL); + break; + case BOLERO_MACRO_EVT_SSR_UP: + swrm_wcd_notify( + wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, + SWR_DEVICE_SSR_UP, NULL); + break; + } + return 0; +} + static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -2617,6 +2644,7 @@ static void wsa_macro_init_ops(struct macro_ops *ops, ops->dai_ptr = wsa_macro_dai; ops->num_dais = ARRAY_SIZE(wsa_macro_dai); ops->mclk_fn = wsa_macro_mclk_ctrl; + ops->event_handler = wsa_macro_event_handler; } static int wsa_macro_probe(struct platform_device *pdev)