@@ -2,6 +2,7 @@
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Linaro Ltd
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/auxiliary_bus.h>
#include <linux/cleanup.h>
@@ -9,6 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/remoteproc/qcom_rproc.h>
#include <linux/rpmsg.h>
#include <linux/slab.h>
#include <linux/soc/qcom/pdr.h>
@@ -39,10 +41,14 @@ struct pmic_glink {
struct mutex state_lock;
unsigned int client_state;
unsigned int pdr_state;
+ unsigned int ssr_state;
/* serializing clients list updates */
spinlock_t client_lock;
struct list_head clients;
+
+ struct notifier_block ssr_nb;
+ void *ssr_handle;
};
static struct pmic_glink *__pmic_glink;
@@ -205,10 +211,12 @@ static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
unsigned long flags;
if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
- if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ if ((pg->pdr_state == SERVREG_SERVICE_STATE_UP ||
+ pg->ssr_state == QCOM_SSR_AFTER_POWERUP) && pg->ept)
new_state = SERVREG_SERVICE_STATE_UP;
} else {
- if (pg->pdr_state == SERVREG_SERVICE_STATE_DOWN || !pg->ept)
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_DOWN ||
+ pg->ssr_state == QCOM_SSR_BEFORE_SHUTDOWN || !pg->ept)
new_state = SERVREG_SERVICE_STATE_DOWN;
}
@@ -231,6 +239,18 @@ static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
pmic_glink_state_notify_clients(pg);
}
+static int pmic_glink_ssr_callback(struct notifier_block *nb, unsigned long code, void *data)
+{
+ struct pmic_glink *pg = container_of(nb, struct pmic_glink, ssr_nb);
+
+ mutex_lock(&pg->state_lock);
+ pg->ssr_state = code;
+
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+ return 0;
+}
+
static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
{
struct pmic_glink *pg;
@@ -281,6 +301,7 @@ static struct rpmsg_driver pmic_glink_rpmsg_driver = {
static int pmic_glink_probe(struct platform_device *pdev)
{
const unsigned long *match_data;
+ const char *subsys_name = NULL;
struct pdr_service *service;
struct pmic_glink *pg;
int ret;
@@ -333,6 +354,22 @@ static int pmic_glink_probe(struct platform_device *pdev)
goto out_release_aux_devices;
}
+ if (device_property_present(&pdev->dev, "qcom,subsys-name")) {
+ device_property_read_string(&pdev->dev, "qcom,subsys-name", &subsys_name);
+ if (!subsys_name) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->ssr_handle),
+ "failed to read subsys_name string from dt\n");
+ goto out_release_aux_devices;
+ }
+ pg->ssr_nb.notifier_call = pmic_glink_ssr_callback;
+ pg->ssr_handle = qcom_register_ssr_notifier(subsys_name, &pg->ssr_nb);
+ if (IS_ERR(pg->ssr_handle)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->ssr_handle),
+ "failed adding ssr notifier\n");
+ goto out_release_aux_devices;
+ }
+ }
+
mutex_lock(&__pmic_glink_lock);
__pmic_glink = pg;
mutex_unlock(&__pmic_glink_lock);
@@ -360,6 +397,8 @@ static void pmic_glink_remove(struct platform_device *pdev)
pdr_handle_release(pg->pdr);
+ if (pg->ssr_handle)
+ qcom_unregister_ssr_notifier(pg->ssr_handle, &pg->ssr_nb);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux);
if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
Add support for PMIC Glink clients to receive notificiation when the subsystem goes down and comes up again. Signed-off-by: Anjelique Melendez <anjelique.melendez@oss.qualcomm.com> --- drivers/soc/qcom/pmic_glink.c | 43 +++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-)