Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f884eeaf authored by Yuanyuan Liu's avatar Yuanyuan Liu
Browse files

icnss: Monitor external clock for WLAN



There's a change in WLAN FW clock resource which uses RFCLK3 on
Timex. In order to make sure that clock is up before accessing
WLAN hardware, ICNSS platform driver needs to register to MDM
SSR notification and wait for POWER_UP event before starting QMI handshake.

CRs-Fixed: 2450895
Change-Id: I257fc28ab102b63df84d2af5507db50413a2da07
Signed-off-by: default avatarYuanyuan Liu <yuanliu@codeaurora.org>
parent e6f67830
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ Optional properties:
  - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
  - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory
  - qcom,hyp_disabled: Boolean context flag to disable hyperviser
  - qcom,clk-monitor-enable: Boolean context flag to enable monitoring external clock

WLAN SMP2P sub nodes

+96 −2
Original line number Diff line number Diff line
@@ -70,6 +70,9 @@
#define ICNSS_QUIRKS_DEFAULT		BIT(FW_REJUVENATE_ENABLE)
#define ICNSS_MAX_PROBE_CNT		2

#define SUBSYS_INTERNAL_MODEM_NAME	"modem"
#define SUBSYS_EXTERNAL_MODEM_NAME	"esoc0"

#define PROBE_TIMEOUT			5000

static struct icnss_priv *penv;
@@ -964,6 +967,13 @@ static int icnss_driver_event_server_arrive(void *data)

	set_bit(ICNSS_WLFW_CONNECTED, &penv->state);

	if (penv->clk_monitor_enable &&
	    !test_bit(ICNSS_CLK_UP, &penv->state)) {
		reinit_completion(&penv->clk_complete);
		icnss_pr_dbg("Waiting for CLK up notification\n");
		wait_for_completion(&penv->clk_complete);
	}

	ret = icnss_hw_power_on(penv);
	if (ret)
		goto clear_server;
@@ -1560,6 +1570,68 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
	return NOTIFY_OK;
}

static int icnss_ext_modem_notifier_nb(struct notifier_block *nb,
				       unsigned long code,
				       void *data)
{
	struct icnss_priv *priv = container_of(nb, struct icnss_priv,
					       ext_modem_ssr_nb);
	icnss_pr_vdbg("EXT-Modem-Notify: event %lu\n", code);


	if (code == SUBSYS_AFTER_POWERUP) {
		set_bit(ICNSS_CLK_UP, &priv->state);
		complete(&priv->clk_complete);
	}

	return NOTIFY_OK;
}

static int icnss_ext_modem_ssr_register_notifier(struct icnss_priv *priv)
{
	int ret = 0;

	priv->ext_modem_ssr_nb.notifier_call = icnss_ext_modem_notifier_nb;

	priv->ext_modem_notify_handler =
		subsys_notif_register_notifier(SUBSYS_EXTERNAL_MODEM_NAME,
					       &priv->ext_modem_ssr_nb);

	if (IS_ERR_OR_NULL(priv->ext_modem_notify_handler)) {
		ret = PTR_ERR(priv->ext_modem_notify_handler);
		icnss_pr_err("External Modem register notifier failed %d\n",
			     ret);
		priv->ext_modem_notify_handler = NULL;
		/* In NULL case */
		if (ret == 0)
			ret = -EINVAL;
		return ret;
	}

	init_completion(&priv->clk_complete);

	return ret;
}

static int icnss_ext_modem_ssr_unregister_notifier(struct icnss_priv *priv)
{
	int ret = 0;

	if (!priv->ext_modem_notify_handler)
		return 0;

	complete_all(&priv->clk_complete);
	ret = subsys_notif_unregister_notifier(priv->ext_modem_notify_handler,
					       &priv->ext_modem_ssr_nb);
	if (ret)
		icnss_pr_err("Fail to unregister external Modem notifier %d\n",
			     ret);

	priv->ext_modem_notify_handler = NULL;

	return 0;
}

static int icnss_modem_ssr_register_notifier(struct icnss_priv *priv)
{
	int ret = 0;
@@ -1567,7 +1639,8 @@ static int icnss_modem_ssr_register_notifier(struct icnss_priv *priv)
	priv->modem_ssr_nb.notifier_call = icnss_modem_notifier_nb;

	priv->modem_notify_handler =
		subsys_notif_register_notifier("modem", &priv->modem_ssr_nb);
		subsys_notif_register_notifier(SUBSYS_INTERNAL_MODEM_NAME,
					       &priv->modem_ssr_nb);

	if (IS_ERR(priv->modem_notify_handler)) {
		ret = PTR_ERR(priv->modem_notify_handler);
@@ -2826,6 +2899,10 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
			continue;
		case ICNSS_PDR:
			seq_puts(s, "PDR TRIGGERED");
			continue;
		case ICNSS_CLK_UP:
			seq_puts(s, "CLK UP");
			continue;
		}

		seq_printf(s, "UNKNOWN-%d", i);
@@ -3492,6 +3569,19 @@ static int icnss_probe(struct platform_device *pdev)
		}
	}

	if (of_property_read_bool(pdev->dev.of_node,
				  "qcom,clk-monitor-enable")) {
		priv->clk_monitor_enable = true;
		icnss_pr_dbg("CLK monitor is enabled\n");
	}

	if (priv->clk_monitor_enable) {
		ret = icnss_ext_modem_ssr_register_notifier(priv);
		if (ret)
			goto out_smmu_deinit;

	}

	spin_lock_init(&priv->event_lock);
	spin_lock_init(&priv->on_off_lock);
	mutex_init(&priv->dev_lock);
@@ -3500,7 +3590,7 @@ static int icnss_probe(struct platform_device *pdev)
	if (!priv->event_wq) {
		icnss_pr_err("Workqueue creation failed\n");
		ret = -EFAULT;
		goto out_smmu_deinit;
		goto out_unregister_ext_modem;
	}

	INIT_WORK(&priv->event_work, icnss_driver_event_work);
@@ -3533,6 +3623,8 @@ static int icnss_probe(struct platform_device *pdev)

out_destroy_wq:
	destroy_workqueue(priv->event_wq);
out_unregister_ext_modem:
	icnss_ext_modem_ssr_unregister_notifier(priv);
out_smmu_deinit:
	icnss_smmu_deinit(priv);
out:
@@ -3563,6 +3655,8 @@ static int icnss_remove(struct platform_device *pdev)
	if (penv->event_wq)
		destroy_workqueue(penv->event_wq);

	icnss_ext_modem_ssr_unregister_notifier(penv);

	icnss_hw_power_off(penv);

	icnss_assign_msa_perm_all(penv, ICNSS_MSA_PERM_HLOS_ALL);
+5 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ enum icnss_driver_state {
	ICNSS_MODE_ON,
	ICNSS_BLOCK_SHUTDOWN,
	ICNSS_PDR,
	ICNSS_CLK_UP,
};

struct ce_irq_list {
@@ -373,6 +374,10 @@ struct icnss_priv {
	struct kobject *icnss_kobject;
	atomic_t is_shutdown;
	bool is_ssr;
	bool clk_monitor_enable;
	void *ext_modem_notify_handler;
	struct notifier_block ext_modem_ssr_nb;
	struct completion clk_complete;
};

int icnss_call_driver_uevent(struct icnss_priv *priv,