soc: qcom: Add snapshot of smp2p sleepstate driver

This snapshot is taken as of msm-5.10 'commit <9650dfff5aba>
("misc: hdcp: add API to talk to OPS service")'.

Change-Id: I974c616cc11a36db4ecda2c9e10a1fb25a92a597
Signed-off-by: Chris Lew <quic_clew@quicinc.com>
This commit is contained in:
Chris Lew 2022-06-27 13:17:35 -07:00
parent e5dd61f069
commit 7ea15f7955
3 changed files with 143 additions and 0 deletions

View File

@ -226,6 +226,16 @@ config QCOM_SMSM
Say yes here to support the Qualcomm Shared Memory State Machine.
The state machine is represented by bits in shared memory.
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.
config QTI_PMIC_GLINK
tristate "Enable support for PMIC GLINK"
depends on RPMSG

View File

@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_SMP2P_SLEEPSTATE) += smp2p_sleepstate.o
obj-$(CONFIG_QTI_PMIC_GLINK) += pmic_glink.o
obj-$(CONFIG_QTI_BATTERY_GLINK_DEBUG) += qti_battery_debug.o
obj-$(CONFIG_QTI_CHARGER_ULOG_GLINK) += charger-ulog-glink.o

View File

@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014-2022 Qualcomm Innovation Center, Inc. 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;
}
notify_ws = wakeup_source_register(&pdev->dev, "smp2p-sleepstate");
if (!notify_ws) {
return -ENOMEM;
goto err_ws;
}
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_unregister(notify_ws);
__pm_relax(notify_ws);
err_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");