diff --git a/drivers/soc/qcom/icnss2/main.c b/drivers/soc/qcom/icnss2/main.c index 8f8de8d35170..f806ccf37afc 100644 --- a/drivers/soc/qcom/icnss2/main.c +++ b/drivers/soc/qcom/icnss2/main.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "main.h" #include "qmi.h" #include "debug.h" @@ -2761,6 +2763,8 @@ EXPORT_SYMBOL(icnss_idle_restart); int icnss_exit_power_save(struct device *dev) { struct icnss_priv *priv = dev_get_drvdata(dev); + unsigned int value = 0; + int ret; icnss_pr_dbg("Calling Exit Power Save\n"); @@ -2768,8 +2772,18 @@ int icnss_exit_power_save(struct device *dev) !test_bit(ICNSS_MODE_ON, &priv->state)) return 0; - return wlfw_power_save_send_msg(priv, - (enum wlfw_power_save_mode_v01)ICNSS_POWER_SAVE_EXIT); + value |= priv->smp2p_info.seq++; + value <<= ICNSS_SMEM_SEQ_NO_POS; + value |= ICNSS_POWER_SAVE_EXIT; + ret = qcom_smem_state_update_bits( + priv->smp2p_info.smem_state, + ICNSS_SMEM_VALUE_MASK, + value); + if (ret) + icnss_pr_dbg("Error in SMP2P sent ret: %d\n", ret); + + icnss_pr_dbg("SMP2P sent value: 0x%X\n", value); + return ret; } EXPORT_SYMBOL(icnss_exit_power_save); @@ -3154,6 +3168,20 @@ static void icnss_init_control_params(struct icnss_priv *priv) } } +static inline void icnss_get_smp2p_info(struct icnss_priv *priv) +{ + + priv->smp2p_info.smem_state = + qcom_smem_state_get(&priv->pdev->dev, + "wlan-smp2p-out", + &priv->smp2p_info.smem_bit); + if (IS_ERR(priv->smp2p_info.smem_state)) { + icnss_pr_dbg("Failed to get smem state %d", + PTR_ERR(priv->smp2p_info.smem_state)); + } + +} + static inline void icnss_runtime_pm_init(struct icnss_priv *priv) { pm_runtime_get_sync(&priv->pdev->dev); @@ -3275,6 +3303,7 @@ static int icnss_probe(struct platform_device *pdev) icnss_runtime_pm_init(priv); icnss_get_cpr_info(priv); + icnss_get_smp2p_info(priv); set_bit(ICNSS_COLD_BOOT_CAL, &priv->state); } @@ -3344,6 +3373,7 @@ static int icnss_remove(struct platform_device *pdev) static int icnss_pm_suspend(struct device *dev) { struct icnss_priv *priv = dev_get_drvdata(dev); + unsigned int value = 0; int ret = 0; if (priv->magic != ICNSS_MAGIC) { @@ -3355,6 +3385,7 @@ static int icnss_pm_suspend(struct device *dev) icnss_pr_vdbg("PM Suspend, state: 0x%lx\n", priv->state); if (!priv->ops || !priv->ops->pm_suspend || + IS_ERR(priv->smp2p_info.smem_state) || !test_bit(ICNSS_DRIVER_PROBED, &priv->state)) return 0; @@ -3362,11 +3393,23 @@ static int icnss_pm_suspend(struct device *dev) if (ret == 0) { if (priv->device_id == WCN6750_DEVICE_ID) { - ret = wlfw_power_save_send_msg(priv, - (enum wlfw_power_save_mode_v01) - ICNSS_POWER_SAVE_ENTER); + if (test_bit(ICNSS_PD_RESTART, &priv->state) || + !test_bit(ICNSS_MODE_ON, &priv->state)) + return 0; + + value |= priv->smp2p_info.seq++; + value <<= ICNSS_SMEM_SEQ_NO_POS; + value |= ICNSS_POWER_SAVE_ENTER; + + ret = qcom_smem_state_update_bits( + priv->smp2p_info.smem_state, + ICNSS_SMEM_VALUE_MASK, + value); if (ret) - return priv->ops->pm_resume(dev); + icnss_pr_dbg("Error in SMP2P sent ret: %d\n", + ret); + + icnss_pr_dbg("SMP2P sent value: 0x%X\n", value); } priv->stats.pm_suspend++; set_bit(ICNSS_PM_SUSPEND, &priv->state); @@ -3390,6 +3433,7 @@ static int icnss_pm_resume(struct device *dev) icnss_pr_vdbg("PM resume, state: 0x%lx\n", priv->state); if (!priv->ops || !priv->ops->pm_resume || + IS_ERR(priv->smp2p_info.smem_state) || !test_bit(ICNSS_DRIVER_PROBED, &priv->state)) goto out; @@ -3467,6 +3511,7 @@ out: static int icnss_pm_runtime_suspend(struct device *dev) { struct icnss_priv *priv = dev_get_drvdata(dev); + unsigned int value = 0; int ret = 0; if (priv->magic != ICNSS_MAGIC) { @@ -3475,17 +3520,29 @@ static int icnss_pm_runtime_suspend(struct device *dev) return -EINVAL; } - if (!priv->ops || !priv->ops->runtime_suspend) + if (!priv->ops || !priv->ops->runtime_suspend || + IS_ERR(priv->smp2p_info.smem_state)) goto out; icnss_pr_vdbg("Runtime suspend\n"); ret = priv->ops->runtime_suspend(dev); if (!ret) { - ret = wlfw_power_save_send_msg(priv, - (enum wlfw_power_save_mode_v01) - ICNSS_POWER_SAVE_ENTER); + if (test_bit(ICNSS_PD_RESTART, &priv->state) || + !test_bit(ICNSS_MODE_ON, &priv->state)) + return 0; + + value |= priv->smp2p_info.seq++; + value <<= ICNSS_SMEM_SEQ_NO_POS; + value |= ICNSS_POWER_SAVE_ENTER; + + ret = qcom_smem_state_update_bits( + priv->smp2p_info.smem_state, + ICNSS_SMEM_VALUE_MASK, + value); if (ret) - return priv->ops->runtime_resume(dev); + icnss_pr_dbg("Error in SMP2P sent ret: %d\n", ret); + + icnss_pr_dbg("SMP2P sent value: 0x%X\n", value); } out: return ret; @@ -3502,7 +3559,8 @@ static int icnss_pm_runtime_resume(struct device *dev) return -EINVAL; } - if (!priv->ops || !priv->ops->runtime_resume) + if (!priv->ops || !priv->ops->runtime_resume || + IS_ERR(priv->smp2p_info.smem_state)) goto out; icnss_pr_vdbg("Runtime resume, state: 0x%lx\n", priv->state); diff --git a/drivers/soc/qcom/icnss2/main.h b/drivers/soc/qcom/icnss2/main.h index 451b7d205624..58a3b313b9b6 100644 --- a/drivers/soc/qcom/icnss2/main.h +++ b/drivers/soc/qcom/icnss2/main.h @@ -22,6 +22,9 @@ #define ADRASTEA_DEVICE_ID 0xabcd #define QMI_WLFW_MAX_NUM_MEM_SEG 32 #define THERMAL_NAME_LENGTH 20 +#define ICNSS_SMEM_VALUE_MASK 0xFFFFFFFF +#define ICNSS_SMEM_SEQ_NO_POS 16 + extern uint64_t dynamic_feature_mask; enum icnss_bdf_type { @@ -169,7 +172,7 @@ struct icnss_fw_mem { }; enum icnss_power_save_mode { - ICNSS_POWER_SAVE_ENTER, + ICNSS_POWER_SAVE_ENTER = 1, ICNSS_POWER_SAVE_EXIT, }; struct icnss_stats { @@ -310,6 +313,12 @@ struct icnss_thermal_cdev { struct thermal_cooling_device *tcdev; }; +struct smp2p_out_info { + unsigned short seq; + unsigned int smem_bit; + struct qcom_smem_state *smem_state; +}; + struct icnss_priv { uint32_t magic; struct platform_device *pdev; @@ -386,6 +395,7 @@ struct icnss_priv { struct mutex dev_lock; uint32_t fw_error_fatal_irq; uint32_t fw_early_crash_irq; + struct smp2p_out_info smp2p_info; struct completion unblock_shutdown; struct adc_tm_param vph_monitor_params; struct adc_tm_chip *adc_tm_dev;