diff --git a/asoc/bengal-port-config.h b/asoc/bengal-port-config.h index a20a6d5448..37d4f740aa 100644 --- a/asoc/bengal-port-config.h +++ b/asoc/bengal-port-config.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _BENGAL_PORT_CONFIG @@ -21,6 +21,15 @@ static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = { {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0}, }; +static struct port_params rx_frame_params_rouleur[SWR_MSTR_PORT_LEN] = { + {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, + {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, + {31, 1, 0, 0xFF, 0xFF, 4, 1, 0xFF, 0}, + {7, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, + {0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0}, +}; + + static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = { {3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1}, {31, 0, 0, 3, 6, 7, 0, 0xFF, 0}, @@ -42,4 +51,9 @@ static struct swr_mstr_port_map sm_port_map[] = { {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, }; +static struct swr_mstr_port_map sm_port_map_rouleur[] = { + {VA_MACRO, SWR_UC0, tx_frame_params_default}, + {RX_MACRO, SWR_UC0, rx_frame_params_rouleur}, + {RX_MACRO, SWR_UC1, rx_frame_params_dsd}, +}; #endif /* _BENGAL_PORT_CONFIG */ diff --git a/asoc/bengal.c b/asoc/bengal.c index 22677cb258..74a831fd3e 100644 --- a/asoc/bengal.c +++ b/asoc/bengal.c @@ -59,10 +59,12 @@ #define WCD9XXX_MBHC_DEF_RLOADS 5 #define WCD9XXX_MBHC_DEF_BUTTONS 8 +#define ROULEUR_MBHC_DEF_BUTTONS 5 #define CODEC_EXT_CLK_RATE 9600000 #define ADSP_STATE_READY_TIMEOUT_MS 3000 #define DEV_NAME_STR_LEN 32 #define WCD_MBHC_HS_V_MAX 1600 +#define ROULEUR_MBHC_HS_V_MAX 1700 #define TDM_CHANNEL_MAX 8 #define DEV_NAME_STR_LEN 32 @@ -555,6 +557,7 @@ static int dmic_0_1_gpio_cnt; static int dmic_2_3_gpio_cnt; static void *def_wcd_mbhc_cal(void); +static void *def_rouleur_mbhc_cal(void); /* * Need to report LINEIN @@ -4259,6 +4262,9 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dapm_context *dapm; struct snd_card *card; struct snd_info_entry *entry; + struct platform_device *pdev = NULL; + int i = 0; + char *data = NULL; struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -4305,8 +4311,38 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_sync(dapm); - bolero_set_port_map(component, ARRAY_SIZE(sm_port_map), - sm_port_map); + for (i = 0; i < rtd->card->num_aux_devs; i++) + { + if (msm_aux_dev[i].name != NULL ) { + if (strstr(msm_aux_dev[i].name, "wsa")) + continue; + } + + if (msm_aux_dev[i].codec_of_node) { + pdev = of_find_device_by_node( + msm_aux_dev[i].codec_of_node); + + if (pdev) + data = (char*) of_device_get_match_data( + &pdev->dev); + if (data != NULL) { + if (!strncmp(data, "wcd937x", + sizeof("wcd937x"))) { + bolero_set_port_map(component, + ARRAY_SIZE(sm_port_map), + sm_port_map); + break; + } else if (!strncmp( data, "rouleur", + sizeof("rouleur"))) { + bolero_set_port_map(component, + ARRAY_SIZE(sm_port_map_rouleur), + sm_port_map_rouleur); + break; + } + } + } + } + card = rtd->card->snd_card; if (!pdata->codec_root) { entry = snd_info_create_subdir(card->module, "codecs", @@ -4356,6 +4392,34 @@ static void *def_wcd_mbhc_cal(void) return wcd_mbhc_cal; } +static void *def_rouleur_mbhc_cal(void) +{ + void *wcd_mbhc_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_high; + + wcd_mbhc_cal = kzalloc(WCD_MBHC_CAL_SIZE(ROULEUR_MBHC_DEF_BUTTONS, + WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!wcd_mbhc_cal) + return NULL; + + WCD_MBHC_CAL_PLUG_TYPE_PTR(wcd_mbhc_cal)->v_hs_max = + ROULEUR_MBHC_HS_V_MAX; + WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal)->num_btn = + ROULEUR_MBHC_DEF_BUTTONS; + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(wcd_mbhc_cal); + btn_high = ((void *)&btn_cfg->_v_btn_low) + + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); + + btn_high[0] = 75; + btn_high[1] = 150; + btn_high[2] = 237; + btn_high[3] = 500; + btn_high[4] = 500; + + return wcd_mbhc_cal; +} + /* Digital audio interface glue - connects codec <---> CPU */ static struct snd_soc_dai_link msm_common_dai_links[] = { /* FrontEnd DAI Links */ @@ -4985,6 +5049,22 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, .ops = &msm_cdc_dma_be_ops, }, + {/* hw:x,39 */ + .name = MSM_DAILINK_NAME(Compress3), + .stream_name = "Compress3", + .cpu_dai_name = "MultiMedia10", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA10, + }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { @@ -5075,6 +5155,33 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = { .ignore_suspend = 1, .ignore_pmdown_time = 1, }, + /* Proxy Tx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_TX, + .stream_name = "Proxy Capture", + .cpu_dai_name = "msm-dai-q6-dev.8195", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PROXY_TX, + .ignore_suspend = 1, + }, + /* Proxy Rx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_RX, + .stream_name = "Proxy Playback", + .cpu_dai_name = "msm-dai-q6-dev.8194", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PROXY_RX, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, { .name = LPASS_BE_USB_AUDIO_RX, .stream_name = "USB Audio Playback", @@ -6115,16 +6222,21 @@ static int msm_aux_codec_init(struct snd_soc_component *component) } mbhc_cfg_cal: - mbhc_calibration = def_wcd_mbhc_cal(); - if (!mbhc_calibration) - return -ENOMEM; - wcd_mbhc_cfg.calibration = mbhc_calibration; if (data != NULL) { - if (!strncmp(data, "wcd937x", sizeof("wcd937x"))) - ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg); - else if (!strncmp( data, "rouleur", sizeof("rouleur"))) - ret = rouleur_mbhc_hs_detect(component, &wcd_mbhc_cfg); - } + if (!strncmp(data, "wcd937x", sizeof("wcd937x"))) { + mbhc_calibration = def_wcd_mbhc_cal(); + if (!mbhc_calibration) + return -ENOMEM; + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg); + } else if (!strncmp( data, "rouleur", sizeof("rouleur"))) { + mbhc_calibration = def_rouleur_mbhc_cal(); + if (!mbhc_calibration) + return -ENOMEM; + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = rouleur_mbhc_hs_detect(component, &wcd_mbhc_cfg); + } + } if (ret) { dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n", @@ -6714,10 +6826,16 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) } buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); - if (IS_ERR_OR_NULL(buf) || len <= 0 || len > sizeof(32)) { + if (IS_ERR_OR_NULL(buf)) { dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__); goto ret; } + if (len <= 0 || len > sizeof(u32)) { + dev_dbg(&pdev->dev, "%s: nvmem cell length out of range: %d\n", + __func__, len); + kfree(buf); + goto ret; + } memcpy(&adsp_var_idx, buf, len); kfree(buf); va_disable = adsp_var_idx; diff --git a/asoc/codecs/bolero/bolero-cdc.c b/asoc/codecs/bolero/bolero-cdc.c index 8546aca4de..e7fd7a287e 100644 --- a/asoc/codecs/bolero/bolero-cdc.c +++ b/asoc/codecs/bolero/bolero-cdc.c @@ -600,6 +600,28 @@ int bolero_dmic_clk_enable(struct snd_soc_component *component, } EXPORT_SYMBOL(bolero_dmic_clk_enable); +bool bolero_is_va_macro_registered(struct device *dev) +{ + struct bolero_priv *priv; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return false; + } + if (!bolero_is_valid_child_dev(dev)) { + dev_err(dev, "%s: child device calling is not added yet\n", + __func__); + return false; + } + priv = dev_get_drvdata(dev->parent); + if (!priv) { + dev_err(dev, "%s: priv is null\n", __func__); + return false; + } + return priv->macros_supported[VA_MACRO]; +} +EXPORT_SYMBOL(bolero_is_va_macro_registered); + /** * bolero_register_macro - Registers macro to bolero * @@ -644,7 +666,6 @@ int bolero_register_macro(struct device *dev, u16 macro_id, bolero_mclk_mux_tbl[macro_id][MCLK_MUX0]; if (macro_id == TX_MACRO) { priv->macro_params[macro_id].reg_wake_irq = ops->reg_wake_irq; - priv->macro_params[macro_id].clk_switch = ops->clk_switch; priv->macro_params[macro_id].reg_evt_listener = ops->reg_evt_listener; priv->macro_params[macro_id].clk_enable = ops->clk_enable; @@ -661,7 +682,7 @@ int bolero_register_macro(struct device *dev, u16 macro_id, priv->num_macros_registered++; priv->macros_supported[macro_id] = true; - dev_dbg(dev, "%s: register macro successful:%d\n", macro_id); + dev_info(dev, "%s: register macro successful:%d\n", __func__, macro_id); if (priv->num_macros_registered == priv->num_macros) { ret = bolero_copy_dais_from_macro(priv); @@ -719,7 +740,6 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id) priv->macro_params[macro_id].dev = NULL; if (macro_id == TX_MACRO) { priv->macro_params[macro_id].reg_wake_irq = NULL; - priv->macro_params[macro_id].clk_switch = NULL; priv->macro_params[macro_id].reg_evt_listener = NULL; priv->macro_params[macro_id].clk_enable = NULL; } @@ -836,6 +856,18 @@ static int bolero_ssr_enable(struct device *dev, void *data) BOLERO_MACRO_EVT_CLK_RESET, 0x0); } trace_printk("%s: clk count reset\n", __func__); + + if (priv->rsc_clk_cb) + priv->rsc_clk_cb(priv->clk_dev, BOLERO_MACRO_EVT_SSR_GFMUX_UP); + + 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->component, + BOLERO_MACRO_EVT_PRE_SSR_UP, 0x0); + } + regcache_cache_only(priv->regmap, false); mutex_lock(&priv->clk_lock); priv->dev_up = true; @@ -1004,40 +1036,6 @@ int bolero_register_wake_irq(struct snd_soc_component *component, } EXPORT_SYMBOL(bolero_register_wake_irq); -/** - * bolero_tx_clk_switch - Switch tx macro clock - * - * @component: pointer to codec component instance. - * - * @clk_src: 0 for TX_RCG and 1 for VA_RCG - * - * Returns 0 on success or -EINVAL on error. - */ -int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src) -{ - struct bolero_priv *priv = NULL; - int ret = 0; - - if (!component) - return -EINVAL; - - priv = snd_soc_component_get_drvdata(component); - if (!priv) - return -EINVAL; - - if (!bolero_is_valid_codec_dev(priv->dev)) { - dev_err(component->dev, "%s: invalid codec\n", __func__); - return -EINVAL; - } - - if (priv->macro_params[TX_MACRO].clk_switch) - ret = priv->macro_params[TX_MACRO].clk_switch(component, - clk_src); - - return ret; -} -EXPORT_SYMBOL(bolero_tx_clk_switch); - /** * bolero_tx_mclk_enable - Enable/Disable TX Macro mclk * diff --git a/asoc/codecs/bolero/bolero-cdc.h b/asoc/codecs/bolero/bolero-cdc.h index ca4324ac4a..eee4c0c2a7 100644 --- a/asoc/codecs/bolero/bolero-cdc.h +++ b/asoc/codecs/bolero/bolero-cdc.h @@ -37,11 +37,6 @@ enum { BOLERO_ADC_MAX }; -enum { - CLK_SRC_TX_RCG = 0, - CLK_SRC_VA_RCG, -}; - enum { BOLERO_MACRO_EVT_RX_MUTE = 1, /* for RX mute/unmute */ BOLERO_MACRO_EVT_IMPED_TRUE, /* for imped true */ @@ -52,7 +47,9 @@ enum { BOLERO_MACRO_EVT_CLK_RESET, BOLERO_MACRO_EVT_REG_WAKE_IRQ, BOLERO_MACRO_EVT_RX_COMPANDER_SOFT_RST, - BOLERO_MACRO_EVT_BCS_CLK_OFF + BOLERO_MACRO_EVT_BCS_CLK_OFF, + BOLERO_MACRO_EVT_SSR_GFMUX_UP, + BOLERO_MACRO_EVT_PRE_SSR_UP, }; enum { @@ -74,7 +71,6 @@ struct macro_ops { int (*set_port_map)(struct snd_soc_component *component, u32 uc, u32 size, void *data); int (*clk_div_get)(struct snd_soc_component *component); - int (*clk_switch)(struct snd_soc_component *component, int clk_src); int (*reg_evt_listener)(struct snd_soc_component *component, bool en); int (*clk_enable)(struct snd_soc_component *c, bool en); char __iomem *io_base; @@ -87,6 +83,7 @@ typedef int (*rsc_clk_cb_t)(struct device *dev, u16 event); #if IS_ENABLED(CONFIG_SND_SOC_BOLERO) int bolero_register_res_clk(struct device *dev, rsc_clk_cb_t cb); void bolero_unregister_res_clk(struct device *dev); +bool bolero_is_va_macro_registered(struct device *dev); int bolero_register_macro(struct device *dev, u16 macro_id, struct macro_ops *ops); void bolero_unregister_macro(struct device *dev, u16 macro_id); @@ -100,7 +97,6 @@ void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n); int bolero_runtime_resume(struct device *dev); int bolero_runtime_suspend(struct device *dev); int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data); -int bolero_tx_clk_switch(struct snd_soc_component *component, int clk_src); int bolero_register_event_listener(struct snd_soc_component *component, bool enable); void bolero_wsa_pa_on(struct device *dev); @@ -118,6 +114,11 @@ static inline void bolero_unregister_res_clk(struct device *dev) { } +static bool bolero_is_va_macro_registered(struct device *dev) +{ + return false; +} + static inline int bolero_register_macro(struct device *dev, u16 macro_id, struct macro_ops *ops) @@ -168,12 +169,6 @@ static inline int bolero_set_port_map(struct snd_soc_component *component, return 0; } -static inline int bolero_tx_clk_switch(struct snd_soc_component *component, - int clk_src) -{ - return 0; -} - static inline int bolero_register_event_listener( struct snd_soc_component *component, bool enable) diff --git a/asoc/codecs/bolero/bolero-clk-rsc.c b/asoc/codecs/bolero/bolero-clk-rsc.c index 7e28c5bfeb..b134819e0c 100644 --- a/asoc/codecs/bolero/bolero-clk-rsc.c +++ b/asoc/codecs/bolero/bolero-clk-rsc.c @@ -38,6 +38,7 @@ struct bolero_clk_rsc { int reg_seq_en_cnt; int va_tx_clk_cnt; bool dev_up; + bool dev_up_gfmux; u32 num_fs_reg; u32 *fs_gen_seq; int default_clk_id[MAX_CLK]; @@ -65,10 +66,14 @@ static int bolero_clk_rsc_cb(struct device *dev, u16 event) } mutex_lock(&priv->rsc_clk_lock); - if (event == BOLERO_MACRO_EVT_SSR_UP) + if (event == BOLERO_MACRO_EVT_SSR_UP) { priv->dev_up = true; - else if (event == BOLERO_MACRO_EVT_SSR_DOWN) + } else if (event == BOLERO_MACRO_EVT_SSR_DOWN) { priv->dev_up = false; + priv->dev_up_gfmux = false; + } else if (event == BOLERO_MACRO_EVT_SSR_GFMUX_UP) { + priv->dev_up_gfmux = true; + } mutex_unlock(&priv->rsc_clk_lock); return 0; @@ -282,10 +287,12 @@ static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv, * care in DSP itself */ if (clk_id != VA_CORE_CLK) { - iowrite32(0x1, clk_muxsel); - muxsel = ioread32(clk_muxsel); - trace_printk("%s: muxsel value after enable: %d\n", - __func__, muxsel); + if (priv->dev_up_gfmux) { + iowrite32(0x1, clk_muxsel); + muxsel = ioread32(clk_muxsel); + trace_printk("%s: muxsel value after enable: %d\n", + __func__, muxsel); + } bolero_clk_rsc_mux0_clk_request(priv, default_clk_id, false); @@ -313,10 +320,12 @@ static int bolero_clk_rsc_mux1_clk_request(struct bolero_clk_rsc *priv, * This configuration would be taken * care in DSP itself. */ - iowrite32(0x0, clk_muxsel); - muxsel = ioread32(clk_muxsel); - trace_printk("%s: muxsel value after disable: %d\n", - __func__, muxsel); + if (priv->dev_up_gfmux) { + iowrite32(0x0, clk_muxsel); + muxsel = ioread32(clk_muxsel); + trace_printk("%s: muxsel value after disable: %d\n", + __func__, muxsel); + } } } if (priv->clk[clk_id + NPL_CLK_OFFSET]) @@ -706,6 +715,7 @@ static int bolero_clk_rsc_probe(struct platform_device *pdev) } priv->dev = &pdev->dev; priv->dev_up = true; + priv->dev_up_gfmux = true; mutex_init(&priv->rsc_clk_lock); mutex_init(&priv->fs_gen_lock); dev_set_drvdata(&pdev->dev, priv); diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index 62da031f26..e5fcc856f9 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -387,6 +387,7 @@ enum { RX_MACRO_AIF3_PB, RX_MACRO_AIF4_PB, RX_MACRO_AIF_ECHO, + RX_MACRO_AIF5_PB, RX_MACRO_AIF6_PB, RX_MACRO_MAX_DAIS, }; @@ -719,6 +720,20 @@ static struct snd_soc_dai_driver rx_macro_dai[] = { }, .ops = &rx_macro_dai_ops, }, + { + .name = "rx_macro_rx5", + .id = RX_MACRO_AIF5_PB, + .playback = { + .stream_name = "RX_MACRO_AIF5 Playback", + .rates = RX_MACRO_RATES | RX_MACRO_FRAC_RATES, + .formats = RX_MACRO_FORMATS, + .rate_max = 384000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &rx_macro_dai_ops, + }, { .name = "rx_macro_rx6", .id = RX_MACRO_AIF6_PB, @@ -1138,6 +1153,13 @@ static int rx_macro_get_channel_map(struct snd_soc_dai *dai, "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d active_mask: 0x%x\n", __func__, dai->id, *rx_slot, *rx_num, rx_priv->active_ch_mask[dai->id]); break; + case RX_MACRO_AIF5_PB: + *rx_slot = 0x1; + *rx_num = 0x01; + dev_dbg(rx_priv->dev, + "%s: dai->id:%d, ch_mask:0x%x, active_ch_cnt:%d\n", + __func__, dai->id, *rx_slot, *rx_num); + break; case RX_MACRO_AIF6_PB: *rx_slot = 0x1; *rx_num = 0x01; @@ -1410,11 +1432,7 @@ static int rx_macro_event_handler(struct snd_soc_component *component, } } break; - case BOLERO_MACRO_EVT_SSR_UP: - trace_printk("%s, enter SSR up\n", __func__); - rx_priv->dev_up = true; - /* reset swr after ssr/pdr */ - rx_priv->reset_swr = true; + case BOLERO_MACRO_EVT_PRE_SSR_UP: /* enable&disable RX_CORE_CLK to reset GFMUX reg */ ret = bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, @@ -1427,6 +1445,12 @@ static int rx_macro_event_handler(struct snd_soc_component *component, bolero_clk_rsc_request_clock(rx_priv->dev, rx_priv->default_clk_id, RX_CORE_CLK, false); + break; + case BOLERO_MACRO_EVT_SSR_UP: + trace_printk("%s, enter SSR up\n", __func__); + rx_priv->dev_up = true; + /* reset swr after ssr/pdr */ + rx_priv->reset_swr = true; if (rx_priv->swr_ctrl_data) swrm_wcd_notify( @@ -1709,13 +1733,6 @@ static int rx_macro_config_compander(struct snd_soc_component *component, dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", __func__, event, comp + 1, rx_priv->comp_enabled[comp]); - if (!rx_priv->comp_enabled[comp]) - return 0; - - comp_ctl0_reg = BOLERO_CDC_RX_COMPANDER0_CTL0 + - (comp * RX_MACRO_COMP_OFFSET); - rx_path_cfg0_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0 + - (comp * RX_MACRO_RX_PATH_OFFSET); rx_path_cfg3_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG3 + (comp * RX_MACRO_RX_PATH_OFFSET); rx0_path_ctl_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + @@ -1731,6 +1748,19 @@ static int rx_macro_config_compander(struct snd_soc_component *component, else val = 0x00; + if (SND_SOC_DAPM_EVENT_ON(event)) + snd_soc_component_update_bits(component, rx_path_cfg3_reg, + 0x03, val); + if (SND_SOC_DAPM_EVENT_OFF(event)) + snd_soc_component_update_bits(component, rx_path_cfg3_reg, + 0x03, 0x03); + if (!rx_priv->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = BOLERO_CDC_RX_COMPANDER0_CTL0 + + (comp * RX_MACRO_COMP_OFFSET); + rx_path_cfg0_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG0 + + (comp * RX_MACRO_RX_PATH_OFFSET); if (SND_SOC_DAPM_EVENT_ON(event)) { /* Enable Compander Clock */ snd_soc_component_update_bits(component, comp_ctl0_reg, @@ -1741,8 +1771,6 @@ static int rx_macro_config_compander(struct snd_soc_component *component, 0x02, 0x00); snd_soc_component_update_bits(component, rx_path_cfg0_reg, 0x02, 0x02); - snd_soc_component_update_bits(component, rx_path_cfg3_reg, - 0x03, val); } if (SND_SOC_DAPM_EVENT_OFF(event)) { @@ -1754,8 +1782,6 @@ static int rx_macro_config_compander(struct snd_soc_component *component, 0x01, 0x00); snd_soc_component_update_bits(component, comp_ctl0_reg, 0x04, 0x00); - snd_soc_component_update_bits(component, rx_path_cfg3_reg, - 0x03, 0x03); } return 0; @@ -1930,7 +1956,12 @@ static int rx_macro_config_classh(struct snd_soc_component *component, 0x40, 0x40); break; case INTERP_HPHR: - snd_soc_component_update_bits(component, + if (rx_priv->is_ear_mode_on) + snd_soc_component_update_bits(component, + BOLERO_CDC_RX_CLSH_HPH_V_PA, + 0x3F, 0x39); + else + snd_soc_component_update_bits(component, BOLERO_CDC_RX_CLSH_HPH_V_PA, 0x3F, 0x1C); snd_soc_component_update_bits(component, @@ -2988,21 +3019,24 @@ static int rx_macro_set_iir_gain(struct snd_soc_dapm_widget *w, } static const struct snd_kcontrol_new rx_macro_snd_controls[] = { - SOC_SINGLE_SX_TLV("RX_RX0 Digital Volume", + SOC_SINGLE_S8_TLV("RX_RX0 Digital Volume", BOLERO_CDC_RX_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX_RX1 Digital Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Digital Volume", BOLERO_CDC_RX_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX_RX2 Digital Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Digital Volume", BOLERO_CDC_RX_RX2_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX_RX0 Mix Digital Volume", - BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX_RX1 Mix Digital Volume", - BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX_RX2 Mix Digital Volume", - BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX0 Mix Digital Volume", + BOLERO_CDC_RX_RX0_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX1 Mix Digital Volume", + BOLERO_CDC_RX_RX1_RX_VOL_MIX_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX_RX2 Mix Digital Volume", + BOLERO_CDC_RX_RX2_RX_VOL_MIX_CTL, + -84, 40, digital_gain), SOC_SINGLE_EXT("RX_COMP1 Switch", SND_SOC_NOPM, RX_MACRO_COMP1, 1, 0, rx_macro_get_compander, rx_macro_set_compander), @@ -3031,29 +3065,29 @@ static const struct snd_kcontrol_new rx_macro_snd_controls[] = { rx_macro_aux_hpf_mode_get, rx_macro_aux_hpf_mode_put), - SOC_SINGLE_SX_TLV("IIR0 INP0 Volume", - BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP1 Volume", - BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP2 Volume", - BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP3 Volume", - BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + BOLERO_CDC_RX_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP0 Volume", - BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", - BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", - BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", - BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + BOLERO_CDC_RX_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40, digital_gain), SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, @@ -3179,6 +3213,9 @@ static const struct snd_soc_dapm_widget rx_macro_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("RX AIF_ECHO", "RX_AIF_ECHO Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX AIF5 PB", "RX_MACRO_AIF5 Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX AIF6 PB", "RX_MACRO_AIF6 Playback", 0, SND_SOC_NOPM, 0, 0), @@ -3849,6 +3886,7 @@ static int rx_macro_init(struct snd_soc_component *component) snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF2 Playback"); snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF3 Playback"); snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF4 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF5 Playback"); snd_soc_dapm_ignore_suspend(dapm, "RX_MACRO_AIF6 Playback"); snd_soc_dapm_ignore_suspend(dapm, "HPHL_OUT"); snd_soc_dapm_ignore_suspend(dapm, "HPHR_OUT"); @@ -4016,6 +4054,12 @@ static int rx_macro_probe(struct platform_device *pdev) u32 is_used_rx_swr_gpio = 1; const char *is_used_rx_swr_gpio_dt = "qcom,is-used-swr-gpio"; + if (!bolero_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + rx_priv = devm_kzalloc(&pdev->dev, sizeof(struct rx_macro_priv), GFP_KERNEL); if (!rx_priv) diff --git a/asoc/codecs/bolero/tx-macro.c b/asoc/codecs/bolero/tx-macro.c index 2539577678..2e05a54da4 100644 --- a/asoc/codecs/bolero/tx-macro.c +++ b/asoc/codecs/bolero/tx-macro.c @@ -176,6 +176,7 @@ struct tx_macro_priv { int bcs_ch; bool bcs_clk_en; bool hs_slow_insert_complete; + int amic_sample_rate; }; static bool tx_macro_get_data(struct snd_soc_component *component, @@ -411,6 +412,9 @@ static int tx_macro_event_handler(struct snd_soc_component *component, else tx_priv->hs_slow_insert_complete = false; break; + default: + pr_debug("%s Invalid Event\n", __func__); + break; } return 0; } @@ -497,6 +501,29 @@ static void tx_macro_tx_hpf_corner_freq_callback(struct work_struct *work) hpf_cut_off_freq << 5); snd_soc_component_update_bits(component, hpf_gate_reg, 0x03, 0x02); + /* Add delay between toggle hpf gate based on sample rate */ + switch(tx_priv->amic_sample_rate) { + case 8000: + usleep_range(125, 130); + break; + case 16000: + usleep_range(62, 65); + break; + case 32000: + usleep_range(31, 32); + break; + case 48000: + usleep_range(20, 21); + break; + case 96000: + usleep_range(10, 11); + break; + case 192000: + usleep_range(5, 6); + break; + default: + usleep_range(125, 130); + } snd_soc_component_update_bits(component, hpf_gate_reg, 0x03, 0x01); } else { @@ -932,6 +959,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, u16 dec_cfg_reg = 0; u16 hpf_gate_reg = 0; u16 tx_gain_ctl_reg = 0; + u16 tx_fs_reg = 0; u8 hpf_cut_off_freq = 0; u16 adc_mux_reg = 0; int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS; @@ -957,6 +985,11 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w, TX_MACRO_TX_PATH_OFFSET * decimator; adc_mux_reg = BOLERO_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + TX_MACRO_ADC_MUX_CFG_OFFSET * decimator; + tx_fs_reg = BOLERO_CDC_TX0_TX_PATH_CTL + + TX_MACRO_TX_PATH_OFFSET * decimator; + + tx_priv->amic_sample_rate = (snd_soc_component_read32(component, + tx_fs_reg) & 0x0F); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -2362,18 +2395,18 @@ static const struct snd_soc_dapm_route tx_audio_map[] = { }; static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = { - SOC_SINGLE_SX_TLV("TX_DEC0 Volume", + SOC_SINGLE_S8_TLV("TX_DEC0 Volume", BOLERO_CDC_TX0_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC1 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC1 Volume", BOLERO_CDC_TX1_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC2 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC2 Volume", BOLERO_CDC_TX2_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC3 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC3 Volume", BOLERO_CDC_TX3_TX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum, tx_macro_dec_mode_get, tx_macro_dec_mode_put), @@ -2398,18 +2431,18 @@ static const struct snd_kcontrol_new tx_macro_snd_controls_common[] = { }; static const struct snd_kcontrol_new tx_macro_snd_controls_v3[] = { - SOC_SINGLE_SX_TLV("TX_DEC4 Volume", + SOC_SINGLE_S8_TLV("TX_DEC4 Volume", BOLERO_CDC_TX4_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC5 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC5 Volume", BOLERO_CDC_TX5_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC6 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC6 Volume", BOLERO_CDC_TX6_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC7 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC7 Volume", BOLERO_CDC_TX7_TX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), SOC_ENUM_EXT("DEC4 MODE", dec_mode_mux_enum, tx_macro_dec_mode_get, tx_macro_dec_mode_put), @@ -2425,30 +2458,30 @@ static const struct snd_kcontrol_new tx_macro_snd_controls_v3[] = { }; static const struct snd_kcontrol_new tx_macro_snd_controls[] = { - SOC_SINGLE_SX_TLV("TX_DEC0 Volume", + SOC_SINGLE_S8_TLV("TX_DEC0 Volume", BOLERO_CDC_TX0_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC1 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC1 Volume", BOLERO_CDC_TX1_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC2 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC2 Volume", BOLERO_CDC_TX2_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC3 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC3 Volume", BOLERO_CDC_TX3_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC4 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC4 Volume", BOLERO_CDC_TX4_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC5 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC5 Volume", BOLERO_CDC_TX5_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC6 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC6 Volume", BOLERO_CDC_TX6_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("TX_DEC7 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("TX_DEC7 Volume", BOLERO_CDC_TX7_TX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), SOC_ENUM_EXT("DEC0 MODE", dec_mode_mux_enum, tx_macro_dec_mode_get, tx_macro_dec_mode_put), @@ -2722,36 +2755,6 @@ static int tx_macro_clk_div_get(struct snd_soc_component *component) return tx_priv->dmic_clk_div; } -static int tx_macro_clk_switch(struct snd_soc_component *component, int clk_src) -{ - struct device *tx_dev = NULL; - struct tx_macro_priv *tx_priv = NULL; - int ret = 0; - - if (!component) - return -EINVAL; - - tx_dev = bolero_get_device_ptr(component->dev, TX_MACRO); - if (!tx_dev) { - dev_err(component->dev, - "%s: null device for macro!\n", __func__); - return -EINVAL; - } - tx_priv = dev_get_drvdata(tx_dev); - if (!tx_priv) { - dev_err(component->dev, - "%s: priv is null for macro!\n", __func__); - return -EINVAL; - } - if (tx_priv->swr_ctrl_data) { - ret = swrm_wcd_notify( - tx_priv->swr_ctrl_data[0].tx_swr_pdev, - SWR_REQ_CLK_SWITCH, &clk_src); - } - - return ret; -} - static int tx_macro_core_vote(void *handle, bool enable) { struct tx_macro_priv *tx_priv = (struct tx_macro_priv *) handle; @@ -3233,7 +3236,6 @@ static void tx_macro_init_ops(struct macro_ops *ops, ops->reg_wake_irq = tx_macro_reg_wake_irq; ops->set_port_map = tx_macro_set_port_map; ops->clk_div_get = tx_macro_clk_div_get; - ops->clk_switch = tx_macro_clk_switch; ops->reg_evt_listener = tx_macro_register_event_listener; ops->clk_enable = __tx_macro_mclk_enable; } @@ -3249,6 +3251,12 @@ static int tx_macro_probe(struct platform_device *pdev) u32 is_used_tx_swr_gpio = 1; const char *is_used_tx_swr_gpio_dt = "qcom,is-used-swr-gpio"; + if (!bolero_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + tx_priv = devm_kzalloc(&pdev->dev, sizeof(struct tx_macro_priv), GFP_KERNEL); if (!tx_priv) diff --git a/asoc/codecs/bolero/va-macro.c b/asoc/codecs/bolero/va-macro.c index edef14dc24..9efebe6c78 100644 --- a/asoc/codecs/bolero/va-macro.c +++ b/asoc/codecs/bolero/va-macro.c @@ -298,8 +298,7 @@ static int va_macro_event_handler(struct snd_soc_component *component, "%s: va_mclk_users is non-zero still, audio SSR fail!!\n", __func__); break; - case BOLERO_MACRO_EVT_SSR_UP: - trace_printk("%s, enter SSR up\n", __func__); + case BOLERO_MACRO_EVT_PRE_SSR_UP: /* enable&disable VA_CORE_CLK to reset GFMUX reg */ ret = bolero_clk_rsc_request_clock(va_priv->dev, va_priv->default_clk_id, @@ -312,6 +311,9 @@ static int va_macro_event_handler(struct snd_soc_component *component, bolero_clk_rsc_request_clock(va_priv->dev, va_priv->default_clk_id, VA_CORE_CLK, false); + break; + case BOLERO_MACRO_EVT_SSR_UP: + trace_printk("%s, enter SSR up\n", __func__); /* reset swr after ssr/pdr */ va_priv->reset_swr = true; if (va_priv->swr_ctrl_data) @@ -378,7 +380,6 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, int ret = 0; struct device *va_dev = NULL; struct va_macro_priv *va_priv = NULL; - int clk_src = 0; if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) return -EINVAL; @@ -391,30 +392,12 @@ static int va_macro_swr_pwr_event_v2(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - if (va_priv->swr_ctrl_data) { - clk_src = CLK_SRC_VA_RCG; - ret = swrm_wcd_notify( - va_priv->swr_ctrl_data[0].va_swr_pdev, - SWR_REQ_CLK_SWITCH, &clk_src); - if (ret) - dev_dbg(va_dev, "%s: clock switch failed\n", - __func__); - } msm_cdc_pinctrl_set_wakeup_capable( va_priv->va_swr_gpio_p, false); break; case SND_SOC_DAPM_POST_PMD: msm_cdc_pinctrl_set_wakeup_capable( va_priv->va_swr_gpio_p, true); - if (va_priv->swr_ctrl_data) { - clk_src = CLK_SRC_TX_RCG; - ret = swrm_wcd_notify( - va_priv->swr_ctrl_data[0].va_swr_pdev, - SWR_REQ_CLK_SWITCH, &clk_src); - if (ret) - dev_dbg(va_dev, "%s: clock switch failed\n", - __func__); - } break; default: dev_err(va_priv->dev, @@ -452,10 +435,6 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w, "%s: lpass audio hw enable failed\n", __func__); } - if (!ret) - if (bolero_tx_clk_switch(component, CLK_SRC_VA_RCG)) - dev_dbg(va_dev, "%s: clock switch failed\n", - __func__); if (va_priv->lpi_enable) { bolero_register_event_listener(component, true); va_priv->register_event_listener = true; @@ -466,8 +445,6 @@ static int va_macro_swr_pwr_event(struct snd_soc_dapm_widget *w, va_priv->register_event_listener = false; bolero_register_event_listener(component, false); } - if (bolero_tx_clk_switch(component, CLK_SRC_TX_RCG)) - dev_dbg(va_dev, "%s: clock switch failed\n",__func__); if (va_priv->lpass_audio_hw_vote) digital_cdc_rsc_mgr_hw_vote_disable( va_priv->lpass_audio_hw_vote); @@ -507,7 +484,6 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, int ret = 0; struct device *va_dev = NULL; struct va_macro_priv *va_priv = NULL; - int clk_src = 0; if (!va_macro_get_data(component, &va_dev, &va_priv, __func__)) return -EINVAL; @@ -528,27 +504,10 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w, ret = bolero_tx_mclk_enable(component, 1); break; case SND_SOC_DAPM_POST_PMD: - if (va_priv->lpi_enable) { - if (va_priv->version == BOLERO_VERSION_2_1) { - if (va_priv->swr_ctrl_data) { - clk_src = CLK_SRC_TX_RCG; - ret = swrm_wcd_notify( - va_priv->swr_ctrl_data[0].va_swr_pdev, - SWR_REQ_CLK_SWITCH, &clk_src); - if (ret) - dev_dbg(va_dev, - "%s: clock switch failed\n", - __func__); - } - } else if (bolero_tx_clk_switch(component, - CLK_SRC_TX_RCG)) { - dev_dbg(va_dev, "%s: clock switch failed\n", - __func__); - } + if (va_priv->lpi_enable) va_macro_mclk_enable(va_priv, 0, true); - } else { + else bolero_tx_mclk_enable(component, 0); - } if (va_priv->tx_clk_status > 0) { bolero_clk_rsc_request_clock(va_priv->dev, @@ -2536,30 +2495,30 @@ static const struct soc_enum dec_mode_mux_enum = dec_mode_mux_text); static const struct snd_kcontrol_new va_macro_snd_controls[] = { - SOC_SINGLE_SX_TLV("VA_DEC0 Volume", + SOC_SINGLE_S8_TLV("VA_DEC0 Volume", BOLERO_CDC_VA_TX0_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC1 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC1 Volume", BOLERO_CDC_VA_TX1_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC2 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC2 Volume", BOLERO_CDC_VA_TX2_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC3 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC3 Volume", BOLERO_CDC_VA_TX3_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC4 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC4 Volume", BOLERO_CDC_VA_TX4_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC5 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC5 Volume", BOLERO_CDC_VA_TX5_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC6 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC6 Volume", BOLERO_CDC_VA_TX6_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC7 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC7 Volume", BOLERO_CDC_VA_TX7_TX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0, va_macro_lpi_get, va_macro_lpi_put), @@ -2577,23 +2536,23 @@ static const struct snd_kcontrol_new va_macro_snd_controls[] = { }; static const struct snd_kcontrol_new va_macro_snd_controls_common[] = { - SOC_SINGLE_SX_TLV("VA_DEC0 Volume", + SOC_SINGLE_S8_TLV("VA_DEC0 Volume", BOLERO_CDC_VA_TX0_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC1 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC1 Volume", BOLERO_CDC_VA_TX1_TX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_EXT("LPI Enable", 0, 0, 1, 0, va_macro_lpi_get, va_macro_lpi_put), }; static const struct snd_kcontrol_new va_macro_snd_controls_v3[] = { - SOC_SINGLE_SX_TLV("VA_DEC2 Volume", + SOC_SINGLE_S8_TLV("VA_DEC2 Volume", BOLERO_CDC_VA_TX2_TX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("VA_DEC3 Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("VA_DEC3 Volume", BOLERO_CDC_VA_TX3_TX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), }; static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, diff --git a/asoc/codecs/bolero/wsa-macro.c b/asoc/codecs/bolero/wsa-macro.c index 7579957aa4..70a1ce2901 100644 --- a/asoc/codecs/bolero/wsa-macro.c +++ b/asoc/codecs/bolero/wsa-macro.c @@ -1022,10 +1022,7 @@ static int wsa_macro_event_handler(struct snd_soc_component *component, } } break; - case BOLERO_MACRO_EVT_SSR_UP: - trace_printk("%s, enter SSR up\n", __func__); - /* reset swr after ssr/pdr */ - wsa_priv->reset_swr = true; + case BOLERO_MACRO_EVT_PRE_SSR_UP: /* enable&disable WSA_CORE_CLK to reset GFMUX reg */ ret = bolero_clk_rsc_request_clock(wsa_priv->dev, wsa_priv->default_clk_id, @@ -1038,6 +1035,11 @@ static int wsa_macro_event_handler(struct snd_soc_component *component, bolero_clk_rsc_request_clock(wsa_priv->dev, wsa_priv->default_clk_id, WSA_CORE_CLK, false); + break; + case BOLERO_MACRO_EVT_SSR_UP: + trace_printk("%s, enter SSR up\n", __func__); + /* reset swr after ssr/pdr */ + wsa_priv->reset_swr = true; if (wsa_priv->swr_ctrl_data) swrm_wcd_notify( wsa_priv->swr_ctrl_data[0].wsa_swr_pdev, @@ -1178,45 +1180,6 @@ static int wsa_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w, return 0; } -static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - u16 gain_reg; - int offset_val = 0; - int val = 0; - - dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); - - switch (w->reg) { - case BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL: - gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL; - break; - case BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL: - gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL; - break; - default: - dev_err(component->dev, "%s: No gain register avail for %s\n", - __func__, w->name); - return 0; - } - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - val = snd_soc_component_read32(component, gain_reg); - val += offset_val; - snd_soc_component_write(component, gain_reg, val); - break; - case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - w->reg, 0x20, 0x00); - break; - } - - return 0; -} - static void wsa_macro_hd2_control(struct snd_soc_component *component, u16 reg, int event) { @@ -1303,6 +1266,44 @@ static int wsa_macro_enable_swr(struct snd_soc_dapm_widget *w, return 0; } +static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + dev_dbg(component->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "WSA_RX0 MIX INP"))) { + gain_reg = BOLERO_CDC_WSA_RX0_RX_VOL_MIX_CTL; + } else if (!(strcmp(w->name, "WSA_RX1 MIX INP"))) { + gain_reg = BOLERO_CDC_WSA_RX1_RX_VOL_MIX_CTL; + } else { + dev_err(component->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wsa_macro_enable_swr(w, kcontrol, event); + val = snd_soc_component_read32(component, gain_reg); + val += offset_val; + snd_soc_component_write(component, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + w->reg, 0x20, 0x00); + wsa_macro_enable_swr(w, kcontrol, event); + break; + } + + return 0; +} + static int wsa_macro_config_compander(struct snd_soc_component *component, int comp, int event) { @@ -2007,10 +2008,12 @@ static int wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol, int value = ucontrol->value.integer.value[0]; int wsa_rx_shift = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; + int ret = 0; if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) return -EINVAL; + pm_runtime_get_sync(wsa_priv->dev); switch (wsa_rx_shift) { case 0: snd_soc_component_update_bits(component, @@ -2035,13 +2038,16 @@ static int wsa_macro_set_rx_mute_status(struct snd_kcontrol *kcontrol, default: pr_err("%s: invalid argument rx_shift = %d\n", __func__, wsa_rx_shift); - return -EINVAL; + ret = -EINVAL; } + pm_runtime_mark_last_busy(wsa_priv->dev); + pm_runtime_put_autosuspend(wsa_priv->dev); dev_dbg(component->dev, "%s: WSA Digital Mute RX %d Enable %d\n", __func__, wsa_rx_shift, value); wsa_priv->wsa_digital_mute_status[wsa_rx_shift] = value; - return 0; + + return ret; } static int wsa_macro_get_compander(struct snd_kcontrol *kcontrol, @@ -2370,12 +2376,12 @@ static const struct snd_kcontrol_new wsa_macro_snd_controls[] = { WSA_MACRO_SOFTCLIP1, 1, 0, wsa_macro_soft_clip_enable_get, wsa_macro_soft_clip_enable_put), - SOC_SINGLE_SX_TLV("WSA_RX0 Digital Volume", + SOC_SINGLE_S8_TLV("WSA_RX0 Digital Volume", BOLERO_CDC_WSA_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("WSA_RX1 Digital Volume", + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("WSA_RX1 Digital Volume", BOLERO_CDC_WSA_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), + -84, 40, digital_gain), SOC_SINGLE_EXT("WSA_RX0 Digital Mute", SND_SOC_NOPM, WSA_MACRO_RX0, 1, 0, wsa_macro_get_rx_mute_status, wsa_macro_set_rx_mute_status), @@ -2550,7 +2556,7 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux, wsa_macro_enable_swr, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", BOLERO_CDC_WSA_RX0_RX_PATH_MIX_CTL, + SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, 0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX_E("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, @@ -2562,7 +2568,7 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux, wsa_macro_enable_swr, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", BOLERO_CDC_WSA_RX1_RX_PATH_MIX_CTL, + SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, 0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, @@ -3138,6 +3144,12 @@ static int wsa_macro_probe(struct platform_device *pdev) u32 is_used_wsa_swr_gpio = 1; const char *is_used_wsa_swr_gpio_dt = "qcom,is-used-swr-gpio"; + if (!bolero_is_va_macro_registered(&pdev->dev)) { + dev_err(&pdev->dev, + "%s: va-macro not registered yet, defer\n", __func__); + return -EPROBE_DEFER; + } + wsa_priv = devm_kzalloc(&pdev->dev, sizeof(struct wsa_macro_priv), GFP_KERNEL); if (!wsa_priv) @@ -3175,6 +3187,8 @@ static int wsa_macro_probe(struct platform_device *pdev) __func__); return -EPROBE_DEFER; } + msm_cdc_pinctrl_set_wakeup_capable( + wsa_priv->wsa_swr_gpio_p, false); wsa_io_base = devm_ioremap(&pdev->dev, wsa_base_addr, WSA_MACRO_MAX_OFFSET); @@ -3221,6 +3235,7 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa_macro_init_ops(&ops, wsa_io_base); ops.clk_id_req = wsa_priv->default_clk_id; ops.default_clk_id = wsa_priv->default_clk_id; + ret = bolero_register_macro(&pdev->dev, WSA_MACRO, &ops); if (ret < 0) { dev_err(&pdev->dev, "%s: register macro failed\n", __func__); diff --git a/asoc/codecs/csra66x0/csra66x0.c b/asoc/codecs/csra66x0/csra66x0.c index e0e702f565..9cdbbdaaab 100644 --- a/asoc/codecs/csra66x0/csra66x0.c +++ b/asoc/codecs/csra66x0/csra66x0.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include #include @@ -602,6 +602,25 @@ static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = { {"PGA", NULL, "DAC"}, {"SPKR", NULL, "PGA"}, }; +/* + * csra66x0_hw_free_mute - Update csra66x0 mute register + * + * @component - csra66x0 component + * + */ +void csra66x0_hw_free_mute(struct snd_soc_component *component) +{ + int val = 0; + + if (component == NULL) + return; + + val = snd_soc_component_read32(component, + CSRA66X0_MISC_CONTROL_STATUS_1_FA); + snd_soc_component_write(component, CSRA66X0_MISC_CONTROL_STATUS_1_FA, + val | 0x04); +} +EXPORT_SYMBOL(csra66x0_hw_free_mute); static int csra66x0_wait_for_config_state(struct snd_soc_component *component) { diff --git a/asoc/codecs/csra66x0/csra66x0.h b/asoc/codecs/csra66x0/csra66x0.h index 04d9ef836d..2bde3cc06b 100644 --- a/asoc/codecs/csra66x0/csra66x0.h +++ b/asoc/codecs/csra66x0/csra66x0.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef _CSRA66X0_H @@ -226,4 +226,6 @@ #define FAULT_STATUS_TEMP 0x10 #define FAULT_STATUS_PROTECT 0x20 + +void csra66x0_hw_free_mute(struct snd_soc_component *component); #endif /* _CSRA66X0_H */ diff --git a/asoc/codecs/ep92/ep92.c b/asoc/codecs/ep92/ep92.c index 6077070441..07a3281893 100644 --- a/asoc/codecs/ep92/ep92.c +++ b/asoc/codecs/ep92/ep92.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -40,6 +40,10 @@ static const unsigned int ep92_samp_freq_table[8] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000, 768000 }; +static const unsigned int ep92_dsd_freq_table[4] = { + 64, 128, 256, 0 +}; + static bool ep92_volatile_register(struct device *dev, unsigned int reg) { /* do not cache register state in regmap */ @@ -549,6 +553,23 @@ static void ep92_read_audio_info(struct snd_soc_component *component, send_uevent = true; } + old = ep92->ai.system_status_1; + ep92->ai.system_status_1 = snd_soc_read(codec, + EP92_AUDIO_INFO_SYSTEM_STATUS_1); + if (ep92->ai.system_status_1 == 0xff) { + dev_dbg(codec->dev, + "ep92 EP92_AUDIO_INFO_SYSTEM_STATUS_1 read 0xff\n"); + ep92->ai.system_status_1 = old; + } + change = ep92->ai.system_status_1 ^ old; + if (change & EP92_AI_DSD_RATE_MASK) { + dev_dbg(codec->dev, "ep92 dsd rate changed to %d\n", + ep92_dsd_freq_table[(ep92->ai.system_status_1 & + EP92_AI_DSD_RATE_MASK) + >> EP92_AI_DSD_RATE_SHIFT]); + send_uevent = true; + } + old = ep92->ai.audio_status; ep92->ai.audio_status = snd_soc_component_read32(component, EP92_AUDIO_INFO_AUDIO_STATUS); @@ -580,7 +601,9 @@ static void ep92_read_audio_info(struct snd_soc_component *component, } new_mode = ep92->old_mode; - if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) { + if (ep92->ai.audio_status & EP92_AI_DSD_ADO_MASK) + new_mode = 2; /* One bit audio */ + else if (ep92->ai.audio_status & EP92_AI_STD_ADO_MASK) { if (ep92->ai.cs[0] & EP92_AI_NPCM_MASK) new_mode = 1; /* Compr */ else @@ -897,6 +920,27 @@ static ssize_t ep92_sysfs_rda_audio_format(struct device *dev, return ret; } +static ssize_t ep92_sysfs_rda_dsd_rate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int val; + struct ep92_pdata *ep92 = dev_get_drvdata(dev); + + if (!ep92 || !ep92->codec) { + dev_err(dev, "%s: device error\n", __func__); + return -ENODEV; + } + + val = ep92_dsd_freq_table[(ep92->ai.system_status_1 & + EP92_AI_DSD_RATE_MASK) >> EP92_AI_DSD_RATE_SHIFT]; + + ret = snprintf(buf, EP92_SYSFS_ENTRY_MAX_LEN, "%d\n", val); + dev_dbg(dev, "%s: '%d'\n", __func__, val); + + return ret; +} + static ssize_t ep92_sysfs_rda_audio_rate(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1621,6 +1665,7 @@ static DEVICE_ATTR(cec_volume, 0644, ep92_sysfs_rda_cec_volume, static DEVICE_ATTR(runout, 0444, ep92_sysfs_rda_runout, NULL); static DEVICE_ATTR(force_inactive, 0644, ep92_sysfs_rda_force_inactive, ep92_sysfs_wta_force_inactive); +static DEVICE_ATTR(dsd_rate, 0444, ep92_sysfs_rda_dsd_rate, NULL); static struct attribute *ep92_fs_attrs[] = { &dev_attr_chipid.attr, @@ -1647,6 +1692,7 @@ static struct attribute *ep92_fs_attrs[] = { &dev_attr_cec_volume.attr, &dev_attr_runout.attr, &dev_attr_force_inactive.attr, + &dev_attr_dsd_rate.attr, NULL, }; diff --git a/asoc/codecs/ep92/ep92.h b/asoc/codecs/ep92/ep92.h index 18cb0105f5..22384fbb67 100644 --- a/asoc/codecs/ep92/ep92.h +++ b/asoc/codecs/ep92/ep92.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #ifndef __EP92_H__ @@ -175,6 +175,10 @@ static struct reg_default ep92_reg_defaults[] = { #define EP92_AI_PREEMPH_MASK 0x38 #define EP92_AI_CH_COUNT_MASK 0x07 #define EP92_AI_CH_ALLOC_MASK 0xff +#define EP92_AI_DSD_ADO_SHIFT 4 +#define EP92_AI_DSD_ADO_MASK 0x10 +#define EP92_AI_DSD_RATE_SHIFT 4 +#define EP92_AI_DSD_RATE_MASK 0x30 #define EP92_2CHOICE_MASK 1 #define EP92_GC_CEC_VOLUME_MIN 0 diff --git a/asoc/codecs/msm-cdc-pinctrl.c b/asoc/codecs/msm-cdc-pinctrl.c index 88121fd1e7..9f90a84337 100644 --- a/asoc/codecs/msm-cdc-pinctrl.c +++ b/asoc/codecs/msm-cdc-pinctrl.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -21,6 +21,7 @@ struct msm_cdc_pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *pinctrl_active; struct pinctrl_state *pinctrl_sleep; + struct pinctrl_state *pinctrl_alt_active; int gpio; bool state; u32 tlmm_gpio[MAX_GPIOS]; @@ -104,6 +105,31 @@ int msm_cdc_pinctrl_select_sleep_state(struct device_node *np) } EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state); +/* + * msm_cdc_pinctrl_select_alt_active_state: select pinctrl alt_active state + * @np: pointer to struct device_node + * + * Returns error code for failure + */ +int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return -EINVAL; + + if (!gpio_data->pinctrl_alt_active) { + pr_err("%s: pinctrl alt_active state is null\n", __func__); + return -EINVAL; + } + gpio_data->state = true; + + return pinctrl_select_state(gpio_data->pinctrl, + gpio_data->pinctrl_alt_active); +} +EXPORT_SYMBOL(msm_cdc_pinctrl_select_alt_active_state); + /* * msm_cdc_pinctrl_select_active_state: select pinctrl active state * @np: pointer to struct device_node @@ -231,6 +257,14 @@ static int msm_cdc_pinctrl_probe(struct platform_device *pdev) ret = PTR_ERR(gpio_data->pinctrl_sleep); goto err_lookup_state; } + + gpio_data->pinctrl_alt_active = pinctrl_lookup_state( + gpio_data->pinctrl, "aud_alt_active"); + if (IS_ERR_OR_NULL(gpio_data->pinctrl_alt_active)) { + dev_dbg(&pdev->dev, "%s: Cannot get aud_alt_active pinctrl state:%ld\n", + __func__, PTR_ERR(gpio_data->pinctrl_alt_active)); + } + /* skip setting to sleep state for LPI_TLMM GPIOs */ if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) { /* Set pinctrl state to aud_sleep by default */ diff --git a/asoc/codecs/msm-cdc-supply.c b/asoc/codecs/msm-cdc-supply.c index 230a7f9981..1618b83a55 100644 --- a/asoc/codecs/msm-cdc-supply.c +++ b/asoc/codecs/msm-cdc-supply.c @@ -60,9 +60,22 @@ static int msm_cdc_dt_parse_vreg_info(struct device *dev, } cdc_vreg->optimum_uA = prop_val; - dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n", + /* Parse supply - LPM or NOM mode(default NOM) */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-lpm-supported", name); + rc = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (rc) { + dev_dbg(dev, "%s: Looking up %s property in node %s failed", + __func__, prop_name, dev->of_node->full_name); + cdc_vreg->lpm_supported = 0; + rc = 0; + } else { + cdc_vreg->lpm_supported = prop_val; + } + + dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d lpm %d\n", __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV, - cdc_vreg->optimum_uA, cdc_vreg->ondemand); + cdc_vreg->optimum_uA, cdc_vreg->ondemand, + cdc_vreg->lpm_supported); done: return rc; @@ -260,6 +273,59 @@ int msm_cdc_enable_ondemand_supply(struct device *dev, } EXPORT_SYMBOL(msm_cdc_enable_ondemand_supply); +/* + * msm_cdc_set_supplies_lpm_mode: + * Update load for given supply string + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: supply name to be checked + * @min_max: Apply optimum or 0 current + * + * Return error code if set current fail + */ +int msm_cdc_set_supplies_lpm_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + bool flag) +{ + int rc = 0, i; + + if (!supplies) { + pr_err("%s: supplies is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].lpm_supported) { + rc = regulator_set_load( + supplies[i].consumer, + flag ? 0 : cdc_vreg[i].optimum_uA); + if (rc) + dev_err(dev, + "%s: failed to set supply %s to %s, err:%d\n", + __func__, supplies[i].supply, + flag ? "LPM" : "NOM", + rc); + else + dev_dbg(dev, "%s: regulator %s load set to %s\n", + __func__, supplies[i].supply, + flag ? "LPM" : "NOM"); + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_set_supplies_lpm_mode); + /* * msm_cdc_disable_static_supplies: * Disable codec static supplies diff --git a/asoc/codecs/msm_hdmi_codec_rx.c b/asoc/codecs/msm_hdmi_codec_rx.c index 1588c56767..609dd45ea3 100644 --- a/asoc/codecs/msm_hdmi_codec_rx.c +++ b/asoc/codecs/msm_hdmi_codec_rx.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #include #include @@ -25,8 +25,8 @@ static SOC_ENUM_SINGLE_DECL(ext_disp_audio_ack_state##index, \ SND_SOC_NOPM, index, ext_disp_audio_ack_text) -#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id) \ - codec_info.type = EXT_DISPLAY_TYPE_DP; \ +#define SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type) \ + codec_info.type = type; \ codec_info.ctrl_id = codec_data->ctl[dai_id]; \ codec_info.stream_id = codec_data->stream[dai_id]; \ @@ -38,6 +38,7 @@ enum { enum { DP_STREAM0 = 0, DP_STREAM1, + HDMI, DP_STREAM_MAX, }; @@ -49,6 +50,7 @@ enum { DP_DAI1 = 1, DP_DAI2, HDMI_DAI, + HDMI_MS_DAI, DP_DAI_MAX, }; @@ -60,6 +62,8 @@ SOC_EXT_DISP_AUDIO_TYPE(1); SOC_EXT_DISP_AUDIO_ACK_STATE(1); SOC_EXT_DISP_AUDIO_TYPE(2); SOC_EXT_DISP_AUDIO_ACK_STATE(2); +SOC_EXT_DISP_AUDIO_TYPE(3); +SOC_EXT_DISP_AUDIO_ACK_STATE(3); struct msm_ext_disp_audio_codec_rx_data { struct platform_device *ext_disp_core_pdev; @@ -80,6 +84,7 @@ static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol, int rc = 0; struct msm_ext_disp_codec_id codec_info; int dai_id = kcontrol->private_value; + int type; codec_data = snd_soc_component_get_drvdata(component); if (!codec_data) { @@ -91,7 +96,11 @@ static int msm_ext_disp_edid_ctl_info(struct snd_kcontrol *kcontrol, codec_data->ctl[dai_id], codec_data->stream[dai_id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai_id); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) { @@ -126,6 +135,7 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol, struct msm_ext_disp_codec_id codec_info; int rc = 0; int dai_id = kcontrol->private_value; + int type; codec_data = snd_soc_component_get_drvdata(component); if (!codec_data) { @@ -138,7 +148,11 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol, codec_data->ctl[dai_id], codec_data->stream[dai_id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai_id); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); if (!codec_data->ext_disp_ops.get_audio_edid_blk || rc) { @@ -147,7 +161,6 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec_data->dp_ops_lock); return -EINVAL; } - rc = codec_data->ext_disp_ops.get_audio_edid_blk( codec_data->ext_disp_core_pdev, &edid_blk); mutex_unlock(&codec_data->dp_ops_lock); @@ -188,6 +201,7 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, struct msm_ext_disp_codec_id codec_info; int rc = 0; int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l; + int type; codec_data = snd_soc_component_get_drvdata(component); if (!codec_data) { @@ -200,7 +214,11 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, codec_data->ctl[dai_id], codec_data->stream[dai_id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai_id); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); @@ -213,7 +231,7 @@ static int msm_ext_disp_audio_type_get(struct snd_kcontrol *kcontrol, } cable_state = codec_data->ext_disp_ops.cable_status( - codec_data->ext_disp_core_pdev, 1); + codec_data->ext_disp_core_pdev, 1); if (cable_state < 0) { dev_err(component->dev, "%s: Error retrieving cable state from ext_disp, err:%d\n", __func__, cable_state); @@ -274,6 +292,7 @@ static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol, struct msm_ext_disp_codec_id codec_info; int rc = 0; int dai_id = ((struct soc_enum *) kcontrol->private_value)->shift_l; + int type; codec_data = snd_soc_component_get_drvdata(component); if (!codec_data) { @@ -287,7 +306,11 @@ static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol, codec_data->ctl[dai_id], codec_data->stream[dai_id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai_id); + if (dai_id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai_id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); @@ -421,6 +444,15 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { .get = msm_ext_disp_edid_get, .private_value = HDMI_DAI, }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "HDMI MS EDID", + .info = msm_ext_disp_edid_ctl_info, + .get = msm_ext_disp_edid_get, + .private_value = HDMI_MS_DAI, + }, { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -445,12 +477,18 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { SOC_ENUM_EXT("External Display1 Type", ext_disp_audio_type2, msm_ext_disp_audio_type_get, NULL), + SOC_ENUM_EXT("External HDMI Type", + ext_disp_audio_type3, + msm_ext_disp_audio_type_get, NULL), SOC_ENUM_EXT("External Display Audio Ack", ext_disp_audio_ack_state1, NULL, msm_ext_disp_audio_ack_set), SOC_ENUM_EXT("External Display1 Audio Ack", ext_disp_audio_ack_state2, NULL, msm_ext_disp_audio_ack_set), + SOC_ENUM_EXT("External HDMI Audio Ack", + ext_disp_audio_ack_state3, + NULL, msm_ext_disp_audio_ack_set), SOC_SINGLE_MULTI_EXT("External Display Audio Device", SND_SOC_NOPM, DP_DAI1, DP_STREAM_MAX - 1, 0, 2, @@ -460,6 +498,11 @@ static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = { SND_SOC_NOPM, DP_DAI2, DP_STREAM_MAX - 1, 0, 2, msm_ext_disp_audio_device_get, msm_ext_disp_audio_device_set), + SOC_SINGLE_MULTI_EXT("External HDMI Device", + SND_SOC_NOPM, HDMI_MS_DAI, DP_STREAM_MAX - 1, 0, 2, + msm_ext_disp_audio_device_get, + msm_ext_disp_audio_device_set), + }; static int msm_ext_disp_audio_codec_rx_dai_startup( @@ -470,6 +513,7 @@ static int msm_ext_disp_audio_codec_rx_dai_startup( struct msm_ext_disp_codec_id codec_info; struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->component->dev); + int type; if (!codec_data) { dev_err(dai->dev, "%s() codec_data is null\n", @@ -482,7 +526,11 @@ static int msm_ext_disp_audio_codec_rx_dai_startup( codec_data->ctl[dai->id], codec_data->stream[dai->id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai->id); + if (dai->id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); @@ -524,7 +572,7 @@ static int msm_ext_disp_audio_codec_rx_dai_hw_params( struct msm_ext_disp_codec_id codec_info; int rc = 0; struct msm_ext_disp_audio_setup_params audio_setup_params = {0}; - + int type; struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->component->dev); @@ -539,7 +587,11 @@ static int msm_ext_disp_audio_codec_rx_dai_hw_params( codec_data->ctl[dai->id], codec_data->stream[dai->id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai->id); + if (dai->id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); @@ -609,7 +661,7 @@ static int msm_ext_disp_audio_codec_rx_dai_hw_params( audio_setup_params.down_mix = down_mix; mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai->id); + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); if (rc) @@ -636,6 +688,7 @@ static void msm_ext_disp_audio_codec_rx_dai_shutdown( struct msm_ext_disp_audio_codec_rx_data *codec_data = dev_get_drvdata(dai->component->dev); + int type; if (!codec_data) { dev_err(dai->dev, "%s() codec_data is null\n", @@ -648,7 +701,11 @@ static void msm_ext_disp_audio_codec_rx_dai_shutdown( codec_data->ctl[dai->id], codec_data->stream[dai->id]); mutex_lock(&codec_data->dp_ops_lock); - SWITCH_DP_CODEC(codec_info, codec_data, dai->id); + if (dai->id == HDMI_MS_DAI) + type = EXT_DISPLAY_TYPE_HDMI; + else + type = EXT_DISPLAY_TYPE_DP; + SWITCH_DP_CODEC(codec_info, codec_data, dai->id, type); rc = msm_ext_disp_select_audio_codec(codec_data->ext_disp_core_pdev, &codec_info); @@ -754,6 +811,20 @@ static struct snd_soc_dai_driver msm_ext_disp_audio_codec_rx_dais[] = { }, .ops = &msm_ext_disp_audio_codec_rx_dai_ops, }, + { + .name = "msm_hdmi_ms_audio_codec_rx_dai", + .id = HDMI_MS_DAI, + .playback = { + .stream_name = "HDMI MS Playback", + .channels_min = 1, + .channels_max = 8, + .rate_min = 48000, + .rate_max = 48000, + .rates = MSM_EXT_DISP_PCM_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &msm_ext_disp_audio_codec_rx_dai_ops, + }, { .name = "msm_dp_audio_codec_rx_dai", .id = DP_DAI1, diff --git a/asoc/codecs/rouleur/internal.h b/asoc/codecs/rouleur/internal.h index 7104685d7c..cc1500be70 100644 --- a/asoc/codecs/rouleur/internal.h +++ b/asoc/codecs/rouleur/internal.h @@ -50,6 +50,7 @@ struct rouleur_priv { bool comp1_enable; bool comp2_enable; + bool dapm_bias_off; struct irq_domain *virq; struct wcd_irq_info irq_info; @@ -82,6 +83,8 @@ struct rouleur_priv { int mbias_cnt; struct mutex rx_clk_lock; struct mutex main_bias_lock; + bool dev_up; + bool usbc_hs_status; }; struct rouleur_micbias_setting { @@ -169,4 +172,6 @@ extern int rouleur_mbhc_micb_adjust_voltage(struct snd_soc_component *component, extern int rouleur_get_micb_vout_ctl_val(u32 micb_mv); extern int rouleur_micbias_control(struct snd_soc_component *component, int micb_num, int req, bool is_dapm); +extern int rouleur_global_mbias_enable(struct snd_soc_component *component); +extern int rouleur_global_mbias_disable(struct snd_soc_component *component); #endif diff --git a/asoc/codecs/rouleur/rouleur-mbhc.c b/asoc/codecs/rouleur/rouleur-mbhc.c index 91ddc104ac..c7ba03cd2b 100644 --- a/asoc/codecs/rouleur/rouleur-mbhc.c +++ b/asoc/codecs/rouleur/rouleur-mbhc.c @@ -22,20 +22,19 @@ #define ROULEUR_ZDET_SUPPORTED true /* Z value defined in milliohm */ -#define ROULEUR_ZDET_VAL_32 32000 -#define ROULEUR_ZDET_VAL_400 400000 -#define ROULEUR_ZDET_VAL_1200 1200000 #define ROULEUR_ZDET_VAL_100K 100000000 /* Z floating defined in ohms */ #define ROULEUR_ZDET_FLOATING_IMPEDANCE 0x0FFFFFFE -#define ROULEUR_ZDET_NUM_MEASUREMENTS 900 -#define ROULEUR_MBHC_GET_C1(c) ((c & 0xC000) >> 14) -#define ROULEUR_MBHC_GET_X1(x) (x & 0x3FFF) -/* Z value compared in milliOhm */ -#define ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) -#define ROULEUR_MBHC_ZDET_CONST (86 * 16384) -#define ROULEUR_MBHC_MOISTURE_RREF R_24_KOHM +#define ROULEUR_ZDET_NUM_MEASUREMENTS 100 +#define ROULEUR_ZDET_RMAX 1280000 +#define ROULEUR_ZDET_C1 7500000 +#define ROULEUR_ZDET_C2 187 +#define ROULEUR_ZDET_C3 4500 + +/* Cross connection thresholds in mV */ +#define ROULEUR_HPHL_CROSS_CONN_THRESHOLD 350 +#define ROULEUR_HPHR_CROSS_CONN_THRESHOLD 350 static struct wcd_mbhc_register wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { @@ -88,7 +87,7 @@ static struct wcd_mbhc_register WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", ROULEUR_ANA_MBHC_RESULT_3, 0xFF, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", - ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x04, 2, 0), + ROULEUR_ANA_MICBIAS_MICB_1_2_EN, 0x06, 1, 0), WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", SND_SOC_NOPM, 0x00, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", @@ -153,9 +152,6 @@ struct rouleur_mbhc_zdet_param { u16 ldo_ctl; u16 noff; u16 nshift; - u16 btn5; - u16 btn6; - u16 btn7; }; static int rouleur_mbhc_request_irq(struct snd_soc_component *component, @@ -320,11 +316,11 @@ static void rouleur_mbhc_micb_ramp_control(struct snd_soc_component *component, 0x1C, 0x0C); snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MICB2_RAMP, - 0xA0, 0x80); + 0x80, 0x80); } else { snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MICB2_RAMP, - 0xA0, 0x00); + 0x80, 0x00); snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_MICB2_RAMP, 0x1C, 0x00); @@ -376,174 +372,180 @@ static int rouleur_mbhc_micb_ctrl_threshold_mic( return rc; } -static inline void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur, - s16 *d1_a, u16 noff, - int32_t *zdet) +static void rouleur_mbhc_get_result_params(struct rouleur_priv *rouleur, + struct snd_soc_component *component, + int32_t *zdet) { int i; - int val = 0, val1 = 0; - s16 c1 = 0; - s32 x1 = 0, d1 = 0; - int32_t denom; - int minCode_param[] = { - 3277, 1639, 820, 410, 205, 103, 52, 26 - }; + int zcode = 0, zcode1 = 0, zdet_cal_result = 0, zdet_est_range = 0; + int noff = 0, ndac = 14; + int zdet_cal_coeff = 0, div_ratio = 0; + int num = 0, denom = 0; + /* Charge enable and wait for zcode to be updated */ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x20); for (i = 0; i < ROULEUR_ZDET_NUM_MEASUREMENTS; i++) { - regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val); - if (val & 0x80) + regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &zcode); + if (zcode & 0x80) break; + usleep_range(200, 210); } - val = val << 0x8; - regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val1); - val |= val1; - regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00); - x1 = ROULEUR_MBHC_GET_X1(val); - c1 = ROULEUR_MBHC_GET_C1(val); - /* If ramp is not complete, give additional 5ms */ - if ((c1 < 2) && x1) - usleep_range(5000, 5050); - if (!c1 || !x1) { + /* If zcode updation is not complete, give additional 10ms */ + if (!(zcode & 0x80)) + usleep_range(10000, 10100); + + regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &zcode); + if (!(zcode & 0x80)) { dev_dbg(rouleur->dev, - "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", - __func__, c1, x1); - goto ramp_down; + "%s: Impedance detect calculation error, zcode=0x%x\n", + __func__, zcode); + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, + 0x20, 0x00); + return; } - d1 = d1_a[c1]; - denom = (x1 * d1) - (1 << (14 - noff)); + zcode = zcode << 0x8; + zcode = zcode & 0x3FFF; + regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &zcode1); + zcode |= zcode1; + + dev_dbg(rouleur->dev, + "%s: zcode: %d, zcode1: %d\n", __func__, zcode, zcode1); + + /* Calculate calibration coefficient */ + zdet_cal_result = (snd_soc_component_read32(component, + ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)) & 0x1F; + zdet_cal_coeff = ROULEUR_ZDET_C1 / + ((ROULEUR_ZDET_C2 * zdet_cal_result) + ROULEUR_ZDET_C3); + /* Rload calculation */ + zdet_est_range = (snd_soc_component_read32(component, + ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT) & 0x60) >> 5; + + dev_dbg(rouleur->dev, + "%s: zdet_cal_result: %d, zdet_cal_coeff: %d, zdet_est_range: %d\n", + __func__, zdet_cal_result, zdet_cal_coeff, zdet_est_range); + switch (zdet_est_range) { + case 0: + default: + noff = 0; + div_ratio = 320; + break; + case 1: + noff = 0; + div_ratio = 64; + break; + case 2: + noff = 4; + div_ratio = 64; + break; + case 3: + noff = 5; + div_ratio = 40; + break; + } + + num = zdet_cal_coeff * ROULEUR_ZDET_RMAX; + denom = ((zcode * div_ratio * 100) - (1 << (ndac - noff)) * 1000); + dev_dbg(rouleur->dev, + "%s: num: %d, denom: %d\n", __func__, num, denom); if (denom > 0) - *zdet = (ROULEUR_MBHC_ZDET_CONST * 1000) / denom; - else if (x1 < minCode_param[noff]) + *zdet = (int32_t) ((num / denom) * 1000); + else *zdet = ROULEUR_ZDET_FLOATING_IMPEDANCE; - dev_dbg(rouleur->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", - __func__, d1, c1, x1, *zdet); -ramp_down: - i = 0; - while (x1) { - regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_1, &val); - regmap_read(rouleur->regmap, ROULEUR_ANA_MBHC_RESULT_2, &val1); - val = val << 0x8; - val |= val1; - x1 = ROULEUR_MBHC_GET_X1(val); - i++; - if (i == ROULEUR_ZDET_NUM_MEASUREMENTS) - break; - } + dev_dbg(rouleur->dev, "%s: z_val=%d(milliOhm)\n", + __func__, *zdet); + /* Start discharge */ + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x20, 0x00); } -#if 0 -static void rouleur_mbhc_zdet_ramp(struct snd_soc_component *component, - struct rouleur_mbhc_zdet_param *zdet_param, - int32_t *zl, int32_t *zr, s16 *d1_a) +static void rouleur_mbhc_zdet_start(struct snd_soc_component *component, + int32_t *zl, int32_t *zr) { struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); int32_t zdet = 0; - snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL, - 0x70, zdet_param->ldo_ctl << 4); - snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN5, 0xFC, - zdet_param->btn5); - snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN6, 0xFC, - zdet_param->btn6); - snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_BTN7, 0xFC, - zdet_param->btn7); - snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL, - 0x0F, zdet_param->noff); - snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ZDET_RAMP_CTL, - 0x0F, zdet_param->nshift); - if (!zl) goto z_right; - /* Start impedance measurement for HPH_L */ + + /* HPHL pull down switch to force OFF */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x30, 0x00); + /* Averaging enable for reliable results */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x80); + /* ZDET left measurement enable */ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x80, 0x80); - dev_dbg(rouleur->dev, "%s: ramp for HPH_L, noff = %d\n", - __func__, zdet_param->noff); - rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet); + /* Calculate the left Rload result */ + rouleur_mbhc_get_result_params(rouleur, component, &zdet); + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x80, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x30, 0x20); *zl = zdet; z_right: if (!zr) return; - /* Start impedance measurement for HPH_R */ + /* HPHR pull down switch to force OFF */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x0C, 0x00); + /* Averaging enable for reliable results */ + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x80); + /* ZDET right measurement enable */ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x40, 0x40); - dev_dbg(rouleur->dev, "%s: ramp for HPH_R, noff = %d\n", - __func__, zdet_param->noff); - rouleur_mbhc_get_result_params(rouleur, d1_a, zdet_param->noff, &zdet); + + /* Calculate the right Rload result */ + rouleur_mbhc_get_result_params(rouleur, component, &zdet); + regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ZDET, 0x40, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_MBHC_ZDET_ANA_CTL, 0x80, 0x00); + regmap_update_bits(rouleur->regmap, + ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x0C, 0x08); *zr = zdet; } -static inline void rouleur_wcd_mbhc_qfuse_cal( - struct snd_soc_component *component, - int32_t *z_val, int flag_l_r) -{ - s16 q1; - int q1_cal; - - if (*z_val < (ROULEUR_ZDET_VAL_400/1000)) - q1 = snd_soc_component_read32(component, - ROULEUR_DIGITAL_EFUSE_REG_23 + (2 * flag_l_r)); - else - q1 = snd_soc_component_read32(component, - ROULEUR_DIGITAL_EFUSE_REG_24 + (2 * flag_l_r)); - if (q1 & 0x80) - q1_cal = (10000 - ((q1 & 0x7F) * 25)); - else - q1_cal = (10000 + (q1 * 25)); - if (q1_cal > 0) - *z_val = ((*z_val) * 10000) / q1_cal; -} - static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) { struct snd_soc_component *component = mbhc->component; struct rouleur_priv *rouleur = dev_get_drvdata(component->dev); - s16 reg0, reg1, reg2, reg3, reg4; + s16 reg0; int32_t z1L, z1R, z1Ls; int zMono, z_diff1, z_diff2; bool is_fsm_disable = false; - struct rouleur_mbhc_zdet_param zdet_param[] = { - {4, 0, 4, 0x08, 0x14, 0x18}, /* < 32ohm */ - {2, 0, 3, 0x18, 0x7C, 0x90}, /* 32ohm < Z < 400ohm */ - {1, 4, 5, 0x18, 0x7C, 0x90}, /* 400ohm < Z < 1200ohm */ - {1, 6, 7, 0x18, 0x7C, 0x90}, /* >1200ohm */ - }; - struct rouleur_mbhc_zdet_param *zdet_param_ptr = NULL; - s16 d1_a[][4] = { - {0, 30, 90, 30}, - {0, 30, 30, 5}, - {0, 30, 30, 5}, - {0, 30, 30, 5}, - }; - s16 *d1 = NULL; WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); - reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN5); - reg1 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN6); - reg2 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_BTN7); - reg3 = snd_soc_component_read32(component, ROULEUR_MBHC_CTL_CLK); - reg4 = snd_soc_component_read32(component, - ROULEUR_ANA_MBHC_ZDET_ANA_CTL); + reg0 = snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT); - if (snd_soc_component_read32(component, ROULEUR_ANA_MBHC_ELECT) & - 0x80) { + if (reg0 & 0x80) { is_fsm_disable = true; regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ELECT, 0x80, 0x00); } + /* Enable electrical bias */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, + 0x01, 0x01); + + /* Enable codec main bias */ + rouleur_global_mbias_enable(component); + + /* Enable RCO clock */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_CTL_1, + 0x80, 0x80); + /* For NO-jack, disable L_DET_EN before Z-det measurements */ if (mbhc->hphl_swh) regmap_update_bits(rouleur->regmap, @@ -553,79 +555,34 @@ static void rouleur_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_MECH, 0x01, 0x00); - /* Disable surge protection before impedance detection. + /* + * Disable surge protection before impedance detection. * This is done to give correct value for high impedance. */ - regmap_update_bits(rouleur->regmap, - ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0x00); + snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN, + 0xC0, 0x00); /* 1ms delay needed after disable surge protection */ usleep_range(1000, 1010); - /* First get impedance on Left */ - d1 = d1_a[1]; - zdet_param_ptr = &zdet_param[1]; - rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); - - if (!ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1L)) - goto left_ch_impedance; - - /* Second ramp for left ch */ - if (z1L < ROULEUR_ZDET_VAL_32) { - zdet_param_ptr = &zdet_param[0]; - d1 = d1_a[0]; - } else if ((z1L > ROULEUR_ZDET_VAL_400) && - (z1L <= ROULEUR_ZDET_VAL_1200)) { - zdet_param_ptr = &zdet_param[2]; - d1 = d1_a[2]; - } else if (z1L > ROULEUR_ZDET_VAL_1200) { - zdet_param_ptr = &zdet_param[3]; - d1 = d1_a[3]; - } - rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, &z1L, NULL, d1); - -left_ch_impedance: + /* Start of left ch impedance calculation */ + rouleur_mbhc_zdet_start(component, &z1L, NULL); if ((z1L == ROULEUR_ZDET_FLOATING_IMPEDANCE) || - (z1L > ROULEUR_ZDET_VAL_100K)) { + (z1L > ROULEUR_ZDET_VAL_100K)) *zl = ROULEUR_ZDET_FLOATING_IMPEDANCE; - zdet_param_ptr = &zdet_param[1]; - d1 = d1_a[1]; - } else { + else *zl = z1L/1000; - rouleur_wcd_mbhc_qfuse_cal(component, zl, 0); - } + dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", __func__, *zl); - /* Start of right impedance ramp and calculation */ - rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, &z1R, d1); - if (ROULEUR_MBHC_IS_SECOND_RAMP_REQUIRED(z1R)) { - if (((z1R > ROULEUR_ZDET_VAL_1200) && - (zdet_param_ptr->noff == 0x6)) || - ((*zl) != ROULEUR_ZDET_FLOATING_IMPEDANCE)) - goto right_ch_impedance; - /* Second ramp for right ch */ - if (z1R < ROULEUR_ZDET_VAL_32) { - zdet_param_ptr = &zdet_param[0]; - d1 = d1_a[0]; - } else if ((z1R > ROULEUR_ZDET_VAL_400) && - (z1R <= ROULEUR_ZDET_VAL_1200)) { - zdet_param_ptr = &zdet_param[2]; - d1 = d1_a[2]; - } else if (z1R > ROULEUR_ZDET_VAL_1200) { - zdet_param_ptr = &zdet_param[3]; - d1 = d1_a[3]; - } - rouleur_mbhc_zdet_ramp(component, zdet_param_ptr, NULL, - &z1R, d1); - } -right_ch_impedance: + /* Start of right ch impedance calculation */ + rouleur_mbhc_zdet_start(component, NULL, &z1R); if ((z1R == ROULEUR_ZDET_FLOATING_IMPEDANCE) || - (z1R > ROULEUR_ZDET_VAL_100K)) { + (z1R > ROULEUR_ZDET_VAL_100K)) *zr = ROULEUR_ZDET_FLOATING_IMPEDANCE; - } else { + else *zr = z1R/1000; - rouleur_wcd_mbhc_qfuse_cal(component, zr, 1); - } + dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", __func__, *zr); @@ -647,24 +604,10 @@ right_ch_impedance: mbhc->hph_type = WCD_MBHC_HPH_MONO; goto zdet_complete; } - snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST, - 0x02, 0x02); - snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2, - 0x40, 0x01); - if (*zl < (ROULEUR_ZDET_VAL_32/1000)) - rouleur_mbhc_zdet_ramp(component, &zdet_param[0], &z1Ls, - NULL, d1); - else - rouleur_mbhc_zdet_ramp(component, &zdet_param[1], &z1Ls, - NULL, d1); - snd_soc_component_update_bits(component, ROULEUR_HPH_PA_CTL2, - 0x40, 0x00); - snd_soc_component_update_bits(component, ROULEUR_HPH_R_ATEST, - 0x02, 0x00); - z1Ls /= 1000; - rouleur_wcd_mbhc_qfuse_cal(component, &z1Ls, 0); - /* Parallel of left Z and 9 ohm pull down resistor */ - zMono = ((*zl) * 9) / ((*zl) + 9); + + z1Ls = z1L/1000; + /* Parallel of left Z and 20 ohm pull down resistor */ + zMono = ((*zl) * 20) / ((*zl) + 20); z_diff1 = (z1Ls > zMono) ? (z1Ls - zMono) : (zMono - z1Ls); z_diff2 = ((*zl) > z1Ls) ? ((*zl) - z1Ls) : (z1Ls - (*zl)); if ((z_diff1 * (*zl + z1Ls)) > (z_diff2 * (z1Ls + zMono))) { @@ -677,13 +620,10 @@ right_ch_impedance: mbhc->hph_type = WCD_MBHC_HPH_MONO; } +zdet_complete: /* Enable surge protection again after impedance detection */ regmap_update_bits(rouleur->regmap, - ROULEUR_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); -zdet_complete: - snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN5, reg0); - snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN6, reg1); - snd_soc_component_write(component, ROULEUR_ANA_MBHC_BTN7, reg2); + ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0); /* Turn on 100k pull down on HPHL */ regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_MECH, 0x01, 0x01); @@ -693,13 +633,14 @@ zdet_complete: regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_MECH, 0x80, 0x80); - snd_soc_component_write(component, ROULEUR_ANA_MBHC_ZDET_ANA_CTL, reg4); - snd_soc_component_write(component, ROULEUR_MBHC_CTL_CLK, reg3); + /* Restore electrical bias state */ + snd_soc_component_update_bits(component, ROULEUR_ANA_MBHC_ELECT, 0x01, + reg0 >> 7); if (is_fsm_disable) regmap_update_bits(rouleur->regmap, ROULEUR_ANA_MBHC_ELECT, 0x80, 0x80); + rouleur_global_mbias_disable(component); } -#endif static void rouleur_mbhc_gnd_det_ctrl(struct snd_soc_component *component, bool enable) @@ -723,10 +664,10 @@ static void rouleur_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, if (enable) { snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_CNP_CTL_2, - 0x30, 0x10); + 0x30, 0x20); snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_CNP_CTL_2, - 0x0C, 0x04); + 0x0C, 0x08); } else { snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_CNP_CTL_2, @@ -820,6 +761,54 @@ static void rouleur_mbhc_bcs_enable(struct wcd_mbhc *mbhc, rouleur_disable_bcs_before_slow_insert(mbhc->component, true); } +static void rouleur_mbhc_get_micbias_val(struct wcd_mbhc *mbhc, int *mb) +{ + u8 vout_ctl = 0; + + /* Read MBHC Micbias (Mic Bias2) voltage */ + WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl); + + /* Formula for getting micbias from vout + * micbias = 1.6V + VOUT_CTL * 50mV + */ + *mb = 1600 + (vout_ctl * 50); + pr_debug("%s: vout_ctl: %d, micbias: %d\n", __func__, vout_ctl, *mb); +} + +static void rouleur_mbhc_comp_autozero_control(struct wcd_mbhc *mbhc, + bool az_enable) +{ + if (az_enable) + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_MBHC_CTL_CLK, 0x08, 0x08); + else + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_MBHC_CTL_CLK, 0x08, 0x00); + +} + +static void rouleur_mbhc_surge_control(struct wcd_mbhc *mbhc, + bool surge_enable) +{ + if (surge_enable) + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0); + else + snd_soc_component_update_bits(mbhc->component, + ROULEUR_ANA_SURGE_EN, 0xC0, 0x00); + +} + +static void rouleur_mbhc_update_cross_conn_thr(struct wcd_mbhc *mbhc) +{ + mbhc->hphl_cross_conn_thr = ROULEUR_HPHL_CROSS_CONN_THRESHOLD; + mbhc->hphr_cross_conn_thr = ROULEUR_HPHR_CROSS_CONN_THRESHOLD; + + pr_debug("%s: Cross connection threshold for hphl: %d, hphr: %d\n", + __func__, mbhc->hphl_cross_conn_thr, + mbhc->hphr_cross_conn_thr); +} + static const struct wcd_mbhc_cb mbhc_cb = { .request_irq = rouleur_mbhc_request_irq, .irq_control = rouleur_mbhc_irq_control, @@ -837,13 +826,17 @@ static const struct wcd_mbhc_cb mbhc_cb = { .mbhc_micb_ramp_control = rouleur_mbhc_micb_ramp_control, .get_hwdep_fw_cal = rouleur_get_hwdep_fw_cal, .mbhc_micb_ctrl_thr_mic = rouleur_mbhc_micb_ctrl_threshold_mic, - //.compute_impedance = rouleur_wcd_mbhc_calc_impedance, + .compute_impedance = rouleur_wcd_mbhc_calc_impedance, .mbhc_gnd_det_ctrl = rouleur_mbhc_gnd_det_ctrl, .hph_pull_down_ctrl = rouleur_mbhc_hph_pull_down_ctrl, .mbhc_moisture_config = rouleur_mbhc_moisture_config, .mbhc_get_moisture_status = rouleur_mbhc_get_moisture_status, .mbhc_moisture_detect_en = rouleur_mbhc_moisture_detect_en, .bcs_enable = rouleur_mbhc_bcs_enable, + .get_micbias_val = rouleur_mbhc_get_micbias_val, + .mbhc_comp_autozero_control = rouleur_mbhc_comp_autozero_control, + .mbhc_surge_ctl = rouleur_mbhc_surge_control, + .update_cross_conn_thr = rouleur_mbhc_update_cross_conn_thr, }; static int rouleur_get_hph_type(struct snd_kcontrol *kcontrol, diff --git a/asoc/codecs/rouleur/rouleur-registers.h b/asoc/codecs/rouleur/rouleur-registers.h index 816e49237d..8cc0ae473a 100644 --- a/asoc/codecs/rouleur/rouleur-registers.h +++ b/asoc/codecs/rouleur/rouleur-registers.h @@ -45,7 +45,7 @@ enum { #define ROULEUR_ANA_MBHC_ZDET_RAMP_CTL (ROULEUR_ANA_BASE_ADDR+0x06A) #define ROULEUR_ANA_MBHC_FSM_STATUS (ROULEUR_ANA_BASE_ADDR+0x06B) #define ROULEUR_ANA_MBHC_ADC_RESULT (ROULEUR_ANA_BASE_ADDR+0x06C) -#define ROULEUR_ANA_MBHC_MCLK (ROULEUR_ANA_BASE_ADDR+0x06D) +#define ROULEUR_ANA_MBHC_CTL_CLK (ROULEUR_ANA_BASE_ADDR+0x06D) #define ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT (ROULEUR_ANA_BASE_ADDR+0x072) #define ROULEUR_ANA_NCP_EN (ROULEUR_ANA_BASE_ADDR+0x077) #define ROULEUR_ANA_HPHPA_CNP_CTL_1 (ROULEUR_ANA_BASE_ADDR+0x083) diff --git a/asoc/codecs/rouleur/rouleur-regmap.c b/asoc/codecs/rouleur/rouleur-regmap.c index 71e5e1901f..23b8ddc967 100644 --- a/asoc/codecs/rouleur/rouleur-regmap.c +++ b/asoc/codecs/rouleur/rouleur-regmap.c @@ -38,13 +38,15 @@ static const struct reg_default rouleur_defaults[] = { { ROULEUR_ANA_MBHC_ZDET_RAMP_CTL, 0x00 }, { ROULEUR_ANA_MBHC_FSM_STATUS, 0x00 }, { ROULEUR_ANA_MBHC_ADC_RESULT, 0x00 }, - { ROULEUR_ANA_MBHC_MCLK, 0x30 }, + { ROULEUR_ANA_MBHC_CTL_CLK, 0x30 }, { ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 }, { ROULEUR_ANA_NCP_EN, 0x00 }, { ROULEUR_ANA_HPHPA_CNP_CTL_1, 0x54 }, { ROULEUR_ANA_HPHPA_CNP_CTL_2, 0x2B }, { ROULEUR_ANA_HPHPA_PA_STATUS, 0x00 }, { ROULEUR_ANA_HPHPA_FSM_CLK, 0x12 }, + { ROULEUR_ANA_HPHPA_L_GAIN, 0x00 }, + { ROULEUR_ANA_HPHPA_R_GAIN, 0x00 }, { ROULEUR_SWR_HPHPA_HD2, 0x1B }, { ROULEUR_ANA_HPHPA_SPARE_CTL, 0x02 }, { ROULEUR_ANA_SURGE_EN, 0x38 }, diff --git a/asoc/codecs/rouleur/rouleur-tables.c b/asoc/codecs/rouleur/rouleur-tables.c index ba2fa9a40a..7912267dac 100644 --- a/asoc/codecs/rouleur/rouleur-tables.c +++ b/asoc/codecs/rouleur/rouleur-tables.c @@ -33,13 +33,15 @@ const u8 rouleur_reg_access_analog[ROULEUR_REG( [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_RAMP_CTL)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_MBHC_FSM_STATUS)] = RD_REG, [ROULEUR_REG(ROULEUR_ANA_MBHC_ADC_RESULT)] = RD_REG, - [ROULEUR_REG(ROULEUR_ANA_MBHC_MCLK)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_MBHC_CTL_CLK)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_MBHC_ZDET_CALIB_RESULT)] = RD_REG, [ROULEUR_REG(ROULEUR_ANA_NCP_EN)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_1)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_CNP_CTL_2)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_PA_STATUS)] = RD_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_FSM_CLK)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_L_GAIN)] = RD_WR_REG, + [ROULEUR_REG(ROULEUR_ANA_HPHPA_R_GAIN)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_HPHPA_SPARE_CTL)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_SWR_HPHPA_HD2)] = RD_WR_REG, [ROULEUR_REG(ROULEUR_ANA_SURGE_EN)] = RD_WR_REG, diff --git a/asoc/codecs/rouleur/rouleur.c b/asoc/codecs/rouleur/rouleur.c index d028ed48b5..d2cf31a510 100644 --- a/asoc/codecs/rouleur/rouleur.c +++ b/asoc/codecs/rouleur/rouleur.c @@ -46,6 +46,7 @@ enum { HPH_COMP_DELAY, HPH_PA_DELAY, AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, }; /* TODO: Check on the step values */ @@ -107,6 +108,9 @@ static int rouleur_handle_post_irq(void *data) static int rouleur_init_reg(struct snd_soc_component *component) { + /* Disable HPH OCP */ + snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_CNP_CTL_2, + 0x03, 0x00); /* Enable surge protection */ snd_soc_component_update_bits(component, ROULEUR_ANA_SURGE_EN, 0xC0, 0xC0); @@ -301,7 +305,7 @@ static int rouleur_rx_connect_port(struct snd_soc_component *component, return ret; } -static int rouleur_global_mbias_enable(struct snd_soc_component *component) +int rouleur_global_mbias_enable(struct snd_soc_component *component) { struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); @@ -319,7 +323,7 @@ static int rouleur_global_mbias_enable(struct snd_soc_component *component) return 0; } -static int rouleur_global_mbias_disable(struct snd_soc_component *component) +int rouleur_global_mbias_disable(struct snd_soc_component *component) { struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); @@ -354,7 +358,7 @@ static int rouleur_rx_clk_enable(struct snd_soc_component *component) usleep_range(5000, 5100); rouleur_global_mbias_enable(component); snd_soc_component_update_bits(component, - ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x11); + ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x11); snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x80); snd_soc_component_update_bits(component, @@ -382,14 +386,14 @@ static int rouleur_rx_clk_disable(struct snd_soc_component *component) snd_soc_component_update_bits(component, ROULEUR_ANA_HPHPA_FSM_CLK, 0x80, 0x00); snd_soc_component_update_bits(component, - ROULEUR_ANA_HPHPA_FSM_CLK, 0x11, 0x00); + ROULEUR_ANA_HPHPA_FSM_CLK, 0x7F, 0x00); snd_soc_component_update_bits(component, ROULEUR_ANA_NCP_EN, 0x01, 0x00); - rouleur_global_mbias_disable(component); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x20, 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x10, 0x00); + rouleur_global_mbias_disable(component); } mutex_unlock(&rouleur->rx_clk_lock); @@ -469,23 +473,27 @@ static int rouleur_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, } snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX0_CTL, - 0x7C, 0x7C); + 0x80, 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, 0x04, 0x04); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x01); - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_PDM_WD_CTL0, - 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMD: snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_PDM_WD_CTL0, - 0x03, 0x00); + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, + 0x01, 0x00); snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, - 0x01, 0x00); + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX0_CTL, + 0x80, 0x80); + if (rouleur->comp1_enable) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x02, 0x00); break; } @@ -540,22 +548,26 @@ static int rouleur_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, } snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX1_CTL, - 0x7C, 0x7C); + 0x80, 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, 0x08, 0x08); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x02); - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_PDM_WD_CTL1, - 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_PDM_WD_CTL1, - 0x03, 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x02, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x08, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX1_CTL, + 0x80, 0x80); + if (rouleur->comp2_enable) + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_COMP_CTL_0, + 0x01, 0x00); break; } @@ -578,25 +590,25 @@ static int rouleur_codec_ear_lo_dac_event(struct snd_soc_dapm_widget *w, rouleur_rx_clk_enable(component); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX0_CTL, - 0x7C, 0x7C); - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, - 0x01, 0x01); - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_PDM_WD_CTL0, - 0x03, 0x03); + 0x80, 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, 0x04, 0x04); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, + 0x01, 0x01); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - ROULEUR_DIG_SWR_PDM_WD_CTL0, - 0x03, 0x00); snd_soc_component_update_bits(component, ROULEUR_DIG_SWR_CDC_RX_CLK_CTL, 0x01, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX_GAIN_CTL, + 0x04, 0x00); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_CDC_RX0_CTL, + 0x80, 0x80); break; }; @@ -622,14 +634,11 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, rouleur->rx_swr_dev->dev_num, true); - snd_soc_component_update_bits(component, - ROULEUR_ANA_HPHPA_CNP_CTL_2, - 0x40, 0x40); set_bit(HPH_PA_DELAY, &rouleur->status_mask); - /* TODO: WHY SECOND TIME */ - ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, - rouleur->rx_swr_dev->dev_num, - true); + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL1, + 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMU: /* @@ -676,8 +685,8 @@ static int rouleur_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, WCD_EVENT_POST_HPHR_PA_OFF, &rouleur->mbhc->wcd_mbhc); snd_soc_component_update_bits(component, - ROULEUR_ANA_HPHPA_CNP_CTL_2, - 0x40, 0x00); + ROULEUR_DIG_SWR_PDM_WD_CTL1, + 0x03, 0x00); break; }; return ret; @@ -700,10 +709,11 @@ static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, rouleur->rx_swr_dev->dev_num, true); - snd_soc_component_update_bits(component, - ROULEUR_ANA_HPHPA_CNP_CTL_2, - 0x80, 0x80); set_bit(HPH_PA_DELAY, &rouleur->status_mask); + usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMU: /* @@ -748,8 +758,8 @@ static int rouleur_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, WCD_EVENT_POST_HPHL_PA_OFF, &rouleur->mbhc->wcd_mbhc); snd_soc_component_update_bits(component, - ROULEUR_ANA_HPHPA_CNP_CTL_2, - 0x80, 0x00); + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x00); break; }; @@ -773,10 +783,10 @@ static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, rouleur->rx_swr_dev->dev_num, true); - snd_soc_component_update_bits(component, - ROULEUR_ANA_COMBOPA_CTL, - 0x80, 0x80); usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMU: if (rouleur->update_wcd_event) @@ -795,10 +805,10 @@ static int rouleur_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, (WCD_RX1 << 0x10 | 0x1)); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - ROULEUR_ANA_COMBOPA_CTL, - 0x80, 0x00); usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x00); }; return ret; } @@ -823,10 +833,10 @@ static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(component, ROULEUR_ANA_COMBOPA_CTL, 0x40, 0x40); - snd_soc_component_update_bits(component, - ROULEUR_ANA_COMBOPA_CTL, - 0x80, 0x80); usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x03); break; case SND_SOC_DAPM_POST_PMU: if (rouleur->update_wcd_event) @@ -845,13 +855,13 @@ static int rouleur_codec_enable_lo_pa(struct snd_soc_dapm_widget *w, (WCD_RX1 << 0x10 | 0x1)); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - ROULEUR_ANA_COMBOPA_CTL, - 0x80, 0x00); snd_soc_component_update_bits(component, ROULEUR_ANA_COMBOPA_CTL, 0x40, 0x00); usleep_range(5000, 5100); + snd_soc_component_update_bits(component, + ROULEUR_DIG_SWR_PDM_WD_CTL0, + 0x03, 0x00); }; return ret; } @@ -1166,6 +1176,7 @@ int rouleur_micbias_control(struct snd_soc_component *component, int post_on_event = 0, post_dapm_off = 0; int post_dapm_on = 0; u8 pullup_mask = 0, enable_mask = 0; + int ret = 0; if ((micb_index < 0) || (micb_index > ROULEUR_MAX_MICBIAS - 1)) { dev_err(component->dev, "%s: Invalid micbias index, micb_ind:%d\n", @@ -1201,6 +1212,12 @@ int rouleur_micbias_control(struct snd_soc_component *component, switch (req) { case MICB_PULLUP_ENABLE: + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } rouleur->pullup_ref[micb_index]++; if ((rouleur->pullup_ref[micb_index] == 1) && (rouleur->micb_ref[micb_index] == 0)) @@ -1208,6 +1225,12 @@ int rouleur_micbias_control(struct snd_soc_component *component, pullup_mask, pullup_mask); break; case MICB_PULLUP_DISABLE: + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } if (rouleur->pullup_ref[micb_index] > 0) rouleur->pullup_ref[micb_index]--; if ((rouleur->pullup_ref[micb_index] == 0) && @@ -1216,11 +1239,15 @@ int rouleur_micbias_control(struct snd_soc_component *component, pullup_mask, 0x00); break; case MICB_ENABLE: + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } rouleur->micb_ref[micb_index]++; if (rouleur->micb_ref[micb_index] == 1) { rouleur_global_mbias_enable(component); - snd_soc_component_update_bits(component, micb_reg, - 0x80, 0x80); snd_soc_component_update_bits(component, micb_reg, enable_mask, enable_mask); if (post_on_event) @@ -1236,16 +1263,27 @@ int rouleur_micbias_control(struct snd_soc_component *component, case MICB_DISABLE: if (rouleur->micb_ref[micb_index] > 0) rouleur->micb_ref[micb_index]--; + if (!rouleur->dev_up) { + dev_dbg(component->dev, "%s: enable req %d wcd device down\n", + __func__, req); + ret = -ENODEV; + goto done; + } if ((rouleur->micb_ref[micb_index] == 0) && - (rouleur->pullup_ref[micb_index] == 0)) { + (rouleur->pullup_ref[micb_index] > 0)) { + snd_soc_component_update_bits(component, micb_reg, + pullup_mask, pullup_mask); + snd_soc_component_update_bits(component, micb_reg, + enable_mask, 0x00); + rouleur_global_mbias_disable(component); + } else if ((rouleur->micb_ref[micb_index] == 0) && + (rouleur->pullup_ref[micb_index] == 0)) { if (pre_off_event && rouleur->mbhc) blocking_notifier_call_chain( &rouleur->mbhc->notifier, pre_off_event, &rouleur->mbhc->wcd_mbhc); snd_soc_component_update_bits(component, micb_reg, enable_mask, 0x00); - snd_soc_component_update_bits(component, micb_reg, - 0x80, 0x00); rouleur_global_mbias_disable(component); if (post_off_event && rouleur->mbhc) blocking_notifier_call_chain( @@ -1263,8 +1301,8 @@ int rouleur_micbias_control(struct snd_soc_component *component, dev_dbg(component->dev, "%s: micb_num:%d, micb_ref: %d, pullup_ref: %d\n", __func__, micb_num, rouleur->micb_ref[micb_index], rouleur->pullup_ref[micb_index]); +done: mutex_unlock(&rouleur->micb_lock); - return 0; } EXPORT_SYMBOL(rouleur_micbias_control); @@ -1304,6 +1342,17 @@ static int rouleur_get_logical_addr(struct swr_device *swr_dev) return 0; } +static bool get_usbc_hs_status(struct snd_soc_component *component, + struct wcd_mbhc_config *mbhc_cfg) +{ + if (mbhc_cfg->enable_usbc_analog) { + if (!(snd_soc_component_read32(component, ROULEUR_ANA_MBHC_MECH) + & 0x20)) + return true; + } + return false; +} + static int rouleur_event_notify(struct notifier_block *block, unsigned long val, void *data) @@ -1333,8 +1382,11 @@ static int rouleur_event_notify(struct notifier_block *block, 0x80, 0x00); break; case BOLERO_WCD_EVT_SSR_DOWN: + rouleur->dev_up = false; rouleur->mbhc->wcd_mbhc.deinit_in_progress = true; mbhc = &rouleur->mbhc->wcd_mbhc; + rouleur->usbc_hs_status = get_usbc_hs_status(component, + mbhc->mbhc_cfg); rouleur_mbhc_ssr_down(rouleur->mbhc, component); rouleur_reset(rouleur->dev, 0x01); break; @@ -1356,8 +1408,11 @@ static int rouleur_event_notify(struct notifier_block *block, __func__); } else { rouleur_mbhc_hs_detect(component, mbhc->mbhc_cfg); + if (rouleur->usbc_hs_status) + mdelay(500); } rouleur->mbhc->wcd_mbhc.deinit_in_progress = false; + rouleur->dev_up = true; break; default: dev_err(component->dev, "%s: invalid event %d\n", __func__, @@ -1552,6 +1607,9 @@ static int rouleur_codec_enable_pa_vpos(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: set_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask); + ret = swr_slvdev_datapath_control(rouleur->rx_swr_dev, + rouleur->rx_swr_dev->dev_num, + false); break; } return 0; @@ -1822,7 +1880,7 @@ static ssize_t rouleur_version_read(struct snd_info_entry *entry, switch (priv->version) { case ROULEUR_VERSION_1_0: - len = snprintf(buffer, sizeof(buffer), "rouleur_1_0\n"); + len = snprintf(buffer, sizeof(buffer), "ROULEUR_1_0\n"); break; default: len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); @@ -1986,6 +2044,7 @@ static int rouleur_soc_codec_probe(struct snd_soc_component *component) return ret; } } + rouleur->dev_up = true; done: return ret; } @@ -2003,6 +2062,26 @@ static void rouleur_soc_codec_remove(struct snd_soc_component *component) false); } +static int rouleur_soc_codec_suspend(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) + return 0; + rouleur->dapm_bias_off = true; + return 0; +} + +static int rouleur_soc_codec_resume(struct snd_soc_component *component) +{ + struct rouleur_priv *rouleur = snd_soc_component_get_drvdata(component); + + if (!rouleur) + return 0; + rouleur->dapm_bias_off = false; + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_rouleur = { .name = DRV_NAME, .probe = rouleur_soc_codec_probe, @@ -2013,6 +2092,8 @@ static const struct snd_soc_component_driver soc_codec_dev_rouleur = { .num_dapm_widgets = ARRAY_SIZE(rouleur_dapm_widgets), .dapm_routes = rouleur_audio_map, .num_dapm_routes = ARRAY_SIZE(rouleur_audio_map), + .suspend = rouleur_soc_codec_suspend, + .resume = rouleur_soc_codec_resume, }; #ifdef CONFIG_PM_SLEEP @@ -2049,11 +2130,45 @@ static int rouleur_suspend(struct device *dev) } clear_bit(ALLOW_VPOS_DISABLE, &rouleur->status_mask); } + if (rouleur->dapm_bias_off) { + msm_cdc_set_supplies_lpm_mode(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask); + } return 0; } static int rouleur_resume(struct device *dev) { + struct rouleur_priv *rouleur = NULL; + struct rouleur_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + rouleur = dev_get_drvdata(dev); + if (!rouleur) + return -EINVAL; + + pdata = dev_get_platdata(rouleur->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask)) { + msm_cdc_set_supplies_lpm_mode(rouleur->dev, + rouleur->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &rouleur->status_mask); + } + return 0; } #endif @@ -2484,10 +2599,8 @@ static int rouleur_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static const struct dev_pm_ops rouleur_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS( - rouleur_suspend, - rouleur_resume - ) + .suspend_late = rouleur_suspend, + .resume_early = rouleur_resume }; #endif diff --git a/asoc/codecs/rouleur/rouleur_slave.c b/asoc/codecs/rouleur/rouleur_slave.c index 8fac8a6fbf..5ea4fe4522 100644 --- a/asoc/codecs/rouleur/rouleur_slave.c +++ b/asoc/codecs/rouleur/rouleur_slave.c @@ -11,15 +11,276 @@ #include #include +#ifdef CONFIG_DEBUG_FS +#include +#include + +#define SWR_SLV_MAX_REG_ADDR 0x2009 +#define SWR_SLV_START_REG_ADDR 0x40 +#define SWR_SLV_MAX_BUF_LEN 20 +#define BYTES_PER_LINE 12 +#define SWR_SLV_RD_BUF_LEN 8 +#define SWR_SLV_WR_BUF_LEN 32 +#define SWR_SLV_MAX_DEVICES 2 +#endif /* CONFIG_DEBUG_FS */ + struct rouleur_slave_priv { struct swr_device *swr_slave; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_rouleur_dent; + struct dentry *debugfs_peek; + struct dentry *debugfs_poke; + struct dentry *debugfs_reg_dump; + unsigned int read_data; +#endif }; +#ifdef CONFIG_DEBUG_FS +static int codec_debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static int get_parameters(char *buf, u32 *param1, int num_of_par) +{ + char *token = NULL; + int base = 0, cnt = 0; + + token = strsep(&buf, " "); + for (cnt = 0; cnt < num_of_par; cnt++) { + if (token) { + if ((token[1] == 'x') || (token[1] == 'X')) + base = 16; + else + base = 10; + + if (kstrtou32(token, base, ¶m1[cnt]) != 0) + return -EINVAL; + + token = strsep(&buf, " "); + } else { + return -EINVAL; + } + } + return 0; +} + +static bool is_swr_slv_reg_readable(int reg) +{ + int ret = true; + + if (((reg > 0x46) && (reg < 0x4A)) || + ((reg > 0x4A) && (reg < 0x50)) || + ((reg > 0x55) && (reg < 0xD0)) || + ((reg > 0xD0) && (reg < 0xE0)) || + ((reg > 0xE0) && (reg < 0xF0)) || + ((reg > 0xF0) && (reg < 0x100)) || + ((reg > 0x105) && (reg < 0x120)) || + ((reg > 0x205) && (reg < 0x220)) || + ((reg > 0x305) && (reg < 0x320)) || + ((reg > 0x405) && (reg < 0x420)) || + ((reg > 0x128) && (reg < 0x130)) || + ((reg > 0x228) && (reg < 0x230)) || + ((reg > 0x328) && (reg < 0x330)) || + ((reg > 0x428) && (reg < 0x430)) || + ((reg > 0x138) && (reg < 0x205)) || + ((reg > 0x238) && (reg < 0x305)) || + ((reg > 0x338) && (reg < 0x405)) || + ((reg > 0x405) && (reg < 0xF00)) || + ((reg > 0xF05) && (reg < 0xF20)) || + ((reg > 0xF25) && (reg < 0xF30)) || + ((reg > 0xF35) && (reg < 0x2000))) + ret = false; + + return ret; +} + +static ssize_t rouleur_swrslave_reg_show(struct swr_device *pdev, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + int i, reg_val, len; + ssize_t total = 0; + char tmp_buf[SWR_SLV_MAX_BUF_LEN]; + + if (!ubuf || !ppos) + return 0; + + for (i = (((int) *ppos/BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR); + i <= SWR_SLV_MAX_REG_ADDR; i++) { + if (!is_swr_slv_reg_readable(i)) + continue; + swr_read(pdev, pdev->dev_num, i, ®_val, 1); + len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, + (reg_val & 0xFF)); + if (len < 0) { + pr_err("%s: fail to fill the buffer\n", __func__); + total = -EFAULT; + goto copy_err; + } + if (((total + len) >= count - 1) || (len < 0)) + break; + if (copy_to_user((ubuf + total), tmp_buf, len)) { + pr_err("%s: fail to copy reg dump\n", __func__); + total = -EFAULT; + goto copy_err; + } + total += len; + *ppos += len; + } + +copy_err: + *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE; + return total; +} + +static ssize_t codec_debug_dump(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct swr_device *pdev; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + return rouleur_swrslave_reg_show(pdev, ubuf, count, ppos); +} + +static ssize_t codec_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char lbuf[SWR_SLV_RD_BUF_LEN]; + struct swr_device *pdev = NULL; + struct rouleur_slave_priv *rouleur_slave = NULL; + + if (!count || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + rouleur_slave = swr_get_dev_data(pdev); + if (!rouleur_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + snprintf(lbuf, sizeof(lbuf), "0x%x\n", + (rouleur_slave->read_data & 0xFF)); + + return simple_read_from_buffer(ubuf, count, ppos, lbuf, + strnlen(lbuf, 7)); +} + +static ssize_t codec_debug_peek_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev = NULL; + struct rouleur_slave_priv *rouleur_slave = NULL; + + if (!cnt || !file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + rouleur_slave = swr_get_dev_data(pdev); + if (!rouleur_slave) + return -EINVAL; + + if (*ppos < 0) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 1); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))) + return -EINVAL; + swr_read(pdev, pdev->dev_num, param[0], &rouleur_slave->read_data, 1); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static ssize_t codec_debug_write(struct file *file, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char lbuf[SWR_SLV_WR_BUF_LEN]; + int rc = 0; + u32 param[5]; + struct swr_device *pdev; + + if (!file || !ppos || !ubuf) + return -EINVAL; + + pdev = file->private_data; + if (!pdev) + return -EINVAL; + + if (cnt > sizeof(lbuf) - 1) + return -EINVAL; + + rc = copy_from_user(lbuf, ubuf, cnt); + if (rc) + return -EFAULT; + + lbuf[cnt] = '\0'; + rc = get_parameters(lbuf, param, 2); + if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && + (param[1] <= 0xFF) && (rc == 0))) + return -EINVAL; + swr_write(pdev, pdev->dev_num, param[0], ¶m[1]); + if (rc == 0) + rc = cnt; + else + pr_err("%s: rc = %d\n", __func__, rc); + + return rc; +} + +static const struct file_operations codec_debug_write_ops = { + .open = codec_debug_open, + .write = codec_debug_write, +}; + +static const struct file_operations codec_debug_read_ops = { + .open = codec_debug_open, + .read = codec_debug_read, + .write = codec_debug_peek_write, +}; + +static const struct file_operations codec_debug_dump_ops = { + .open = codec_debug_open, + .read = codec_debug_dump, +}; +#endif + static int rouleur_slave_bind(struct device *dev, struct device *master, void *data) { int ret = 0; - struct rouleur_slave_priv *rouleur_slave = NULL; uint8_t devnum = 0; struct swr_device *pdev = to_swr_device(dev); @@ -28,15 +289,6 @@ static int rouleur_slave_bind(struct device *dev, return -EINVAL; } - rouleur_slave = devm_kzalloc(&pdev->dev, - sizeof(struct rouleur_slave_priv), GFP_KERNEL); - if (!rouleur_slave) - return -ENOMEM; - - swr_set_dev_data(pdev, rouleur_slave); - - rouleur_slave->swr_slave = pdev; - ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); if (ret) { dev_dbg(&pdev->dev, @@ -67,7 +319,6 @@ static void rouleur_slave_unbind(struct device *dev, return; } - swr_set_dev_data(pdev, NULL); } static const struct swr_device_id rouleur_swr_id[] = { @@ -104,12 +355,61 @@ static int rouleur_swr_reset(struct swr_device *pdev) static int rouleur_swr_probe(struct swr_device *pdev) { + struct rouleur_slave_priv *rouleur_slave = NULL; + + rouleur_slave = devm_kzalloc(&pdev->dev, + sizeof(struct rouleur_slave_priv), GFP_KERNEL); + if (!rouleur_slave) + return -ENOMEM; + + swr_set_dev_data(pdev, rouleur_slave); + + rouleur_slave->swr_slave = pdev; +#ifdef CONFIG_DEBUG_FS + if (!rouleur_slave->debugfs_rouleur_dent) { + rouleur_slave->debugfs_rouleur_dent = debugfs_create_dir( + dev_name(&pdev->dev), 0); + if (!IS_ERR(rouleur_slave->debugfs_rouleur_dent)) { + rouleur_slave->debugfs_peek = + debugfs_create_file("swrslave_peek", + S_IFREG | 0444, + rouleur_slave->debugfs_rouleur_dent, + (void *) pdev, + &codec_debug_read_ops); + + rouleur_slave->debugfs_poke = + debugfs_create_file("swrslave_poke", + S_IFREG | 0444, + rouleur_slave->debugfs_rouleur_dent, + (void *) pdev, + &codec_debug_write_ops); + + rouleur_slave->debugfs_reg_dump = + debugfs_create_file( + "swrslave_reg_dump", + S_IFREG | 0444, + rouleur_slave->debugfs_rouleur_dent, + (void *) pdev, + &codec_debug_dump_ops); + } + } +#endif return component_add(&pdev->dev, &rouleur_slave_comp_ops); } static int rouleur_swr_remove(struct swr_device *pdev) { +#ifdef CONFIG_DEBUG_FS + struct rouleur_slave_priv *rouleur_slave = swr_get_dev_data(pdev); + + if (rouleur_slave) { + debugfs_remove_recursive(rouleur_slave->debugfs_rouleur_dent); + rouleur_slave->debugfs_rouleur_dent = NULL; + } +#endif component_del(&pdev->dev, &rouleur_slave_comp_ops); + swr_set_dev_data(pdev, NULL); + swr_remove_device(pdev); return 0; } @@ -140,5 +440,5 @@ static void __exit rouleur_slave_exit(void) module_init(rouleur_slave_init); module_exit(rouleur_slave_exit); -MODULE_DESCRIPTION("WCD937X Swr Slave driver"); +MODULE_DESCRIPTION("Rouleur Swr Slave driver"); MODULE_LICENSE("GPL v2"); diff --git a/asoc/codecs/swr-dmic.c b/asoc/codecs/swr-dmic.c index 4f5b23c2f2..e7269e2729 100644 --- a/asoc/codecs/swr-dmic.c +++ b/asoc/codecs/swr-dmic.c @@ -30,6 +30,9 @@ #include "wcd938x/wcd938x.h" #include "swr-dmic.h" +#define NUM_ATTEMPTS 5 +#define SWRS_SCP_CONTROL 0x44 + static int swr_master_channel_map[] = { ZERO, SWRM_TX1_CH1, @@ -64,6 +67,7 @@ struct swr_dmic_priv { int is_en_supply; int port_type; u8 tx_master_port_map[SWR_DMIC_MAX_PORTS]; + struct notifier_block nblock; }; const char *codec_name_list[] = { @@ -243,38 +247,6 @@ static int dmic_swr_ctrl(struct snd_soc_dapm_widget *w, return ret; } -static int swr_dmic_enable_supply(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - struct swr_dmic_priv *swr_dmic = - snd_soc_component_get_drvdata(component); - int ret = 0; - - dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, - w->name, event); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - ret = swr_dmic_up(swr_dmic->swr_slave); - break; - case SND_SOC_DAPM_POST_PMU: - ret = swr_dmic_reset(swr_dmic->swr_slave); - break; - case SND_SOC_DAPM_POST_PMD: - ret = swr_dmic_down(swr_dmic->swr_slave); - break; - } - - if (ret) - dev_dbg(component->dev, "%s wname: %s event: %d ret : %d\n", - __func__, w->name, event, ret); - - return ret; -} - static const char * const tx_master_port_text[] = { "ZERO", "SWRM_TX1_CH1", "SWRM_TX1_CH2", "SWRM_TX1_CH3", "SWRM_TX1_CH4", "SWRM_TX2_CH1", "SWRM_TX2_CH2", "SWRM_TX2_CH3", "SWRM_TX2_CH4", @@ -304,10 +276,6 @@ static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = { SND_SOC_DAPM_INPUT("SWR_DMIC"), - SND_SOC_DAPM_SUPPLY_S("SMIC_SUPPLY", 1, SND_SOC_NOPM, 0, 0, - swr_dmic_enable_supply, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUT_DRV_E("SMIC_PORT_EN", SND_SOC_NOPM, 0, 0, NULL, 0, swr_dmic_port_enable, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), @@ -315,7 +283,6 @@ static const struct snd_soc_dapm_widget swr_dmic_dapm_widgets[] = { }; static const struct snd_soc_dapm_route swr_dmic_audio_map[] = { - {"SWR_DMIC", NULL, "SMIC_SUPPLY"}, {"SWR_DMIC_MIXER", "Switch", "SWR_DMIC"}, {"SMIC_PORT_EN", NULL, "SWR_DMIC_MIXER"}, {"SWR_DMIC_OUTPUT", NULL, "SMIC_PORT_EN"}, @@ -325,11 +292,38 @@ static int swr_dmic_codec_probe(struct snd_soc_component *component) { struct swr_dmic_priv *swr_dmic = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char w_name[100]; if (!swr_dmic) return -EINVAL; swr_dmic->component = component; + snd_soc_dapm_ignore_suspend(dapm, + swr_dmic->dai_driver->capture.stream_name); + memset(w_name, 0, 100); + strlcpy(w_name, component->name_prefix, 100); + strlcat(w_name, " SWR_DMIC", 100); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, 100); + strlcpy(w_name, component->name_prefix, 100); + strlcat(w_name, " SMIC_SUPPLY", 100); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, 100); + strlcpy(w_name, component->name_prefix, 100); + strlcat(w_name, " SMIC_PORT_EN", 100); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + memset(w_name, 0, 100); + strlcpy(w_name, component->name_prefix, 100); + strlcat(w_name, " SWR_DMIC_OUTPUT", 100); + snd_soc_dapm_ignore_suspend(dapm, w_name); + + snd_soc_dapm_sync(dapm); + return 0; } @@ -364,6 +358,8 @@ static int enable_wcd_codec_supply(struct swr_dmic_priv *swr_dmic, bool enable) pr_err("%s: component is NULL\n", __func__); return -EINVAL; } + dev_dbg(component->dev, "%s: supply %d micbias: %d enable: %d\n", + __func__, swr_dmic->is_en_supply, micb_num, enable); if (enable) rc = wcd938x_codec_force_enable_micbias_v2(component, @@ -412,6 +408,29 @@ static struct snd_soc_dai_driver swr_dmic_dai[] = { }, }; +static int swr_dmic_event_notify(struct notifier_block *block, + unsigned long val, + void *data) +{ + u16 event = (val & 0xffff); + int ret = 0; + struct swr_dmic_priv *swr_dmic = container_of(block, + struct swr_dmic_priv, + nblock); + switch (event) { + case WCD938X_EVT_SSR_DOWN: + ret = swr_dmic_down(swr_dmic->swr_slave); + break; + case WCD938X_EVT_SSR_UP: + ret = swr_dmic_up(swr_dmic->swr_slave); + if (!ret) + ret = swr_dmic_reset(swr_dmic->swr_slave); + break; + } + + return ret; +} + static int swr_dmic_probe(struct swr_device *pdev) { int ret = 0; @@ -423,6 +442,7 @@ static int swr_dmic_probe(struct swr_device *pdev) const char *swr_dmic_name_prefix_of = NULL; const char *swr_dmic_codec_name_of = NULL; struct snd_soc_component *component = NULL; + int num_retry = NUM_ATTEMPTS; swr_dmic = devm_kzalloc(&pdev->dev, sizeof(struct swr_dmic_priv), GFP_KERNEL); @@ -485,13 +505,18 @@ static int swr_dmic_probe(struct swr_device *pdev) * as per HW requirement. */ usleep_range(5000, 5010); - ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum); + do { + /* Add delay for soundwire enumeration */ + usleep_range(100, 110); + ret = swr_get_logical_dev_num(pdev, pdev->addr, &swr_devnum); + } while (ret && --num_retry); + if (ret) { - dev_dbg(&pdev->dev, - "%s get devnum %d for dev addr %lx failed\n", + dev_info(&pdev->dev, + "%s get devnum %d for dev addr %llx failed\n", __func__, swr_devnum, pdev->addr); ret = -EPROBE_DEFER; - goto err; + goto dev_err; } pdev->dev_num = swr_devnum; @@ -561,10 +586,9 @@ static int swr_dmic_probe(struct swr_device *pdev) strlen(swr_dmic_name_prefix_of) + 1); component->name_prefix = prefix_name; - if (swr_dmic->is_en_supply == 1) { - enable_wcd_codec_supply(swr_dmic, false); - --swr_dmic->is_en_supply; - } + swr_dmic->nblock.notifier_call = swr_dmic_event_notify; + wcd938x_swr_dmic_register_notifier(swr_dmic->supply_component, + &swr_dmic->nblock, true); return 0; @@ -589,7 +613,10 @@ static int swr_dmic_remove(struct swr_device *pdev) dev_err(&pdev->dev, "%s: swr_dmic is NULL\n", __func__); return -EINVAL; } - + if (swr_dmic->is_en_supply == 1) { + enable_wcd_codec_supply(swr_dmic, false); + --swr_dmic->is_en_supply; + } snd_soc_unregister_component(&pdev->dev); swr_set_dev_data(pdev, NULL); return 0; @@ -624,6 +651,8 @@ static int swr_dmic_down(struct swr_device *pdev) return -EINVAL; } + dev_dbg(&pdev->dev, "%s: is_en_supply: %d\n", + __func__, swr_dmic->is_en_supply); --swr_dmic->is_en_supply; if (swr_dmic->is_en_supply < 0) { dev_warn(&pdev->dev, "%s: mismatch in supply count %d\n", @@ -641,7 +670,7 @@ done: static int swr_dmic_reset(struct swr_device *pdev) { struct swr_dmic_priv *swr_dmic; - u8 retry = 5; + u8 retry = NUM_ATTEMPTS; u8 devnum = 0; swr_dmic = swr_get_dev_data(pdev); @@ -706,7 +735,6 @@ static struct swr_driver swr_dmic_driver = { .probe = swr_dmic_probe, .remove = swr_dmic_remove, .id_table = swr_dmic_id, - .device_down = swr_dmic_down, }; static int __init swr_dmic_init(void) diff --git a/asoc/codecs/swr-haptics.c b/asoc/codecs/swr-haptics.c index b4d3b17bc5..4e1a576930 100644 --- a/asoc/codecs/swr-haptics.c +++ b/asoc/codecs/swr-haptics.c @@ -186,12 +186,6 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_PRE_PMD: - swr_disconnect_port(swr_hap->swr_slave, &port_id, num_port, - &ch_mask, &port_type); - break; - case SND_SOC_DAPM_POST_PMD: - swr_slvdev_datapath_control(swr_hap->swr_slave, - swr_hap->swr_slave->dev_num, false); /* stop SWR play */ val = 0; rc = regmap_write(swr_hap->regmap, SWR_PLAY_REG, val); @@ -200,6 +194,12 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, __func__, rc); return rc; } + break; + case SND_SOC_DAPM_POST_PMD: + swr_disconnect_port(swr_hap->swr_slave, &port_id, num_port, + &ch_mask, &port_type); + swr_slvdev_datapath_control(swr_hap->swr_slave, + swr_hap->swr_slave->dev_num, false); swr_device_wakeup_unvote(swr_hap->swr_slave); break; default: @@ -314,6 +314,7 @@ static int swr_haptics_probe(struct swr_device *sdev) struct swr_haptics_dev *swr_hap; int rc; u8 devnum; + int retry = 5; swr_hap = devm_kzalloc(&sdev->dev, sizeof(struct swr_haptics_dev), GFP_KERNEL); @@ -346,8 +347,12 @@ static int swr_haptics_probe(struct swr_device *sdev) __func__, rc); goto clean; } + do { + /* Add delay for soundwire enumeration */ + usleep_range(500, 510); + rc = swr_get_logical_dev_num(sdev, sdev->addr, &devnum); + } while (rc && --retry); - rc = swr_get_logical_dev_num(sdev, sdev->addr, &devnum); if (rc) { dev_err(swr_hap->dev, "%s: failed to get devnum for swr-haptics, rc=%d\n", __func__, rc); diff --git a/asoc/codecs/wcd-mbhc-adc.c b/asoc/codecs/wcd-mbhc-adc.c index c57c011dfd..89f0f7ed19 100644 --- a/asoc/codecs/wcd-mbhc-adc.c +++ b/asoc/codecs/wcd-mbhc-adc.c @@ -33,16 +33,20 @@ static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc) int micbias = 0; u8 vout_ctl = 0; - /* Read MBHC Micbias (Mic Bias2) voltage */ - WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl); - - /* Formula for getting micbias from vout - * micbias = 1.0V + VOUT_CTL * 50mV - */ - micbias = 1000 + (vout_ctl * 50); - pr_debug("%s: vout_ctl: %d, micbias: %d\n", - __func__, vout_ctl, micbias); + if (mbhc->mbhc_cb->get_micbias_val) { + mbhc->mbhc_cb->get_micbias_val(mbhc, &micbias); + pr_debug("%s: micbias: %d\n", __func__, micbias); + } else { + /* Read MBHC Micbias (Mic Bias2) voltage */ + WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl); + /* Formula for getting micbias from vout + * micbias = 1.0V + VOUT_CTL * 50mV + */ + micbias = 1000 + (vout_ctl * 50); + pr_debug("%s: vout_ctl: %d, micbias: %d\n", + __func__, vout_ctl, micbias); + } return micbias; } @@ -76,8 +80,22 @@ static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); /* Set the MUX selection to IN2P */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_IN2P); + + /* + * Current source mode requires Auto zeroing to be enabled + * automatically. If HW doesn't do it, SW has to take care of this + * for button interrupts to work fine and to avoid + * fake electrical removal interrupts by enabling autozero before FSM + * enable and disable it after FSM enable + */ + if (mbhc->mbhc_cb->mbhc_comp_autozero_control) + mbhc->mbhc_cb->mbhc_comp_autozero_control(mbhc, + true); /* Enable MBHC FSM */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1); + if (mbhc->mbhc_cb->mbhc_comp_autozero_control) + mbhc->mbhc_cb->mbhc_comp_autozero_control(mbhc, + false); /* Enable ADC_ENABLE bit */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1); @@ -290,6 +308,10 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); + /* Disable surge detection before ADC measurement */ + if (mbhc->mbhc_cb->mbhc_surge_ctl) + mbhc->mbhc_cb->mbhc_surge_ctl(mbhc, false); + /* Read and set ADC to single measurement */ WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode); /* Read ADC Enable bit to restore after adc measurement */ @@ -313,7 +335,12 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) goto done; } - if (hphl_adc_res > 100 || hphr_adc_res > 100) { + /* Update cross connection threshold voltages if needed */ + if (mbhc->mbhc_cb->update_cross_conn_thr) + mbhc->mbhc_cb->update_cross_conn_thr(mbhc); + + if (hphl_adc_res > mbhc->hphl_cross_conn_thr || + hphr_adc_res > mbhc->hphr_cross_conn_thr) { plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP; pr_debug("%s: Cross connection identified\n", __func__); } else { @@ -335,6 +362,10 @@ done: /* Restore FSM state */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en); + /* Restore surge detection */ + if (mbhc->mbhc_cb->mbhc_surge_ctl) + mbhc->mbhc_cb->mbhc_surge_ctl(mbhc, true); + /* Restore electrical detection */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c index 0da12eb653..08d7678b7d 100644 --- a/asoc/codecs/wcd-mbhc-v2.c +++ b/asoc/codecs/wcd-mbhc-v2.c @@ -80,10 +80,12 @@ static void wcd_program_hs_vref(struct wcd_mbhc *mbhc) struct snd_soc_component *component = mbhc->component; u32 reg_val; - plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration); + plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR( + mbhc->mbhc_cfg->calibration); reg_val = ((plug_type_cfg->v_hs_max - HS_VREF_MIN_VAL) / 100); - dev_dbg(component->dev, "%s: reg_val = %x\n", __func__, reg_val); + dev_dbg(component->dev, "%s: reg_val = %x\n", + __func__, reg_val); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_VREF, reg_val); } @@ -1619,6 +1621,8 @@ static int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc) static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, unsigned long mode, void *ptr) { + unsigned int l_det_en = 0; + unsigned int detection_type = 0; struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, fsa_nb); if (!mbhc) @@ -1631,6 +1635,23 @@ static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, mbhc->mbhc_cb->clk_setup(mbhc->component, true); /* insertion detected, enable L_DET_EN */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + } else { + WCD_MBHC_REG_READ(WCD_MBHC_MECH_DETECTION_TYPE, detection_type); + WCD_MBHC_REG_READ(WCD_MBHC_L_DET_EN, l_det_en); + /* If both l_det_en and detection type are set, it means device was + * unplugged during SSR and detection interrupt was not handled. + * So trigger device disconnect */ + if (detection_type && l_det_en) { + /* Set the detection type appropriately */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE, + !detection_type); + /* Set current plug type to the state before SSR */ + mbhc->current_plug = mbhc->plug_before_ssr; + + wcd_mbhc_swch_irq_handler(mbhc); + mbhc->mbhc_cb->lock_sleep(mbhc, false); + mbhc->plug_before_ssr = MBHC_PLUG_TYPE_NONE; + } } return 0; } @@ -1838,6 +1859,8 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_component *component, mbhc->hph_type = WCD_MBHC_HPH_NONE; mbhc->wcd_mbhc_regs = wcd_mbhc_regs; mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD; + mbhc->hphl_cross_conn_thr = HPHL_CROSS_CONN_THRESHOLD; + mbhc->hphr_cross_conn_thr = HPHR_CROSS_CONN_THRESHOLD; if (mbhc->intr_ids == NULL) { pr_err("%s: Interrupt mapping not provided\n", __func__); diff --git a/asoc/codecs/wcd9335.c b/asoc/codecs/wcd9335.c index 054a56dc3c..cfe328ba8b 100644 --- a/asoc/codecs/wcd9335.c +++ b/asoc/codecs/wcd9335.c @@ -8608,95 +8608,95 @@ static const struct soc_enum amic_pwr_lvl_enum = amic_pwr_lvl_text); static const struct snd_kcontrol_new tasha_snd_controls[] = { - SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, - 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", WCD9335_CDC_RX0_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", WCD9335_CDC_RX1_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", WCD9335_CDC_RX2_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", WCD9335_CDC_RX3_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", WCD9335_CDC_RX4_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", WCD9335_CDC_RX5_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", WCD9335_CDC_RX6_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", WCD9335_CDC_RX7_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", WCD9335_CDC_RX8_RX_VOL_MIX_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ + -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("DEC0 Volume", WCD9335_CDC_TX0_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC0 Volume", WCD9335_CDC_TX0_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC1 Volume", WCD9335_CDC_TX1_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC1 Volume", WCD9335_CDC_TX1_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC2 Volume", WCD9335_CDC_TX2_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC2 Volume", WCD9335_CDC_TX2_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC3 Volume", WCD9335_CDC_TX3_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC3 Volume", WCD9335_CDC_TX3_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC4 Volume", WCD9335_CDC_TX4_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC4 Volume", WCD9335_CDC_TX4_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC5 Volume", WCD9335_CDC_TX5_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC5 Volume", WCD9335_CDC_TX5_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC6 Volume", WCD9335_CDC_TX6_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC6 Volume", WCD9335_CDC_TX6_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC7 Volume", WCD9335_CDC_TX7_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC7 Volume", WCD9335_CDC_TX7_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC8 Volume", WCD9335_CDC_TX8_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC8 Volume", WCD9335_CDC_TX8_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP0 Volume", - WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP1 Volume", - WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP2 Volume", - WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP3 Volume", - WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP0 Volume", - WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", - WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", - WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", - WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40, digital_gain), SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tasha_get_anc_slot, diff --git a/asoc/codecs/wcd934x/wcd934x.c b/asoc/codecs/wcd934x/wcd934x.c index 4fa5c3414c..3d7d39bb28 100644 --- a/asoc/codecs/wcd934x/wcd934x.c +++ b/asoc/codecs/wcd934x/wcd934x.c @@ -6548,77 +6548,77 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = { SOC_SINGLE_TLV("ADC3 Volume", WCD934X_ANA_AMIC3, 0, 20, 0, analog_gain), SOC_SINGLE_TLV("ADC4 Volume", WCD934X_ANA_AMIC4, 0, 20, 0, analog_gain), - SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL, - 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ - SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL, - 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", - WCD934X_CDC_RX0_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", - WCD934X_CDC_RX1_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", - WCD934X_CDC_RX2_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", - WCD934X_CDC_RX3_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", - WCD934X_CDC_RX4_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", - WCD934X_CDC_RX7_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", - WCD934X_CDC_RX8_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL, + -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL, + -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", + WCD934X_CDC_RX0_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", + WCD934X_CDC_RX1_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", + WCD934X_CDC_RX2_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", + WCD934X_CDC_RX3_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", + WCD934X_CDC_RX4_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", + WCD934X_CDC_RX7_RX_VOL_MIX_CTL, -84, 40, digital_gain), + SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", + WCD934X_CDC_RX8_RX_VOL_MIX_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC5 Volume", WCD934X_CDC_TX5_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC6 Volume", WCD934X_CDC_TX6_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL, 0, + SOC_SINGLE_S8_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP0 Volume", - WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP0 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP1 Volume", - WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP1 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP2 Volume", - WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP2 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR0 INP3 Volume", - WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR0 INP3 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP0 Volume", - WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP0 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", - WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", - WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, -84, 40, digital_gain), - SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", - WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40, + SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, -84, 40, digital_gain), SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tavil_get_anc_slot, diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h index 77a93b91d3..e7cf9eb75d 100644 --- a/asoc/codecs/wcd937x/internal.h +++ b/asoc/codecs/wcd937x/internal.h @@ -17,6 +17,7 @@ #define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) #define MAX_PORT 8 #define MAX_CH_PER_PORT 8 +#define MAX_TX_PWR_CH 2 #define WCD937X_MAX_SLAVE_PORT_TYPES 10 extern struct regmap_config wcd937x_regmap_config; @@ -91,6 +92,7 @@ struct wcd937x_priv { struct mutex ana_tx_clk_lock; u8 tx_master_ch_map[WCD937X_MAX_SLAVE_CH_TYPES]; bool usbc_hs_status; + u32 tx_ch_pwr[MAX_TX_PWR_CH]; }; struct wcd937x_micbias_setting { diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index 2e3d27df0f..daf7a3d7a2 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -1777,6 +1777,48 @@ static int wcd937x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, return 0; } +static int wcd937x_tx_ch_pwr_level_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + + if (strnstr(kcontrol->id.name, "CH1", sizeof(kcontrol->id.name))) + ucontrol->value.integer.value[0] = wcd937x->tx_ch_pwr[0]; + else if (strnstr(kcontrol->id.name, "CH3", sizeof(kcontrol->id.name))) + ucontrol->value.integer.value[0] = wcd937x->tx_ch_pwr[1]; + + return 0; +} + +static int wcd937x_tx_ch_pwr_level_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); + u32 pwr_level = ucontrol->value.enumerated.item[0]; + + dev_dbg(component->dev, "%s: tx ch pwr_level: %d\n", + __func__, pwr_level); + + if (strnstr(kcontrol->id.name, "CH1", + sizeof(kcontrol->id.name))) { + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH1, 0x60, + pwr_level << 0x5); + wcd937x->tx_ch_pwr[0] = pwr_level; + } else if (strnstr(kcontrol->id.name, "CH3", + sizeof(kcontrol->id.name))) { + snd_soc_component_update_bits(component, + WCD937X_ANA_TX_CH3, 0x60, + pwr_level << 0x5); + wcd937x->tx_ch_pwr[1] = pwr_level; + } + return 0; +} + static int wcd937x_ear_pa_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2001,6 +2043,10 @@ static int wcd937x_tx_master_ch_put(struct snd_kcontrol *kcontrol, return 0; } +static const char * const wcd937x_tx_ch_pwr_level_text[] = { + "L0", "L1", "L2", "L3", +}; + static const char * const wcd937x_ear_pa_gain_text[] = { "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", "G_0_DB", "G_M1P5_DB", "G_M3_DB", "G_M4P5_DB", @@ -2016,6 +2062,9 @@ static const struct soc_enum rx_hph_mode_mux_enum = static SOC_ENUM_SINGLE_EXT_DECL(wcd937x_ear_pa_gain_enum, wcd937x_ear_pa_gain_text); +static SOC_ENUM_SINGLE_EXT_DECL(wcd937x_tx_ch_pwr_level_enum, + wcd937x_tx_ch_pwr_level_text); + static const struct snd_kcontrol_new wcd937x_snd_controls[] = { SOC_ENUM_EXT("EAR PA GAIN", wcd937x_ear_pa_gain_enum, wcd937x_ear_pa_gain_get, wcd937x_ear_pa_gain_put), @@ -2054,6 +2103,10 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = { wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), SOC_ENUM_EXT("DMIC5 ChMap", tx_master_ch_enum, wcd937x_tx_master_ch_get, wcd937x_tx_master_ch_put), + SOC_ENUM_EXT("TX CH1 PWR", wcd937x_tx_ch_pwr_level_enum, + wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put), + SOC_ENUM_EXT("TX CH3 PWR", wcd937x_tx_ch_pwr_level_enum, + wcd937x_tx_ch_pwr_level_get, wcd937x_tx_ch_pwr_level_put), }; static const struct snd_kcontrol_new adc1_switch[] = { @@ -3114,7 +3167,9 @@ static int wcd937x_bind(struct device *dev) dev_err(dev, "%s: bad micbias pdata\n", __func__); goto err_irq; } - + /* default L1 power setting */ + wcd937x->tx_ch_pwr[0] = 1; + wcd937x->tx_ch_pwr[1] = 1; mutex_init(&wcd937x->micb_lock); mutex_init(&wcd937x->ana_tx_clk_lock); /* Request for watchdog interrupt */ diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h index 0baf0ded9b..dc668e95a0 100644 --- a/asoc/codecs/wcd938x/internal.h +++ b/asoc/codecs/wcd938x/internal.h @@ -73,6 +73,7 @@ struct wcd938x_priv { bool comp2_enable; bool ldoh; bool bcs_dis; + bool dapm_bias_off; struct irq_domain *virq; struct wcd_irq_info irq_info; u32 rx_clk_cnt; @@ -105,6 +106,9 @@ struct wcd938x_priv { bool dev_up; u8 tx_master_ch_map[WCD938X_MAX_SLAVE_CH_TYPES]; bool usbc_hs_status; + /* wcd to swr dmic notification */ + bool notify_swr_dmic; + struct blocking_notifier_head notifier; }; struct wcd938x_micbias_setting { diff --git a/asoc/codecs/wcd938x/wcd938x-slave.c b/asoc/codecs/wcd938x/wcd938x-slave.c index 75cc7839c6..9ea5bac282 100644 --- a/asoc/codecs/wcd938x/wcd938x-slave.c +++ b/asoc/codecs/wcd938x/wcd938x-slave.c @@ -24,6 +24,8 @@ #define SWR_SLV_MAX_DEVICES 2 #endif /* CONFIG_DEBUG_FS */ +#define SWR_MAX_RETRY 5 + struct wcd938x_slave_priv { struct swr_device *swr_slave; #ifdef CONFIG_DEBUG_FS @@ -278,17 +280,24 @@ static int wcd938x_slave_bind(struct device *dev, int ret = 0; uint8_t devnum = 0; struct swr_device *pdev = to_swr_device(dev); + int retry = SWR_MAX_RETRY; if (!pdev) { pr_err("%s: invalid swr device handle\n", __func__); return -EINVAL; } - ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + do { + /* Add delay for soundwire enumeration */ + usleep_range(100, 110); + ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum); + } while (ret && --retry); + if (ret) { dev_dbg(&pdev->dev, - "%s get devnum %d for dev addr %lx failed\n", + "%s get devnum %d for dev addr %llx failed\n", __func__, devnum, pdev->addr); + ret = -EPROBE_DEFER; return ret; } pdev->dev_num = devnum; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index a6652bd4e4..fbea986e18 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -72,6 +72,11 @@ enum { HPH_COMP_DELAY, HPH_PA_DELAY, AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, + WCD_ADC1_MODE, + WCD_ADC2_MODE, + WCD_ADC3_MODE, + WCD_ADC4_MODE, }; enum { @@ -1540,13 +1545,17 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: if (strnstr(w->name, "ADC", sizeof("ADC"))) { - if (test_bit(WCD_ADC1, &wcd938x->status_mask)) + if (test_bit(WCD_ADC1, &wcd938x->status_mask) || + test_bit(WCD_ADC1_MODE, &wcd938x->status_mask)) mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; - if (test_bit(WCD_ADC2, &wcd938x->status_mask)) + if (test_bit(WCD_ADC2, &wcd938x->status_mask) || + test_bit(WCD_ADC2_MODE, &wcd938x->status_mask)) mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; - if (test_bit(WCD_ADC3, &wcd938x->status_mask)) + if (test_bit(WCD_ADC3, &wcd938x->status_mask) || + test_bit(WCD_ADC3_MODE, &wcd938x->status_mask)) mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; - if (test_bit(WCD_ADC4, &wcd938x->status_mask)) + if (test_bit(WCD_ADC4, &wcd938x->status_mask) || + test_bit(WCD_ADC4_MODE, &wcd938x->status_mask)) mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; if (mode != 0) { @@ -1593,6 +1602,14 @@ static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, if (strnstr(w->name, "ADC", sizeof("ADC"))) wcd938x_set_swr_clk_rate(component, rate, bank); + if (strnstr(w->name, "ADC1", sizeof("ADC1"))) + clear_bit(WCD_ADC1_MODE, &wcd938x->status_mask); + else if (strnstr(w->name, "ADC2", sizeof("ADC2"))) + clear_bit(WCD_ADC2_MODE, &wcd938x->status_mask); + else if (strnstr(w->name, "ADC3", sizeof("ADC3"))) + clear_bit(WCD_ADC3_MODE, &wcd938x->status_mask); + else if (strnstr(w->name, "ADC4", sizeof("ADC4"))) + clear_bit(WCD_ADC4_MODE, &wcd938x->status_mask); break; }; @@ -1633,57 +1650,6 @@ static int wcd938x_get_adc_mode(int val) return ret; } -static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event){ - struct snd_soc_component *component = - snd_soc_dapm_to_component(w->dapm); - struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - int clk_rate = 0, ret = 0; - - dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, - w->name, event); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08); - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); - set_bit(w->shift, &wcd938x->status_mask); - clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]); - ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num, - true); - break; - case SND_SOC_DAPM_POST_PMD: - ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, - wcd938x->tx_swr_dev->dev_num, - false); - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00); - clear_bit(w->shift, &wcd938x->status_mask); - break; - }; - - return ret; -} - -void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component, - bool bcs_disable) -{ - struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - - if (wcd938x->update_wcd_event) { - if (bcs_disable) - wcd938x->update_wcd_event(wcd938x->handle, - WCD_BOLERO_EVT_BCS_CLK_OFF, 0); - else - wcd938x->update_wcd_event(wcd938x->handle, - WCD_BOLERO_EVT_BCS_CLK_OFF, 1); - } -} - int wcd938x_tx_channel_config(struct snd_soc_component *component, int channel, int mode) { @@ -1724,14 +1690,14 @@ int wcd938x_tx_channel_config(struct snd_soc_component *component, return ret; } -static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ +static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event){ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - int mode; - int ret = 0; struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int clk_rate = 0, ret = 0; + int mode; dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -1739,9 +1705,14 @@ static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02); + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x08); snd_soc_component_update_bits(component, - WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00); + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + set_bit(w->shift, &wcd938x->status_mask); + clk_rate = wcd938x_get_clk_rate(wcd938x->tx_mode[w->shift]); + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + true); ret = wcd938x_tx_channel_config(component, w->shift, 1); mode = wcd938x_get_adc_mode(wcd938x->tx_mode[w->shift]); if (mode < 0) { @@ -1817,6 +1788,51 @@ static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, default: break; } + ret = swr_slvdev_datapath_control(wcd938x->tx_swr_dev, + wcd938x->tx_swr_dev->dev_num, + false); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x08, 0x00); + clear_bit(w->shift, &wcd938x->status_mask); + break; + }; + + return ret; +} + +void wcd938x_disable_bcs_before_slow_insert(struct snd_soc_component *component, + bool bcs_disable) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (wcd938x->update_wcd_event) { + if (bcs_disable) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_BCS_CLK_OFF, 0); + else + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_BCS_CLK_OFF, 1); + } +} + +static int wcd938x_enable_req(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + int ret = 0; + + dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_REQ_CTL, 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_CDC_REQ_CTL, 0x01, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: snd_soc_component_update_bits(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); break; @@ -1991,15 +2007,16 @@ static int wcd938x_get_logical_addr(struct swr_device *swr_dev) int num_retry = NUM_ATTEMPTS; do { + /* retry after 1ms */ + usleep_range(1000, 1010); 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); - /* retry after 1ms */ - usleep_range(1000, 1010); - } } while (ret && --num_retry); + + if (ret) + dev_err(&swr_dev->dev, + "%s get devnum %d for dev addr %llx failed\n", + __func__, devnum, swr_dev->addr); + swr_dev->dev_num = devnum; return 0; } @@ -2015,6 +2032,27 @@ static bool get_usbc_hs_status(struct snd_soc_component *component, return false; } +int wcd938x_swr_dmic_register_notifier(struct snd_soc_component *component, + struct notifier_block *nblock, + bool enable) +{ + struct wcd938x_priv *wcd938x_priv; + if(NULL == component) { + pr_err("%s: wcd938x component is NULL\n", __func__); + return -EINVAL; + } + + wcd938x_priv = snd_soc_component_get_drvdata(component); + wcd938x_priv->notify_swr_dmic = enable; + if (enable) + return blocking_notifier_chain_register(&wcd938x_priv->notifier, + nblock); + else + return blocking_notifier_chain_unregister( + &wcd938x_priv->notifier, nblock); +} +EXPORT_SYMBOL(wcd938x_swr_dmic_register_notifier); + static int wcd938x_event_notify(struct notifier_block *block, unsigned long val, void *data) @@ -2030,21 +2068,25 @@ static int wcd938x_event_notify(struct notifier_block *block, if (test_bit(WCD_ADC1, &wcd938x->status_mask)) { snd_soc_component_update_bits(component, WCD938X_ANA_TX_CH2, 0x40, 0x00); + set_bit(WCD_ADC1_MODE, &wcd938x->status_mask); clear_bit(WCD_ADC1, &wcd938x->status_mask); } if (test_bit(WCD_ADC2, &wcd938x->status_mask)) { snd_soc_component_update_bits(component, WCD938X_ANA_TX_CH2, 0x20, 0x00); + set_bit(WCD_ADC2_MODE, &wcd938x->status_mask); clear_bit(WCD_ADC2, &wcd938x->status_mask); } if (test_bit(WCD_ADC3, &wcd938x->status_mask)) { snd_soc_component_update_bits(component, WCD938X_ANA_TX_CH4, 0x40, 0x00); + set_bit(WCD_ADC3_MODE, &wcd938x->status_mask); clear_bit(WCD_ADC3, &wcd938x->status_mask); } if (test_bit(WCD_ADC4, &wcd938x->status_mask)) { snd_soc_component_update_bits(component, WCD938X_ANA_TX_CH4, 0x20, 0x00); + set_bit(WCD_ADC4_MODE, &wcd938x->status_mask); clear_bit(WCD_ADC4, &wcd938x->status_mask); } break; @@ -2058,7 +2100,13 @@ static int wcd938x_event_notify(struct notifier_block *block, break; case BOLERO_WCD_EVT_SSR_DOWN: wcd938x->dev_up = false; + if(wcd938x->notify_swr_dmic) + blocking_notifier_call_chain(&wcd938x->notifier, + WCD938X_EVT_SSR_DOWN, + NULL); wcd938x->mbhc->wcd_mbhc.deinit_in_progress = true; + wcd938x->mbhc->wcd_mbhc.plug_before_ssr = + wcd938x->mbhc->wcd_mbhc.current_plug; mbhc = &wcd938x->mbhc->wcd_mbhc; wcd938x->usbc_hs_status = get_usbc_hs_status(component, mbhc->mbhc_cfg); @@ -2089,6 +2137,10 @@ static int wcd938x_event_notify(struct notifier_block *block, } wcd938x->mbhc->wcd_mbhc.deinit_in_progress = false; wcd938x->dev_up = true; + if(wcd938x->notify_swr_dmic) + blocking_notifier_call_chain(&wcd938x->notifier, + WCD938X_EVT_SSR_UP, + NULL); break; case BOLERO_WCD_EVT_CLK_NOTIFY: snd_soc_component_update_bits(component, @@ -2272,6 +2324,9 @@ static int wcd938x_enable_micbias(struct wcd938x_priv *wcd938x, return -EINVAL; }; + pr_debug("%s: req: %d micb_num: %d micb_ref: %d pullup_ref: %d\n", + __func__, req, micb_num, wcd938x->micb_ref[micb_index], + wcd938x->pullup_ref[micb_index]); mutex_lock(&wcd938x->micb_lock); switch (req) { @@ -2336,6 +2391,8 @@ int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component, int event, int micb_num) { struct wcd938x_priv *wcd938x_priv = NULL; + int ret = 0; + int micb_index = micb_num - 1; if(NULL == component) { pr_err("%s: wcd938x component is NULL\n", __func__); @@ -2352,6 +2409,15 @@ int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component, wcd938x_priv = snd_soc_component_get_drvdata(component); + if (!wcd938x_priv->dev_up) { + if ((wcd938x_priv->pullup_ref[micb_index] > 0) && + (event == SND_SOC_DAPM_POST_PMD)) { + wcd938x_priv->pullup_ref[micb_index]--; + ret = -ENODEV; + goto done; + } + } + switch (event) { case SND_SOC_DAPM_PRE_PMU: wcd938x_wakeup(wcd938x_priv, true); @@ -2365,7 +2431,8 @@ int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *component, break; } - return 0; +done: + return ret; } EXPORT_SYMBOL(wcd938x_codec_force_enable_micbias_v2); @@ -3050,9 +3117,17 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AMIC5"), SND_SOC_DAPM_INPUT("AMIC6"), SND_SOC_DAPM_INPUT("AMIC7"), + SND_SOC_DAPM_INPUT("IN1_HPHL"), SND_SOC_DAPM_INPUT("IN2_HPHR"), SND_SOC_DAPM_INPUT("IN3_AUX"), + /* + * These dummy widgets are null connected to WCD938x dapm input and + * output widgets which are not actual path endpoints. This ensures + * dapm doesnt set these dapm input and output widgets as endpoints. + */ + SND_SOC_DAPM_INPUT("WCD_TX_DUMMY"), + SND_SOC_DAPM_OUTPUT("WCD_RX_DUMMY"), /*tx widgets*/ SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, @@ -3289,6 +3364,7 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { static const struct snd_soc_dapm_route wcd938x_audio_map[] = { + {"WCD_TX_DUMMY", NULL, "WCD_TX_OUTPUT"}, {"WCD_TX_OUTPUT", NULL, "ADC1_MIXER"}, {"ADC1_MIXER", "Switch", "ADC1 REQ"}, {"ADC1 REQ", NULL, "ADC1"}, @@ -3343,6 +3419,7 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = { {"WCD_TX_OUTPUT", NULL, "DMIC8_MIXER"}, {"DMIC8_MIXER", "Switch", "DMIC8"}, + {"IN1_HPHL", NULL, "WCD_RX_DUMMY"}, {"IN1_HPHL", NULL, "VDD_BUCK"}, {"IN1_HPHL", NULL, "CLS_H_PORT"}, {"RX1", NULL, "IN1_HPHL"}, @@ -3351,6 +3428,7 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = { {"HPHL PGA", NULL, "HPHL_RDAC"}, {"HPHL", NULL, "HPHL PGA"}, + {"IN2_HPHR", NULL, "WCD_RX_DUMMY"}, {"IN2_HPHR", NULL, "VDD_BUCK"}, {"IN2_HPHR", NULL, "CLS_H_PORT"}, {"RX2", NULL, "IN2_HPHR"}, @@ -3359,6 +3437,7 @@ static const struct snd_soc_dapm_route wcd938x_audio_map[] = { {"HPHR PGA", NULL, "HPHR_RDAC"}, {"HPHR", NULL, "HPHR PGA"}, + {"IN3_AUX", NULL, "WCD_RX_DUMMY"}, {"IN3_AUX", NULL, "VDD_BUCK"}, {"IN3_AUX", NULL, "CLS_H_PORT"}, {"RX3", NULL, "IN3_AUX"}, @@ -3634,6 +3713,8 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) goto err_hwdep; } + snd_soc_dapm_ignore_suspend(dapm, "WCD938X_AIF Playback"); + snd_soc_dapm_ignore_suspend(dapm, "WCD938X_AIF Capture"); snd_soc_dapm_ignore_suspend(dapm, "AMIC1"); snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); snd_soc_dapm_ignore_suspend(dapm, "AMIC3"); @@ -3649,6 +3730,8 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) snd_soc_dapm_ignore_suspend(dapm, "AUX"); snd_soc_dapm_ignore_suspend(dapm, "HPHL"); snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_TX_DUMMY"); + snd_soc_dapm_ignore_suspend(dapm, "WCD_RX_DUMMY"); snd_soc_dapm_sync(dapm); wcd_cls_h_init(&wcd938x->clsh_info); @@ -3688,7 +3771,6 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) return ret; } } - wcd938x->dev_up = true; return ret; err_hwdep: @@ -3713,6 +3795,26 @@ static void wcd938x_soc_codec_remove(struct snd_soc_component *component) false); } +static int wcd938x_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return 0; + wcd938x->dapm_bias_off = true; + return 0; +} + +static int wcd938x_soc_codec_resume(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return 0; + wcd938x->dapm_bias_off = false; + return 0; +} + static struct snd_soc_component_driver soc_codec_dev_wcd938x = { .name = WCD938X_DRV_NAME, .probe = wcd938x_soc_codec_probe, @@ -3723,6 +3825,8 @@ static struct snd_soc_component_driver soc_codec_dev_wcd938x = { .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), .dapm_routes = wcd938x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), + .suspend = wcd938x_soc_codec_suspend, + .resume = wcd938x_soc_codec_resume, }; static int wcd938x_reset(struct device *dev) @@ -4026,6 +4130,7 @@ static int wcd938x_bind(struct device *dev) __func__); goto err_irq; } + wcd938x->dev_up = true; return ret; err_irq: @@ -4242,19 +4347,51 @@ static int wcd938x_suspend(struct device *dev) } clear_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask); } + if (wcd938x->dapm_bias_off) { + msm_cdc_set_supplies_lpm_mode(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask); + } return 0; } static int wcd938x_resume(struct device *dev) { + struct wcd938x_priv *wcd938x = NULL; + struct wcd938x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd938x = dev_get_drvdata(dev); + if (!wcd938x) + return -EINVAL; + + pdata = dev_get_platdata(wcd938x->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask)) { + msm_cdc_set_supplies_lpm_mode(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask); + } + return 0; } static const struct dev_pm_ops wcd938x_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS( - wcd938x_suspend, - wcd938x_resume - ) + .suspend_late = wcd938x_suspend, + .resume_early = wcd938x_resume, }; #endif diff --git a/asoc/codecs/wcd938x/wcd938x.h b/asoc/codecs/wcd938x/wcd938x.h index bf952055e8..1cc8c7d859 100644 --- a/asoc/codecs/wcd938x/wcd938x.h +++ b/asoc/codecs/wcd938x/wcd938x.h @@ -17,6 +17,12 @@ enum { WCD9385 = 5, }; +/* from WCD to SWR DMIC events */ +enum { + WCD938X_EVT_SSR_DOWN, + WCD938X_EVT_SSR_UP, +}; + struct swr_slave_ch_map { u8 ch_type; u8 index; @@ -62,6 +68,9 @@ int wcd938x_info_create_codec_entry(struct snd_info_entry *codec_root, int wcd938x_get_codec_variant(struct snd_soc_component *component); int wcd938x_codec_force_enable_micbias_v2(struct snd_soc_component *wcd938x, int event, int micb_num); +int wcd938x_swr_dmic_register_notifier(struct snd_soc_component *wcd938x, + struct notifier_block *nblock, + bool enable); static inline int wcd938x_slave_get_master_ch_val(int ch) { diff --git a/asoc/codecs/wsa881x.c b/asoc/codecs/wsa881x.c index adb4d91baf..c4624f0fdc 100644 --- a/asoc/codecs/wsa881x.c +++ b/asoc/codecs/wsa881x.c @@ -1083,6 +1083,9 @@ static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w, 0x80, 0x00); if (wsa881x->visense_enable) { wsa881x_visense_adc_ctrl(component, DISABLE); + snd_soc_component_update_bits(component, + WSA881X_ADC_EN_SEL_IBAIS, + 0x07, 0x00); wsa881x_visense_txfe_ctrl(component, DISABLE, 0x00, 0x01, 0x01); } @@ -1614,8 +1617,6 @@ static int wsa881x_swr_down(struct swr_device *pdev) else wsa881x->state = WSA881X_DEV_DOWN; - if (delayed_work_pending(&wsa881x->ocp_ctl_work)) - cancel_delayed_work_sync(&wsa881x->ocp_ctl_work); return ret; } diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h index 4868d2df83..3dc362784d 100644 --- a/asoc/codecs/wsa883x/internal.h +++ b/asoc/codecs/wsa883x/internal.h @@ -97,6 +97,7 @@ struct wsa883x_priv { bool comp_enable; bool visense_enable; bool ext_vdd_spk; + bool dapm_bias_off; struct swr_port port[WSA883X_MAX_SWR_PORTS]; int global_pa_cnt; int dev_mode; diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c index de83f2c535..8993c102b9 100644 --- a/asoc/codecs/wsa883x/wsa883x.c +++ b/asoc/codecs/wsa883x/wsa883x.c @@ -123,6 +123,7 @@ static const struct wsa_reg_mask_val reg_init[] = { {WSA883X_GMAMP_SUP1, 0x60, 0x60}, }; +static int wsa883x_handle_post_irq(void *data); static int wsa883x_get_temperature(struct snd_soc_component *component, int *temp); enum { @@ -132,6 +133,7 @@ enum { enum { SPKR_STATUS = 0, + WSA_SUPPLIES_LPM_MODE, }; enum { @@ -172,9 +174,24 @@ static struct regmap_irq_chip wsa883x_regmap_irq_chip = { .ack_base = WSA883X_INTR_CLEAR0, .use_ack = 1, .runtime_pm = false, + .handle_post_irq = wsa883x_handle_post_irq, .irq_drv_data = NULL, }; +static int wsa883x_handle_post_irq(void *data) +{ + struct wsa883x_priv *wsa883x = data; + u32 sts1 = 0, sts2 = 0; + + regmap_read(wsa883x->regmap, WSA883X_INTR_STATUS0, &sts1); + regmap_read(wsa883x->regmap, WSA883X_INTR_STATUS1, &sts2); + + wsa883x->swr_slave->slave_irq_pending = + ((sts1 || sts2) ? true : false); + + return IRQ_HANDLED; +} + #ifdef CONFIG_DEBUG_FS static int codec_debug_open(struct inode *inode, struct file *file) { @@ -253,7 +270,12 @@ static ssize_t swr_slave_reg_show(struct swr_device *pdev, char __user *ubuf, swr_read(pdev, pdev->dev_num, i, ®_val, 1); len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i, (reg_val & 0xFF)); - if (((total + len) >= count - 1) || (len < 0)) + if (len < 0) { + pr_err("%s: fail to fill the buffer\n", __func__); + total = -EFAULT; + goto copy_err; + } + if ((total + len) >= count - 1) break; if (copy_to_user((ubuf + total), tmp_buf, len)) { pr_err("%s: fail to copy reg dump\n", __func__); @@ -598,9 +620,14 @@ static int wsa_get_temp(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); int temp = 0; - wsa883x_get_temperature(component, &temp); + if (test_bit(SPKR_STATUS, &wsa883x->status_mask)) + temp = wsa883x->curr_temp; + else + wsa883x_get_temperature(component, &temp); + ucontrol->value.integer.value[0] = temp; return 0; @@ -989,6 +1016,7 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, wsa883x->swr_slave->dev_num, true); wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD); + wcd_enable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO); /* Force remove group */ swr_remove_from_group(wsa883x->swr_slave, wsa883x->swr_slave->dev_num); @@ -998,6 +1026,7 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(component, WSA883X_PA_FSM_CTL, 0x01, 0x00); wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PDM_WD); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO); clear_bit(SPKR_STATUS, &wsa883x->status_mask); break; } @@ -1186,6 +1215,8 @@ static int wsa883x_codec_probe(struct snd_soc_component *component) struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); struct swr_device *dev; int variant = 0, version = 0; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); if (!wsa883x) return -EINVAL; @@ -1205,6 +1236,10 @@ static int wsa883x_codec_probe(struct snd_soc_component *component) wsa883x_codec_init(component); wsa883x->global_pa_cnt = 0; + snd_soc_dapm_ignore_suspend(dapm, + wsa883x->dai_driver->playback.stream_name); + snd_soc_dapm_sync(dapm); + return 0; } @@ -1220,6 +1255,28 @@ static void wsa883x_codec_remove(struct snd_soc_component *component) return; } +static int wsa883x_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (!wsa883x) + return 0; + + wsa883x->dapm_bias_off = true; + return 0; +} + +static int wsa883x_soc_codec_resume(struct snd_soc_component *component) +{ + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (!wsa883x) + return 0; + + wsa883x->dapm_bias_off = false; + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_wsa883x_wsa = { .name = "", .probe = wsa883x_codec_probe, @@ -1230,6 +1287,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wsa883x_wsa = { .num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets), .dapm_routes = wsa883x_audio_map, .num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map), + .suspend = wsa883x_soc_codec_suspend, + .resume = wsa883x_soc_codec_resume, }; static int wsa883x_gpio_ctrl(struct wsa883x_priv *wsa883x, bool enable) @@ -1454,12 +1513,18 @@ static int wsa883x_swr_probe(struct swr_device *pdev) wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR, "WSA SAF2WAR", wsa883x_saf2war_handle_irq, NULL); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_SAF2WAR); + wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF, "WSA WAR2SAF", wsa883x_war2saf_handle_irq, NULL); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_WAR2SAF); + wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE, "WSA OTP", wsa883x_otp_handle_irq, NULL); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_DISABLE); + wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_OCP, "WSA OCP", wsa883x_ocp_handle_irq, NULL); @@ -1483,10 +1548,14 @@ static int wsa883x_swr_probe(struct swr_device *pdev) wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN, "WSA EXT INT", wsa883x_ext_int_handle_irq, NULL); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_INTR_PIN); + /* Under Voltage Lock out (UVLO) interrupt handle */ wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO, "WSA UVLO", wsa883x_uvlo_handle_irq, NULL); + wcd_disable_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_UVLO); + wcd_request_irq(&wsa883x->irq_info, WSA883X_IRQ_INT_PA_ON_ERR, "WSA PA ERR", wsa883x_pa_on_err_handle_irq, NULL); @@ -1692,7 +1761,20 @@ static int wsa883x_swr_remove(struct swr_device *pdev) #ifdef CONFIG_PM_SLEEP static int wsa883x_swr_suspend(struct device *dev) { + struct wsa883x_priv *wsa883x = swr_get_dev_data(to_swr_device(dev)); + + if (!wsa883x) { + dev_err(dev, "%s: wsa883x private data is NULL\n", __func__); + return -EINVAL; + } dev_dbg(dev, "%s: system suspend\n", __func__); + if (wsa883x->dapm_bias_off) { + msm_cdc_set_supplies_lpm_mode(dev, wsa883x->supplies, + wsa883x->regulator, + wsa883x->num_supplies, + true); + set_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask); + } return 0; } @@ -1704,13 +1786,21 @@ static int wsa883x_swr_resume(struct device *dev) dev_err(dev, "%s: wsa883x private data is NULL\n", __func__); return -EINVAL; } + if (test_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask)) { + msm_cdc_set_supplies_lpm_mode(dev, wsa883x->supplies, + wsa883x->regulator, + wsa883x->num_supplies, + false); + clear_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask); + } dev_dbg(dev, "%s: system resume\n", __func__); return 0; } #endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops wsa883x_swr_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(wsa883x_swr_suspend, wsa883x_swr_resume) + .suspend_late = wsa883x_swr_suspend, + .resume_early = wsa883x_swr_resume, }; static const struct swr_device_id wsa883x_swr_id[] = { diff --git a/asoc/kona.c b/asoc/kona.c index c2e71db557..c69b676f02 100644 --- a/asoc/kona.c +++ b/asoc/kona.c @@ -47,9 +47,11 @@ #define DEV_NAME_STR_LEN 32 #define WCD_MBHC_HS_V_MAX 1600 -#define WSA8810_NAME_1 "wsa881x.20170211" -#define WSA8810_NAME_2 "wsa881x.20170212" +#define WSA8810_NAME_1 "wsa881x.1020170211" +#define WSA8810_NAME_2 "wsa881x.1020170212" +#define WSA8815_NAME_1 "wsa881x.1021170213" +#define WSA8815_NAME_2 "wsa881x.1021170214" #define WCN_CDC_SLIM_RX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX 2 diff --git a/asoc/lahaina.c b/asoc/lahaina.c index baf8274154..dcf428d136 100644 --- a/asoc/lahaina.c +++ b/asoc/lahaina.c @@ -384,9 +384,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = { { .name = LPASS_BE_RT_PROXY_PCM_TX, .stream_name = LPASS_BE_RT_PROXY_PCM_TX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -398,9 +395,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = { { .name = LPASS_BE_RT_PROXY_PCM_RX, .stream_name = LPASS_BE_RT_PROXY_PCM_RX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -412,9 +406,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = { { .name = LPASS_BE_USB_AUDIO_RX, .stream_name = LPASS_BE_USB_AUDIO_RX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -426,9 +417,6 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = { { .name = LPASS_BE_USB_AUDIO_TX, .stream_name = LPASS_BE_USB_AUDIO_TX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -442,9 +430,6 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { { .name = LPASS_BE_SLIMBUS_7_RX, .stream_name = LPASS_BE_SLIMBUS_7_RX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -458,9 +443,6 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { { .name = LPASS_BE_SLIMBUS_7_TX, .stream_name = LPASS_BE_SLIMBUS_7_TX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -476,9 +458,6 @@ static struct snd_soc_dai_link ext_disp_be_dai_link[] = { { .name = LPASS_BE_DISPLAY_PORT_RX, .stream_name = LPASS_BE_DISPLAY_PORT_RX, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -486,22 +465,6 @@ static struct snd_soc_dai_link ext_disp_be_dai_link[] = { .ignore_suspend = 1, SND_SOC_DAILINK_REG(display_port), }, -#if 0 - /* DISP PORT 1 BACK END DAI Link */ - { - .name = LPASS_BE_DISPLAY_PORT1, - .stream_name = LPASS_BE_DISPLAY_PORT1, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ - .playback_only = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST}, - .ignore_pmdown_time = 1, - .ignore_suspend = 1, - SND_SOC_DAILINK_REG(display_port1), - }, -#endif }; #endif @@ -510,9 +473,6 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_WSA_CDC_DMA_RX_0, .stream_name = LPASS_BE_WSA_CDC_DMA_RX_0, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -525,9 +485,6 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_WSA_CDC_DMA_RX_1, .stream_name = LPASS_BE_WSA_CDC_DMA_RX_1, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -539,9 +496,6 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_WSA_CDC_DMA_TX_1, .stream_name = LPASS_BE_WSA_CDC_DMA_TX_1, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -556,9 +510,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_RX_CDC_DMA_RX_0, .stream_name = LPASS_BE_RX_CDC_DMA_RX_0, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -571,9 +522,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_RX_CDC_DMA_RX_1, .stream_name = LPASS_BE_RX_CDC_DMA_RX_1, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -581,13 +529,11 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { .ignore_suspend = 1, .ops = &msm_common_be_ops, SND_SOC_DAILINK_REG(rx_dma_rx1), + .init = &msm_int_audrx_init, }, { .name = LPASS_BE_RX_CDC_DMA_RX_2, .stream_name = LPASS_BE_RX_CDC_DMA_RX_2, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -599,9 +545,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_RX_CDC_DMA_RX_3, .stream_name = LPASS_BE_RX_CDC_DMA_RX_3, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -610,12 +553,20 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { .ops = &msm_common_be_ops, SND_SOC_DAILINK_REG(rx_dma_rx3), }, + { + .name = LPASS_BE_RX_CDC_DMA_RX_5, + .stream_name = LPASS_BE_RX_CDC_DMA_RX_5, + .playback_only = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_common_be_ops, + SND_SOC_DAILINK_REG(rx_dma_rx5), + }, { .name = LPASS_BE_RX_CDC_DMA_RX_6, .stream_name = LPASS_BE_RX_CDC_DMA_RX_6, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .playback_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -628,9 +579,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_TX_CDC_DMA_TX_3, .stream_name = LPASS_BE_TX_CDC_DMA_TX_3, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -641,9 +589,6 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_TX_CDC_DMA_TX_4, .stream_name = LPASS_BE_TX_CDC_DMA_TX_4, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -657,9 +602,6 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_VA_CDC_DMA_TX_0, .stream_name = LPASS_BE_VA_CDC_DMA_TX_0, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -670,9 +612,6 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_VA_CDC_DMA_TX_1, .stream_name = LPASS_BE_VA_CDC_DMA_TX_1, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -683,9 +622,6 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = { { .name = LPASS_BE_VA_CDC_DMA_TX_2, .stream_name = LPASS_BE_VA_CDC_DMA_TX_2, -#if IS_ENABLED(CONFIG_AUDIO_QGKI) - .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, -#endif /* CONFIG_AUDIO_QGKI */ .capture_only = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, @@ -855,6 +791,45 @@ static const struct of_device_id lahaina_asoc_machine_of_match[] = { {}, }; +static int msm_snd_card_late_probe(struct snd_soc_card *card) +{ + struct snd_soc_component *component = NULL; + const char *be_dl_name = LPASS_BE_RX_CDC_DMA_RX_0; + struct snd_soc_pcm_runtime *rtd; + int ret = 0; + void *mbhc_calibration; + + 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); + return -EINVAL; + } + + component = snd_soc_rtdcom_lookup(rtd, WCD938X_DRV_NAME); + if (!component) { + pr_err("%s component is NULL\n", __func__); + return -EINVAL; + } + + mbhc_calibration = def_wcd_mbhc_cal(); + if (!mbhc_calibration) + return -ENOMEM; + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg); + if (ret) { + dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n", + __func__, ret); + goto err_hs_detect; + } + return 0; + +err_hs_detect: + kfree(mbhc_calibration); + return ret; +} + static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = NULL; @@ -934,6 +909,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) if (card) { card->dai_link = dailink; card->num_links = total_links; + card->late_probe = msm_snd_card_late_probe; } return card; @@ -958,6 +934,10 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_card_get_drvdata(rtd->card); int ret = 0; + if (codec_reg_done) { + return 0; + } + if (pdata->wsa_max_devs > 0) { component = snd_soc_rtdcom_lookup(rtd, "wsa-codec.1"); if (!component) { @@ -1064,8 +1044,6 @@ static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = NULL; struct snd_soc_dapm_context *dapm = NULL; - int ret = 0; - void *mbhc_calibration; struct snd_info_entry *entry; struct snd_card *card = NULL; struct msm_asoc_mach_data *pdata; @@ -1095,8 +1073,7 @@ static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd) if (!entry) { dev_dbg(component->dev, "%s: Cannot create codecs module entry\n", __func__); - ret = 0; - goto mbhc_cfg_cal; + return 0; } pdata->codec_root = entry; } @@ -1121,23 +1098,8 @@ static int msm_aux_codec_init(struct snd_soc_pcm_runtime *rtd) } #endif -mbhc_cfg_cal: - mbhc_calibration = def_wcd_mbhc_cal(); - if (!mbhc_calibration) - return -ENOMEM; - wcd_mbhc_cfg.calibration = mbhc_calibration; - ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg); - if (ret) { - dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n", - __func__, ret); - goto err_hs_detect; - } msm_common_dai_link_init(rtd); return 0; - -err_hs_detect: - kfree(mbhc_calibration); - return ret; } static int lahaina_ssr_enable(struct device *dev, void *data) diff --git a/asoc/msm-compress-q6-v2.h b/asoc/msm-compress-q6-v2.h new file mode 100644 index 0000000000..86d12879e8 --- /dev/null +++ b/asoc/msm-compress-q6-v2.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. +*/ +int msm_compr_new(struct snd_soc_pcm_runtime *rtd, int num); diff --git a/asoc/msm_dailink.h b/asoc/msm_dailink.h index c01eb1afb6..44179588e7 100644 --- a/asoc/msm_dailink.h +++ b/asoc/msm_dailink.h @@ -5,7 +5,6 @@ #include - SND_SOC_DAILINK_DEFS(usb_audio_rx, DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")), DAILINK_COMP_ARRAY(COMP_DUMMY()), @@ -16,7 +15,6 @@ SND_SOC_DAILINK_DEFS(usb_audio_tx, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); - SND_SOC_DAILINK_DEFS(slimbus_7_rx, DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")), DAILINK_COMP_ARRAY(COMP_CODEC("btfmslim_slave", @@ -96,6 +94,12 @@ SND_SOC_DAILINK_DEFS(rx_dma_rx3, COMP_CODEC("wcd938x_codec", "wcd938x_cdc")), DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); +SND_SOC_DAILINK_DEFS(rx_dma_rx5, + DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")), + DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx5"), + COMP_CODEC("wcd938x_codec", "wcd938x_cdc")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); + SND_SOC_DAILINK_DEFS(rx_dma_rx6, DAILINK_COMP_ARRAY(COMP_CPU("snd-soc-dummy-dai")), DAILINK_COMP_ARRAY(COMP_CODEC("bolero_codec", "rx_macro_rx6"), diff --git a/asoc/qcs405.c b/asoc/qcs405.c index 18dfb82207..8e439467be 100644 --- a/asoc/qcs405.c +++ b/asoc/qcs405.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include #include @@ -148,6 +148,11 @@ enum { SPDIF_TX_MAX, }; +enum { + HDMI_RX_IDX = 0, + EXT_HDMI_RX_IDX_MAX, +}; + struct mi2s_conf { struct mutex lock; u32 ref_cnt; @@ -344,7 +349,9 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ } }; - +static struct dev_config ext_hdmi_rx_cfg[] = { + [HDMI_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; /* Default configuration of slimbus channels */ static struct dev_config slim_rx_cfg[] = { @@ -488,6 +495,12 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_88P2", "KHZ_96", "KHZ_176P4", "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static char const *ext_hdmi_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_32", "KHZ_44P1", + "KHZ_88P2", "KHZ_176P4"}; +static char const *ext_hdmi_bit_format_text[] = {"S16_LE", "S24_LE", + "S24_3LE"}; + static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"}; @@ -539,6 +552,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); @@ -546,6 +560,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_format, ext_hdmi_bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); @@ -553,6 +568,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_sink, bt_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_sample_rate, + ext_hdmi_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text); @@ -2110,6 +2127,191 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } +static int ext_hdmi_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx; + + if (strnstr(kcontrol->id.name, "HDMI_RX", + sizeof("HDMI_RX"))) { + idx = HDMI_RX_IDX; + } else { + pr_err("%s: unsupported BE: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int ext_hdmi_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_hdmi_rx_cfg[idx].bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: ext_hdmi_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_hdmi_rx_cfg[idx].bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int ext_hdmi_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ucontrol->value.integer.value[0]) { + case 1: + ext_hdmi_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + ext_hdmi_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: ext_hdmi_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_hdmi_rx_cfg[idx].bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int ext_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.integer.value[0] = + ext_hdmi_rx_cfg[idx].channels - 2; + + pr_debug("%s: ext_hdmi_rx[%d].ch = %d\n", __func__, + idx, ext_hdmi_rx_cfg[idx].channels); + + return 0; +} + +static int ext_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ext_hdmi_rx_cfg[idx].channels = + ucontrol->value.integer.value[0] + 2; + + pr_debug("%s: ext_hdmi_rx[%d].ch = %d\n", __func__, + idx, ext_hdmi_rx_cfg[idx].channels); + return 0; +} + +static int ext_hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_hdmi_rx_cfg[idx].sample_rate) { + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 6; + break; + + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 5; + break; + + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 4; + break; + + case SAMPLING_RATE_32KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: ext_hdmi_rx[%d].sample_rate = %d\n", __func__, + idx, ext_hdmi_rx_cfg[idx].sample_rate); + + return 0; +} + + +static int ext_hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ucontrol->value.integer.value[0]) { + case 6: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 5: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 4: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ; + break; + case 2: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, ext_hdmi_rx[%d].sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], idx, + ext_hdmi_rx_cfg[idx].sample_rate); + return 0; +} + static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3842,6 +4044,14 @@ static const struct snd_kcontrol_new msm_snd_sb_controls[] = { slim_rx_bit_format_get, slim_rx_bit_format_put), SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format, slim_tx_bit_format_get, slim_tx_bit_format_put), + SOC_ENUM_EXT("HDMI_RX Bit Format", ext_hdmi_rx_format, + ext_hdmi_rx_format_get, ext_hdmi_rx_format_put), + SOC_ENUM_EXT("HDMI_RX SampleRate", ext_hdmi_rx_sample_rate, + ext_hdmi_rx_sample_rate_get, + ext_hdmi_rx_sample_rate_put), + SOC_ENUM_EXT("HDMI_RX Channels", ext_hdmi_rx_chs, + ext_hdmi_rx_ch_get, + ext_hdmi_rx_ch_put), SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate, @@ -4506,6 +4716,23 @@ static int msm_slim_get_ch_from_beid(int32_t be_id) return ch_id; } +static int msm_ext_hdmi_get_idx_from_beid(int32_t be_id) +{ + int idx; + + switch (be_id) { + case MSM_BACKEND_DAI_HDMI_RX_MS: + idx = HDMI_RX_IDX; + break; + default: + pr_err("%s: Incorrect ext_hdmi BE id %d\n", __func__, be_id); + idx = -EINVAL; + break; + } + + return idx; +} + static int msm_cdc_dma_get_idx_from_beid(int32_t be_id) { int idx = 0; @@ -5040,11 +5267,27 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = afe_lb_tx_cfg.channels; break; + case MSM_BACKEND_DAI_HDMI_RX_MS: + idx = msm_ext_hdmi_get_idx_from_beid(dai_link->id); + + if (idx < 0) { + pr_err("%s: Incorrect ext hdmi idx %d\n", + __func__, idx); + rc = idx; + goto done; + } + + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + ext_hdmi_rx_cfg[idx].bit_format); + rate->min = rate->max = ext_hdmi_rx_cfg[idx].sample_rate; + channels->min = channels->max = ext_hdmi_rx_cfg[idx].channels; + break; + default: rate->min = rate->max = SAMPLING_RATE_48KHZ; break; } - +done: return rc; } @@ -6104,7 +6347,6 @@ static struct snd_soc_ops msm_fe_qos_ops = { .prepare = msm_fe_qos_prepare, }; - static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) { int ret = 0; @@ -6177,6 +6419,36 @@ err: return ret; } +static int msm_mi2s_snd_hw_free(struct snd_pcm_substream *substream) +{ + int i, data_format = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int index = rtd->cpu_dai->id; + struct snd_soc_card *card = rtd->card; + struct snd_soc_component *component; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + data_format = mi2s_rx_cfg[index].data_format; + else + data_format = mi2s_tx_cfg[index].data_format; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + /* Call csra mute function if data format is DSD, else return */ + if (data_format != AFE_DSD_DATA) + return 0; + + for (i = 0; i < card->num_aux_devs; i++) { + component = + soc_find_component(card->aux_dev[i].codec_of_node, + NULL); + csra66x0_hw_free_mute(component); + } + + return 0; +} + static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) { int ret; @@ -6279,6 +6551,7 @@ static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream) unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; struct snd_soc_card *card = rtd->card; struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + u16 port_id = 0; dev_dbg(rtd->card->dev, "%s: substream = %s stream = %d, dai name %s, dai ID %d\n", @@ -6312,6 +6585,13 @@ static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream) meta_mi2s_intf_conf[index].clk_enable[i] = true; if (i == 0) { + port_id = msm_get_port_id(rtd->dai_link->id); + ret = afe_set_clk_id(port_id, + mi2s_clk[member_port].clk_id); + if (ret < 0) + pr_err("%s: afe_set_clk_id fail %d\n", + __func__, ret); + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); if (ret < 0) { pr_err("%s: set fmt cpu dai failed for META_MI2S (%d), err:%d\n", @@ -6504,6 +6784,7 @@ static void msm_spdif_snd_shutdown(struct snd_pcm_substream *substream) static struct snd_soc_ops msm_mi2s_be_ops = { .startup = msm_mi2s_snd_startup, + .hw_free = msm_mi2s_snd_hw_free, .shutdown = msm_mi2s_snd_shutdown, }; @@ -7298,6 +7579,24 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { }, }; +static struct snd_soc_dai_link ext_hdmi_be_dai_link[] = { + /* HDMI RX BACK END DAI Link */ + { + .name = LPASS_BE_HDMI_MS, + .stream_name = "HDMI MS Playback", + .cpu_dai_name = "msm-dai-q6-hdmi.24578", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-ext-disp-audio-codec-rx", + .codec_dai_name = "msm_hdmi_ms_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_HDMI_RX_MS, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_common_be_dai_links[] = { /* Backend AFE DAI Links */ { @@ -8305,7 +8604,8 @@ static struct snd_soc_dai_link msm_qcs405_dai_links[ ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) + ARRAY_SIZE(msm_bolero_fe_dai_links) + ARRAY_SIZE(msm_spdif_be_dai_links) + - ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)]; + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) + + ARRAY_SIZE(ext_hdmi_be_dai_link)]; static int msm_snd_card_tasha_late_probe(struct snd_soc_card *card) { @@ -8556,6 +8856,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0; uint32_t spdif_audio_intf = 0, wcn_audio_intf = 0; uint32_t afe_loopback_intf = 0, meta_mi2s_intf = 0; + uint32_t ext_disp_hdmi_rx = 0; const struct of_device_id *match; char __iomem *spdif_cfg, *spdif_pin_ctl; int rc = 0; @@ -8743,6 +9044,20 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); } } + rc = of_property_read_u32(dev->of_node, + "qcom,ext-disp-audio-rx", &ext_disp_hdmi_rx); + if (rc) { + dev_dbg(dev, "%s: No DT match ext disp hdmi rx\n", + __func__); + } else { + if (ext_disp_hdmi_rx) { + memcpy(msm_qcs405_dai_links + total_links, + ext_hdmi_be_dai_link, + sizeof(ext_hdmi_be_dai_link)); + total_links += ARRAY_SIZE(ext_hdmi_be_dai_link); + } + } + dailink = msm_qcs405_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; @@ -8756,7 +9071,6 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) msm_stub_be_dai_links, sizeof(msm_stub_be_dai_links)); total_links += ARRAY_SIZE(msm_stub_be_dai_links); - dailink = msm_stub_dai_links; } diff --git a/dsp/Kbuild b/dsp/Kbuild index 3a7b336d7e..b5b60adf84 100644 --- a/dsp/Kbuild +++ b/dsp/Kbuild @@ -157,6 +157,10 @@ ifdef CONFIG_DIGITAL_CDC_RSC_MGR SPF_CORE_OBJS += digital-cdc-rsc-mgr.o endif +ifdef CONFIG_DIGITAL_CDC_RSC_MGR + Q6_OBJS += digital-cdc-rsc-mgr.o +endif + LINUX_INC += -Iinclude/linux INCS += $(COMMON_INC) \ diff --git a/dsp/adsp-loader.c b/dsp/adsp-loader.c index d73ffc45ae..783a93d0c9 100644 --- a/dsp/adsp-loader.c +++ b/dsp/adsp-loader.c @@ -28,6 +28,7 @@ enum apr_subsys_state { APR_SUBSYS_DOWN, APR_SUBSYS_UP, APR_SUBSYS_LOADED, + APR_SUBSYS_UNKNOWN, }; static ssize_t adsp_boot_store(struct kobject *kobj, @@ -61,6 +62,53 @@ static struct work_struct adsp_ldr_work; static struct platform_device *adsp_private; static void adsp_loader_unload(struct platform_device *pdev); +static int adsp_restart_subsys(void) +{ + struct subsys_device *adsp_dev = NULL; + struct platform_device *pdev = adsp_private; + struct adsp_loader_private *priv = NULL; + int rc = -EINVAL; + + priv = platform_get_drvdata(pdev); + if (!priv) + return rc; + + adsp_dev = (struct subsys_device *)priv->pil_h; + if (!adsp_dev) + return rc; + + /* subsystem_restart_dev has worker queue to handle */ + rc = subsystem_restart_dev(adsp_dev); + if (rc) { + dev_err(&pdev->dev, "subsystem_restart_dev failed\n"); + return rc; + } + pr_debug("%s :: Restart Success %d\n", __func__, rc); + return rc; +} + +#if 0 +static void adsp_load_state_notify_cb(enum apr_subsys_state state, + void *phandle) +{ + struct platform_device *pdev = adsp_private; + struct adsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + if (!priv) + return; + if (phandle != adsp_private) { + pr_err("%s:callback is not for adsp-loader client\n", __func__); + return; + } + pr_debug("%s:: Received cb for ADSP restart\n", __func__); + if (state == APR_SUBSYS_UNKNOWN) + adsp_restart_subsys(); + else + pr_debug("%s:Ignore restart request for ADSP", __func__); +} +#endif + static void adsp_load_fw(struct work_struct *adsp_ldr_work) { struct platform_device *pdev = adsp_private; @@ -69,6 +117,7 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work) int rc = 0; u32 adsp_state; const char *img_name; +// void *padsp_restart_cb = &adsp_load_state_notify_cb; if (!pdev) { dev_err(&pdev->dev, "%s: Platform device null\n", __func__); @@ -125,7 +174,7 @@ static void adsp_load_fw(struct work_struct *adsp_ldr_work) } dev_dbg(&pdev->dev, "%s: Q6/MDSP image is loaded\n", __func__); - return; + goto success; } load_adsp: @@ -159,10 +208,13 @@ load_adsp: } dev_dbg(&pdev->dev, "%s: Q6/ADSP image is loaded\n", __func__); - return; +// apr_register_adsp_state_cb(padsp_restart_cb, adsp_private); + goto success; } fail: dev_err(&pdev->dev, "%s: Q6 image loading failed\n", __func__); +success: + return; } static void adsp_loader_do(struct platform_device *pdev) @@ -176,37 +228,24 @@ static ssize_t adsp_ssr_store(struct kobject *kobj, size_t count) { int ssr_command = 0; - struct subsys_device *adsp_dev = NULL; struct platform_device *pdev = adsp_private; struct adsp_loader_private *priv = NULL; - int rc; + int rc = -EINVAL; dev_dbg(&pdev->dev, "%s: going to call adsp ssr\n ", __func__); + priv = platform_get_drvdata(pdev); + if (!priv) + return rc; + if (kstrtoint(buf, 10, &ssr_command) < 0) return -EINVAL; if (ssr_command != SSR_RESET_CMD) return -EINVAL; - priv = platform_get_drvdata(pdev); - if (!priv) - return -EINVAL; - - adsp_dev = (struct subsys_device *)priv->pil_h; - if (!adsp_dev) - return -EINVAL; - - dev_err(&pdev->dev, "requesting for ADSP restart\n"); - - /* subsystem_restart_dev has worker queue to handle */ - rc = subsystem_restart_dev(adsp_dev); - if (rc) { - dev_err(&pdev->dev, "subsystem_restart_dev failed\n"); - return rc; - } - - dev_dbg(&pdev->dev, "ADSP restarted\n"); + adsp_restart_subsys(); + dev_dbg(&pdev->dev, "%s :: ADSP restarted\n", __func__); return count; } @@ -339,6 +378,8 @@ static int adsp_loader_probe(struct platform_device *pdev) int fw_name_size; u32 adsp_var_idx = 0; int ret = 0; + u32 adsp_fuse_not_supported = 0; + const char *adsp_fw_name; ret = adsp_loader_init_sysfs(pdev); if (ret != 0) { @@ -350,15 +391,58 @@ static int adsp_loader_probe(struct platform_device *pdev) /* get adsp variant idx */ cell = nvmem_cell_get(&pdev->dev, "adsp_variant"); if (IS_ERR_OR_NULL(cell)) { - dev_dbg(&pdev->dev, "%s: FAILED to get nvmem cell \n", __func__); + dev_dbg(&pdev->dev, "%s: FAILED to get nvmem cell \n", + __func__); + + /* + * When ADSP variant read from fuse register is not + * supported, check if image with different fw image + * name needs to be loaded + */ + ret = of_property_read_u32(pdev->dev.of_node, + "adsp-fuse-not-supported", + &adsp_fuse_not_supported); + if (ret) { + dev_dbg(&pdev->dev, + "%s: adsp_fuse_not_supported prop not found", + __func__, ret); + goto wqueue; + } + + if (adsp_fuse_not_supported) { + /* Read ADSP firmware image name */ + ret = of_property_read_string(pdev->dev.of_node, + "adsp-fw-name", + &adsp_fw_name); + if (ret < 0) { + dev_dbg(&pdev->dev, "%s: unable to read fw-name\n", + __func__); + goto wqueue; + } + + fw_name_size = strlen(adsp_fw_name) + 1; + priv->adsp_fw_name = devm_kzalloc(&pdev->dev, + fw_name_size, + GFP_KERNEL); + if (!priv->adsp_fw_name) + goto wqueue; + strlcpy(priv->adsp_fw_name, adsp_fw_name, + fw_name_size); + } goto wqueue; } buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); - if (IS_ERR_OR_NULL(buf) || len <= 0 || len > sizeof(u32)) { + if (IS_ERR_OR_NULL(buf)) { dev_dbg(&pdev->dev, "%s: FAILED to read nvmem cell \n", __func__); goto wqueue; } + if (len <= 0 || len > sizeof(u32)) { + dev_dbg(&pdev->dev, "%s: nvmem cell length out of range: %d\n", + __func__, len); + kfree(buf); + goto wqueue; + } memcpy(&adsp_var_idx, buf, len); kfree(buf); diff --git a/dsp/audio_notifier.c b/dsp/audio_notifier.c index 888d162d43..9f2d4d5c10 100644 --- a/dsp/audio_notifier.c +++ b/dsp/audio_notifier.c @@ -606,6 +606,7 @@ static int __init audio_notifier_late_init(void) return 0; } +#ifdef CONFIG_MSM_QDSP6_PDR static int __init audio_notifier_init(void) { int ret; @@ -624,6 +625,17 @@ static int __init audio_notifier_init(void) return 0; } +#else +static int __init audio_notifier_init(void) +{ + audio_notifier_subsys_init(); + audio_notifier_disable_service(AUDIO_NOTIFIER_PDR_SERVICE); + + audio_notifier_late_init(); + + return 0; +} +#endif module_init(audio_notifier_init); static void __exit audio_notifier_exit(void) diff --git a/dsp/digital-cdc-rsc-mgr.c b/dsp/digital-cdc-rsc-mgr.c index 4206523ea8..be5d5cad79 100644 --- a/dsp/digital-cdc-rsc-mgr.c +++ b/dsp/digital-cdc-rsc-mgr.c @@ -87,13 +87,13 @@ void digital_cdc_rsc_mgr_hw_vote_reset(struct clk* vote_handle) } EXPORT_SYMBOL(digital_cdc_rsc_mgr_hw_vote_reset); -void digital_cdc_rsc_mgr_init() +void digital_cdc_rsc_mgr_init(void) { mutex_init(&hw_vote_lock); is_init_done = true; } -void digital_cdc_rsc_mgr_exit() +void digital_cdc_rsc_mgr_exit(void) { mutex_destroy(&hw_vote_lock); is_init_done = false; diff --git a/include/asoc/msm-cdc-pinctrl.h b/include/asoc/msm-cdc-pinctrl.h index 89fe699ccb..3179a8408e 100644 --- a/include/asoc/msm-cdc-pinctrl.h +++ b/include/asoc/msm-cdc-pinctrl.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef __MFD_CDC_PINCTRL_H_ @@ -11,6 +11,7 @@ #if IS_ENABLED(CONFIG_MSM_CDC_PINCTRL) extern int msm_cdc_pinctrl_select_sleep_state(struct device_node *np); extern int msm_cdc_pinctrl_select_active_state(struct device_node *np); +extern int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np); extern int msm_cdc_pinctrl_get_state(struct device_node *np); extern int msm_cdc_get_gpio_state(struct device_node *np); extern int msm_cdc_pinctrl_set_wakeup_capable(struct device_node *np, @@ -27,6 +28,10 @@ int msm_cdc_pinctrl_select_active_state(struct device_node *np) { return 0; } +int msm_cdc_pinctrl_select_alt_active_state(struct device_node *np) +{ + return 0; +} int msm_cdc_get_gpio_state(struct device_node *np) { return 0; diff --git a/include/asoc/msm-cdc-supply.h b/include/asoc/msm-cdc-supply.h index f7fec21c03..c740400754 100644 --- a/include/asoc/msm-cdc-supply.h +++ b/include/asoc/msm-cdc-supply.h @@ -15,6 +15,7 @@ struct cdc_regulator { int max_uV; int optimum_uA; bool ondemand; + bool lpm_supported; struct regulator *regulator; }; @@ -51,6 +52,11 @@ extern int msm_cdc_enable_static_supplies(struct device *dev, struct regulator_bulk_data *supplies, struct cdc_regulator *cdc_vreg, int num_supplies); +extern int msm_cdc_set_supplies_lpm_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + bool flag); extern int msm_cdc_init_supplies(struct device *dev, struct regulator_bulk_data **supplies, struct cdc_regulator *cdc_vreg, diff --git a/include/asoc/wcd-mbhc-v2.h b/include/asoc/wcd-mbhc-v2.h index c7e412b344..e9dd2ae165 100644 --- a/include/asoc/wcd-mbhc-v2.h +++ b/include/asoc/wcd-mbhc-v2.h @@ -145,6 +145,8 @@ do { \ #define FW_READ_ATTEMPTS 15 #define FW_READ_TIMEOUT 4000000 #define FAKE_REM_RETRY_ATTEMPTS 3 +#define HPHL_CROSS_CONN_THRESHOLD 100 +#define HPHR_CROSS_CONN_THRESHOLD 100 #define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50 #define ANC_DETECT_RETRY_CNT 7 @@ -456,6 +458,14 @@ struct wcd_mbhc_register { }; struct wcd_mbhc_cb { + void (*update_cross_conn_thr) + (struct wcd_mbhc *mbhc); + void (*mbhc_surge_ctl) + (struct wcd_mbhc *mbhc, bool surge_en); + void (*mbhc_comp_autozero_control) + (struct wcd_mbhc *mbhc, bool az_enable); + void (*get_micbias_val) + (struct wcd_mbhc *mbhc, int *mb); void (*bcs_enable) (struct wcd_mbhc *mbhc, bool bcs_enable); int (*enable_mb_source)(struct wcd_mbhc *mbhc, bool turn_on); @@ -541,6 +551,7 @@ struct wcd_mbhc { wait_queue_head_t wait_btn_press; bool is_btn_press; u8 current_plug; + u8 plug_before_ssr; bool in_swch_irq_handler; bool hphl_swh; /*track HPHL switch NC / NO */ bool gnd_swh; /*track GND switch NC / NO */ @@ -551,6 +562,8 @@ struct wcd_mbhc { u32 moist_vref; u32 moist_iref; u32 moist_rref; + u32 hphl_cross_conn_thr; + u32 hphr_cross_conn_thr; u8 micbias1_cap_mode; /* track ext cap setting */ u8 micbias2_cap_mode; /* track ext cap setting */ bool hs_detect_work_stop; diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 2860016c6e..090bceb4d5 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -598,7 +598,7 @@ struct adm_cmd_device_open_v8 { * In all other use cases this should be set to 0xffff */ - u16 reserved; + u16 compressed_data_type; } __packed; /* @@ -1356,6 +1356,7 @@ struct adm_cmd_connect_afe_port_v5 { #define RT_PROXY_PORT_001_RX 0x2000 #define RT_PROXY_PORT_001_TX 0x2001 #define AFE_LOOPBACK_TX 0x6001 +#define HDMI_RX_MS 0x6002 #define DISPLAY_PORT_RX 0x6020 #define AFE_LANE_MASK_INVALID 0 @@ -1562,6 +1563,8 @@ struct adm_cmd_connect_afe_port_v5 { #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_9_RX 0x4012 /* SLIMbus Tx port on channel 9. */ #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_9_TX 0x4013 +/*AFE Rx port for audio over hdmi*/ +#define AFE_PORT_ID_HDMI_MS 0x6002 /* AFE Rx port for audio over Display port */ #define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020 /*USB AFE port */ @@ -2554,6 +2557,7 @@ struct afe_port_data_cmd_rt_proxy_port_read_v2 { #define AFE_GENERIC_COMPRESSED 0x8 #define AFE_LINEAR_PCM_DATA_PACKED_16BIT 0X6 #define AFE_DSD_DOP_W_MARKER_DATA 0x9 +#define AFE_DSD_DATA 0xA /* This param id is used to configure I2S interface */ #define AFE_PARAM_ID_I2S_CONFIG 0x0001020D @@ -4139,6 +4143,16 @@ struct afe_id_aptx_adaptive_enc_init #define AFE_MODULE_ID_DEPACKETIZER_COP 0x00013233 #define AFE_MODULE_ID_DEPACKETIZER_COP_V1 0x000132E9 +/* Macros for dynamic loading of modules by AVCS */ + +#define AVS_MODULE_ID_PACKETIZER_COP 0x0001322A + +#define AVS_MODULE_ID_PACKETIZER_COP_V1 0x000132E8 + +#define AVS_MODULE_ID_DEPACKETIZER_COP 0x00013233 + +#define AVS_MODULE_ID_DEPACKETIZER_COP_V1 0x000132E9 + /* * Depacketizer type parameter for the #AVS_MODULE_ID_DECODER module. * This parameter cannot be set runtime. @@ -4734,6 +4748,56 @@ struct afe_enc_config { union afe_enc_config_data data; }; +/* + * Enable TTP generator in AFE. + */ +#define AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_STATE 0x000132EF +/* + * Configure TTP generator params in AFE. + */ +#define AVS_DEPACKETIZER_PARAM_ID_TTP_GEN_CFG 0x000132F0 +#define MAX_TTP_OFFSET_PAIRS 4 +struct afe_ttp_gen_enable_t { + uint16_t enable; + uint16_t reserved; +} __packed; + +struct afe_ttp_ssrc_offset_pair_t { + uint32_t ssrc; + uint32_t offset; +} __packed; + +struct afe_ttp_gen_cfg_t { + uint32_t ttp_offset_default; + /* + * TTP offset uses for all other cases + * where no valid SSRC is received. + */ + uint32_t settling_time; + /* + * If settling_mode==0x00: time in [us] + * after first received packet until + * packets are no longer dropped. + */ + uint16_t settling_mode; + /* + * 0x00(Drop), 0x01(Settle) + */ + uint16_t num_ssrc_offsets; + /* + * Number of SSRC/TTPOFFSET pairs to follow + */ + struct afe_ttp_ssrc_offset_pair_t ssrc_ttp_offset[MAX_TTP_OFFSET_PAIRS]; + /* + * Array of ssrc/offset pairs + */ +} __packed; + +struct afe_ttp_config { + struct afe_ttp_gen_enable_t ttp_gen_enable; + struct afe_ttp_gen_cfg_t ttp_gen_cfg; +}; + union afe_dec_config_data { struct asm_sbc_dec_cfg_t sbc_config; struct asm_aac_dec_cfg_v2_t aac_config; @@ -4876,6 +4940,9 @@ struct avs_dec_congestion_buffer_param_t { /* Payload of the AFE_PARAM_ID_ISLAND_CONFIG parameter used by * AFE_MODULE_AUDIO_DEV_INTERFACE. */ + +#define AFE_PARAM_ID_POWER_MODE_CONFIG 0x0002002c +#define AFE_API_VERSION_POWER_MODE_CONFIG 0x1 struct afe_param_id_island_cfg_t { uint32_t island_cfg_minor_version; /* Tracks the configuration of this parameter. @@ -4889,6 +4956,19 @@ struct afe_param_id_island_cfg_t { */ } __packed; +struct afe_param_id_power_mode_cfg_t { + uint32_t power_mode_cfg_minor_version; + /* Tracks the configuration of this parameter + * Supported values: #AFE_API_VERSION_POWER_MODE_CONFIG + */ + + uint32_t power_mode_enable; + /* Specifies whether island mode should be enabled or disabled for the + * use-case being setup. + * Supported values: 0 - Disable, 1 - Enable + */ +} __packed; + /* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to configure * the Codec DMA interface. */ @@ -5380,6 +5460,7 @@ struct afe_param_id_lpass_core_shared_clk_cfg { #define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY 0x00010774 #define VPM_TX_SM_ECNS_V2_COPP_TOPOLOGY 0x00010F89 #define VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY 0x10000003 +#define VPM_TX_VOICE_FLUENCE_SM_COPP_TOPOLOGY 0x10000004 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75 #define VPM_TX_DM_RFECNS_COPP_TOPOLOGY 0x00010F86 @@ -8887,6 +8968,13 @@ struct asm_data_cmd_remove_silence { /* Shift value for the IEC 61937 to 61937 pass-through capture. */ #define ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG 0 +/* Bitmask for the DSD pass-through capture. */ +#define ASM_BIT_MASK_COMPRESSED_FORMAT_FLAG (0x00000003UL) + +/* Shift value for the DSD pass-through capture. */ +#define ASM_SHIFT_DSD_COMPRESSED_FORMAT_FLAG 0 + +#define ASM_DSD_FORMAT_FLAG 2 struct asm_stream_cmd_open_read_compressed { struct apr_hdr hdr; u32 mode_flags; @@ -8898,6 +8986,12 @@ struct asm_stream_cmd_open_read_compressed { * - Use #ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG to set the bitmask * and #ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG to set the shift value * for this bit. + * Supported values for bit 1: (DSD native pass-through mode) + * 0 -- non DSD operation + * 1 -- Pass-through transfer of the DSD format stream + * To set this bit, use #ASM_BIT_MASK_DSD_PASS_THROUGH_FLAG and + * use #ASM_SHIFT_DSD_PASS_THROUGH_FLAG to set the shift value for + * this bit * Supported values for bit 4: * - 0 -- Return data buffer contains all encoded frames only; it does * not contain frame metadata. @@ -8914,6 +9008,9 @@ struct asm_stream_cmd_open_read_compressed { * Supported values: should be greater than 0 for IEC to RAW compressed * unpack mode. * Value is don't care for IEC 61937 pass-through mode. + * @values + * - >0 -- For IEC 61937-to-RAW Compressed Unpack mode + * - 1 -- For IEC 61937 or DSD Pass-through mode */ } __packed; @@ -12102,6 +12199,35 @@ struct afe_clk_cfg { #define AFE_MODULE_CLOCK_SET 0x0001028F #define AFE_PARAM_ID_CLOCK_SET 0x00010290 +struct afe_set_clk_drift { + /* + * Clock ID + * @values + * - 0x100 to 0x10E + * - 0x200 to 0x20C + * - 0x500 to 0x505 + */ + uint32_t clk_id; + + /* + * Clock drift (in PPB) to be set. + * @values + * - need to get values from DSP team + */ + int32_t clk_drift; + + /* + * Clock rest. + * @values + * - 1 -- Reset PLL with the original frequency + * - 0 -- Adjust the clock with the clk drift value + */ + uint32_t clk_reset; +} __packed; + +/* This param id is used to adjust audio interface PLL*/ +#define AFE_PARAM_ID_CLOCK_ADJUST 0x000102C6 + enum afe_lpass_digital_clk_src { Q6AFE_LPASS_DIGITAL_ROOT_INVALID, Q6AFE_LPASS_DIGITAL_ROOT_PRI_MI2S_OSR, diff --git a/include/ipc/apr.h b/include/ipc/apr.h index 7aecee2655..40fc92c7d8 100644 --- a/include/ipc/apr.h +++ b/include/ipc/apr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2017, 2019, 2020, The Linux Foundation. All rights reserved. */ #ifndef __APR_H_ #define __APR_H_ @@ -12,6 +12,7 @@ enum apr_subsys_state { APR_SUBSYS_DOWN, APR_SUBSYS_UP, APR_SUBSYS_LOADED, + APR_SUBSYS_UNKNOWN, }; struct apr_q6 { @@ -19,6 +20,13 @@ struct apr_q6 { atomic_t q6_state; atomic_t modem_state; struct mutex lock; +/* + * ToDo - Multiple client support to be added. + * And checking for state UNKNOWN currently. + */ + void (*state_notify_cb)(enum apr_subsys_state state, + void *client_handle); + void *client_handle; }; struct apr_hdr { @@ -186,4 +194,5 @@ const char *apr_get_lpass_subsys_name(void); uint16_t apr_get_reset_domain(uint16_t proc); int apr_start_rx_rt(void *handle); int apr_end_rx_rt(void *handle); +void apr_register_adsp_state_cb(void *adsp_cb, void *client_handle); #endif diff --git a/include/uapi/audio/sound/audio_effects.h b/include/uapi/audio/sound/audio_effects.h index a2dcea96f9..3cd98b7881 100644 --- a/include/uapi/audio/sound/audio_effects.h +++ b/include/uapi/audio/sound/audio_effects.h @@ -7,9 +7,9 @@ /* CONFIG GET/SET */ -#define CONFIG_CACHE 0 -#define CONFIG_SET 1 -#define CONFIG_GET 2 +#define AUDIO_EFFECTS_CONFIG_CACHE 0 +#define AUDIO_EFFECTS_CONFIG_SET 1 +#define AUDIO_EFFECTS_CONFIG_GET 2 /* CONFIG HEADER */ /* @@ -17,14 +17,14 @@ * DEVICE, * NUM_COMMANDS, * COMMAND_ID_1, - * CONFIG_CACHE/SET/GET, + * AUDIO_EFFECTS_CONFIG_CACHE/SET/GET, * OFFSET_1, * LENGTH_1, * VALUES_1, * ..., * ..., * COMMAND_ID_2, - * CONFIG_CACHE/SET/GET, + * AUDIO_EFFECTS_CONFIG_CACHE/SET/GET, * OFFSET_2, * LENGTH_2, * VALUES_2, diff --git a/include/uapi/audio/sound/lsm_params.h b/include/uapi/audio/sound/lsm_params.h index d7b8eeafd2..722d3ba726 100644 --- a/include/uapi/audio/sound/lsm_params.h +++ b/include/uapi/audio/sound/lsm_params.h @@ -5,9 +5,8 @@ #define LSM_EVENT_TIMESTAMP_MODE_SUPPORT #include -#include -#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 1) +#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 2) #define LSM_MAX_STAGES_PER_SESSION 2 #define LSM_STAGE_INDEX_FIRST 0 @@ -34,7 +33,10 @@ #define LSM_POLLING_ENABLE (7) #define LSM_DET_EVENT_TYPE (8) #define LSM_LAB_CONTROL (9) -#define LSM_PARAMS_MAX (LSM_LAB_CONTROL + 1) +#define LSM_REG_MULTI_SND_MODEL (10) +#define LSM_DEREG_MULTI_SND_MODEL (11) +#define LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS (12) +#define LSM_PARAMS_MAX (LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS + 1) #define LSM_EVENT_NON_TIME_STAMP_MODE (0) #define LSM_EVENT_TIME_STAMP_MODE (1) @@ -227,6 +229,7 @@ struct lsm_params_info { * Member variables applicable only to V2: * @instance_id: instance id of the param to which parameter is to be set * @stage_idx: detection stage for which the param is applicable + * @model_id: an unique number to identify sound models in DSP */ struct lsm_params_info_v2 { __u32 module_id; @@ -236,6 +239,7 @@ struct lsm_params_info_v2 { __u32 param_type; __u16 instance_id; __u16 stage_idx; + __u32 model_id; }; /* diff --git a/include/uapi/audio/sound/msmcal-hwdep.h b/include/uapi/audio/sound/msmcal-hwdep.h index f2891863fa..eb05fa97dd 100644 --- a/include/uapi/audio/sound/msmcal-hwdep.h +++ b/include/uapi/audio/sound/msmcal-hwdep.h @@ -1,6 +1,8 @@ #ifndef _CALIB_HWDEP_H #define _CALIB_HWDEP_H +#include + #define WCD9XXX_CODEC_HWDEP_NODE 1000 #define AQT1000_CODEC_HWDEP_NODE 1001 #define Q6AFE_HWDEP_NODE 1002 diff --git a/include/uapi/audio/sound/voice_params.h b/include/uapi/audio/sound/voice_params.h index 43e3b9d0aa..357a6fac3b 100644 --- a/include/uapi/audio/sound/voice_params.h +++ b/include/uapi/audio/sound/voice_params.h @@ -2,7 +2,6 @@ #define __VOICE_PARAMS_H__ #include -#include enum voice_lch_mode { VOICE_LCH_START = 1, diff --git a/soc/pinctrl-lpi.c b/soc/pinctrl-lpi.c index 3ed438d330..ef12ca3f35 100644 --- a/soc/pinctrl-lpi.c +++ b/soc/pinctrl-lpi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -489,6 +490,8 @@ static int lpi_notifier_service_cb(struct notifier_block *this, /* Reset HW votes after SSR */ if (!lpi_dev_up) { + /* Add 100ms sleep to ensure AVS is up after SSR */ + msleep(100); if (state->lpass_core_hw_vote) digital_cdc_rsc_mgr_hw_vote_reset( state->lpass_core_hw_vote); diff --git a/soc/soundwire.c b/soc/soundwire.c index 72a94ace14..04b74f8270 100644 --- a/soc/soundwire.c +++ b/soc/soundwire.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -473,10 +473,6 @@ int swr_get_logical_dev_num(struct swr_device *dev, u64 dev_id, } mutex_lock(&master->mlock); ret = master->get_logical_dev_num(master, dev_id, dev_num); - if (ret) { - pr_err("%s: Error %d to get logical addr for device %llx\n", - __func__, ret, dev_id); - } mutex_unlock(&master->mlock); return ret; } diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 63d496c4ac..3089a0d711 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -41,7 +41,6 @@ #define SWRM_DSD_PARAMS_PORT 4 #define SWR_BROADCAST_CMD_ID 0x0F -#define SWR_AUTO_SUSPEND_DELAY 1 /* delay in sec */ #define SWR_DEV_ID_MASK 0xFFFFFFFFFFFF #define SWR_REG_VAL_PACK(data, dev, id, reg) \ ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24)) @@ -82,7 +81,7 @@ #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 /* pm runtime auto suspend timer in msecs */ -static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000; +static int auto_suspend_timer = 500; module_param(auto_suspend_timer, int, 0664); MODULE_PARM_DESC(auto_suspend_timer, "timer for auto suspend"); @@ -121,7 +120,7 @@ static bool swrm_lock_sleep(struct swr_mstr_ctrl *swrm); static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm); static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr); static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val); - +static int swrm_runtime_resume(struct device *dev); static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq) { @@ -647,6 +646,7 @@ static int swr_master_bulk_write(struct swr_mstr_ctrl *swrm, u32 *reg_addr, usleep_range(50, 55); swr_master_write(swrm, reg_addr[i], val[i]); } + usleep_range(100, 110); mutex_unlock(&swrm->iolock); } return 0; @@ -901,6 +901,8 @@ static int swrm_read(struct swr_master *master, u8 dev_num, u16 reg_addr, mutex_unlock(&swrm->devlock); pm_runtime_get_sync(swrm->dev); + if (swrm->req_clk_switch) + swrm_runtime_resume(swrm->dev); ret = swrm_cmd_fifo_rd_cmd(swrm, &val, dev_num, 0, reg_addr, len); if (!ret) @@ -934,6 +936,8 @@ static int swrm_write(struct swr_master *master, u8 dev_num, u16 reg_addr, mutex_unlock(&swrm->devlock); pm_runtime_get_sync(swrm->dev); + if (swrm->req_clk_switch) + swrm_runtime_resume(swrm->dev); ret = swrm_cmd_fifo_wr_cmd(swrm, reg_val, dev_num, 0, reg_addr); pm_runtime_put_autosuspend(swrm->dev); @@ -1105,6 +1109,8 @@ int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq) bus_clk_freq = SWR_CLK_RATE_4P8MHZ; else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ) bus_clk_freq = SWR_CLK_RATE_9P6MHZ; + else + bus_clk_freq = SWR_CLK_RATE_9P6MHZ; } else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ) bus_clk_freq = SWR_CLK_RATE_11P2896MHZ; @@ -1871,7 +1877,7 @@ handle_irq: swrm_enable_slave_irq(swrm); if (status == swrm->slave_status) { dev_dbg(swrm->dev, - "%s: No change in slave status: %d\n", + "%s: No change in slave status: 0x%x\n", __func__, status); break; } @@ -1923,16 +1929,22 @@ handle_irq: swrm->intr_mask); break; case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW: - dev_dbg(swrm->dev, "%s: SWR read FIFO overflow\n", - __func__); + value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS); + dev_err(swrm->dev, + "%s: SWR read FIFO overflow fifo status\n", + __func__, value); break; case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW: - dev_dbg(swrm->dev, "%s: SWR read FIFO underflow\n", - __func__); + value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS); + dev_err(swrm->dev, + "%s: SWR read FIFO underflow fifo status\n", + __func__, value); break; case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW: - dev_dbg(swrm->dev, "%s: SWR write FIFO overflow\n", - __func__); + value = swr_master_read(swrm, SWRM_CMD_FIFO_STATUS); + dev_err(swrm->dev, + "%s: SWR write FIFO overflow fifo status\n", + __func__, value); swr_master_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); break; case SWRM_INTERRUPT_STATUS_CMD_ERROR: @@ -2175,17 +2187,19 @@ static int swrm_get_logical_dev_num(struct swr_master *mstr, u64 dev_id, if ((id & SWR_DEV_ID_MASK) == dev_id) { *dev_num = i; ret = 0; + dev_info(swrm->dev, + "%s: devnum %d assigned for dev %llx\n", + __func__, i, + swr_dev->addr); } - dev_dbg(swrm->dev, - "%s: devnum %d is assigned for dev addr %lx\n", - __func__, i, swr_dev->addr); } } } } if (ret) - dev_err(swrm->dev, "%s: device 0x%llx is not ready\n", - __func__, dev_id); + dev_err_ratelimited(swrm->dev, + "%s: device 0x%llx is not ready\n", + __func__, dev_id); pm_runtime_mark_last_busy(swrm->dev); pm_runtime_put_autosuspend(swrm->dev); @@ -2659,6 +2673,8 @@ static int swrm_probe(struct platform_device *pdev) * controller will be up now */ swr_master_add_boarddevices(&swrm->master); + if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) + dev_dbg(&pdev->dev, "%s: Audio HW Vote is failed\n", __func__); mutex_lock(&swrm->mlock); swrm_clk_request(swrm, true); swrm->version = swr_master_read(swrm, SWRM_COMP_HW_VERSION); @@ -2721,13 +2737,13 @@ err_mstr_fail: swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm, SWR_IRQ_FREE); } else if (swrm->irq) { - free_irq(swrm->irq, swrm); irqd_set_trigger_type( irq_get_irq_data(swrm->irq), IRQ_TYPE_NONE); + if (swrm->swr_irq_wakeup_capable) + irq_set_irq_wake(swrm->irq, 0); + free_irq(swrm->irq, swrm); } - if (swrm->swr_irq_wakeup_capable) - irq_set_irq_wake(swrm->irq, 0); err_irq_fail: mutex_destroy(&swrm->irq_lock); mutex_destroy(&swrm->mlock); @@ -2751,15 +2767,15 @@ static int swrm_remove(struct platform_device *pdev) swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm, SWR_IRQ_FREE); } else if (swrm->irq) { - free_irq(swrm->irq, swrm); irqd_set_trigger_type( irq_get_irq_data(swrm->irq), IRQ_TYPE_NONE); + if (swrm->swr_irq_wakeup_capable) + irq_set_irq_wake(swrm->irq, 0); + free_irq(swrm->irq, swrm); } else if (swrm->wake_irq > 0) { free_irq(swrm->wake_irq, swrm); } - if (swrm->swr_irq_wakeup_capable) - irq_set_irq_wake(swrm->irq, 0); cancel_work_sync(&swrm->wakeup_work); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); @@ -2799,7 +2815,6 @@ static int swrm_runtime_resume(struct device *dev) int ret = 0; bool swrm_clk_req_err = false; bool hw_core_err = false; - bool aud_core_err = false; struct swr_master *mstr = &swrm->master; struct swr_device *swr_dev; u32 temp = 0; @@ -2815,11 +2830,9 @@ static int swrm_runtime_resume(struct device *dev) __func__); hw_core_err = true; } - if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) { + if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) dev_err(dev, "%s:lpass audio hw enable failed\n", __func__); - aud_core_err = true; - } if ((swrm->state == SWR_MSTR_DOWN) || (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) { @@ -2911,8 +2924,6 @@ static int swrm_runtime_resume(struct device *dev) swrm->state = SWR_MSTR_UP; } exit: - if (!aud_core_err) - swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false); if (!hw_core_err) swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); if (swrm_clk_req_err) @@ -2921,6 +2932,8 @@ exit: else pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer); + if (swrm->req_clk_switch) + swrm->req_clk_switch = false; mutex_unlock(&swrm->reslock); trace_printk("%s: pm_runtime: resume done, state:%d\n", @@ -2934,7 +2947,6 @@ static int swrm_runtime_suspend(struct device *dev) struct swr_mstr_ctrl *swrm = platform_get_drvdata(pdev); int ret = 0; bool hw_core_err = false; - bool aud_core_err = false; struct swr_master *mstr = &swrm->master; struct swr_device *swr_dev; int current_state = 0; @@ -2953,11 +2965,6 @@ static int swrm_runtime_suspend(struct device *dev) __func__); hw_core_err = true; } - if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, true)) { - dev_err(dev, "%s:lpass audio hw enable failed\n", - __func__); - aud_core_err = true; - } if ((current_state == SWR_MSTR_UP) || (current_state == SWR_MSTR_SSR)) { @@ -3036,12 +3043,14 @@ static int swrm_runtime_suspend(struct device *dev) } } + if (swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false)) + dev_dbg(dev, "%s:lpass audio hw enable failed\n", + __func__); + /* Retain SSR state until resume */ if (current_state != SWR_MSTR_SSR) swrm->state = SWR_MSTR_DOWN; exit: - if (!aud_core_err) - swrm_request_hw_vote(swrm, LPASS_AUDIO_CORE, false); if (!hw_core_err) swrm_request_hw_vote(swrm, LPASS_HW_CORE, false); mutex_unlock(&swrm->reslock); @@ -3214,8 +3223,12 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data) } mutex_lock(&swrm->mlock); if (swrm->clk_src != *(int *)data) { - if (swrm->state == SWR_MSTR_UP) + if (swrm->state == SWR_MSTR_UP) { + swrm->req_clk_switch = true; swrm_device_suspend(&pdev->dev); + if (swrm->state == SWR_MSTR_UP) + swrm->req_clk_switch = false; + } swrm->clk_src = *(int *)data; } mutex_unlock(&swrm->mlock); diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index c8444032d8..89d35b5423 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -175,6 +175,7 @@ struct swr_mstr_ctrl { u32 ipc_wakeup; bool dev_up; bool ipc_wakeup_triggered; + bool req_clk_switch; struct pm_qos_request pm_qos_req; enum swrm_pm_state pm_state; wait_queue_head_t pm_wq;