mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
soc: qcom: smp2p: Add support for suspend to disk
Add support in smp2p driver for suspend to disk feature. Handling SMEM enumeration during resume from hibernation. Change-Id: I5dd17057cc68a293a1a510ebedafc93defd8c556 Signed-off-by: Arun Prakash <app@codeaurora.org>
This commit is contained in:
parent
a2839ca38b
commit
95bf9f5f7f
1 changed files with 100 additions and 6 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015, Sony Mobile Communications AB.
|
||||
* Copyright (c) 2012-2013, 2018-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2013, 2018-2020 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
|
@ -632,7 +632,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
|
|||
goto release_mbox;
|
||||
|
||||
for_each_available_child_of_node(pdev->dev.of_node, node) {
|
||||
entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry) {
|
||||
ret = -ENOMEM;
|
||||
goto unwind_interfaces;
|
||||
|
|
@ -686,11 +686,15 @@ unreg_ws:
|
|||
wakeup_source_unregister(smp2p->ws);
|
||||
|
||||
unwind_interfaces:
|
||||
list_for_each_entry(entry, &smp2p->inbound, node)
|
||||
list_for_each_entry(entry, &smp2p->inbound, node) {
|
||||
irq_domain_remove(entry->domain);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
list_for_each_entry(entry, &smp2p->outbound, node)
|
||||
list_for_each_entry(entry, &smp2p->outbound, node) {
|
||||
qcom_smem_state_unregister(entry->state);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
smp2p->out->valid_entries = 0;
|
||||
|
||||
|
|
@ -711,11 +715,15 @@ static int qcom_smp2p_remove(struct platform_device *pdev)
|
|||
|
||||
wakeup_source_unregister(smp2p->ws);
|
||||
|
||||
list_for_each_entry(entry, &smp2p->inbound, node)
|
||||
list_for_each_entry(entry, &smp2p->inbound, node) {
|
||||
irq_domain_remove(entry->domain);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
list_for_each_entry(entry, &smp2p->outbound, node)
|
||||
list_for_each_entry(entry, &smp2p->outbound, node) {
|
||||
qcom_smem_state_unregister(entry->state);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
mbox_free_channel(smp2p->mbox_chan);
|
||||
|
||||
|
|
@ -724,6 +732,91 @@ static int qcom_smp2p_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_smp2p_restore(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct qcom_smp2p *smp2p = dev_get_drvdata(dev);
|
||||
struct smp2p_entry *entry;
|
||||
struct device_node *node;
|
||||
struct platform_device *pdev = container_of(dev, struct
|
||||
platform_device, dev);
|
||||
|
||||
ret = qcom_smp2p_alloc_outbound_item(smp2p);
|
||||
if (ret < 0)
|
||||
goto print_err;
|
||||
|
||||
for_each_available_child_of_node(pdev->dev.of_node, node) {
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry) {
|
||||
ret = -ENOMEM;
|
||||
goto print_err;
|
||||
}
|
||||
|
||||
entry->smp2p = smp2p;
|
||||
spin_lock_init(&entry->lock);
|
||||
ret = of_property_read_string(node, "qcom,entry-name",
|
||||
&entry->name);
|
||||
if (ret < 0)
|
||||
goto rel_entry;
|
||||
|
||||
if (!of_property_read_bool(node, "interrupt-controller")) {
|
||||
ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
|
||||
if (ret < 0)
|
||||
goto rel_entry;
|
||||
list_add(&entry->node, &smp2p->outbound);
|
||||
} else {
|
||||
kfree(entry);
|
||||
}
|
||||
}
|
||||
|
||||
smp2p->ws = wakeup_source_register(&pdev->dev, "smp2p");
|
||||
enable_irq_wake(smp2p->irq);
|
||||
/* Kick the outgoing edge after allocating entries */
|
||||
qcom_smp2p_kick(smp2p);
|
||||
|
||||
rel_entry:
|
||||
kfree(entry);
|
||||
|
||||
print_err:
|
||||
if (ret < 0 && ret != -EEXIST)
|
||||
dev_err(dev, "failed to alloc items ret = %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_smp2p_freeze(struct device *dev)
|
||||
{
|
||||
struct qcom_smp2p *smp2p = dev_get_drvdata(dev);
|
||||
struct smp2p_entry *entry;
|
||||
struct smp2p_entry *next_entry;
|
||||
|
||||
disable_irq_wake(smp2p->irq);
|
||||
/* Walk through the out bound list and release state and entry */
|
||||
list_for_each_entry_safe(entry, next_entry, &smp2p->outbound, node) {
|
||||
qcom_smem_state_unregister(entry->state);
|
||||
list_del(&entry->node);
|
||||
kfree(entry);
|
||||
}
|
||||
INIT_LIST_HEAD(&smp2p->outbound);
|
||||
|
||||
/* Walk through the in bound list and reset last value */
|
||||
list_for_each_entry_safe(entry, next_entry, &smp2p->inbound, node) {
|
||||
entry->last_value = 0;
|
||||
}
|
||||
/* make null to point it to valid smem item during first interrupt */
|
||||
smp2p->in = NULL;
|
||||
smp2p->valid_entries = 0;
|
||||
/* remove wakeup source */
|
||||
wakeup_source_unregister(smp2p->ws);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops qcom_smp2p_pm_ops = {
|
||||
.freeze = qcom_smp2p_freeze,
|
||||
.restore = qcom_smp2p_restore,
|
||||
.thaw = qcom_smp2p_restore,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_smp2p_of_match[] = {
|
||||
{ .compatible = "qcom,smp2p" },
|
||||
{}
|
||||
|
|
@ -736,6 +829,7 @@ static struct platform_driver qcom_smp2p_driver = {
|
|||
.driver = {
|
||||
.name = "qcom_smp2p",
|
||||
.of_match_table = qcom_smp2p_of_match,
|
||||
.pm = &qcom_smp2p_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(qcom_smp2p_driver);
|
||||
|
|
|
|||
Loading…
Reference in a new issue