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:
Arun Prakash 2020-03-08 14:57:28 +05:30 • committed by Gerrit - the friendly Code Review server
commit 95bf9f5f7f

View file

@ -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);