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

Commit 29731607 authored by Chris Lew's avatar Chris Lew
Browse files

soc: qcom: Add snapshot for smp2p sleepstate driver



This snapshot is taken as of msm-4.14 'commit <5043ac1ca6a6>
("Merge "drivers: mailbox: rpmh: Use high priority tasklet"")'.

In addition change copyrights to SPDX format and fix init error
handling and prints.

Change-Id: I56febbc674ccaafbb20fc0837ffd193c99ab47f2
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent b810f6d4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -595,6 +595,16 @@ config QCOM_GLINK_PKT
	  This enable the userspace clients to read and write to
	  some glink packets channel.

config QCOM_SMP2P_SLEEPSTATE
	bool "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 QCOM_QDSS_BRIDGE
	bool "Configure bridge driver for QTI/Qualcomm Technologies, Inc. MDM"
	depends on MHI_BUS
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ obj-$(CONFIG_QCOM_BUS_SCALING) += msm_bus/
obj-$(CONFIG_QCOM_FSA4480_I2C) += fsa4480-i2c.o
obj-$(CONFIG_QCOM_GLINK) += glink_probe.o
obj-$(CONFIG_QCOM_GLINK_PKT) += glink_pkt.o
obj-$(CONFIG_QCOM_SMP2P_SLEEPSTATE) += smp2p_sleepstate.o
obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o
obj-$(CONFIG_MSM_QBT_HANDLER) += qbt_handler.o
obj-$(CONFIG_QSEE_IPC_IRQ) += qsee_ipc_irq.o
+125 −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_trash(&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");