diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index e9ccee430a..5001b7f26b 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 3e8197d58e..aa524918e6 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 9e8a74c5e3..0129c395f1 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 a0e189b5d5..6c936cbc01 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 9cfd94d6b6..44826de51f 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 eb069fa0c3..1d28e411fa 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 3fe637e9a3..d5271865b2 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) diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h index 0818c05eb6..4ca82726a5 100644 --- a/asoc/codecs/wcd937x/internal.h +++ b/asoc/codecs/wcd937x/internal.h @@ -123,6 +123,8 @@ enum { enum { BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR = 1, + BOLERO_WCD_EVT_SSR_DOWN, + BOLERO_WCD_EVT_SSR_UP, }; enum { diff --git a/asoc/codecs/wcd937x/wcd937x-mbhc.c b/asoc/codecs/wcd937x/wcd937x-mbhc.c index 52bc009d87..c95de4bad7 100644 --- a/asoc/codecs/wcd937x/wcd937x-mbhc.c +++ b/asoc/codecs/wcd937x/wcd937x-mbhc.c @@ -974,6 +974,7 @@ int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc, return -EINVAL; } + wcd937x_mbhc_hs_detect_exit(codec); wcd_mbhc_deinit(wcd_mbhc); ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb, &intr_ids, wcd_mbhc_registers, WCD937X_ZDET_SUPPORTED); diff --git a/asoc/codecs/wcd937x/wcd937x-regmap.c b/asoc/codecs/wcd937x/wcd937x-regmap.c index f445abceed..0d15c105f2 100644 --- a/asoc/codecs/wcd937x/wcd937x-regmap.c +++ b/asoc/codecs/wcd937x/wcd937x-regmap.c @@ -450,8 +450,10 @@ static bool wcd937x_volatile_register(struct device *dev, unsigned int reg) { if(reg <= WCD937X_BASE_ADDRESS) return 0; - return (wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG) - & ~(wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG); + if ((wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG) + && !(wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG)) + return true; + return false; } struct regmap_config wcd937x_regmap_config = { diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index b599b1f327..0bdfda1a52 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -48,6 +48,8 @@ static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); static int wcd937x_handle_post_irq(void *data); +static int wcd937x_reset(struct device *dev); +static int wcd937x_reset_low(struct device *dev); static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = { REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), @@ -1216,6 +1218,23 @@ int wcd937x_micbias_control(struct snd_soc_codec *codec, } EXPORT_SYMBOL(wcd937x_micbias_control); +static int wcd937x_get_logical_addr(struct swr_device *swr_dev) +{ + int ret = 0; + uint8_t devnum = 0; + + ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum); + if (ret) { + dev_err(&swr_dev->dev, + "%s get devnum %d for dev addr %lx failed\n", + __func__, devnum, swr_dev->addr); + swr_remove_device(swr_dev); + return ret; + } + swr_dev->dev_num = devnum; + return 0; +} + static int wcd937x_event_notify(struct notifier_block *block, unsigned long val, void *data) @@ -1223,8 +1242,10 @@ static int wcd937x_event_notify(struct notifier_block *block, u16 event = (val & 0xffff); u16 amic = (val >> 0x10); u16 mask = 0x40, reg = 0x0; + int ret = 0; struct wcd937x_priv *wcd937x = dev_get_drvdata((struct device *)data); struct snd_soc_codec *codec = wcd937x->codec; + struct wcd_mbhc *mbhc; switch (event) { case BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR: @@ -1238,6 +1259,25 @@ static int wcd937x_event_notify(struct notifier_block *block, mask = 0x20; snd_soc_update_bits(codec, reg, mask, 0x00); break; + case BOLERO_WCD_EVT_SSR_DOWN: + wcd937x_reset_low(wcd937x->dev); + break; + case BOLERO_WCD_EVT_SSR_UP: + wcd937x_reset(wcd937x->dev); + wcd937x_get_logical_addr(wcd937x->tx_swr_dev); + wcd937x_get_logical_addr(wcd937x->rx_swr_dev); + regcache_mark_dirty(wcd937x->regmap); + regcache_sync(wcd937x->regmap); + /* Initialize MBHC module */ + mbhc = &wcd937x->mbhc->wcd_mbhc; + ret = wcd937x_mbhc_post_ssr_init(wcd937x->mbhc, codec); + if (ret) { + dev_err(codec->dev, "%s: mbhc initialization failed\n", + __func__); + } else { + wcd937x_mbhc_hs_detect(codec, mbhc->mbhc_cfg); + } + break; default: dev_err(codec->dev, "%s: invalid event %d\n", __func__, event); break; @@ -1923,7 +1963,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wcd937x = { }, }; -int wcd937x_reset(struct device *dev) +static int wcd937x_reset(struct device *dev) { struct wcd937x_priv *wcd937x = NULL; int rc = 0; @@ -2026,6 +2066,36 @@ static void wcd937x_dt_parse_micbias_info(struct device *dev, } } +static int wcd937x_reset_low(struct device *dev) +{ + struct wcd937x_priv *wcd937x = NULL; + int rc = 0; + + if (!dev) + return -ENODEV; + + wcd937x = dev_get_drvdata(dev); + if (!wcd937x) + return -EINVAL; + + if (!wcd937x->rst_np) { + dev_err(dev, "%s: reset gpio device node not specified\n", + __func__); + return -EINVAL; + } + + rc = msm_cdc_pinctrl_select_sleep_state(wcd937x->rst_np); + if (rc) { + dev_err(dev, "%s: wcd sleep state request fail!\n", + __func__); + return rc; + } + /* 20ms sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + + return rc; +} + struct wcd937x_pdata *wcd937x_populate_dt_data(struct device *dev) { struct wcd937x_pdata *pdata = NULL; diff --git a/asoc/codecs/wcd937x/wcd937x_slave.c b/asoc/codecs/wcd937x/wcd937x_slave.c index 36c2af1e71..252504fe0f 100644 --- a/asoc/codecs/wcd937x/wcd937x_slave.c +++ b/asoc/codecs/wcd937x/wcd937x_slave.c @@ -85,6 +85,21 @@ static const struct component_ops wcd937x_slave_comp_ops = { .unbind = wcd937x_slave_unbind, }; +static int wcd937x_swr_up(struct swr_device *pdev) +{ + return 0; +} + +static int wcd937x_swr_down(struct swr_device *pdev) +{ + return 0; +} + +static int wcd937x_swr_reset(struct swr_device *pdev) +{ + return 0; +} + static int wcd937x_swr_probe(struct swr_device *pdev) { return component_add(&pdev->dev, &wcd937x_slave_comp_ops); @@ -105,6 +120,9 @@ static struct swr_driver wcd937x_slave_driver = { .probe = wcd937x_swr_probe, .remove = wcd937x_swr_remove, .id_table = wcd937x_swr_id, + .device_up = wcd937x_swr_up, + .device_down = wcd937x_swr_down, + .reset_device = wcd937x_swr_reset, }; static int __init wcd937x_slave_init(void) diff --git a/asoc/sm6150.c b/asoc/sm6150.c index f62c39ec0f..4aac78e0ba 100644 --- a/asoc/sm6150.c +++ b/asoc/sm6150.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include "device_event.h" @@ -201,6 +201,7 @@ struct msm_asoc_mach_data { struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */ + bool is_afe_config_done; }; struct msm_asoc_wcd93xx_codec { @@ -628,10 +629,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_3_sample_rate, static SOC_ENUM_SINGLE_EXT_DECL(tx_cdc_dma_tx_4_sample_rate, cdc_dma_sample_rate_text); -static struct platform_device *spdev; - static int msm_hifi_control; -static bool is_initial_boot; static bool codec_reg_done; static struct snd_soc_aux_dev *msm_aux_dev; static struct snd_soc_codec_conf *msm_codec_conf; @@ -4643,121 +4641,6 @@ static void msm_afe_clear_config(void) afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG); } -static int msm_adsp_power_up_config(struct snd_soc_codec *codec, - struct snd_card *card) -{ - int ret = 0; - unsigned long timeout; - int adsp_ready = 0; - bool snd_card_online = 0; - - timeout = jiffies + - msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); - - do { - if (!snd_card_online) { - snd_card_online = snd_card_is_online_state(card); - pr_debug("%s: Sound card is %s\n", __func__, - snd_card_online ? "Online" : "Offline"); - } - if (!adsp_ready) { - adsp_ready = q6core_is_adsp_ready(); - pr_debug("%s: ADSP Audio is %s\n", __func__, - adsp_ready ? "ready" : "not ready"); - } - if (snd_card_online && adsp_ready) - break; - - /* - * Sound card/ADSP will be coming up after subsystem restart and - * it might not be fully up when the control reaches - * here. So, wait for 50msec before checking ADSP state - */ - msleep(50); - } while (time_after(timeout, jiffies)); - - if (!snd_card_online || !adsp_ready) { - pr_err("%s: Timeout. Sound card is %s, ADSP Audio is %s\n", - __func__, - snd_card_online ? "Online" : "Offline", - adsp_ready ? "ready" : "not ready"); - ret = -ETIMEDOUT; - goto err; - } - - ret = msm_afe_set_config(codec); - if (ret) - pr_err("%s: Failed to set AFE config. err %d\n", - __func__, ret); - - return 0; - -err: - return ret; -} - -static int sm6150_notifier_service_cb(struct notifier_block *this, - unsigned long opcode, void *ptr) -{ - int ret; - struct snd_soc_card *card = NULL; - const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX; - struct snd_soc_pcm_runtime *rtd; - struct snd_soc_codec *codec; - - pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode); - - switch (opcode) { - case AUDIO_NOTIFIER_SERVICE_DOWN: - /* - * Use flag to ignore initial boot notifications - * On initial boot msm_adsp_power_up_config is - * called on init. There is no need to clear - * and set the config again on initial boot. - */ - if (is_initial_boot) - break; - msm_afe_clear_config(); - break; - case AUDIO_NOTIFIER_SERVICE_UP: - if (is_initial_boot) { - is_initial_boot = false; - break; - } - if (!spdev) - return -EINVAL; - - card = platform_get_drvdata(spdev); - rtd = snd_soc_get_pcm_runtime(card, be_dl_name); - if (!rtd) { - dev_err(card->dev, - "%s: snd_soc_get_pcm_runtime for %s failed!\n", - __func__, be_dl_name); - ret = -EINVAL; - goto err; - } - codec = rtd->codec; - - ret = msm_adsp_power_up_config(codec, card->snd_card); - if (ret < 0) { - dev_err(card->dev, - "%s: msm_adsp_power_up_config failed ret = %d!\n", - __func__, ret); - goto err; - } - break; - default: - break; - } -err: - return NOTIFY_OK; -} - -static struct notifier_block service_nb = { - .notifier_call = sm6150_notifier_service_cb, - .priority = -INT_MAX, -}; - static int msm_audrx_tavil_init(struct snd_soc_pcm_runtime *rtd) { int ret = 0; @@ -4845,11 +4728,12 @@ static int msm_audrx_tavil_init(struct snd_soc_pcm_runtime *rtd) msm_codec_fn.get_afe_config_fn = tavil_get_afe_config; - ret = msm_adsp_power_up_config(codec, rtd->card->snd_card); + ret = msm_afe_set_config(codec); if (ret) { pr_err("%s: Failed to set AFE config %d\n", __func__, ret); goto err; } + pdata->is_afe_config_done = true; config_data = msm_codec_fn.get_afe_config_fn(codec, AFE_AANC_VERSION); @@ -8357,6 +8241,108 @@ static void msm_i2s_auxpcm_deinit(void) mi2s_intf_conf[count].msm_is_mi2s_master = 0; } } + +static int sm6150_ssr_enable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata; + int ret = 0; + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + if (!strcmp(card->name, "sm6150-tavil-snd-card")) { + pdata = snd_soc_card_get_drvdata(card); + if (!pdata->is_afe_config_done) { + const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX; + struct snd_soc_pcm_runtime *rtd; + + rtd = snd_soc_get_pcm_runtime(card, be_dl_name); + if (!rtd) { + dev_err(dev, + "%s: snd_soc_get_pcm_runtime for %s failed!\n", + __func__, be_dl_name); + ret = -EINVAL; + goto err; + } + ret = msm_afe_set_config(rtd->codec); + if (ret) + dev_err(dev, "%s: Failed to set AFE config. err %d\n", + __func__, ret); + else + pdata->is_afe_config_done = true; + } + } + snd_soc_card_change_online_state(card, 1); + dev_dbg(dev, "%s: setting snd_card to ONLINE\n", __func__); + +err: + return ret; +} + +static void sm6150_ssr_disable(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata; + + if (!card) { + dev_err(dev, "%s: card is NULL\n", __func__); + return; + } + + dev_dbg(dev, "%s: setting snd_card to OFFLINE\n", __func__); + snd_soc_card_change_online_state(card, 0); + + if (!strcmp(card->name, "sm6150-tavil-snd-card")) { + pdata = snd_soc_card_get_drvdata(card); + msm_afe_clear_config(); + pdata->is_afe_config_done = false; + } +} + +static const struct snd_event_ops sm6150_ssr_ops = { + .enable = sm6150_ssr_enable, + .disable = sm6150_ssr_disable, +}; + +static int msm_audio_ssr_compare(struct device *dev, void *data) +{ + struct device_node *node = data; + + dev_dbg(dev, "%s: dev->of_node = 0x%p, node = 0x%p\n", + __func__, dev->of_node, node); + return (dev->of_node && dev->of_node == node); +} + +static int msm_audio_ssr_register(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct snd_event_clients *ssr_clients = NULL; + struct device_node *node; + int ret; + int i; + + for (i = 0; ; i++) { + node = of_parse_phandle(np, "qcom,msm_audio_ssr_devs", i); + if (!node) + break; + snd_event_mstr_add_client(&ssr_clients, + msm_audio_ssr_compare, node); + } + + ret = snd_event_master_register(dev, &sm6150_ssr_ops, + ssr_clients, NULL); + if (!ret) + snd_event_notify(dev, SND_EVENT_UP); + + return ret; +} + static int msm_asoc_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card; @@ -8419,7 +8405,6 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) goto err; } dev_info(&pdev->dev, "Sound card %s registered\n", card->name); - spdev = pdev; pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node, "qcom,hph-en1-gpio", 0); @@ -8486,15 +8471,7 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) } msm_i2s_auxpcm_init(pdev); - if (!strcmp(card->name, "sm6150-tavil-snd-card")) { - is_initial_boot = true; - ret = audio_notifier_register("sm6150", - AUDIO_NOTIFIER_ADSP_DOMAIN, - &service_nb); - if (ret < 0) - pr_err("%s: Audio notifier register failed ret = %d\n", - __func__, ret); - } else { + if (strcmp(card->name, "sm6150-tavil-snd-card")) { pdata->dmic01_gpio_p = of_parse_phandle(pdev->dev.of_node, "qcom,cdc-dmic01-gpios", 0); @@ -8502,13 +8479,19 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) "qcom,cdc-dmic23-gpios", 0); } + + ret = msm_audio_ssr_register(&pdev->dev); + if (ret) + pr_err("%s: Registration with SND event FWK failed ret = %d\n", + __func__, ret); + err: return ret; } static int msm_asoc_machine_remove(struct platform_device *pdev) { - audio_notifier_deregister("sm6150"); + snd_event_master_deregister(&pdev->dev); msm_i2s_auxpcm_deinit(); return 0; diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c index f5ba3d64ad..21d51fb0ee 100644 --- a/soc/pinctrl-lpi.c +++ b/soc/pinctrl-lpi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "core.h" @@ -59,6 +60,7 @@ #define LPI_GPIO_FUNC_FUNC5 "func5" static bool lpi_dev_up; +static struct device *lpi_dev; /* The index of each function in lpi_gpio_functions[] array */ enum lpi_gpio_func_index { @@ -384,12 +386,14 @@ static int lpi_notifier_service_cb(struct notifier_block *this, initial_boot = false; break; } + snd_event_notify(lpi_dev, SND_EVENT_DOWN); lpi_dev_up = false; break; case AUDIO_NOTIFIER_SERVICE_UP: if (initial_boot) initial_boot = false; lpi_dev_up = true; + snd_event_notify(lpi_dev, SND_EVENT_UP); break; default: break; @@ -402,6 +406,15 @@ static struct notifier_block service_nb = { .priority = -INT_MAX, }; +static void lpi_pinctrl_ssr_disable(struct device *dev, void *data) +{ + lpi_dev_up = false; +} + +static const struct snd_event_ops lpi_pinctrl_ssr_ops = { + .disable = lpi_pinctrl_ssr_disable, +}; + #ifdef CONFIG_DEBUG_FS #include @@ -576,6 +589,7 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) goto err_range; } + lpi_dev = &pdev->dev; lpi_dev_up = true; ret = audio_notifier_register("lpi_tlmm", AUDIO_NOTIFIER_ADSP_DOMAIN, &service_nb); @@ -585,8 +599,19 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) goto err_range; } + ret = snd_event_client_register(dev, &lpi_pinctrl_ssr_ops, NULL); + if (!ret) { + snd_event_notify(dev, SND_EVENT_UP); + } else { + dev_err(dev, "%s: snd_event registration failed, ret [%d]\n", + __func__, ret); + goto err_snd_evt; + } + return 0; +err_snd_evt: + audio_notifier_deregister("lpi_tlmm"); err_range: gpiochip_remove(&state->chip); err_chip: @@ -597,6 +622,7 @@ static int lpi_pinctrl_remove(struct platform_device *pdev) { struct lpi_gpio_state *state = platform_get_drvdata(pdev); + snd_event_client_deregister(&pdev->dev); audio_notifier_deregister("lpi_tlmm"); gpiochip_remove(&state->chip); return 0;