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

Commit 51669ff0 authored by Chris Lew's avatar Chris Lew Committed by Gerrit - the friendly Code Review server
Browse files

soc: qcom: Add snapshot of smp2p sleepstate driver



This snapshot is taken as of msm-4.19 'commit <dac6e981b55e>
("Merge "icnss: Skip removing WLAN host driver during recovery"")'.

In addition, replace wakeup_source_trash since API is deprecated.

Change-Id: I0bd88adc9a8e604300b610d7f24dae6cd4e57281
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent a221c54d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -238,4 +238,14 @@ config QMP_DEBUGFS_CLIENT
	  to Alway On processor using QMP transport. Users can echo a message
	  into an exposed debugfs node to send to AOP. The driver expects the
	  passed in string argument to be formatted correctly for AOP to read.

config QCOM_SMP2P_SLEEPSTATE
	tristate "SMP2P Sleepstate notifier"
	depends on QCOM_SMP2P
	help
	  When this option is enabled, notifications are sent to remote procs
	  for the power state changes on the local processor. The notifications
	  are sent through the smp2p framework. This driver can also receive
	  notifications from the remote to prevent suspend on the local
	  processor.
endmenu
+1 −0
Original line number Diff line number Diff line
@@ -30,3 +30,4 @@ obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
obj-$(CONFIG_QCOM_SMP2P_SLEEPSTATE) += smp2p_sleepstate.o
+126 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
 */
#include <linux/module.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/pm_wakeup.h>

#define PROC_AWAKE_ID 12 /* 12th bit */
#define AWAKE_BIT BIT(PROC_AWAKE_ID)
static struct qcom_smem_state *state;
static struct wakeup_source notify_ws;

/**
 * sleepstate_pm_notifier() - PM notifier callback function.
 * @nb:		Pointer to the notifier block.
 * @event:	Suspend state event from PM module.
 * @unused:	Null pointer from PM module.
 *
 * This function is register as callback function to get notifications
 * from the PM module on the system suspend state.
 */
static int sleepstate_pm_notifier(struct notifier_block *nb,
				  unsigned long event, void *unused)
{
	switch (event) {
	case PM_SUSPEND_PREPARE:
		qcom_smem_state_update_bits(state, AWAKE_BIT, 0);
		break;

	case PM_POST_SUSPEND:
		qcom_smem_state_update_bits(state, AWAKE_BIT, AWAKE_BIT);
		break;
	}

	return NOTIFY_DONE;
}

static struct notifier_block sleepstate_pm_nb = {
	.notifier_call = sleepstate_pm_notifier,
	.priority = INT_MAX,
};

static irqreturn_t smp2p_sleepstate_handler(int irq, void *ctxt)
{
	__pm_wakeup_event(&notify_ws, 200);
	return IRQ_HANDLED;
}

static int smp2p_sleepstate_probe(struct platform_device *pdev)
{
	int ret;
	int irq;
	struct device *dev = &pdev->dev;
	struct device_node *node = dev->of_node;

	state = qcom_smem_state_get(&pdev->dev, 0, &ret);
	if (IS_ERR(state))
		return PTR_ERR(state);
	qcom_smem_state_update_bits(state, AWAKE_BIT, AWAKE_BIT);

	ret = register_pm_notifier(&sleepstate_pm_nb);
	if (ret) {
		dev_err(dev, "%s: power state notif error %d\n", __func__, ret);
		return ret;
	}
	wakeup_source_init(&notify_ws, "smp2p-sleepstate");

	irq = of_irq_get_byname(node, "smp2p-sleepstate-in");
	if (irq <= 0) {
		dev_err(dev, "failed to get irq for smp2p_sleep_state\n");
		ret = -EPROBE_DEFER;
		goto err;
	}
	dev_dbg(dev, "got smp2p-sleepstate-in irq %d\n", irq);
	ret = devm_request_threaded_irq(dev, irq, NULL,
					smp2p_sleepstate_handler,
					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
					"smp2p_sleepstate", dev);
	if (ret) {
		dev_err(dev, "fail to register smp2p threaded_irq=%d\n", irq);
		goto err;
	}
	return 0;
err:
	wakeup_source_remove(&notify_ws);
	__pm_relax(&notify_ws);
	unregister_pm_notifier(&sleepstate_pm_nb);
	return ret;
}

static const struct of_device_id smp2p_slst_match_table[] = {
	{.compatible = "qcom,smp2p-sleepstate"},
	{},
};

static struct platform_driver smp2p_sleepstate_driver = {
	.probe = smp2p_sleepstate_probe,
	.driver = {
		.name = "smp2p_sleepstate",
		.of_match_table = smp2p_slst_match_table,
	},
};

static int __init smp2p_sleepstate_init(void)
{
	int ret;

	ret = platform_driver_register(&smp2p_sleepstate_driver);
	if (ret) {
		pr_err("%s: register failed %d\n", __func__, ret);
		return ret;
	}

	return 0;
}

module_init(smp2p_sleepstate_init);
MODULE_DESCRIPTION("SMP2P SLEEP STATE");
MODULE_LICENSE("GPL v2");