[PATCH v2 1/2] soc: qcom: pmic_glink: Add RTC client support
From: Kamal Wadhwa
Date: Mon Nov 02 2026 - 17:43:35 EST
On some Qualcomm targets like Hamoa and Glymur, PMIC RTC is only reachable over
the GLINK interface, so add a new RTC auxiliary device ("rtc-glink") to let the
new RTC glink driver bind against it, mirroring the existing
altmode/UCSI/power-supply clients.
Also add pmic_glink_client_unregister() so the RTC aux client can detach from the
clients list before unregistering the RTC in order to avoid use-after-free issue
in a scenario when an alarm IRQ is received during teardown.
Enable the RTC client on Glymur and Hamoa/X1E80100 variants, as only those
currently support this RTC client from the firmware side.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Raj Aryan <raryan@xxxxxxxxxxxxxxxx>
Signed-off-by: Kamal Wadhwa <kamal.wadhwa@xxxxxxxxxxxxxxxx>
---
drivers/soc/qcom/pmic_glink.c | 43 ++++++++++++++++++++++++++++++++++++-
include/linux/soc/qcom/pmic_glink.h | 1 +
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
index 84fd0c82c0c4..8af6f4a65e61 100644
--- a/drivers/soc/qcom/pmic_glink.c
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -21,6 +21,7 @@ enum {
PMIC_GLINK_CLIENT_BATT = 0,
PMIC_GLINK_CLIENT_ALTMODE,
PMIC_GLINK_CLIENT_UCSI,
+ PMIC_GLINK_CLIENT_RTC,
};
struct pmic_glink_data {
@@ -40,6 +41,7 @@ struct pmic_glink {
struct auxiliary_device altmode_aux;
struct auxiliary_device ps_aux;
struct auxiliary_device ucsi_aux;
+ struct auxiliary_device rtc_aux;
/* serializing client_state and pdr_state updates */
struct mutex state_lock;
@@ -118,6 +120,17 @@ void pmic_glink_client_register(struct pmic_glink_client *client)
}
EXPORT_SYMBOL_GPL(pmic_glink_client_register);
+void pmic_glink_client_unregister(struct pmic_glink_client *client)
+{
+ struct pmic_glink *pg = client->pg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pg->client_lock, flags);
+ list_del_init(&client->node);
+ spin_unlock_irqrestore(&pg->client_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pmic_glink_client_unregister);
+
int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
{
struct pmic_glink *pg = client->pg;
@@ -342,6 +355,12 @@ static int pmic_glink_probe(struct platform_device *pdev)
goto out_release_altmode_aux;
}
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_RTC)) {
+ ret = pmic_glink_add_aux_device(pg, &pg->rtc_aux, "rtc-glink");
+ if (ret)
+ goto out_release_ps_aux;
+ }
+
if (pg->data->charger_pdr_service_name && pg->data->charger_pdr_service_path) {
service = pdr_add_lookup(pg->pdr, pg->data->charger_pdr_service_name,
pg->data->charger_pdr_service_path);
@@ -359,6 +378,9 @@ static int pmic_glink_probe(struct platform_device *pdev)
return 0;
out_release_aux_devices:
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_RTC))
+ pmic_glink_del_aux_device(pg, &pg->rtc_aux);
+out_release_ps_aux:
if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux);
out_release_altmode_aux:
@@ -385,11 +407,20 @@ static void pmic_glink_remove(struct platform_device *pdev)
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_RTC))
+ pmic_glink_del_aux_device(pg, &pg->rtc_aux);
guard(mutex)(&__pmic_glink_lock);
__pmic_glink = NULL;
}
+static const struct pmic_glink_data pmic_glink_glymur_data = {
+ .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
+ BIT(PMIC_GLINK_CLIENT_ALTMODE) |
+ BIT(PMIC_GLINK_CLIENT_UCSI) |
+ BIT(PMIC_GLINK_CLIENT_RTC),
+};
+
static const struct pmic_glink_data pmic_glink_adsp_data = {
.client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
BIT(PMIC_GLINK_CLIENT_ALTMODE) |
@@ -404,10 +435,20 @@ static const struct pmic_glink_data pmic_glink_soccp_data = {
BIT(PMIC_GLINK_CLIENT_UCSI),
};
+static const struct pmic_glink_data pmic_glink_x1e80100_data = {
+ .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
+ BIT(PMIC_GLINK_CLIENT_ALTMODE) |
+ BIT(PMIC_GLINK_CLIENT_UCSI) |
+ BIT(PMIC_GLINK_CLIENT_RTC),
+ .charger_pdr_service_name = "tms/servreg",
+ .charger_pdr_service_path = "msm/adsp/charger_pd",
+};
+
static const struct of_device_id pmic_glink_of_match[] = {
- { .compatible = "qcom,glymur-pmic-glink", .data = &pmic_glink_soccp_data },
+ { .compatible = "qcom,glymur-pmic-glink", .data = &pmic_glink_glymur_data },
{ .compatible = "qcom,kaanapali-pmic-glink", .data = &pmic_glink_soccp_data },
{ .compatible = "qcom,pmic-glink", .data = &pmic_glink_adsp_data },
+ { .compatible = "qcom,x1e80100-pmic-glink", .data = &pmic_glink_x1e80100_data },
{}
};
MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
diff --git a/include/linux/soc/qcom/pmic_glink.h b/include/linux/soc/qcom/pmic_glink.h
index 7cddf1027752..c78dc7a8c99e 100644
--- a/include/linux/soc/qcom/pmic_glink.h
+++ b/include/linux/soc/qcom/pmic_glink.h
@@ -29,5 +29,6 @@ struct pmic_glink_client *devm_pmic_glink_client_alloc(struct device *dev,
void (*pdr)(void *, int),
void *priv);
void pmic_glink_client_register(struct pmic_glink_client *client);
+void pmic_glink_client_unregister(struct pmic_glink_client *client);
#endif
--
2.43.0